All notable changes to Edgelet are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Microservice control WebSocket signals: when controller
microserviceConfigchanges, Edgelet pushes opcode0xCon/v1/microservices/controlso workloads can fetchGET /v1/microservices/config. Agent hot reload pushes opcode0xFfor resource-limit changes. edgelet system statusresource breakdown:agentCpuPercent,agentMemoryMiB, optional embeddedruntime*fields, andedgeletTotal*stack totals onGET /v1/system/status.
- Agent log WebSocket idle disconnect: quiet
follow=truestreams no longer drop at ~60s withi/o timeoutand Controller close code 1006. Agent log sockets now use exec-parity WS ping/pong keepalive, a 120s pending read deadline aligned with ControllerlogPendingTimeoutMs, and no read deadline while actively streaming. Intentional session stop sends WebSocket close 1000 with reasonsession stopped. Pair with Controller WS ping on agent log/exec sockets. - Agent exec WebSocket idle policy: exec agent sockets now match log keepalive (120s pending, no read deadline while active, graceful 1000 on intentional stop). Controller exec shell sessions use a 24-hour agent-side max duration (was 30 minutes).
-
Controller log/exec session cap: agent log streaming stops after 24 hours with close reason
max session duration(edge safety cap; Controller session TTL may apply sooner). -
Agent resource metrics:
cpuUsage/memoryUsagenow report edgelet stack totals using process RSS and smoothed CPU (control plane + embedded containerd child when present). ControllerPUT statuskeys are unchanged; reported values are more accurate (especially memory). Externaldocker/podmanengines remain agent-only totals.
Release candidate introducing multi-session exec (Controller Plan 17 parity), local concurrent edgelet ms exec, and control-plane restart. Pair with Controller v3.8.x including Plan 17 multi-exec sessions.
- Multi-exec session model: field agent polls
GET /api/v3/agent/exec/sessionsand attaches persessionIdover session-scoped agent WebSocket; MessagePackexecIdequalssessionId. - Local concurrent exec: unlimited concurrent
edgelet ms execsessions per microservice with owner-safe runtime ids and attach teardown. - Exec start gate:
POST /v1/ms/{id}/exec/sessionsblocks up to 15s; timeout returnsEXEC_START_TIMEOUT(CLI maps to a retry hint). - Status
execSessionIds[]: reports local controller attachment session ids per microservice (not local CLI sessions). - ControlPlane restart:
edgelet controlplane restart [--pull]andPOST /v1/system/controlplane/restartbounce the local controller container while provisioned; preserves UUID and volumes. - Race detector Make targets:
make test-race(full unit-test tree on host),make test-linux-race(+-arm64/-amd64for Linux Docker parity with CI tag matrix).
- Removed legacy agent exec WebSocket path (
WS /agent/exec/{microserviceUuid}) and init MessagePack pairing; exec is no longer gated onexecEnabled. - ProcessManager exec registry: owner-aware sessions on all engines;
StopExecSessionwaits before delete with orphan sweep.
- Local vs controller exec collision: deterministic
{containerID}-execid removed; local and controller sessions no longer cross-kill. - Dead attach after POST 200: sync start gate prevents returning a session id before the shell is ready.
- Network manager boot retry: no longer recurses on missing IPv4 at boot; degraded continue with background retry.
- Embedded containerd stale tasks: orphaned runtime task dirs cleaned on data-plane bootstrap without wiping image cache.
- Controller reconnect reconcile: field agent live-reconciles from Pot on reconnect; deduplicated init reload vs getChanges.
Release candidate fixing controller exec/log WebSocket pairing after failed or timed-out sessions, and decoupling local API startup from Pot controller reachability. Pair with Controller v3.8 (exec teardown raises execSessions: true on all disable paths).
- Exec WebSocket lifecycle: each new exec session calls
Reset()then a fresh dial toGET /api/v3/agent/exec/{microserviceUuid}; stalePending/Activehandler state no longer skipsConnect(). - Log WebSocket lifecycle: same reset-and-reconnect hygiene for log session handlers (
Reset()beforeConnect()on session start;Disconnect()fully clears state). - Exec session reconcile:
HandleExecSessionstreats a finished shell (GetExecSessionStatus→false) as not running; recreates exec when the process is gone or the controller WebSocket is disconnected. - Boot controller sync: provisioned startup loads registries, volume mounts, and microservices from SQLite first via async
bootstrapControllerSync(); live Pot refresh runs after ping succeeds without blocking supervisor startup. - Supervisor startup order: Edgelet API starts after container engine and process-manager wire so
edgelet ms lsand local status work before optional modules finish;OnProcessManagerReady()notifies PM when cache bootstrap completes before PM exists. IsControllerConnected: live paths use cached reachability from ping workers only (no inline controller ping from worker or sync code); cache reads (fromFile=true) unchanged.- JWT vs controller status: valid credentials at boot set
NOT_CONNECTED/controllerVerified=falseuntil a successful ping; JWT success alone no longer implies Pot is reachable. /health/ready: ready when the local API is listening and daemon status is RUNNING or WARNING; not gated on provisioned state or controller connectivity.- CLI startup errors: distinguish
LOCAL_API_STARTING(daemon up, API not ready),DAEMON_UNAVAILABLE(no daemon), andCONTROLLER_OFFLINE(local API up, Pot unreachable); replaces the generic “still initializing” message for connection-refused cases. - Offline volume mounts at boot: cache bootstrap skips live
loadVolumeMounts()when the controller is unreachable; uses SQLite-backed volume-mount state instead.
- Controller TLS for log/exec WebSocket sessions: WSS dials load
controllerCertfrom file paths (same as HTTPS), fixingfailed to decode PEM blockandcertificate signed by unknown authoritywhencontrollerCertpoints at a PEM file. secureModeconfig parsing: valuesfalse,0, andno(including fromedgelet config --sec off) now correctly disable secure mode instead of being treated as enabled.- Stale exec WebSocket after failed pairing: after user timeout or controller cleanup, retrying exec without restarting edgelet no longer logs “skipping Connect (state=3)” while the controller sees no agent upgrade.
Disconnect()state leak: exec and log handlers forceDisconnectedon teardown instead of leavingPending/Activein memory (cached per-UUID handler map).- Orphan exec cleanup:
execEnabled=falsealways stops local exec and resets the WebSocket handler, even when session maps are empty. - Cancelled context on reconnect: handler
ctxis recreated onReset()so ping/read workers survive a second connect. - Slow CLI after restart with Pot down:
edgelet system infoandedgelet ms lsno longer wait on multi-minute sync controller I/O (ping, fog config, live volume mounts) before the local unix socket accepts connections. - Misleading “API still initializing”: connection refused on
/run/edgelet/edgelet.sockwhile the daemon process exists now reports local API startup (LOCAL_API_STARTING) instead of implying controller sync is in progress. - False controller-up at boot: JWT initialization no longer sets
ControllerStatusOKbefore the first successful ping, avoiding live Pot fetches during unreachable-controller startup.
- Pre-release:
v1.0.0-rc.3is a release candidate, not production GA. - Re-init on live socket: controller supports init-frame reuse on an open agent socket; edgelet defaults to a fresh dial per new
execId(optional optimization deferred). - Controller sync SLA: local API target ≤15s with containerd up and Pot down; full microservice reconcile after Pot returns remains best-effort (no hard SLA).
- Boot vs getChanges init: SQLite-first bootstrap runs in parallel with the existing
initialization/config/changeshandshake; duplicate reconcile when Pot comes back may occur (follow-up). - Runtime restart order (split): manual
systemctl restart edgelet && restart edgelet-containerdcan race attach; restartedgelet-containerdfirst, thenedgelet. - Follow-up (not in this rc): network manager unbounded retry on total IPv4 failure; automated stale containerd shim/task-dir cleanup; Pot REST / getChanges semantics unchanged.
Release candidate after provision lifecycle hardening, runtime observability fixes, and supply-chain follow-up. Pair with Controller v3.8.0-beta.1 or newer v3.8 line.
- Lifecycle dev gates:
make pre-it(vet + lint + lifecycle unit tests); optionalmake test-lifecycle-raceandmake test-deadlockfor concurrency audits. - Deadlock audit doc: operator-facing lock inventory and fixes in
docs/edgelet/deadlock-audit.md. - Healthcheck shell helper: shared
ShellCommandForScript(bash → sh → busybox) forCMD-SHELLhealthchecks and default exec sessions on minimal images.
- Live reprovision:
edgelet system provisionon a running daemon reloads registries, volume mounts, microservices, and config without restarting background workers. - Split log basenames:
edgelet.servicewritesedgelet.*.log;edgelet-containerd.servicewritesedgelet-containerd.*.logunder the samelogDirectory(60/40 rotation budget when runtime split is enabled). Seedocs/edgelet/logging.md. - Disk usage metric:
edgelet system statusdiskUsagewalks the full configureddiskDirectoryinstead of legacymessages/archive+volumes/partial sums; automatic archive prune removed (greenfield). - Image drift (embedded engine): reconcile compares images with
imageref.Matchso controller short names (e.g.user/repo:tag) match runtimedocker.io/prefixes without endlessconfig_driftUPDATE loops. - Deprovision cleanup: volume-mount index cleanup no longer holds locks across slow filesystem work that blocked the process-manager monitor during background deprovision.
- Changes worker resilience: panic recovery and per-cycle timeout so
config/changespolling continues atchangeFrequencyafter handler failures. - Go dependencies: minor bumps —
containerd/typeurl/v22.3.0,fsnotify1.10.1,docker/go-connections0.7.0,golang.org/x/crypto0.53.0,pflag1.0.10. - Supply-chain CI: SHA-pinned GitHub Actions bumps (checkout v6, docker setup-buildx/qemu v4, action-gh-release v3, cosign-installer 4.1.2) across ci, release, codeql, govulncheck, and scorecard workflows.
- CI lint:
quality-linux.shruns vet plus a single full golangci pass; CI lint job aligned (no redundant staticcheck chain).
- Volume mount deadlock: CONFIGMAP/SECRET version bumps during
config/changesno longer re-acquireindexLockand freeze the changes worker. - Live reprovision gap: reprovision without daemon restart now loads controller microservices (same path as cold
Start()). - Deprovision monitor stall: process-manager container monitoring continues through deprovision volume cleanup.
- False-positive image drift: embedded-engine reconcile no longer recreates microservices when only the Docker Hub hostname prefix differs.
- Misleading disk metric: status
diskUsagenow reflects deployed workload data under/var/lib/edgelet/when volumes and MS data are present. - Log file confusion: control-plane traffic lands in
edgelet.0.loginstead of being rotated into secondary files whileedgelet-containerdbootstrap stays in its own series. CMD-SHELLhealthchecks: succeed on images with bash but no/bin/shwhen bash is present.
- Pre-release:
v1.0.0-rc.1is a release candidate, not production GA. - Host-network DNS:
edgelet.default.svc.bridge.localinjection remains an accepted limitation for host-network microservices. - Provisioned guard IT: blocked
ms rm/controlplane deletewhen provisioned still deferred (requires live system fog).
Production hardening release paired with Controller v3.8.0-beta.1. Deploy Edgelet and Controller v3.8 together; greenfield ControlPlane YAML only.
- Controller microservice register-once: after provision and local ControlPlane deploy, Edgelet calls
POST /api/v3/agent/controller/registeronce and retries until success; no re-register on spec drift. - OTA controller semver:
GET /api/v3/agent/versionsemverfield normalized tovX.Y.Zforinstall.sh;provisionKeyandexpirationTime(Unix ms) drive post-OTA reprovision (private key rotation only; stableiofogUuid). - Per-OS install paths: documented linux, darwin, and windows directory tables in README and
docs/edgelet/installation.md; embeddeduninstall.shin the install monolith; linux/usr/share/edgelet/ships both scripts after curl-only install.
- ControlPlane manifest v3.8: OIDC auth, EdgeOps Console, TLS, and
controller.publicUrl/trustProxy; canonical env projection (AUTH_*,OIDC_*,CONSOLE_*,TLS_*,INTERMEDIATE_CERT); host ports 51121 (API) and 80 → console. - Config hot-reload: PATCH
/v1/configandedgelet system reloadapply log level without service restart; shared reload path for SIGHUP, PATCH, and POST reload;logging.InstanceConfigUpdatedon hot reload. - Moby SDK (docker/podman engine): replaced legacy
github.com/docker/dockerwithgithub.com/moby/moby/client@v0.4.1andgithub.com/moby/moby/api@v1.54.2; removed govulncheck exceptions GO-2026-4887 / GO-2026-4883. edgelet system reloadUX: human success output (spinner model) when not using structured-o.
- Curl-only linux install:
/usr/share/edgelet/uninstall.shnow present after pipe-to-bash install (embedded in assemble pipeline). - macOS install: darwin uses
/var/run/edgelet(not/run) and/usr/local/share/edgelet/for bundled scripts; avoids failures on default macOS layout.
- Legacy ControlPlane YAML rejected: keys such as
auth.url,ecnViewer*,spec.https, Keycloak/viewer/ssl-era fields fail validation; use v3.8 schema and examples underdocs/edgelet/examples/controlplane.yaml.
- Pre-release:
v1.0.0-beta.3is not production GA; pair with Controller 3.8.0-beta.1 or newer v3.8 line. - Provisioned guard IT: blocked
ms rm/controlplane deletewhen provisioned deferred (requires live system fog); unprovisioned lifecycle covered in CP IT.
- Cgroup preflight on LXC/VM machine roots: OpenRC hosts with
/.lxccgroup layout (e.g. OrbStack Alpine) no longer fail cold boot with a misleading docker--privilegederror. Machine-root paths are distinguished from workload-nested containers;edgelet cgroup-preflightperforms light mount/mode checks only; strict delegation validation runs after bootstrap prep. - LXC/VM machine OpenRC containerd restart:
/.lxc/initstaging cgroups are treated as machine-root boundaries (not workload-nested). Runtime bootstrap skips Moby-style reparent whenedgelet-cgroup-prepalready delegated at the unified root and/.lxc, then prepares the OpenRC/service staging cgroup and/edgeletbefore spawning embedded containerd (OrbStack Alpine cold boot). - OpenRC sysinit prep:
edgelet-cgroup-prepreparents unified root and/.lxccgroups and delegatescpu/memory/pidsbeforeedgelet-containerdstarts (Moby/dind-style).
cgroupNestedstatus:trueonly for workload containers (Docker/k8s dev deploy), not LXC/VM machine boundaries.
Hotfix pre-release after v1.0.0-beta.0. GitHub Releases remain binary-only; install.sh is now self-contained.
- Curl / fresh-host install:
install.shno longer requires co-locatedscripts/lib/orpackaging/init/on the release download path. A singleinstall.shfrom GitHub Releases embeds init helpers and unit templates (assemble pipeline); fixesMissing init helper scriptson first install. - Post-install layout:
/usr/share/edgelet/ships self-containedinstall.sh/uninstall.shand config samples only — notlib/orinit/trees.
- Supply-chain CI: Dependabot (gomod + github-actions), CodeQL for Go, pinned Actions and Docker base images,
read-allworkflow defaults, keyless cosign signatures on release assets, bounded fuzz smoke in CI,SCORECARD_TOKENfor OpenSSF Scorecard branch-protection checks. - Dependencies:
golang.org/x/netbumped (vulnerability reduction).
- Pre-release:
v1.0.0-beta.1is not production GA; expect refinements before 1.0.0.
First public pre-release of Edgelet — a greenfield edge runtime and ioFog/PoT node agent (github.com/eclipse-iofog/edgelet). GitHub Releases are marked Pre-release and ship binary-only artifacts (no DEB/RPM, no release tarballs).
- Single
edgeletbinary per platform: Linux thin wrapper (~31 MiB download) with k3s-style zstd embed and lazy extract to/var/lib/edgelet/data/current/; macOS and Windows monolithic builds for external Docker/Podman only. - Embedded Linux runtime (
containerEngine: edgelet, default on Linux): in-process containerd (k3s fork), CRI socket at/run/edgelet/containerd.sock, staticcrun1.28 in the embed bundle. - Multi-engine support on Linux:
edgelet,docker, orpodmanvia config; desktop platforms supportdockerandpodmanonly. - EdgeletAPI on-device operator API at
https://127.0.0.1:54321with routes under/v1/..., RBAC groupedgelet.iofog.org/v1, TLS/PKI under/etc/edgelet/. - Field agent for Controller sync; Pot REST remains at
/api/v3/...on the controller URL (unchanged contract). - Operator CLI (Cobra): grouped commands (
system,ms,image,registry,runtimeclass,config,deploy,provision), structured-o json|yaml, shell completion, generated docs underdocs/cli/. edgelet init-config: write default config from template when missing (idempotent).- Binary-only install/OTA:
install.sh/uninstall.shfor Linux, macOS, and Windows;--upgrade/--rollbackwith receipt under/var/backups/edgelet/; six Linux init system templates. - Release packaging:
scripts/release-binaries.shproduces seven binaries +SHA256SUMS+ config/CA samples. - Seven release binaries:
edgelet-linux-{amd64,arm64,arm,riscv64},edgelet-darwin-{amd64,arm64},edgelet-windows-amd64.exe. - Dual publish: Eclipse upstream at eclipse-iofog/edgelet; Datasance mirror at Datasance/edgelet with identical tags (separate GHCR namespaces).
- Container image:
ghcr.io/eclipse-iofog/edgelet:<tag>(scratch base,EDGELET_DAEMON=container); Datasance mirror:ghcr.io/datasance/edgelet:<tag>. - macOS release build path:
test/release/build-all.sh(Docker embed loop) for developers without native Linux cross-toolchains. - Arch smoke scripts:
test/release/smoke-linux-{arm,riscv64}.shfor post-build daemon, version, and CRI socket checks. - Security gates:
make security-code(gosec),make vulncheck(govulncheck), CI workflow for vulnerability scanning; see SECURITY.md. - SQLite persistence for local state, deploy manifests, and runtime metadata.
- Local deploy manifest uses single
spec.image(no per-arch image maps). - FogType / arch mapping: amd64, arm64, riscv64, arm (32-bit) for provision and status display.
- Product identity: greenfield rebrand to Edgelet — paths under
/var/lib/edgelet,/etc/edgelet,/run/edgelet; labels and env vars useedgelet.iofog.org/*andEDGELET_*. - Daemon entry: bare
edgeletinvokes the CLI; start the daemon withedgelet daemonorsystemctl start edgelet. - Provision payload includes configured
containerEngineand build metadata sent to the Controller. - CLI redesign (breaking vs legacy ioFog Agent CLI): command groups and flags replaced flat
iofog-agentverbs; see docs/edgelet/migration-from-iofog-agent-cli.md. Daemon unreachable returns exit code 10. - Documentation: operator docs under
docs/edgelet/(architecture, deployment, EdgeletAPI, container engine). - Toolchain: Go 1.26.x; containerd v2.2.3-k3s1 with pinned CRI API replacements.
- Quality tooling: golangci-lint v2 (govet, revive, staticcheck, errcheck, formatters, misspell, errorlint); gosec run separately from lint.
- Embed packaging: single
.tar.zstper arch ingo:embed(prevents multi-arch artifact accumulation inflating binary size). - CRI lifecycle: microservice restart and stop/start on the embedded engine use remove+create+start instead of failing with non-restartable container errors.
- Logging on arm32: size cap avoids int overflow on 32-bit platforms.
- Embed cross-build on macOS: host-arch tooling and zlib dev packages for arm/riscv64 fat-runtime link.
- gosec and vulnerability findings addressed across
cmd/,internal/, andpkg/; documented exceptions only where noted in SECURITY.md.
- Pre-release:
v1.0.0-beta.0is not a production GA; expect API and packaging refinements before 1.0.0. - Windows (Tier 2):
edgelet-windows-amd64.exeis built and published; there is no Windows integration-test matrix or Windows service installer in this release. - macOS: supported as a development platform with external Docker/Podman only — not positioned as a production far-edge node OS.
- linux/arm smoke depth: arm32 (
edgelet-linux-arm) builds in the release matrix; full arch smoke is validated on Linux with binfmt or native hardware. Running arm smoke under macOS Docker/QEMU may segfault after embed extract even when the binary build succeeds. - linux/riscv64: release build and smoke script pass on macOS Docker; fleet validation on real riscv64 hardware is limited in beta.
- Binary-only distribution: no DEB/RPM packages and no release
.tar.gzbundles; useinstall.shor copy the raw binary. - OTA depth: one previous release for thin-binary rollback; fat embed bundle keeps
current/previoussymlinks only. - Codecov: coverage upload not wired; badge is a placeholder until post-beta CI work.
- Dependency exceptions (docker/podman engine): govulncheck documents two accepted findings in the pinned
github.com/docker/dockerclient SDK (Moby AuthZ plugin advisories GO-2026-4887 / GO-2026-4883, CVE-2026-34040). Edgelet uses the SDK as a client to local engines; typical edge deployments do not enable AuthZ plugins. Operators should run a patched Docker Engine (≥ 29.3.1) or equivalent Podman. Full rationale and fix timeline: SECURITY.md.
| Arch | Thin binary | ≤ 55 MiB |
|---|---|---|
| linux/amd64 | ~34.7 MiB | yes |
| linux/arm64 | ~31.7 MiB | yes |
| linux/riscv64 | ~32.2 MiB | yes |
| linux/arm | ~31.8 MiB | yes |