Skip to content

Upgrade installations with the installer - #710

Merged
SaladDay merged 3 commits into
mainfrom
upgrade-installations-with-the-installer
Oct 15, 2026
Merged

SaladDay merged 3 commits into
mainfrom
upgrade-installations-with-the-installer

Conversation

@SaladDay

@SaladDay SaladDay commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

What

Lane B of the in-place upgrade plan: the installers upgrade an existing installation to their own release.

oac install (services/core/cmd/oac)

  • New --upgrade flag. An existing directory's release is read from the OAC_REVISION: line of its compose.yaml.
    • Same release: resume, with or without --upgrade. Saved settings, missing-image pulls, then the start oac apply uses (check-config, then up).
    • Another release without --upgrade: refused after the read-only Docker checks, with no Compose call: This installation runs release <old12>; this installer is <new12>. Back up the installation (Upgrade in the operations guide), then rerun with --upgrade.
    • Another release with --upgrade:
      1. Stage compose.yaml (verified against compose-sha256sums.txt in memory) and oac in <dir>.staging.
      2. Require the staged OAC_REVISION to equal buildRevision.
      3. Pull the images.
      4. Run run --rm --no-deps --entrypoint /usr/local/bin/oac-core core check-config, then run --rm --no-deps init, with -f <stage>/compose.yaml [-f <dir>/compose.override.yaml] --project-directory <dir>.
      5. Rename oac, then compose.yaml.
      6. Start.
    • A failed check returns Upgrade stopped; the running services are unchanged: <docker output>.
    • After a successful start, one more line: Upgraded from <old12> to <new12>. Settings → Sandbox and scheduling offers this release's Runtime; sandboxes keep their current Runtime until you apply it.
  • Every start uses up -d --wait --wait-timeout 180 --pull never --remove-orphans: fresh installs, upgrades, resumes and oac apply. --no-recreate is gone. Resume calls apply itself, so the two share one start step. apply now keeps the check-config output in its error.
  • compose-sha256sums.txt is verified in memory and never written. An upgrade deletes the copy left by an earlier release. The persisted-sums check (verifyCompose) and its test are removed.
  • A fresh install also requires the staged OAC_REVISION to equal buildRevision, because it shares the staging code. The port preflight still runs only for new directories.

install.py (deploy/install-source.py)

  • --upgrade, under fcntl.flock on <dir>.lock, the same lock as runtimefs.LockDirectory. Fresh installs take it too.
  • Steps:
    1. Load the images.
    2. node_payload.publish the release beside the earlier ones.
    3. Stage compose.yaml, the override and oac. The override keeps the operator's JSON and replaces only the four services' image and Web's /node-payload bind.
    4. Run the same two checks.
    5. node_payload.activate.
    6. Rename oac, the override, then compose.yaml.
    7. Start.
  • Refusal of another release without --upgrade: This installation runs release <old12>; this bundle is <new12>. Back up the installation (Upgrade in the operations guide), then rerun with --upgrade.
  • --public-url is required only for a new directory.

deploy/node/node_payload.py

  • prepare_node_payload is split into publish(destination, source), which leaves the pointer alone, and activate(destination, revision).
  • The "Installed node payload differs" refusal of an existing pointer is removed. activate writes the pointer 0644, because Web reads it as another user.

Docs: deploy/README.md (installation lifecycle) and the node_payload.py row in deploy/node/README.md.

Review

Batched blind review over #710 and #711. Fixed in the third commit:

  • Resume and oac apply run init before check-config (apply() in main.go; install.py reverses the two checks on its own release). A fresh install whose first up stopped before init finished could not be resumed, because check-config needs the secrets init creates.
  • A failed check says Upgrade stopped; the running services are unchanged, which stays true if init fails after its receipt write.
  • install.py resumes its own release without --upgrade (This installation runs release <old12>; this bundle is <new12>. … rerun with --upgrade. otherwise), writes compose.override.yaml 0600 and removes .staging-* left by a killed run.
  • Upgrades pull only missing images, like resume.
  • A leftover compose-sha256sums.txt is removed on every existing install, not only in the upgrade branch.
  • docs/configuration.md "How oac apply works" and the rerun sentence in docs/getting-started/install-options.md (EN + zh) match the new start.

Accepted: during the preflight the pointer moves under the old Web until up recreates it (Add node during that window fails its checksum); Windows oac.exe renaming over itself on a rerun from inside the directory (install.ps1 runs from a temp directory).

Interface with Lane A

  • The preflight runs Lane A's init exactly as the plan's §2 describes. Nothing here depends on Lane A's code; the tests use a fake Docker and a mocked run.
  • Deviations from the plan:
    • The success line also names the new revision ("to "), to cover "print the new revision".
    • Bundle files are renamed with compose.yaml last, matching the published flow, so the revision line always names a fully published release.
    • An upgrade deletes a leftover compose-sha256sums.txt.

For Lane C

  • oac apply now runs up -d --wait --wait-timeout 180 --pull never --remove-orphans (operations.md:20, configuration.md "How oac apply works").
  • docs/development.md:89 still says install.py needs an empty directory.

Verification

  • go test ./services/core/cmd/oac/ -run 'TestInstall|TestApply': pass. New and updated cases:
    • another release refused with no Compose call;
    • a failed init leaves the directory byte-identical and removes the stage;
    • --upgrade order: pull, staged check-config, staged init, then up … --remove-orphans. The fixture asserts that staged calls run before publication and up after it;
    • the same release with --upgrade resumes through apply.
    • Mutations that remove the checks, the refusal or the renames fail the tests.
  • go vet ./...: pass. GOOS=windows and GOOS=darwin go vet ./services/core/cmd/oac/: pass.
  • python3 deploy/test_install_source.py: pass. A new upgrade test checks the following:
    • a failed init leaves compose.yaml, the override, .env, oac and active.json byte-identical;
    • after success, the extra Core volume is kept, all four images are replaced, there is one /node-payload bind, the pointer names the new release and both releases are kept.
  • python3 -m unittest test_generation_review_regressions (deploy/node): pass, including a new publish/activate test.
  • python3 scripts/core-distribution-manifest.test.py (Markdown link guard) and python3 scripts/check-names.py: pass.

Skipped

  • Full make check and the CI compose smoke: CI runs the smoke. The upgrade smoke is Lane A's.
  • A real Docker upgrade end to end: it needs Lane A's init. That is mx acceptance hop 1, after both lanes merge.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@blacksmith-sh

This comment has been minimized.

@SaladDay
SaladDay force-pushed the upgrade-installations-with-the-installer branch from a5f2d62 to e1eacb2 Compare October 15, 2026 06:13
oac install --upgrade and install.py --upgrade move an existing
installation to the installer's release in place. They stage the new
files, check them with oac-core check-config and init against the
installation's .env and override, and only then replace oac and
compose.yaml and start the services. Without --upgrade, another release
is refused before any Docker change; the same release resumes through
the start oac apply uses. The release checksum is verified in the stage
only, and starts recreate changed containers and remove orphans.

node_payload is split into publish and activate so a bundle upgrade keeps
earlier releases and moves the active pointer after the checks.
@SaladDay
SaladDay merged commit 9fe22cd into main Oct 15, 2026
22 checks passed
@SaladDay
SaladDay deleted the upgrade-installations-with-the-installer branch October 15, 2026 06:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant