Updates and versions

Two different things are called "an update", and they behave very differently:

UpdateWhat movesDowntimeAutomated rollback
DataMind OS updateThe services the Installer deploysPer service, while containers are recreatedNo
Installer self-updateThe Installer's own backend containerThe Installer is unreachable while it restartsYes — one attempt

Can I update DataMind OS from its own interface, or only from the Installer?

Only the Installer performs it, but the Installer performs it on request — including a request that comes from DataMind OS. A DataMind OS update is always an authenticated call to the Installer:

text
POST /api/deployment/deploy
POST /api/deployment/compose-up
POST /api/deployment/apply-config
POST /api/deployment/pull

The Installer's interface calls these. DataMind OS components authenticate to the Installer with a shared service token, so the platform can drive deployments the same way — the Installer's job is to do the work, not to decide who may ask.

Note

Whether a DataMind OS screen exposes an "update" control is a DataMind OS question, not an Installer question. From the Installer's side the endpoint is the endpoint, whoever calls it.

Can I update the Installer itself from its own interface?

Yes. The title bar carries a version pill: when a newer build is published on your channel it becomes an actionable "update available" indicator, and confirming it starts the self-update.

Under the hood that is POST /api/system/self-update, which is a real API call you can also make directly:

bash
curl -X POST http://localhost:8000/api/system/self-update \
  -H "Authorization: Bearer <access-token>"

Can DataMind OS trigger an update of the Installer?

Technically yes, through the shared service token; the Installer does not restrict that endpoint to a role. POST /api/system/self-update requires authentication but declares no role requirement, and the authentication guard accepts a call carrying the shared service token as an administrator-level caller. Anything that holds that token can therefore start a self-update.

Warning

That is a deliberate trust boundary between two first-party services, not a user permission. If you are assessing risk, treat the service token as the thing that grants this, and guard the place it is stored accordingly. See Access and security.

How much downtime does an Installer self-update cost?

Expect the Installer's interface and API to be unavailable while the backend container is replaced — typically a minute or two, with a hard ceiling of five minutes in the switch step. The work is sequenced to keep the visible outage as short as possible:

  1. Pre-flight, while the Installer is still alive: it re-tags the currently running image as the rollback target, downloads the published compose file, stages it, and pulls the new image.
  2. Switch: a detached helper container recreates the Installer's backend service and waits for it to report healthy, with --wait-timeout 300.
  3. Healthcheck: the new container's healthcheck has a 20-second start period, a 10-second interval and 5 retries, so "healthy" is confirmed rather than assumed.

DataMind OS is not touched by a self-update. The confirmation dialog says so explicitly, which is the point: you can move the Installer forward without disturbing the platform it manages.

Note

The interface reconnects by polling the Installer's health endpoint every 3 seconds, and gives up after 10 minutes with an instruction to reload or check the host. A wait that long means the switch did not come back — see the rollback question below.

How much downtime does a DataMind OS update cost?

Only the services that actually change are recreated, but each recreation is a short outage for that service. The Installer's own confirmation states that running services restart briefly, and that an update touching critical services should be expected to cause a brief outage.

For a targeted rollout, Apply changes is stricter and safer than Update: it recreates services in dependency tiers and waits for each tier to become healthy before starting the next one, and it fails the job if a recreated service crashes immediately.

Omit the body entirely to target everything; name services to target them only:

bash
curl -X POST http://localhost:8000/api/deployment/deploy \
  -H "Authorization: Bearer <access-token>" \
  -H "Content-Type: application/json" \
  -d '{"services":["lurien"]}'
Important

Only one job may run at a time. Starting a second deployment job while one is running is refused with a conflict, and a self-update refuses to start while any job is running — it would kill the job mid-flight.

How do I roll back a failed Installer self-update?

It rolls back by itself, once. The helper script's escalation chain is deliberately short: one switch, one rollback, then stop. If the new image fails to come up healthy within the timeout, the helper restores the compose file it backed up and brings the service up again pinned to the rollback tag — the image that was running before the update, re-tagged during pre-flight.

The outcome is recorded and reported:

OutcomeWhat you see
okThe new build is running
rolled-backThe update did not stick; the previous build is running again
failedNeither worked; the Installer is down and needs manual recovery over SSH

If both paths fail, the helper prints the manual recovery steps: fetch the Installer's compose file from blob storage, then docker compose pull && docker compose up -d.

Warning

The rollback tag is applied during pre-flight and is what protects the previous image from the Installer's own dangling-image prune. Do not remove images tagged rollback by hand.

What is the rollback tag, and how long is it kept?

It is the fixed tag rollback, applied to the image that was running immediately before the update. Because the tag keeps the image referenced, Docker does not treat it as dangling, so the prune that runs after a deployment does not delete it.

There is exactly one such tag: the next self-update re-points it at whatever is running at that moment. So "the rollback target" is always the build you were on before the most recent update — which is precisely the build a bad release needs to fall back to.

Can I roll back a DataMind OS update the same way?

No — there is no automated rollback for a DataMind OS update. The Installer implements one rollback path, and it is for its own container. A stack update recreates services in place; nothing stores a previous stack definition or re-tags previous images for that purpose.

Plan accordingly: test the release on a non-production deployment first, and take a backup before you update production. See Data and backups.

What happens if a database migration ran and the update then failed?

The Installer tells you loudly, because that is the one state it cannot repair. The schema version is recorded before the update starts. If the update does not stick and the database has migrated since, the failure detail says the rollback landed on a changed schema and that the running build must tolerate the new schema — verify manually.

Important

There are no down-migrations by design: reverting a schema is more destructive and less tested than the forward path. A release whose migration genuinely breaks compatibility is therefore non-rollbackable, and the honest answer is to restore from backup rather than to roll back.

How do I find out which build of the Installer is running?

Read the version endpoint, which resolves the digest of the running container — not the tag.

bash
curl -s http://localhost:8000/api/version \
  -H "Authorization: Bearer <access-token>"
json
{"data":{"image":"unistream.azurecr.io/delamain:prod-latest","digest":"sha256:…"}}

Resolving from the running container rather than from the image tag is deliberate: a tag can be re-pointed by a pull while the old container keeps serving, so the tag would confidently name a build that is not executing. This is also why the value is cached for the process lifetime — a container's image cannot change while it runs.

If the Installer is not running in a container at all, image comes back null and the interface shows it as a development build.

How do I find out whether an update is available?

Call the self-update check. It compares the running digest with the digest published on your channel, and separately reports whether your local compose file has drifted from the published one.

bash
curl -s http://localhost:8000/api/system/self-update-check \
  -H "Authorization: Bearer <access-token>"
json
{
  "data": {
    "updateAvailable": true,
    "currentDigest": "sha256:…",
    "remoteDigest": "sha256:…",
    "composeChanged": true,
    "error": null,
    "lastUpdate": { "status": "completed", "detail": null, "at": "2026-09-29T…", "targetDigest": "sha256:…" }
  }
}

For DataMind OS services, GET /api/deployment/update-check does the same job per service and reports, for each one, whether the image is present locally and whether the remote digest has moved.

What is compose drift, and why does it matter?

It means your on-disk compose file differs from the one published for your channel. The check normalises line endings and compares the two, reporting composeChanged.

It matters twice: it is your signal that a hand-edit will be replaced by the next update, and it is a precondition of a self-update — the switch installs the published compose file, not your copy.

If the local compose file cannot be read from inside the container, the answer is composeChanged: null with the reason "the local compose file is outside this container", which means undetermined, not unchanged.

What channels exist, and how do I pin one?

The channel decides both the image tag and the compose file that the Installer tracks. It comes from DELAMAIN_CHANNEL in the container environment; the published production compose file sets it to prod, and the development compose file sets it to dev.

ChannelImage tag resolvedPublished compose
prodprod-latestdocker-compose.yml in the delamain container of blob storage
any other channel, e.g. dev<channel>-latestdocker-compose.<channel>.yml in the delamain-<channel> container
Note

If the channel cannot be determined from the running image, both the update check and the update itself refuse rather than guess.

Does a pinned VERSION block an update?

No. The self-update pins the image tag explicitly for the switch, and a shell variable outranks the project's .env, so an operator-pinned VERSION cannot turn the update into a silent no-op. The value written into the switch is the tag the backend just pulled.

Does an update apply my saved configuration changes?

A DataMind OS update does regenerate the environment, but do not rely on it as the mechanism for a configuration change. A deploy job re-downloads the compose file and the environment schema, re-seeds configuration from it and rewrites deployment/.env, then brings services up. Because the .env is freshly rendered, changed values are in the file the recreated containers read.

The precise, observable path for a configuration change is Apply changes, which targets exactly the services the Installer reports as stale.

Where do I see what happened during an update?

Four places, in increasing order of detail:

SourceWhat it gives you
The version pill tooltipCurrent digest, and "last update failed" with the reason
GET /api/system/self-update-checklastUpdate with status, detail, timestamp and target digest
GET /api/deployment/actionsThe audit trail, including every self-update row with status and detail
docker logs delamain-self-updaterThe helper script's own output, still present after the switch

The helper also writes a one-word outcome breadcrumb to .self-update-status in the compose project's working directory — a note for a human reading the host, not something the Installer reads back.

Can an update be cancelled once it has started?

Not safely — and a self-update cannot be cancelled at all. A deployment job can be cancelled from the interface, but if the cancellation lands while compose is already recreating services the warning is explicit: some containers may have been recreated, and you should use Start to finish or Stop to remove them.

A self-update hands off to a detached helper container before the switch, precisely because it is about to kill the process that asked for the update. Once that handoff has happened there is nothing left to cancel; the helper's one-switch-one-rollback chain runs to completion.

What happens to a running job if the Installer restarts?

It is reconciled, not silently forgotten. Every job is persisted with its event stream, and on startup the Installer marks any job that was still running as failed with the message that the Installer restarted while it was running. Job events are kept for 30 days and pruned after that; a finished job's snapshot lives in memory for an hour and is then served from the database.

For the full runbook, including pre-flight checks and the maintenance window, see Updates. If an update or a restart has already gone wrong, Updates and startup is the page to read next.