User Tools

Site Tools


zededa:patch-envelopes

This is an old revision of the document!


EVE-OS Patch Envelopes

What is a patch envelope?

A patch envelope is EVE-OS's mechanism for delivering/updating data to a running edge app instance at runtime — without rebooting the VM, recreating the image, or redeploying the app. It is a container of one or more binary artifacts (blobs): base64-encoded objects that can be anything — a config file, a YAML, certs, a license key, a small binary, etc.

What is it used for?

The core use case is decoupling mutable data/config from the immutable app image. Instead of baking config into the image (and re-rolling the image every time something changes), you attach a patch envelope to the app instance and update just that data. Typical scenarios:

  • Making updated configuration available to a running app without downtime (the app pulls it from the metadata service — nothing is pushed to the guest)
  • Rotating credentials, certs, tokens, license keys
  • Delivering site-specific or device-specific parameters to a generic image
  • Any case where “recreating the image doesn't make sense” or downtime is unacceptable

You manage it from the controller (the PatchEnvelopeConfiguration API), and EVE exposes it to the app locally.

What can the binary artifact be?

You attach one or more binary artifacts to a patch envelope and present them to the app instance; the app then pulls them from the metadata service. So what can that artifact actually be?

Anything — it is an opaque blob to EVE. EVE does not parse, validate, or execute the artifact; it only delivers the bytes into the app's reach. So a binary artifact can be:

  • an .exe, a shell script, a Python file
  • a config file / YAML / JSON / .env
  • certs, keys, a license file, a token
  • a firmware image, a tarball / zip, a small dataset, a DB seed
  • a file with any extension (.ext, .bin, .dat, …) — the extension is meaningless to EVE
  • essentially any file you would otherwise have to bake into the image

EVE never runs it. For an .exe, EVE transfers the bytes; the guest app (e.g. a Windows VM) is what pulls it and executes it. EVE is agnostic about what the blob is or which OS consumes it.

Can I store the binary in my datastore and just consume it via the patch envelope?

Yes — that is the external artifact model (see inline vs. external artifacts below), and it is the right choice for anything larger than the inline limit (e.g. an .exe).

  • Put the binary in a datastore, reference it from the patch envelope, and the app consumes it.
  • The app still pulls it via the metadata service (description.json → download URL); external artifacts appear under VolumeRefs. EVE downloads the volume host-side, but the app is what retrieves/uses it — it is not auto-injected into the guest.
  • External artifacts inherit the datastore's ACLs — the datastore must be reachable and permissioned from the device, same as image datastores.
The exact datastore types supported for patch-envelope external artifacts (HTTP/HTTPS, S3,
Azure blob, container registry, …) may be narrower than the full image-datastore list —
verify against the PatchEnvelopeConfiguration API for your zedcloud version.

Does the app need to constantly poll http://169.254.169.254/... ?

The patch envelope metadata service is pull-only. There is no push, no notification, no interrupt to the guest. So if the app wants to discover that a new config exists, it has to poll description.json. There is no way around that.

Two different things are worth separating:

  • “Constant polling” in the sense of a tight curl loop hammering the endpoint many times a second — not needed.
  • “Polling at all” — this is required if you want the app to notice a change on its own. EVE will not tell it.

So the accurate statement is: yes, the app must poll — you just choose the interval (every 30 s, every 5 min, whatever your freshness tolerance is), and you compare SHA hashes to avoid re-applying unchanged blobs. It is still polling; it is just cheap polling.

The only way to avoid polling entirely is to not have the app auto-discover updates — i.e. only fetch on startup, and force a re-fetch by some external action (redeploy/restart the instance, or bump the app so its entrypoint runs again). That is not the app “noticing” a new config — that is you pushing a lifecycle event.

Bottom line for your design

  • Want the running app to pick up config changes on its own → it must poll (description.json, SHA-compare, re-download on change). Pick a sane interval.
  • Don't want polling → fetch once at boot only, and treat any config change as “restart/redeploy the instance.”

There is no server-push option in the current patch-envelope design.

Metadata endpoints

Endpoint Purpose
GET http://169.254.169.254/eve/v1/patch/description.json Lists patch envelopes available to this app instance — PatchId, blob filenames, SHA hashes, metadata, download URLs, and VolumeRefs
GET http://169.254.169.254/eve/v1/patch/download/{PatchID} Download all artifacts as a single ZIP
GET http://169.254.169.254/eve/v1/patch/download/{PatchID}/{filename} Download one artifact by name
Note: the metadata server is only reachable by app instances attached to a local network
instance (the same 169.254.169.254 link-local service used for cloud-init/ECO metadata).
An app on a pure switch NI with no local-NI path will not see it.

⚠ Gotcha — reachability of 169.254.169.254

The metadata service lives inside EVE on the edge node — it is not exposed outside the node. This has direct consequences for how the workload is networked:

  • Local-type NI can reach it; Switch-type cannot. A Local network instance routes to 169.254.169.254. A Switch NI is pure layer 2 (a bridge to the physical LAN) and has no path to an address that only exists inside EVE. So the app must have an interface on a Local NI to hit the metadata service.
  • Multi-NIC default-route trap. If a workload is attached to two network instances (e.g. one Local + one Switch, or two with default routes) and both provide a default gateway, the guest may pick the Switch interface as its default route — and then traffic to 169.254.169.254 goes out the wrong interface and fails.
  • Fix: when both NIs run simultaneously, add a static host route for the metadata address inside the guest, pinned to the Local interface, e.g.:
    ip route add 169.254.169.254/32 dev <local-iface>

    (or the netplan/cloud-init equivalent). That guarantees metadata traffic always uses the Local NI regardless of which interface owns the default route.

How to detect changes without busy-polling: fetch description.json and compare the SHA hashes of the blobs to what you already applied. If unchanged, do nothing. A lightweight periodic check (e.g. every few minutes) is enough — no constant querying.

Inline vs. external artifacts

There are two flavors, which affects how the data reaches the device:

  1. Inline artifacts (≤ 10 KB) — carried inside the EdgeDevConfig itself and served directly by the metadata server. Good for small configs.
  2. External artifacts — represented as volumes, pulled by EVE's volume manager from a configured datastore, and referenced via VolumeRefs in description.json. Use this for larger blobs (binaries, .exe, tarballs, datasets). These inherit the datastore's ACL/access requirements, so the datastore must be reachable and permissioned correctly.

Practical takeaway

  • In the app's entrypoint: curl description.json once, download the artifact(s), write them where the app expects them, then start.
  • For live updates, add a modest timer (or a reload trigger) that re-fetches description.json, compares SHAs, and re-downloads only on change. No continuous polling needed.
  • The app must be on a local network instance to reach 169.254.169.254.
  • EVE does not auto-mount the envelope into the guest filesystem — the app is responsible for pulling from the metadata service. For external/volume-backed artifacts EVE downloads the volume on the host side, but your app still discovers/retrieves it via the metadata endpoints. There is always an app-side fetch step; it does not “just appear as a file” without your app (or its init script) doing the pull.

Sources

zededa/patch-envelopes.1784848857.txt.gz · Last modified: by mc