Skip to content

feat(runtime)!: put everything Onebox places on a host under onebox - #206

Merged
vishr merged 15 commits into
mainfrom
feat/onebox-managed-names
Sep 23, 2026
Merged

vishr merged 15 commits into
mainfrom
feat/onebox-managed-names

Conversation

@vishr

@vishr vishr commented Sep 23, 2026

Copy link
Copy Markdown
Member

Closes #205.

What changes

Everything Onebox places on a host is named onebox, and nothing it runs for the author carries the application's name. A host has one application, the onebox.app label records which, and ob destroy releases the host only after removing Onebox's resources.

Resource Before After
State directory /var/lib/ob/shop /var/lib/onebox/app
Host state /var/lib/ob/_host /var/lib/onebox/_host
Labels ob.app, ob.workload, … onebox.app, onebox.workload, …
Managed service container shop-postgres-1 onebox-postgres
Restore drill container shop-postgres-restore-1 onebox-postgres-restore
Volumes ob_shop_postgres_data onebox_postgres_data
Service Compose project ob_shop_postgres onebox_postgres
Service network ob_shop onebox_services
Ingress network ob-ingress onebox-ingress
Job units ob-shop-nightly onebox-job-nightly
Backup units ob-backup-shop-production-… onebox-backup-production-…
Proxy routers shop_web_r0 onebox_web_r0
Workload containers, app network shop-web-1, shop_default unchanged

Kept on purpose: the S3 backup prefix (<prefix>/shop_postgres, since a bucket may be shared) and the database name inside PostgreSQL.

The rule going forward

ob is kept only for the command, the project file and the artifacts an operator passes between commands (ob-plan.json, ob-approval.json, …). Every other name begins with onebox, including the onebox-run journal identifier, onebox-wal-g, .onebox-* files, /tmp/onebox-drain, onebox.snapshot.yml and internal markers. The separator shows the kind of name: onebox- for named things, onebox_ for joined names, onebox. for labels.

The naming reference documents the rule. internal/app/namespace_test.go fails the build when a string literal introduces any other ob-, ob_ or ob. name.

Reservations

  • Application names onebox and onebox-*. The ob- rule and the ob reservation are gone, because nothing derives an ob- name any more.
  • Service names proxy, discovery, services.
  • Custom Traefik objects beginning onebox_.

Compatibility code removed

  • Pre-2026.8.6 unit and credential spellings and their migration.
  • Unit ownership recovered from unit bodies.
  • Unlabelled service networks adopted from service state. The application network is still accepted when Compose created it for the application's own project, which is how a Compose file running its own proxy works.
  • Owner records without an environment.
  • The v1alpha1 secret checkpoint.
  • The short-option schedule lock.
  • The old discovery container name.
  • Unlabelled compose-run job containers.

The legacy backup repository layout stays readable, because removing it would make existing backups unrestorable.

Other fixes

  • Comments that justified naming by two applications sharing a host are rewritten.
  • An engine built without an environment takes the one its project was resolved for.

Upgrade: no migration, no fallback

See the new guide Upgrade to onebox names. Without it, commands see an unowned host, deploys are refused because shop-web-1 and shop_default carry the old label, unprotected services would start empty, and old timers keep firing. The guide covers:

  • removing the old units and containers;
  • copying volumes with the new labels;
  • moving the state directory, which holds the service credentials;
  • rewriting the owner record;
  • running ob bootstrap and ob deploy.

Releases from before the upgrade must not be rolled back to.

The unit suites and the Docker end-to-end suite pass locally. The server end-to-end suites were not run.

Containers Onebox runs from its own images now share the onebox-*
namespace with the host proxy and carry no replica ordinal, since none of
them has replicas: managed services are onebox-<service> and restore
drills onebox-<service>-restore. Workload containers keep
<app>-<component>-<replica>. Volumes, Compose projects and networks keep
the application because they hold its data.

Reserve the application name onebox and the service names proxy and
discovery, which would otherwise derive names inside that namespace or
the host proxy's own container names.

Replace comments that justified naming by two applications sharing a
host, which Onebox does not allow.

Closes #205

BREAKING CHANGE: managed service containers are renamed from
<app>-<service>-1 to onebox-<service>, and restore drill containers from
<app>-<service>-restore-1 to onebox-<service>-restore. The next deploy
recreates each managed service container; data volumes are unchanged.
Host-scoped resources Onebox runs now share one prefix: the ingress network
is onebox-ingress, alongside onebox-proxy, onebox-discovery and managed
service containers. Application names may no longer begin with onebox-,
which replaces the single onebox-proxy reservation and keeps an
application's derived names out of that namespace.

Document that derived names do not carry the environment, and that the
host owner record is what separates staging from production. Reword the
proxy lock-order comment that implied several applications per host.

BREAKING CHANGE: the default proxy network changes from ob-ingress to
onebox-ingress, and application names beginning with onebox- are refused.
The next proxy apply creates onebox-ingress and the next deploy moves
routed workloads onto it; routing is interrupted in between. The old
ob-ingress network is left in place and can be removed with
`docker network rm ob-ingress` once nothing is attached.
@vishr vishr changed the title feat(runtime)!: name managed containers onebox-<service> feat(runtime)!: put everything Onebox runs on the host under onebox-* Sep 23, 2026
Volumes, service Compose projects, the service network and restore-drill
resources move from ob_<app>_... to onebox_<app>_..., so every name Onebox
derives outside the author's workload containers begins with onebox.
The derived-name length check now measures the real derived names.

There is no migration and no fallback. Add a guide that lists the renamed
resources, what the next deploy does to a host that still holds ob_
volumes, and the manual steps to copy the data across before deploying.

BREAKING CHANGE: volumes are renamed from ob_<app>_... to
onebox_<app>_..., and Onebox does not migrate them. Deploying to an
existing host without following guides/upgrade-to-onebox-names starts
unprotected services on new, empty volumes, and refuses protected
PostgreSQL services because their recorded data volume is missing. The
old volumes stay on the host untouched.
Volumes, service Compose projects, the service network and restore-drill
resources no longer carry the application: onebox_postgres_data,
onebox_web_uploads, onebox_postgres, onebox_services. A host has one
application, the ob.app label records which, and ob destroy releases
the host only after removing these resources, so the application in the
name distinguished nothing.

Reserve the service name services, whose Compose project would derive
the service network's name.

BREAKING CHANGE: volumes are renamed from ob_<app>_<component>_<volume>
to onebox_<component>_<volume>, the service network from ob_<app> to
onebox_services, and service projects from ob_<app>_<service> to
onebox_<service>. There is no migration; guides/upgrade-to-onebox-names
gives the manual steps.
Finish putting everything Onebox places on a host in the onebox
namespace, without the application's name:

- State lives in <basePath>/app, and the default basePath is
  /var/lib/onebox. The host journal keeps its own directory.
- Scheduled job units are onebox-job-<job>; backup units are
  onebox-backup-<environment>-<service>-<operation>.
- Proxy routers and services are onebox_<workload>[_r<n>]; custom
  Traefik objects may not begin with onebox_.
- Ownership and runtime labels move from ob.* to onebox.*, and the
  compose_ob_label error code becomes compose_onebox_label.
- The ob- application-name rule and the ob reservation are gone; nothing
  derives an ob- name any more.

Remove every compatibility path: the pre-2026.8.6 unit and credential
spellings and their migration, unit ownership recovered from unit
bodies, unlabelled networks adopted from Compose labels or service
state, host owner records without an environment, the v1alpha1 secret
checkpoint, the short-option schedule lock rendezvous, the old discovery
container name, and unlabelled compose-run job containers.

An engine built without an environment now takes the one its resolved
project was resolved for.

The legacy backup repository layout stays readable: removing it would
make existing backups unrestorable.

BREAKING CHANGE: state moves from /var/lib/ob/<app> to
/var/lib/onebox/app, labels from ob.* to onebox.*, units from
ob-<app>-* and ob-backup-<app>-* to onebox-job-* and onebox-backup-*,
and owner records must name an environment. There is no migration;
guides/upgrade-to-onebox-names gives the manual steps.
@vishr vishr changed the title feat(runtime)!: put everything Onebox runs on the host under onebox-* feat(runtime)!: put everything Onebox places on a host under onebox Sep 23, 2026
- Reserve the service name ingress, whose container would take the
  ingress network's onebox-ingress name.
- Refuse to claim a host without an environment, which would write an
  owner record no command can read.
- Strip only onebox- networks on eject; ob- is an author's name again.
- Give the host journal its own directory instead of treating the
  application name _host as a sentinel in AppDir.
- Name the onebox. label namespace in the compose_onebox_label message.
- Remove distinctNames and ownedNames' unused parameters.

In the upgrade guide, remove old units under both spellings of a
hyphenated application name, give copied volumes the Compose project
and volume labels so ob destroy --volumes still finds them, and remove
only the old networks that exist.
A Compose file that runs its own proxy beside the workloads makes Compose
create <app>_default before Onebox does, labelled with the application's
project but not with onebox.app, and Docker cannot add a label to it
afterwards. Removing that evidence as legacy made bootstrap refuse every
such host, including fresh ones: the Docker end-to-end suite failed with
"network obe2e_default exists without Onebox ownership".

Accept the Compose project label again, for the application network only,
in both the engine and preflight. It proves nothing for the service
network or any other name.
Only the command, the project file and the artifacts an operator passes
between commands keep the ob prefix. Every other name Onebox creates now
begins with onebox: the onebox-run journal identifier, the onebox-wal-g
wrapper, .onebox-schedule.lease, .onebox-secret-generations,
.onebox-decrypted-* and .onebox-external-* files, /tmp/onebox-drain,
onebox.snapshot.yml, .onebox-tmp and .onebox-bak, fence and lock-loss
markers, and local temporary directories.

Document the rule and its separators in the naming reference, and add a
test that fails when a string literal introduces any other ob-, ob_ or
ob. name.

BREAKING CHANGE: host-side files, markers and the journal identifier are
renamed without migration; guides/upgrade-to-onebox-names lists them.
Workload containers from an earlier release watch /tmp/ob-drain, so they
must be replaced as the guide describes.
- Schedule and backup reconciliation read each unit's owner from its
  Description and never remove or overwrite another application's unit.
  One owner record per basePath means a second application can share a
  host, and a name alone was trusted to be ours.
- Backup units drop the environment: onebox-backup-<service>-<op>.
- Scheduled runs label their container onebox.execution.job, so the
  durable runner can reclaim one a crash left behind.
- Journal functions take a directory. The host journal is read, written
  and pruned in the same place, and deploy prunes it.
- One rule decides that Compose created the application network, shared
  by the engine and preflight.
- The namespace guard catches bare ob- prefixes and scans e2e, whose
  destroy probes and durable fixture now use the current names.
The host owner record lived under basePath, so an application with a
different basePath got its own record and could claim a host another
application already owned. Every name this branch stopped qualifying
with the application relied on one application per host, and each
shared namespace needed its own patch.

Host state — the owner record, host lock, host journal and proxy — now
lives at /var/lib/onebox/_host whatever basePath says. That restores the
invariant everywhere, so reconciliation no longer parses unit
Descriptions for ownership; that check also failed open when a unit
file could not be read.

ONEBOX_TEST_HOST_STATE_DIR relocates host state for test suites that
cannot write /var/lib, or that run several fixture applications against
one machine. It is not a supported setting.

Also:
- The host journal is pruned after proxy apply, the only place that
  writes it, rather than on every deploy. Names.HostJournalDir is its
  one spelling.
- The derived-name length check measures every name All derives, with
  escaped hyphens, ordinals and restore suffixes.
- matchesRuntimePrefix and Names.BackupTimer are gone.
- The state directory is <basePath>/app, a generic name under a path the
  operator chose. Bootstrap marks it with .onebox-app and refuses to
  adopt a non-empty one without the marker; destroy deletes nothing
  without it, so an unrelated /srv/app survives basePath: /srv.
- Preflight checks that the fixed host state directory is writable, not
  just basePath.
- The host journal is pruned after every proxy check, which is what
  writes it, and pruning is best-effort: it never fails an applied proxy.
- ob warns whenever ONEBOX_TEST_HOST_STATE_DIR is set, and says when a
  relative value is ignored.
- Drop environment fallbacks that engine.New now makes dead.
- Every lock acquisition claims the state directory and its marker, not
  only bootstrap, so no command writes lock, fence, journal or release
  files into a directory Onebox has not marked.
- Bootstrap refuses a foreign owner before touching anything, and claims
  the state directory before the host, so refusing a directory Onebox
  did not create leaves the host unclaimed.
- A destroy that keeps anything keeps the marker, so the later
  `ob destroy --volumes` can still prove the directory and finish.
- An unreadable existing directory counts as not empty.
- The host journal ages out by name, in one rm, whatever its files hold,
  so a torn record no longer stops pruning.
- The engine uses app.HostOwnerRecord rather than a second copy of it.
- The broken-link remedy no longer points at base_path.
- The .onebox-app marker is written only when missing, through a
  temporary file and a rename, so an interrupted write never leaves the
  ownership proof empty and the host locked out.
- Bootstrap reads the owner once, refuses a conflict, checks the state
  directory without changing it, claims the host, and only then lets the
  lock create the directory: a refused bootstrap leaves nothing behind.
- One ownerConflict comparison serves bootstrap, the locked claim and
  RequireHostOwner.
- replicas is capped at 100, in the loader and the schema, so a typo can
  no longer make loading a project build millions of names.
- The test host state override is set explicitly with
  app.SetTestHostStateDir; only the ob command reads its environment
  variable, and warns when it does.
- Host journal pruning is one remote command.
- Stale /var/lib/ob/<app> comments are corrected, and the unreachable
  _host application-name reservation is removed.
Write .onebox-app before creating releases/, through a per-claim staging
file, so an interrupted first claim never strands a non-empty unmarked
directory and two concurrent claims cannot race on one staging path.
Also write the marker in the Linux-only pinned-schedule lock test, which
builds its state directory by hand.
@vishr
vishr merged commit 2157448 into main Sep 23, 2026
5 checks passed
@vishr
vishr deleted the feat/onebox-managed-names branch September 23, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Align container naming rationale with the one-application-per-host contract

1 participant