Skip to main content

Agent package updates

Connhex Edge handles polling, resumable download, integrity checking, extraction, execution and rollback, authenticating with the certificate it enrolled with. You supply a zip archive and a script that does whatever your update needs.

The archive

FileContract
update.shRequiredRun as root with sh update.sh, working directory set to the extracted archive
rollback.shRecommendedRun the same way if update.sh fails or times out, and after an interrupted update is found at boot
Anything elseOptionalYour binaries, assets, migrations. The layout beyond update.sh is yours

Your script receives four variables:

VariableValue
CHX_OTA_PAYLOAD_DIRAbsolute path of the extracted archive
CHX_OTA_VERSION_CURRENTThe version the device is on
CHX_OTA_VERSION_TARGETThe version being installed
CHX_OTA_TIMEOUT_SECHow long the script has

Exit codes

Exit codeWhat Connhex records
0Success
10Success, and the agent restarts itself. Use this when you replaced the agent binary or anything it loaded
anything elseFailure. rollback.sh runs, the device stays on its current version, and the campaign records the failure

A timeout counts as a failure.

A minimal package

fw-update-0.0.3.zip
.
├── update.sh
├── rollback.sh
└── new_service.py
update.sh
#!/bin/sh
set -e

echo "installing $CHX_OTA_VERSION_TARGET over $CHX_OTA_VERSION_CURRENT"

cp /opt/connhex/custom_services/new_service.py /tmp/new_service.py.bak 2>/dev/null || true
cp ./new_service.py /opt/connhex/custom_services/
systemctl restart my-service

echo "done"
rollback.sh
#!/bin/sh
[ -f /tmp/new_service.py.bak ] && cp /tmp/new_service.py.bak /opt/connhex/custom_services/new_service.py
systemctl restart my-service
exit 0

Writing a script that survives the field

Never reboot inside update.sh. A reboot mid-script looks exactly like an interrupted update, and the agent runs your rollback at the next boot. If your update needs a reboot, schedule it for after the script exits and exit 10:

systemd-run --on-active=60s systemctl reboot
exit 10

Stay under the timeout. Ten minutes by default. Raise it on the device's Configuration tab before you ship a slow update, not after.

Make it idempotent. A power cut can mean your script runs twice.

Print progress. Everything the script writes goes to .store/ota/update.log on the device, the first place to look when an update fails.

Agent settings

The OTA settings live under [ota] in agent.toml, and can be changed per device from its Configuration tab.

agent.toml
[ota]
auto_download = true
auto_install = true
check_interval = '1h0m0s'
update_timeout = '10m0s'
SettingWhat it does
auto_downloadDownload an update when one is offered
auto_installRun it once downloaded. Implies auto_download
check_intervalHow often to poll. Minimum 15 minutes. The agent also checks at startup and whenever it comes back online
update_timeoutHow long update.sh may run
ignore_pendingReplace an already-downloaded update with a newer one
Devices with auto-install off

A device that downloads an update and does not install it parks there and stops polling. Campaigns cannot move it, and it shows as overdue for as long as it sits. Keep devices whose installs you gate by hand out of campaigns.

Following an update

Each device's Firmware tab shows what it is running on each channel, what it has been offered, and its recent update history.

A device's firmware tab.

States here are read from the version the device sends at its next check-in, and are labelled inferred. A device that arrives on the target version is recorded as updated. One that keeps arriving on the old version is offered the update again, and recorded as failed once it has had long enough. Campaigns covers the timings.

Flashing an OS image through the agent

update.sh can call anything on the device, swupdate -i included, so an agent package can flash an image. That makes it the answer for a stack with no updater of its own, and the way to deliver the image that first puts SWUpdate on a fleet already running the agent.

What you give up is everything the system image path exists for. The agent runs inside the filesystem being replaced, so it controls no A/B slot, the bootloader arbitrates nothing, and no health check gates the result. The agent records success when your script exits, which is before the new image has proved it can boot.

Four rules keep it out of trouble:

  • Raise update_timeout well above the worst-case flash time. The agent kills the script when the timeout expires, and a flash killed mid-write can leave the device unbootable.
  • Never reboot inside the script. Schedule it and exit 10, as above. A reboot mid-script is indistinguishable from a crash, and the agent runs your rollback against the image you just wrote.
  • Make rollback.sh an exit 0. Image rollback belongs to the bootloader, and a script that also tries fights it.
  • Keep the agent's state directory on a partition that survives the swap. The agent reports the version it has on record, so a state directory that goes with the old slot leaves the device with nothing to report, and the release is offered all over again.

For a product that can carry SWUpdate or RAUC, treat this as the bridge to system image updates.