labstack / labstack/onebox

Workload volume declarations: ownership, backup, and retention

Open
#150 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Go
Stars
3
Forks
0
Avg merge
2h 40m
Merged PRs (30d)
63

Description

Why these are tracked together

Three open issues change what a workloads.*.volumes[] entry means, and each was
filed against a different symptom. They share one substrate, so deciding the
entry shape once is cheaper than touching that schema node three times.

  • #141 — declarative ownership for bind-mounted host directories. Adds host
    provisioning metadata (owner, group, permissions) to an absolute bind source.
  • #142 — backup: on workload volumes. Adds a backup contract to a volume
    holding durable state.
  • #148 — retain workloads whose relative bind-mount content is unchanged.
    Not a schema change; it makes the planner test the content behind a relative
    bind rather than its shape, so an unchanged workload stops being recreated on
    every deploy.

#141 and #142 both add properties to the same node. #148 is a defect in the
planner and retention, and is included here because it is the third thing that
turns on what a volume entry means — a mount that is release-scoped versus one
that is external host state.

Verified state on main (checked at 5e03da0)

  • hasReleasePathDependency (internal/onebox/workload_plan.go:139) marks any
    workload with a relative bind non-retainable, and that case is evaluated above
    the revision comparison (workload_plan.go:70), so retain is unreachable for
    those workloads. #148's reproduction is accurate.
  • RetentionCandidates (internal/release/retention.go:80) protects evidence
    ids, active schedule leases, the current release and its predecessor chain, and
    the activation and secret checkpoints. It never inspects live container mounts,
    so #148's "hard part" is real: a container retained past the chain would mount a
    pruned release directory.
  • A volume entry today has exactly mode, name, path, source. mode is the
    rw/ro enum and a relative source is schema-forced to ro.
  • backup: exists only under a services entry that declares a driver
    (properties/services/additionalProperties/anyOf[1]), and its implementation is
    wal-g and PostgreSQL specific (internal/engine/backup_postgres.go,
    backup_postgres_ops.go, and the renderService wiring in
    internal/app/services.go:350). There is no driver-neutral copy engine to reuse.
  • ob doctor already names the gap #142 describes
    (cmd/ob/doctor.go:496), and docs/product.md:53 lists workload-volume backups
    under "Not owned today".

Decisions that belong here rather than in a child

The entry shape, decided once. #141 proposes host_path, uid, gid and
mode. host_path duplicates the existing source, and mode collides with the
existing rw/ro enum on the same node. A nested block — for example
host: {uid, gid, mode} — leaves the existing keys alone and gives #142 a place
to sit beside it. Whatever is chosen, both children should be written against it
before either is implemented.

Which volumes backup: can attach to. #142's proposal attaches it to an
absolute bind source. Sampling the config corpus, most durable workload state is
in named volumes rather than binds — ext-gitea (data), ext-immich
(upload), ext-n8n (storage), ext-plausible (data), ext-paperless
(pgdata, redisdata). A backup contract that reaches only bind sources would
miss the common case. This is also a partial answer to #142's own open question
about whether one application's inventory is representative.

Whether #142 is taken at all. It moves a documented product boundary and
needs a copy engine that does not exist yet. That is a product decision, not a
backlog pull, and it should be settled before the schema work in #141 assumes it.

Where a declared-path check runs. #141's comment proposes the shared host
prerequisite gate. RequireHostPrerequisites
(internal/app/prerequisites.go:182) takes only a Runner and asserts three
constant Docker commands, so project-declared paths need a sibling gate called
from the same three sites — internal/engine/bootstrap.go:83,
internal/app/preflight.go:84 and internal/engine/preflight.go:33 — rather than
a widened signature.

Suggested order

  1. #141 — smallest, and a directory the platform backs up should be one the
    platform provisioned.
  2. #148 — independent of the schema decision and the only one with measured
    production cost, so it need not wait on #142.
  3. #142 — only after the product boundary question is answered.

Related, not part of this

  • #75 — expose effective persistence settings in canonical and doctor.
  • #97 — relative bind source semantics (closed).
  • #119 — retain unchanged workloads (closed), whose contract #148 restores.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the child issues #141, #142, and #148, then inspect internal/onebox/workload_plan.go, internal/release/retention.go, and the prerequisite call sites named in the issue. Done means the volume entry shape, backup product boundary, and implementation order are decided clearly enough for the children to proceed without conflicting schema or ownership assumptions.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, go
Domain
cli, devops, infrastructure
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.