fog-agent updates: modes, update rings, a minimum version, and a server copy of each release - #1759
Merged
Merged
Conversation
…er copy of each release
FOG_AGENT_UPDATE_MODE is Off, Pinned or Latest. Before this, an empty
FOG_AGENT_DESIRED_VERSION meant off, and no setting followed the newest
release. Schema 438 sets Pinned on a server that named a version and Off
on every other server, so an upgrade starts no updates.
The server resolves Latest, so the agent still receives an exact version.
Update rings are delays in days (FOG_AGENT_UPDATE_RINGS, default 0,3,7),
counted from when this server first saw a release. The ring is a host
column, set on the host form or by mass edit. A blank ring is the last
ring. A host never moves below the version it runs, unless that version
left the manifest.
FOG_AGENT_MIN_VERSION is a floor in every mode. It raises a pin, an
override or a ring delay below it, and it raises a host below it even in
Off mode. The settings page and the host form refuse a pin or an
override below it.
FOGAgentReleaseSync downloads the signed manifest and the files enrolled
hosts need into /opt/fog/agent/versions/<version>/, and keeps the newest
FOG_AGENT_KEEP_VERSIONS (default 3) plus every version a host needs. The
update block carries the manifest, the signature and a payload id, and
GET /agent/v1/payload/update/{id} serves the file. Every agent still
verifies the signature and the hash itself.
Every setting only fog-agent reads moves to the FOG Agent category.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Sbto9eLVhLiCPyGERUZ27
…ate-rings # Conflicts: # tests/mass-edit-form.test.php
…ipts executable The suite on the merged tree failed two checks: - psr4-layout: Releases extends FOGBase, so no rule places it. It goes in TABLE under Agent, beside Update, which it serves. - alpine-openrc-services W: installInitScript copies with cp -f, which keeps the source mode. The new init scripts were committed 0644, so OpenRC could not run the Alpine one. All three are now 0755. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Sbto9eLVhLiCPyGERUZ27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fog-agent updates get three modes, update rings, a minimum version, and a server-side copy of every release. Agents take the manifest and the file from this server instead of from GitHub.
This is the server half of design 0015 as changed on 2026-09-11. The agent half is FOGProject/fog-agent#17.
What changed
Modes (
FOG_AGENT_UPDATE_MODE). Off, Pinned or Latest. Before this, an emptyFOG_AGENT_DESIRED_VERSIONmeant off, and there was no way to follow the newest release. Schema 438 sets Pinned on a server that already named a version and Off on every other server, so an upgrade starts no updates. A host's own Desired Agent Version still wins over every mode.Latest is resolved on the server. The agent still receives an exact version, so agents already in the field follow Latest with no change. The newest release is chosen from the signed manifest that the new daemon downloads. A host is never moved below the version it runs, unless that version was withdrawn from the manifest.
Update rings (
FOG_AGENT_UPDATE_RINGS, hostagentUpdateRing). The rings are delays in days, default0,3,7, counted from when this server first saw a release. The ring is a host column, set on the host form or by mass edit (ADR 0038 decision 1). A blank ring is the last ring, so a new host is never among the first to update.Minimum version (
FOG_AGENT_MIN_VERSION). It is a floor in every mode. A pinned version, a host override or a ring delay below it is raised to it. A host that runs a release below it is raised to it even in Off mode. A lab build (0.1.7-2-gabc) is left alone, because PHP'sversion_compare()and the agent's semver order it differently. The settings page and the host form refuse to save a pin or an override below the minimum. The minimum must be a version in the manifest once one has synced.Server copy of releases (
FOGAgentReleaseSync,agentReleaseArtifacts). A new non-root daemon downloads the manifest and its signature. It indexes every file and downloads the files that enrolled hosts need into/opt/fog/agent/versions/<version>/. It keeps each version a host runs or is told to run, plus the newestFOG_AGENT_KEEP_VERSIONS(default 3). It stays idle while the mode is Off, no host has an override, and no minimum is set. The update block now carriesmanifest,signatureandartifact.GET /agent/v1/payload/update/{id}serves only the file of the version the host is told to run.The server does not verify the signature. Every agent verifies the signature and each file's hash against the root compiled into it. The server checks each file's size and sha256 before it records the file, so it does not serve junk.
Settings grouping. Every setting that only fog-agent reads moves to FOG Agent. Directory placement moves to FOG Agent - Directory Placement.
FOG_GRACE_TIMEOUTandFOG_TASK_FORCE_REBOOTare read by both clients. They stay where they are, and their text says the agent reads them. One setting cannot render in two panels, because the settings form names each input by the setting, and the second copy overwrites the edit.Corrected text.
FOG_AGENT_UPDATE_MANIFEST_URLsaid a mirror serves a site with no internet access. It did not: each file comes from the address inside the signed manifest.Verification
Lab run on the 1.6 lab server, against the real signed manifest at fogproject.org. The lab VM (host 239) ran a fog-agent#17 build stamped
v0.1.7-2-gf344ed3.FOG_AGENT_*settings moved to FOG Agent, andFOG_AGENT_UPDATE_MODEcame outoffbecause the pinned version was empty.5b257450…), and the web user owns every file.manifest,signatureandartifact: 43. nginx loggedGET /fog/agent/v1/payload/update/43 200 7032994, which is the manifest's size for that file. The agent journal loggedupdate: applied (v0.1.7-2-gf344ed3 -> 0.1.7, restarting), then probation, then0.1.7 polled successfully. The VM's binary now hashes to the manifest's sha256, and host 239 showsok.FOGAgentReleaseSync, run as the web user for one pass, loggedAgent releases are current (48 files in the manifest).Not run on the lab: the settings-page and host-form refusals, and the mass-edit ring picker. The browser session sits behind OIDC sign-in. The pure checks cover their logic, and phpstan covers the pages.
tests/agent-update-rings.test.php: 45 checks. Each of 16 defects was put back one at a time, and the test went red each time.sh tests/run-all.sh: 357 passed, 0 failed before the merge of working-1.6 (Let mass edit set the rest of a host's General tab #1758). CI runs the merged tree.$set might not be definedin the new settings cases, fixed at the cause rather than baselined.🤖 Generated with Claude Code
https://claude.ai/code/session_013Sbto9eLVhLiCPyGERUZ27