fix(install): show the download, and pin the version latest resolved to - #192
Merged
Conversation
Two things people hit on a real install. The runtime image download was silent. It ran with output suppressed, so on a plant link the installer sat on one "Pulling" line for minutes and looked hung -- reasonably enough that it got killed. Docker's own per-layer progress is shown now, which needs no explaining because it is what every other docker command shows. The wait that follows also reports the bootloader's state and elapsed time, rewritten in place on a terminal and appended once per change when it is not one. Both images are now pulled before anything is disturbed, runtime first. That was already the intent -- nothing destructive until the images are on disk -- but the runtime image was left for the bootloader to fetch after the native runtime had been stood down, so the long download happened in the window where the device had no PLC. It now happens while the device is still serving the runtime it has. And "latest" is no longer what gets recorded. Installing the newest release is the right default; writing "latest" into the spec is not -- the device would report its version as "latest" and follow the tag on every reconcile, moving to a new runtime because someone published one rather than because anyone chose it here. The concrete version is read out of the image itself (RUNTIME_VERSION, baked in by the release build), so it needs nothing but the registry and is by construction exactly what "latest" pointed at. Verified in a real-systemd container: the spec and the bootloader both report v4.2.2 rather than latest, and the pull prints its progress. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VwWQN5S2ZKbhJz8kxMV9vF
thiagoralves
commented
Sep 4, 2026
thiagoralves
left a comment
Contributor
Author
There was a problem hiding this comment.
Review of the installer changes. Three findings, one of which is a real regression for the offline / local-copy path that this same function is documented to support.
Three review findings on the version pinning, and a comment pass. Pinning the spec to a version the daemon holds only as ":latest" broke the local-copy path. pull_image accepts "registry unreachable, a copy is already here" -- air-gapped, side-loaded, or a device an earlier run left with repo:latest. Reading v4.2.2 out of that image and recording it named a tag the daemon had never seen, so the bootloader compared tag strings, called a working container stale, stopped it, and could not pull the replacement. wait_for_runtime returns 0 on recovery, so the EXIT trap was already cleared and no rollback ran: a device with a working PLC finished the install with none. Reproduced offline with the registry blackholed -- recovery state, no runtime container. The image is now given the pinned name too, and the version is recorded only if that tag succeeds, so the spec can never name something unresolvable. It also drops a registry round-trip in the online case. The progress line read a "reason" that /api/bootloader/capabilities does not carry -- it is on the authenticated status endpoint, which needs a token this script has no way to get. So the field was always empty and the recovery branch printed nothing where it promised an explanation. Removed, and the recovery branch now names the log that does hold the reason. The elapsed counter was counted rather than measured. Each iteration can take a curl timeout plus a sleep, so a bootloader that accepts the connection and then stalls made the loop under-report: 20s claimed after 25s in a stalling-port test, and the 900s bound would have run long while the final message still said 900. It reads the clock now. Also trimmed the comments in this file. They had grown into narration -- what was tried, what went wrong, how it felt -- where a statement of what the code does and why is what is wanted. 204 comment lines to 155, with no code change beyond the three fixes above. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VwWQN5S2ZKbhJz8kxMV9vF
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.
Installer-only follow-up to v4.2.2, from testing the published one-liner
(
curl -fsSL https://runtime.getedge.me | sudo bash) on a real device.Three fixes
The download was silent.
docker pullran with output suppressed, sothe installer sat on a single
Pullingline for as long as the image tookto arrive. On a slow link that reads as a hang, and it got killed. Docker's
own per-layer progress is shown now. The wait that follows also reports the
bootloader's state, its reason, and elapsed seconds -- rewritten in place on
a terminal, appended once per change when it is not one.
The long download happened in the device's no-PLC window. Both images
are now pulled before anything is disturbed, runtime first. Nothing
destructive before the images are on disk was already the intent, but the
runtime image was left for the bootloader to fetch after the native
runtime had been stood down.
latestwas what got recorded. Installing the newest release is theright default; writing
latestinto the device spec is not -- the devicewould report its version as
latestand follow the tag on every reconcile,moving to a new runtime because someone published one rather than because
anyone chose it here. The concrete version is now read out of the image's
own config (
RUNTIME_VERSION, baked in by the release build), so it needsnothing beyond the registry and is by construction exactly what
latestresolved to. If it can't be read, the installer warns and keeps the moving
tag rather than guessing.
Verified
In a privileged real-systemd container with an active
openplc-runtime.serviceto displace, against the live registry:"version": "v4.2.2", and the bootloader agrees(
{"runtimeVersion":"v4.2.2","state":"healthy"})bash -nclean,shellcheck -S warningclean