Skip to main content
Version: 0.1

Upgrading

This page is for the person who runs a gateway through a version change. The gateway upgrades itself on start; your part is the backup, the image and the rollback path.

Before you start​

  1. Take a backup from Gateway > System > Backup & restore, or copy the data volume while the gateway is stopped. The backup must include keys/ beside the database: module state, driver passwords included, cannot be decrypted without it. See Backup and restore.
  2. Note the image tag you are running (docker compose images, or SCADEX_TAG in .env). Keep that image available; it is your rollback.
  3. Read the changelog for the version you are moving to.
warning

Backups taken before this version hold module state in plaintext, and a database written by this version cannot be read by an older gateway. Keep the old backup and the old image together.

Pull or rebuild the image​

The gateway is one container, and the data volume is the state. Upgrading is replacing the image and starting again on the same volume.

With a published image, set the new tag and pull:

# .env: SCADEX_TAG=<new tag>
docker compose pull
docker compose up -d

Building from the repository instead:

git pull
docker compose up -d --build

The container's health check (/api/v1/runtime/health) reports healthy once the gateway is up. Drop-in modules in ./.local/modules are not part of the image; see Module compatibility for whether they still load.

What happens on first start​

Everything below runs automatically, before the gateway accepts requests. None of it needs a flag.

Database schema. The gateway opens scadex.db, creates any table it lacks and adds any column that is missing, with a default for existing rows. It also carries out one-off renames: module ids from before the io.scadex.* naming, and the tag-type root from _types_ to @types (the old name is still accepted on the API). A gateway from before alarm shelving gains the shelvedUntil columns; one from before roles gains the role column.

Roles. Before roles existed, everyone could do everything. The upgrade therefore gives every existing user the admin role, so nobody is locked out, and signs everybody out once. Review the users under Gateway > Security > Users afterwards and set the roles you want. New users created from then on get viewer by default.

Secrets at rest. Module state is encrypted in the database with the keys in DATA_DIR/keys. On start, any row still in plaintext is encrypted, and the database is then rewritten and its WAL emptied so the old text does not linger in free pages. An older gateway cannot read these rows.

Built-in tag types. The gateway writes the types it carries under @types.built-in at every start: added when missing, written again when this version defines them differently, left alone when they are the same. Instances of a changed built-in type re-read the new definition.

Tag types and instances. Every instance is re-materialized against its current type before the gateway is considered ready, so a type whose definition changed with the version is applied to its instances.

Start screens. A gateway from before named start screens had one gateway-wide start screen setting. When the start-screen table is still empty and that setting names a screen, the upgrade creates one start screen entry from it, named after the screen and marked as the default, and clears the old setting.

Staged restore. If a restore was staged from the dashboard before the restart, it is applied now, before anything opens the database, and the previous database is kept under backups/.

Modules the operator had stopped stay stopped (modules.json); module log levels are kept too.

Module compatibility​

Each module declares the Scadex.Sdk contract it was built against in module.json as sdkVersion (major.minor). It loads on a gateway with the same major and the same or a newer minor. This release of the gateway provides contract 1.3.

Module declaresGateway 1.3Result
1.2same major, older minorloads
1.3sameloads
1.4newer minorincompatible, nothing of it runs
2.0other majorincompatible

A refused module shows as incompatible on Gateway > System > Modules with the reason in error; the gateway and the other modules carry on. The modules built into the image always match the image. A drop-in or uploaded module from an older gateway keeps loading as long as its major matches; one built for a newer gateway does not.

A module that needs the script sandbox (the cron module, or your own that uses IModuleContext.Scripts) declares 1.3, so it never loads on an older gateway where that member is missing.

Rolling back​

Rolling back is starting the previous image on a volume whose database it can read. Because the current version rewrites the database (schema and encrypted module state), the safe path is the backup you took first:

  1. Stop the gateway: docker compose down.
  2. Set SCADEX_TAG back to the previous tag in .env.
  3. Restore the pre-upgrade backup, including keys/, over the data volume (or restore it through the dashboard once the old gateway is up, if the old version has that page).
  4. docker compose up -d.

Values recorded by the new version in the meantime are in the JetStream store and the historian's own database; restoring an older scadex.db does not remove them, but anything configured after the backup is gone.

Checklist​

  • Backup with keys/ taken and stored elsewhere.
  • Previous image tag noted and still pullable.
  • After start: health check healthy, Gateway > System > Modules shows every module running, Users roles reviewed, everyone signs in again.