Table of Contents

Patch Envelopes

A Patch Envelope is a bundle of files, configuration, scripts, or binary data that ZEDEDA Cloud can deliver to a running application instance without rebooting the VM or recreating the image. It is the mechanism for updating config, rotating certificates, pushing new scripts, or changing application parameters at runtime across a fleet of edge nodes.

Think of it as a live config injection channel – you change the envelope in ZEDEDA Cloud, the app picks it up at its next poll without any restart or downtime.

What a Patch Envelope Actually Is

A patch envelope is not a volume mount and not a filesystem change pushed by the controller. It is a collection of base64-encoded binary blobs (artifacts) that EVE-OS exposes to the app through a local metadata server running at the link-local address 169.254.169.254. The app is responsible for fetching its own artifacts by calling the metadata server API.

This is an important distinction:

This design means the app must be written (or configured) to poll the metadata server. A vanilla Ubuntu VM with no custom startup script will not automatically receive patch envelope files.

Constraints

Artifact Types

Type How it works Best for
Inline Data pasted directly into ZEDEDA Cloud as base64. Stored in the ZEDEDA controller. Small config files, environment variables, short scripts, certificates under 5 MB
External (Binary Artifact) A binary artifact already uploaded to a datastore, referenced by the envelope. Larger files, pre-compiled binaries, firmware blobs

Both types can coexist in the same envelope.

How the App Receives Patch Envelope Data

EVE-OS runs a metadata server reachable at 169.254.169.254 from inside any app connected to a local network instance. Patch envelope endpoints:

Step 1 – Discover available envelopes:

curl http://169.254.169.254/eve/v1/patch/description.json

Response:

[
  {
    "PatchId": "699fbdb2-e455-448f-84f5-68e547ec1305",
    "Version": "1",
    "BinaryBlobs": [
      {
        "file-name": "app.conf",
        "file-sha": "a3f1...",
        "file-meta-data": "YXJ0aWZhY3QgbWV0YWRhdGE=",
        "url": "http://169.254.169.254/eve/v1/patch/download/699fbdb2.../app.conf"
      },
      {
        "file-name": "update.sh",
        "file-sha": "c9b2...",
        "file-meta-data": "YXJ0aWZhY3QgbWV0YWRhdGE=",
        "url": "http://169.254.169.254/eve/v1/patch/download/699fbdb2.../update.sh"
      }
    ]
  }
]

Step 2 – Download a specific artifact:

curl http://169.254.169.254/eve/v1/patch/download/699fbdb2-e455-448f-84f5-68e547ec1305/app.conf \
  -o /etc/myapp/app.conf

The app checks file-sha against the downloaded file for integrity verification. The file-meta-data field is a base64-encoded string of any custom metadata you attached to the artifact – useful for versioning or targeting logic.

Step 3 – Act on the file:

The app applies the config, runs the script, installs the certificate, or does whatever makes sense for the workload. This is entirely app-side logic.

Typical App-Side Pattern

A well-designed edge app that supports patch envelopes typically runs a polling loop:

#!/bin/sh
METADATA_URL="http://169.254.169.254/eve/v1/patch/description.json"
KNOWN_VERSION=""
while true; do
  ENVELOPE=$(curl -sf $METADATA_URL)
  VERSION=$(echo $ENVELOPE | jq -r '.[0].Version')
  if [ "$VERSION" != "$KNOWN_VERSION" ]; then
    echo "New patch envelope version: $VERSION"
    FILE_URL=$(echo $ENVELOPE | jq -r '.[0].BinaryBlobs[0].url')
    curl -sf $FILE_URL -o /etc/myapp/app.conf
    # reload config, signal the process, etc.
    kill -HUP $(cat /var/run/myapp.pid)
    KNOWN_VERSION=$VERSION
  fi
  sleep 30
done

This pattern: poll description.json every 30 seconds, compare the version, download and apply if changed, signal the app to reload. No restart, no downtime.

Terraform Examples

Creating a Patch Envelope (inline artifact)

An envelope with a config file delivered as an inline base64 artifact:

resource "zedcloud_patch_envelope" "app_config_pe" {
  name        = "myapp-config-v1"
  title       = "MyApp Config Patch Envelope v1"
  description = "Runtime config for myapp -- updated without restart"
  project_id  = zedcloud_project.demo_project.id
  activate    = true
  artifacts {
    artifact_name = "app.conf"
    binary_blob   = base64encode(file("${path.module}/files/app.conf"))
    file_meta_data = base64encode("version=1;type=config")
  }
}

Notes:

Multiple Artifacts in One Envelope

An envelope with both a config file and a shell script:

resource "zedcloud_patch_envelope" "myapp_full_pe" {
  name       = "myapp-full-patch-v2"
  title      = "MyApp Full Patch v2"
  project_id = zedcloud_project.demo_project.id
  activate   = true
  artifacts {
    artifact_name  = "app.conf"
    binary_blob    = base64encode(file("${path.module}/files/app.conf"))
    file_meta_data = base64encode("type=config")
  }
  artifacts {
    artifact_name  = "update.sh"
    binary_blob    = base64encode(file("${path.module}/files/update.sh"))
    file_meta_data = base64encode("type=script")
  }
}

Attaching the Envelope to an App Bundle

The patch envelope is referenced in the app bundle definition, not the app instance. All instances of that bundle automatically inherit the envelope.

resource "zedcloud_application" "myapp" {
  name       = "myapp"
  title      = "MyApp"
  project_id = zedcloud_project.demo_project.id
  drives {
    image_id = zedcloud_image.demo_atl_ub_image_1.id
    maxsize  = 20480
    target   = "Disk"
    drvtype  = "HDD"
  }
  resources {
    name_of_virtual_machine = "myapp"
    cpus   = 2
    memory = 2048
  }
  interfaces {
    netadapter           = "eth0"
    network_id           = zedcloud_network_instance.local_net.id
    default_net_instance = true
  }
  # Attach the patch envelope
  patch_envelope_id = zedcloud_patch_envelope.myapp_full_pe.id
}

The app must be on a local network instance (network_id pointing to a local switch NI). A direct/passthrough NIC does not expose the metadata server.

Updating the Envelope (new version)

To push a config change, create a new envelope resource or update the existing one. When activate = true and you run terraform apply, EVE-OS receives the updated artifact list at the next heartbeat and makes the new version available at the metadata server endpoint. The version number in the description.json response increments, and any app polling the endpoint will detect the change.

resource "zedcloud_patch_envelope" "app_config_pe" {
  name        = "myapp-config-v1"
  title       = "MyApp Config Patch Envelope v1"
  project_id  = zedcloud_project.demo_project.id
  activate    = true
  artifacts {
    artifact_name  = "app.conf"
    binary_blob    = base64encode(file("${path.module}/files/app.conf"))
    file_meta_data = base64encode("version=2;type=config")
  }
}

ZEDUI Walkthrough

Create the Envelope

  1. Navigate to Library > Patch Envelopes
  2. Click the + icon
  3. Fill in Name (permanent), Title, Description, Project
  4. Set Activate Patch to on if you want it live immediately
  5. Click Next to the Artifacts section
  6. Click + to add an artifact:
    1. Inline: paste base64-encoded data directly
    2. External: select a Binary Artifact from your Library
  7. Add more artifacts as needed
  8. Click Add

To get the base64 of a file for inline upload:

cat app.conf | base64

Attach to an App Instance

  1. Navigate to Edge App Instances
  2. Select the target instance
  3. Click the … (More Actions) menu
  4. Click Attach Patch Envelope
  5. Select the envelope from the list
  6. Confirm

To detach: same path, click Detach Patch Envelope.

ZCLI

# Create a patch envelope with an inline artifact
zcli patch-envelope create myapp-config-v1 \
  --title="MyApp Config v1" \
  --project=demo-project \
  --activate=true
# Attach to an app instance
zcli edge-app-instance attach-patch-envelope MY-APP-INSTANCE \
  --patch-envelope=myapp-config-v1

API

# Create envelope
POST /v1/patchenvelopes
{
  "name": "myapp-config-v1",
  "title": "MyApp Config v1",
  "projectId": "<project_id>",
  "activate": true,
  "artifacts": [
    {
      "artifactName": "app.conf",
      "binaryBlob": "<base64_encoded_content>",
      "fileMetaData": "<base64_encoded_metadata>"
    }
  ]
}
# Attach to an app instance
PATCH /v1/appinstances/{app_instance_id}
{
  "patchEnvelopeId": "<envelope_id>"
}

Use Cases

Use Case What Goes in the Envelope How the App Uses It
Config file rotation Updated app.conf or settings.yaml App polls metadata server, detects version change, writes file, sends SIGHUP
Certificate rotation New TLS cert and key PEM files App detects new cert, writes to /etc/ssl/, reloads web server
Feature flags JSON file with feature flag toggles App reads on startup and on change without restart
Script execution Shell script or Python script App downloads, chmod +x, executes – handles patching its own dependencies
Container credentials Registry auth token (encrypted artifact) Docker Compose runtime reads credential for next pull
Edge AI model update New model weights file (up to 5 MB) Inference app detects new model, hot-swaps without restarting