Fuzzball v4.4.0 release notes
Fuzzball v4.4.0 is a feature release. The in-product node health model is replaced by a bundled Prometheus monitoring stack. This new stack can place holds on nodes to cordon, evict or deprovision based on configured policy. Workflow stages can now be retried when they lose their node or exit with a designated code, and later workflow jobs can run based on a dependency fail state. Workflows can build their own container images, and service endpoints can outlive the workflow that serves them.
Substrate now converts images to EROFS on compute nodes at runtime, adding support for layered images and UID/GID.
v4.4.0 rolls up v4.3.1, so these notes are complete for anyone upgrading
directly from v4.3.0; items marked (also in v4.3.1) already shipped there.
Upgrade notes.
- Compute nodes need fuzzball-substrate 2.7.0 or newer. A node whose
orchestrate extension predates EROFS images is cordoned with a
provisionerhold until it is upgraded, so update Orchestrate and the CLI before the compute nodes. A node withhealth.disabled: trueis never held: cordon it before updating Orchestrate. Image URIs must now usedocker://,oras://,fuzzball://orfb://; other schemes and bare references are rejected at submission.image.cacheWriteBacknow defaults tofalse. - The bundled monitoring stack is deployed by default. Set
monitoring.enabled: falsein the FuzzballOrchestrate resource before upgrading to keep it off. It no longer installs prometheus-operator CRDs, a node-exporter DaemonSet, kube-state-metrics or a pushgateway, and no longer exposes Grafana through a catch-all ingress. - Compute nodes serve metrics unauthenticated on every interface:
fuzzball_node_*on port 9101 and a bundled node_exporter on port 9100. Sethealth.metrics-addressin the substrate configuration to narrow them, orhealth.metrics-disabledto turn both off. - A cordoned node now reports
Readyand carries acordonhold.NODE_STATUS_CORDONEDis no longer emitted, and the node health model -- reliability score,DEGRADEDstate, policy engine and automated replacement -- is retired. RetirednodeHealthkeys are ignored with a warning.fuzzball node deprovisionnow waits for the node to empty;--forcekeeps the old immediate teardown. policy.restartis deprecated in favor ofpolicy.retry.on, and setting both on one step is an error. A job with its ownpolicynow inherits the default retry declaration unless it declaresretryorrestartitself, so such jobs may now be rerun on another node.- Endpoints. Path endpoint URLs are now
/endpoints/{endpoint-id}; URLs in the old/endpoints/accounts/...form no longer resolve. Endpoint protocols are limited tohttpandhttps. The proxy now passes a service's ownAuthorizationheader through, so send the Fuzzball token inFB-Authorization. - Workflow image builds are on by default, but a FuzzballOrchestrate
resource created or edited under v4.3 keeps the
enableWorkflowImageBuilds: falseit stored; set it totrueto allow builds, or usefuzzball cluster docker-compose update --sync-filesin a Docker Compose environment. A build runs the workflow'spostscript as root in a confined container, so set the field tofalse, orFUZZBALL_ENABLE_WORKFLOW_IMAGE_BUILDS=falseon Compose, where workflow authors are not trusted with that. - Workflow events report node evictions as
evictedinstead ofpreempted, which now means priority preemption only. - New passwords must be at least 12 characters with mixed case, a digit and
a special character, and must not contain
fuzzball, the username or email. Existing passwords keep working until changed. - Keycloak pods now request and limit 3Gi of memory. Applying this restarts Keycloak, and single-replica deployments lose logins in progress. Reload open Web UI tabs after upgrading, since the access-token cookie is now HttpOnly.
New Features
Node Holds
Cordoning a node used to replace its status with CORDONED, so the status could
no longer show whether the node itself was healthy. A cordon, evict or
deprovision is now a hold kept alongside the status, recording who placed it
and why, and a node can carry any number of them.
- Three effects.
cordonplaces no new work on the node.evictalso takes off what is running: a step declaringpolicy.retry.on: nodeis requeued elsewhere, and anything else fails with the hold's reason.deprovisionplaces no new work and tears the node down once it is empty. - Multiple sources for holds. A hold is attributed to
admin,monitoringorprovisionerfrom the caller's identity.fuzzball node uncordonreleases admin cordon holds only, so it never clears evidence monitoring gathered or a hold the provisioner placed. - CLI.
fuzzball node hold list|add|releaseprovides a general-purpose interface to holds, in addition tofuzzball node cordon|evict|deprovision.cordonanduncordonnow accept several nodes simultaneously,cordonaccepts a--reasonparameter, anddeprovisiongains--evict,--forceand--all.fuzzball node removenow clears an offline node's record and releases its holds, so retired hardware can be removed from the node list. - Seeing holds.
fuzzball node listgains a HOLDS column andfuzzball node showlists each hold with its effect, source, reason and when it was placed. The Web UI shows holds as sortable, filterable node list columns, adds cordon, uncordon and evict actions and the node event log to node details, and replaces the dashboard health rollup with per-cluster counts by hold state. Node events now record provisioning and each rank's allocations. - A site-owned node that goes offline keeps its admin holds and unreleased monitoring holds, so a node held for repair returns still held.
Node Health Monitoring
The bundled monitoring stack now watches compute nodes and acts on what it finds, through Prometheus rules rather than logic internal to Fuzzball.
- Alerts that place holds. Seven node-health rules ship with the stack.
FuzzballNodeAttributedJobFailuresandFuzzballNodeMemoryErrorscordon a node andFuzzballNodeGPUUncorrectableECCevicts one, while still notifying the site's own receiver. Holds arrive through an Alertmanager webhook receiver that authenticates with mTLS on its own port, and the operator issues client certificates to bundled and external Alertmanagers. Thefb_actionandfb_releasealert labels are documented for sites writing their own rules. - A ceiling on automatic holds. Monitoring holds may cover at most
nodeHealth.maxMonitoringHeldPercent(default 20%) of a provisioner definition's nodes; past that, holds are refused andFuzzballNodeHoldCeilingReachedfires. - Node metrics. Compute nodes serve
fuzzball_node_*metrics, including disk I/O errors, read-only disks, memory errors and failed device plugins, and run a bundled node_exporter. A failed device plugin is also reported as adevice_plugin_failedscheduling reason and infuzzball node show. - Reaching them. A Prometheus service discovery endpoint at
/v4/nodes/-/sd_configtracks dynamically provisioned nodes, and a/v4/metrics/nodeproxy relays scrapes over each node's existing connection for clusters that cannot reach node IPs; it requires the newscrape_node_metricspermission. ThenodeMetricscentral config block andmonitoring.nodeMetricsModechoose between them.fuzzball context tokenprints the active access token for a scrape config's bearer header. - Dashboards. Fleet Health, Node Health and Node Resources Grafana
dashboards ship with the stack, the last with LSF
lsload-style load indices. The rules, routes and dashboards are also published for import by sites running their own monitoring. - Prometheus, Alertmanager and Grafana values can be overridden per component
with
valuesOverride.fuzzball_scheduler_node_attributed_job_failuresis deprecated in favor offuzzball_node_attributed_job_failures; both are published.
Retrying Workflow Steps
policy.retry was accepted and ignored in previous releases. It now decides
whether a step may run again, and from the beginning -- Fuzzball does not
checkpoint, so declare it only for work that is safe to repeat.
policy:
retry:
on: [node, 75]
attempts: 3
onis required. Without it nothing is retried.nodecovers an evict hold and a node going offline alike. Exit codes 1-255 retry a job that exits with a listed code; 130 and 143 are not accepted.attemptsis one budget shared by every cause. Node retries are also capped by the cluster-widenodeHealth.maxEvictionRestarts(default 3), and the lower of the two applies.policy.restartstill works:on-node-faultis treated asretry: {on: node}. Declaring nothing leaves a step running through a routine drain and fails it if the node is lost.- Workflow events gain
retriedandretries_exhausted, and failure messages name the field to set. The Web UI workflow editor can set a job's retry policy.
On-Failure Dependencies
A job or service can now run only when another fails, for cleanup or
notification steps. Declare it with status: FAILED in depends-on. When the
dependency succeeds instead, the dependent is skipped and shown as Canceled.
Single-node jobs and services are supported, and the dependent does not run
when the dependency is canceled or preempted.
Persistent Service Endpoints
An endpoint can now outlive the workflow serving it, so a URL handed out once
keeps working across redeployments. fuzzball endpoint create NAME creates
one, and a workflow attaches by declaring an endpoint of that name with
persistent: true. A new workflow claiming an endpoint in use takes it over,
canceling the previous one either at submission or once the new service is
ready (--strategy start|ready). Endpoint commands move to
fuzzball endpoint, and fuzzball workflow endpoints is deprecated. Endpoint
names use lowercase letters, digits, - and _.
Workflows can read their persistent endpoints' URLs from new
FB_SERVICE_<SERVICE>_ENDPOINT_* environment variables, and the Web UI
Connect button becomes a menu when a workflow exposes more than one endpoint.
Building Images in a Workflow
A workflow can now build the container images its jobs need, instead of
relying on an image built and pushed to a registry beforehand. Images are
declared in a top-level images: section and built on a compute node as
stages of the workflow.
images:
tools.sif:
from:
uri: docker://rockylinux/rockylinux:9
post: |
dnf install -y jq ripgrep
jobs:
analyze:
image:
uri: fuzzball://user/tools.sif
- Definitions. A build starts
froma registry or object cache image, writes anyfilesinto it, then runs thepostscript as root inside a confined container. The result is stored in the object cache withscope:userorgroup, with an optionalttl. - Ordering is inferred. A job waits for the images it uses, an image built
fromanother in the same workflow is built after it, and circular definitions are rejected at submission. An unchanged definition is served from the cache rather than rebuilt. - Watching a build. Each step of a build is reported as a workflow event,
and the
postscript's output is the log of the image's stage in the CLI and the Web UI.
Distributed GPU Jobs
Fuzzball v4.4 improves support for multi-GPU jobs, particularly in support of AI training workloads.
- Multi-node NVLink. With fuzzball-substrate-nvidia-gpu-plugin 0.0.20 or
later, multinode jobs are placed inside one NVLink domain when one has
enough free nodes, and can request an IMEX channel with
NVIDIA_IMEX_CHANNELS. - Pinned memory. Job containers set
RLIMIT_MEMLOCKto the job's memory allocation, so NCCL, RDMA and DPDK can lock the memory they need. A job that requests no memory keeps the default. - AWS. The provisioner selects an NVIDIA Fabric Manager AMI for
EFA-equipped NVLink instance types (
p4d,p4de,p5,p5e,p5en). - A new guide covers distributed training with NCCL and
torchrun.
Enhancements
Scheduling Diagnostics
fuzzball workflow whytakes a workflow id on its own and explains every stage still waiting, infuzzball workflow describeorder;--allincludes finished stages.- Placement attempts are reported.
INSUFFICIENT_RESOURCESandBACKFILL_NO_FITnow say how many nodes were looked at, why each group was passed over, and what fell short on the roomiest node. A newNODE_ANNOTATIONS_MISMATCHreason covers nodes with capacity but without the requested annotations. - Submission explains rejections. A job no node of a definition could hold even when idle is rejected, naming the request and the largest node, rather than queued forever, and the error lists why each definition was rejected.
scheduling_blockedevents report, once per cause, a stage that too few nodes could hold, andfuzzball workflow eventsshows their detail.stage_failedandcontainer_exitedevents carry the container exit code.
Images
- EROFS. Container images are converted to EROFS on compute nodes.
- Object cache uploads are visible. Uploading a pulled image to the object cache is reported as stage events with progress, retried, and abandoned when it stalls, without failing the stage.
Authentication and Web Security
- Password policy and lockout. New passwords must be at least 12 characters
with mixed case, a digit and a special character, and must not contain
fuzzball, the username or email. These rules apply to Fuzzball Local and to Fuzzball-managed Keycloak realms that have no password policy of their own, andAddOrganizationMemberrequires a password. Local password login, and sign-in to newly created organization Keycloak realms, locks an account for 15 minutes after 5 failed attempts. - Security headers. HTTPS responses from the Web UI and REST API carry Strict-Transport-Security, and the Web UI sends Content-Security-Policy and X-Content-Type-Options.
- Public endpoints identify organization members who present a Fuzzball token, let them wake an idle pool, and no longer forward that token to the service.
Web UI
- Stage details show the node a job or service ran on, workflows show the set of nodes used, and pending jobs show an estimated backfill start time.
- The workflows list gains a sortable Started column, and job logs gain inline text search.
- Node-local persistent volumes show their holding node, and storage provisioner group fields offer the organization's groups.
- Object preview distinguishes too-large, unsupported and error states, with a "Preview anyway" action for large files.
- The workflows list defaults to Submitted, newest first; storage lists page through results; catalog search matches descriptions; and read-only templates offer Copy and Edit (also in v4.3.1).
Deployment and Infrastructure
- New resource fields.
spec.image.pullPolicylets pods restart from cached images while the registry is unreachable.spec.clusterDomainsupports clusters whose DNS domain is notcluster.local, and the operator detects it otherwise.spec.fuzzball.jetstream.externalService.typeacceptsLoadBalancerfor Substrate hosts that cannot reach node IPs.spec.keycloak.create.resourcessizes Keycloak. - Let's Encrypt staging.
fuzzball cluster <cloud> deployandupdateaccept--lets-encrypt-issuer;updatekeeps the deployed issuer. - Docker Compose accepts a
PULL_POLICYoverride for offline restarts. - The macOS CLI is signed and notarized, so it runs without removing the quarantine attribute.
- Workflow tokens can read secret data, so controller-submitted child workflows
resolve
secret://references; creating or modifying secrets is refused. - Provisioner definitions using the deprecated
unsharedPathare rewritten tolocalon upgrade, with no change in behavior. fuzzball-admin audit listpages, orders and filters events (also in v4.3.1).
Fixes
Security
- Fixed an issue where workflow catalog applications and sources from one group or organization could be listed, rendered or read by users in another. A catalog source's access token is now returned only by the admin API.
- Fixed an issue where volume get, update, status and delete by ID could reach volumes in other organizations.
- Fixed Filestore and hostpath isolation between organizations.
- Fixed the operator's status messages publishing credentials in many error shapes, including nested keys, one-line YAML, request dumps and unencoded Basic passwords.
- Fixed workflow validation errors echoing secret-bearing field values.
- Fixed an issue where the Web UI access-token cookie was readable from JavaScript.
- Fixed provisioned nodes exposing credentials in cloud-init and console logs,
fuzzball debug dumpbundles containing ConfigMap credentials, and the instance metadata guard staying off after a failed startup check (also in v4.3.1).
Workflows
- Fixed task-array workflows hanging, and ignoring cancel, when one task exited non-zero while siblings were still running.
- Fixed jobs staying STARTED and holding capacity after their node lost their lease, such as after a substrate restart. They now fail as stopped responding.
- Fixed single-architecture images failing at pull on mixed-architecture clusters. Jobs and services are now pinned to the architecture an image tag names.
- Fixed
fuzzball workflow start,validate,scoreandupgradeprocessing{{ ... }}in workflow files as a template; files are sent unchanged. - Fixed invalid definitions and mounts of undeclared volumes failing with an internal error instead of InvalidArgument.
- Fixed upgrades of v1 workflows silently resolving nameless persistent
references such as
volume://user/persistent;startandupgradenow warn. - Fixed
fuzzball workflow validaterejecting v1 Fuzzfiles thatstartaccepts, andworkflow upgradeleaving simple v1 files unconverted. Validate now upgrades v1 the way a submission does. - Fixed workflows that set
policyon a service being rejected. The field is accepted again and ignored with a warning, since services do not support execution policies. - Fixed the endpoint proxy answering 404 "Endpoint not found" whenever the endpoint lookup failed, including during an Orchestrate upgrade before the workflow database was migrated. Other lookup failures now return 503, and the database is migrated before the services start.
- Fixed ephemeral volumes binding to a provisioner whose segment had no ready nodes; auto-selected volumes now pick the first eligible provisioner by name.
- Fixed volume egress racing services, Open MPI multinode jobs hanging on the node-local bridge, and services that exited nonzero ending FINISHED (also in v4.3.1).
Scheduler and Provisioner
- Fixed dynamic nodes running forever after their workflow ended, and AWS, GCP and OCI nodes losing their provisioner annotations on substrate restart.
- Fixed a torn-down node being torn down again on every idle sweep, which could terminate a new instance that reused its address.
- Fixed provisioned instances that never joined the cluster being left running. They are now deleted 15 minutes after the registration deadline.
- Fixed workflows failing with a
provision_instances_instance_id_keyduplicate key error when a new instance reused an earlier one's name. - Fixed autoscaled services being rejected, or scale-ups reported as capacity-exhausted, while a pool's capacity was unknown.
- Fixed services declaring the same host port being placed on one node.
- Fixed a newly registered node not waking the scheduler, leaving work waiting up to 60 seconds.
- Fixed node listing failing on nodes running a peer rank of a multinode job.
- Fixed a job that stopped responding counting against its node after it was stopped, finished or being moved.
- Fixed multi-cloud compute grants being ignored, and new organizations not getting a default storage provisioner.
- Fixed appending provisioner definitions through the admin API failing because Orchestrate had not opened the central configuration store.
- Fixed bandwidth metering being disabled on every compute node because its eBPF programs failed to load.
- Fixed the orchestrate extension crashing on hosts whose
/etc/os-releasecontains a blank line, such as Oracle Linux 9. - Fixed
maxNodesbeing exceeded by bursts, provisioned nodes ignoring the configured shared filesystem mount point and writing unvalidated fstab entries, AWS nodes not trusting the cluster CA, and heartbeating nodes being deregistered (also in v4.3.1).
Deployment
- Fixed FuzzballOrchestrate reporting Ready while a Deployment was still rolling out; a stalled rollout now sets Degraded.
- Fixed Orchestrate and Federate reporting Updating indefinitely after an early reconcile failure, and Degraded carrying only a generic message.
- Fixed operator upgrades stalling when the audit or substrate-bridge pod moved to a node that could not attach its ReadWriteOnce volume.
- Fixed the operator downloading Pulumi providers after every restart, which blocked reconciles without internet access, and being OOMKilled; its default memory limit is now 4Gi.
- Fixed the operator hanging when an external CA ClusterIssuer's secret was
outside the cert-manager namespace; set
tls.certManager.clusterResourceNamespace. - Fixed custom-named ingress-nginx classes missing gRPC and TLS annotations;
set
ingress.external.controller. - Fixed a 502 when signing in through an external nginx ingress.
- Fixed CLI and UI login through a bare NodePort ingress with the new
spec.ingress.publicPort; setting it changes the token issuer, so users must log in again. - Fixed Fuzzball pods failing admission on clusters that enforce Pod Security restricted by default.
- Fixed air-gapped installs failing to pull the database reloader image.
- Fixed a federate in-place PostgreSQL upgrade deadlocking when Keycloak was
unavailable, and FuzzballFederate ignoring
nodeSelector, tolerations and affinity for thefuzzball-adminpod. - Fixed in-cluster Substrate failing to reach JetStream and DNS over NodePort on a node running no JetStream or substrate-bridge pod.
- Fixed Docker Compose sizing Keycloak's heap from host RAM; it is now capped at 1GiB, in a 1.75GiB container.
- Fixed JetStream connections and buckets not surviving outages, the pre-upgrade database restore reporting failures as success, internal tokens expiring after a host resumed from suspend, and Compose TLS, DNS and sign-in failures (also in v4.3.1).
Web UI, Catalog and CLI
- Fixed the Workflow Editor dropping a workflow's preemptible, retry and restart
settings when loaded, edited or started. It also keeps the
images:section intact. - Fixed the Workflow Editor leaving uploaded, pasted and v1-syntax workflows unconverted. It now upgrades them to v4 through the server and flags mounts of undefined volumes.
- Fixed an issue where a workflow opened in the Workflow Editor could not be
started when its definition was not
version: v4, such as one submitted from the CLI as a v1 file. Start failed withcannot unmarshal !!str ... into int64because the YAML carried a quotedcache-ttl. The editor now writescache-ttlas an integer and leaves an unset one out. - Fixed unchecking Follow in a stage's log pane not stopping auto-scrolling while logs streamed.
- Fixed live log streams failing permanently after idle disconnects, expired sessions leaving the page broken, and docs preview links opening the landing page.
- Fixed rerunning a workflow appending a
(#N)suffix to its name. - Fixed existing organization members getting an invite email on password reset.
- Fixed organization owners not seeing the account-owner workflow summary.
- Fixed the storage provisioner form showing "undefined" and losing fixed-choice settings on edit.
- Fixed monospace rendering in workflow stage logs.
- Fixed catalog sync ignoring the documented
key_artfield. - Fixed editing a catalog entry clearing its tags, key art, featured flag and
provider, saving a template in the editor removing its enum options, and
workflow catalog updateoverwriting the name and category when-nor-gwas omitted. - Fixed federate clusters labeling official catalog apps as External and
rejecting the official catalog when
allowedHostsis set. - Fixed the password change link from
fuzzball context update-user --new-passwordfailing with "Invalid parameter: redirect_uri" on deployments such as Docker Compose. - Fixed the MCP catalog tools reporting the whole catalog unreachable when a
listing failed, and
group_listmisdescribing its default scope. - Fixed the MCP
workflow_validatetool reporting a workflow valid when the server rejected it. It now returnsvalid: falsewith the server's reason, warns when the server could not be asked, and acceptscluster_id. - Fixed
fuzzball context validate's volume ingress and inter-job DNS checks failing on cloud deployments: the ingress check asked for a provisioner nameddefault, and the DNS check tried only once before the job it called was ready. - Fixed the dashboard showing 0 running workflows, dates ignoring the browser
locale, missing image edges in the workflow graph, and
fuzzball cluster config get -o jsonprinting YAML (also in v4.3.1).