Skip to content

fix(install): show the download, and pin the version latest resolved to - #192

Merged
thiagoralves merged 2 commits into
mainfrom
development
Sep 4, 2026
Merged

fix(install): show the download, and pin the version latest resolved to#192
thiagoralves merged 2 commits into
mainfrom
development

Conversation

@thiagoralves

Copy link
Copy Markdown
Contributor

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 pull ran with output suppressed, so
the installer sat on a single Pulling line for as long as the image took
to 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.

latest was what got recorded. Installing the newest release is the
right default; writing latest into the device 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 now read out of the image's
own config (RUNTIME_VERSION, baked in by the release build), so it needs
nothing beyond the registry and is by construction exactly what latest
resolved 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.service to displace, against the live registry:

  • spec records "version": "v4.2.2", and the bootloader agrees
    ({"runtimeVersion":"v4.2.2","state":"healthy"})
  • the pull prints its progress, digest and status
  • bash -n clean, shellcheck -S warning clean

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 thiagoralves left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread scripts/install-docker.sh
Comment thread scripts/install-docker.sh Outdated
Comment thread scripts/install-docker.sh
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
@thiagoralves
thiagoralves merged commit f264872 into main Sep 4, 2026
8 checks passed
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