Skip to main content
Documentation
Preview
You're viewing the Next docs — a rolling preview of in-development changes. The current release docs may differ.

Rugix Apps Integration

Rugix Apps installs applications on a device independently of its operating system. Each app is delivered as a bundle, and each installation creates a new generation of the app while earlier generations stay on the device for rollback. With the Rugix Apps integration, Nexigon Agent installs, updates, starts, stops, and removes apps as configured in Nexigon Hub. App releases then need neither a system update nor shell access to the device.

This guide shows how to enable the integration in a device image, how to publish app releases that devices install, and how to check the result. Once a device is set up, follow Application Workloads to deploy and manage apps from the web interface.

How It Works

You set the desired state of a device’s apps in the dev.nexigon.rugix-apps.config device property. For each app, it names the release to run, for example the stable tag of a package, and whether the app should run, stay stopped, or be removed. The agent publishes the state of the apps in the dev.nexigon.rugix-apps.status property and records each installation and failure as an event in the apps category. Rugix Apps describes both properties in detail.

The agent checks the apps when it connects to Nexigon Hub, periodically, when a deferred update becomes due, and when you request a check. For each app that the property lists, a check:

  1. Starts, stops, or removes the app as its desired state requires.
  2. Resolves the configured release to a package version.
  3. Waits while a hold, a retry delay, or a spread defers the update. Control When Applications Update explains these settings.
  4. Downloads the bundle for the device’s architecture and installs it as a new generation, while the current generation keeps running.
  5. If the app should run, activates the new generation, which switches the app to it. For a running app, the agent waits for the maintenance window, if one is set. A stopped app starts with the new generation later.
  6. Removes old generations that it no longer needs to keep.

Because installation and activation are separate steps, a maintenance window only has to cover the switch itself, which takes little time. If the new generation fails to start, Rugix Apps returns the app to its previous generation, if there is one, and the agent reports the update as failed. An app that starts but does not work correctly stays on the new generation. To return it to an earlier release, pin that release, for example with the path my-repo/controller/1.0 instead of my-repo/controller/stable.

With each generation, the agent records the package version that it installed the generation from. The device therefore knows which version each app runs, even after Rugix Apps has rolled an app back. If a configured version is still installed, the agent switches back to it without downloading it again.

The agent changes only the apps that the property lists. It reports other installed apps as not managed and leaves them unchanged. The integration can run alongside the system update integration. While a system update installs a new system and reboots into it, the agent does not change apps.

Prepare the Image

The integration requires Rugix Ctrl 1.4 or later, which can record where a generation came from and install a generation without activating it. Rugix Apps is experimental in this version, so its interface may still change. Also install and enable the two systemd services that Rugix Apps needs to restore apps after a reboot and to recover from interruptions, as described under Reliability. The Debian packages of Rugix Ctrl install them.

Each app declares an orchestrator, the component of Rugix Apps that starts, stops, and checks its workload. Install what your apps’ orchestrators need, for example Docker and Docker Compose for the docker-compose orchestrator.

The agent manages apps with rugix-ctrl apps commands, which it runs as its own user. That user needs the privileges to install and run apps. The systemd unit in the agent’s installation instructions and recipes runs the agent as root.

Verify Bundles

Rugix Ctrl installs only bundles that it can verify, in one of two ways:

  • Signature: Rugix Ctrl checks the bundle’s signature against the certificates that the image trusts. See Signed Updates.
  • Hash: With use-bundle-hash enabled in the agent’s configuration, the agent passes a hash from the bundle’s metadata in Nexigon Hub to Rugix Ctrl. You attach this hash when you publish an app. For a bundle without a hash, Rugix Ctrl checks the signature.

Without a trusted signature or a hash, every installation fails.

Configure Nexigon Agent

Enable the integration in the agent’s configuration, here with hash verification:

/etc/nexigon/agent.toml
[integrations.rugix.apps]
enabled = true
use-bundle-hash = true

[commands]
enabled = true

With commands enabled, the web interface requests an immediate check through the nexigon.rugix-apps.check command after each change. Otherwise, the device applies changes at its next check, by default after about four hours. App Management lists all settings.

For Rugix Bakery, add these settings with the extra_config parameter of the nexigon/nexigon-agent-config recipe, as in Getting Started with Rugix. For Yocto, add them with NEXIGON_AGENT_EXTRA_CONF.

Select the Architecture

A release of an app can contain bundles for several architectures. A device installs the bundle named <app>-<arch>.rugixb, where <arch> is its architecture. If the release has no such bundle, the device installs <app>.rugixb, which suits apps that run on every architecture.

The architecture defaults to the one that the agent was built for. The agent uses Rust’s names, such as x86_64 and aarch64, and arm for every 32-bit ARM architecture. Name bundles accordingly, even where other tools use other names. Rugix Bakery, for example, calls x86_64 and aarch64 amd64 and arm64. To tell apart variants that share a name, set the architecture explicitly, for example on a device that runs bundles built for ARMv7:

/etc/nexigon/agent.toml
[integrations.rugix.apps]
enabled = true
arch = "armv7"

The device then installs <app>-armv7.rugixb. It reports its architecture as arch in the status.

Keep Old Versions

After switching an app to a new version, the agent removes old generations with rugix-ctrl apps gc, which also frees their stored files. It keeps the running generation and, by default, one previously running generation, to which the app can switch back without a download. Keeping more generations makes switching back to older releases faster, at the cost of storage:

/etc/nexigon/agent.toml
[integrations.rugix.apps.gc]
keep = 2

The gc policy in dev.nexigon.rugix-apps.config overrides this default for all apps or for a single app.

Verify the Integration

Build an image, boot a device with it, and wait for the agent to connect. Then read the status of the device’s apps on the device:

nexigon-agent device properties get dev.nexigon.rugix-apps.status

The command prints the property as JSON, with the status as value. For example, on a device with one app installed in its image (shortened):

{
  "result": "Found",
  "name": "dev.nexigon.rugix-apps.status",
  "value": {
    "arch": "aarch64",
    "rugixCtrlVersion": "1.4.0",
    "apps": {
      "historian": { "managed": false, "workload": { "state": "running" } }
    }
  }
}

Check that arch is the architecture that you name bundles for and that rugixCtrlVersion is 1.4 or later. Once the status exists, the device’s page in Nexigon Hub shows an Applications section. If the property is missing or reports an error in lastError, inspect the log of the agent:

journalctl -u nexigon-agent -b

Publish an App

Build an app bundle with Rugix Bundler, as described for your app’s orchestrator. The bundle’s manifest sets the name under which Rugix Ctrl installs the app. This name must match the name that the device’s configuration uses for the app.

Publish each app as a package in a repository and each release as a version of that package, with one bundle for each architecture. For example, the following Nexigon CLI commands publish release 1.0 of the controller app for 64-bit ARM devices:

nexigon-cli repositories packages create my-repo controller --kind rugix-app
nexigon-cli repositories versions create my-repo/controller --tag 1.0,locked
nexigon-cli repositories assets upload my-repo controller-aarch64.rugixb
hash=$(rugix-bundler hash controller-aarch64.rugixb)
nexigon-cli repositories versions assets add <version-id> <asset-id> \
    controller-aarch64.rugixb --metadata "{\"rugix\": {\"bundleHash\": \"$hash\"}}"
nexigon-cli repositories versions tag <version-id> --tag stable,reassign

The first command creates the package, which is needed only once. Its kind rugix-app makes the web interface offer the package as an app. The second command creates the version with the locked tag 1.0, which always refers to this release, and prints its ID as versionId. The third uploads the bundle and prints its ID as assetId. The fourth computes the bundle’s hash, and the fifth attaches the bundle to the version under the filename that devices look for, with the hash as metadata. With signed bundles, omit the hash. The last command assigns the stable tag to the version, and reassign moves the tag if another version has it. Publish Software Artifacts explains the commands in detail.

The web interface uses the package name as the app name. If they differ, set rugix.app.name in the package metadata, as described in Publish an Application. If the repository is private, link it to the device’s project under Project Settings → Repositories, so that the device can download its releases.

To keep Rugix Ctrl from installing a bundle on the wrong architecture, declare a host.arch requirement in the bundle’s compatibility metadata. Rugix Ctrl compares it with the architecture that it was built for, using Rust’s names, so use arm and not armv7 for 32-bit ARM devices.

Deploy an App

Deploy the published app, either from the web interface as described in Add an Application to a Device or with Nexigon CLI. The following command sets the device’s configuration to the stable release of controller:

nexigon-cli devices properties set --protected=true <device-id> \
    dev.nexigon.rugix-apps.config \
    '{"apps": {"controller": {"path": "my-repo/controller/stable"}}}'

nexigon-agent device id prints the device ID on the device. The property is protected, so that only operators can change it and the device cannot. The command replaces the device’s own configuration, including other apps that it lists. To configure the apps of many devices, set the property in a device profile. Nexigon CLI does not request a check, so the device applies the change at its next check. To apply it right away, restart the agent on the device with systemctl restart nexigon-agent, which checks the apps when it starts.

The app’s state passes through installing and activating and ends with completed and a running workload. On the device, rugix-ctrl apps info controller lists the new generation with the package version as its origin.

If the update does not complete, the status explains why:

SymptomWhat to Check
The update fails with version ... does not exist.The path names an existing tag or version ID, and a private repository is linked to the device’s project.
The update is blocked with the code no-asset.The release contains a bundle named for the arch that the device reports.
The update fails because Rugix Ctrl cannot verify the bundle.The bundle has a hash in its metadata and use-bundle-hash is enabled, or the bundle is signed with a certificate that the image trusts.
The update fails after the download, for example with the bundle did not install a generation of the app.The bundle’s manifest uses the app name of the configuration. Otherwise, Rugix Ctrl installs the bundle as another app, which then appears as not managed.
The status reports errors of rugix-ctrl, such as failed to inspect the app.The device runs Rugix Ctrl 1.4 or later, as rugixCtrlVersion shows.
The update fails during the activation.The workload’s logs. The new generation failed to start, so Rugix Apps has returned the app to its previous generation. lastError describes the failure.

The agent retries failed updates as the retry policy defines. After you fix the cause, for example by publishing a corrected release, choose Retry Update in the web interface to request a new attempt right away.

Take Over Existing Apps

Apps can reach a device without the integration, for example as part of its image, through a manual installation, or through the device commands of the nexigon/nexigon-rugix-apps recipe. The agent reports such apps as not managed. To manage one, add it to dev.nexigon.rugix-apps.config with a release, as in the example above.

The agent does not know which package version an existing generation came from, because only generations that the agent installs record it. It therefore installs the configured release as a new generation and switches the app to it, even if the app already runs the same release. From then on, the agent recognizes the versions of the app.

To hand an app back, remove it from dev.nexigon.rugix-apps.config. The agent then stops managing the app and leaves it installed. To uninstall the app instead, including its persistent data, set its state to removed.