Skip to content

ateapi: add the ExternalVolume resource - #10

Open
hajiler wants to merge 1 commit into
shared-volumes/01-actor-volume-statusfrom
shared-volumes/03-external-volume
Open

hajiler wants to merge 1 commit into
shared-volumes/01-actor-volume-statusfrom
shared-volumes/03-external-volume

Conversation

@hajiler

@hajiler hajiler commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds ExternalVolume: an atespace-scoped CSI volume whose lifetime is independent of any actor (design: go/substrate-shared-volumes, Milestone 1, "Volume identity" Proposal 3).

  • Resource: metadata, delete_trigger, access_mode, storage_class_name, capacity, volume_id, volume_type, volume_context, status{state, refs[]}. Storage-level ID is substrate-<uid>.
  • DeleteTrigger (mutable): MANUAL (only an explicit delete removes the volume; default when registering an existing volume) or LAST_ACTOR (removed when the last referencing actor is deleted; default when provisioning). Deleting the record always deletes the storage; a reclaim policy is left as a TODO. An ATESPACE trigger is left as a TODO.
  • AccessMode (immutable, set at create, defaults to READ_WRITE_ONCE). READ_WRITE_MANY is rejected for now with a TODO; passing the mode to CSI CreateVolume is also a TODO for M2.
  • ActorRef carries actor_uid, actor_name, and active so references cover paused and suspended actors, not only resumed ones. Nothing writes refs yet; that is PR 4.
  • Create is reserve → provision → finalize; a create that dies leaves a PENDING record that is cleaned up by deleting it. Delete refuses while any ref exists, honours DeleteOptions preconditions, and deletes the storage before the row.
  • Postgres table (ON DELETE RESTRICT from atespaces, like tags), store contract tests, kubectl ate {get,create,update,delete} externalvolume with --delete-trigger and --access-mode.

PR 3 of 4, stacked on #8 (shared-volumes/01-actor-volume-status). Diff against that branch only.

Test plan

  • go test ./cmd/ateapi/internal/controlapi/ ./cmd/ateapi/internal/store/... ./cmd/ateapi/internal/defaults/ ./cmd/kubectl-ate/...
  • go test ./cmd/ateapi/internal/controlapi/functionaltest/ (new TestCreateExternalVolume_*, TestUpdateExternalVolume, TestDeleteExternalVolume)
  • cd tools/apitool && go run . validate
  • hack/verify/{codegen,gofmt,boilerplate,postgresql-migrations,golangci-lint}.sh
  • hack/verify/proto-fmt.sh (clang-format is not installed locally; please let CI confirm)

🤖 Generated with Claude Code

An ExternalVolume is an atespace-scoped CSI volume whose lifetime is
independent of any actor. It is provisioned from a StorageClass or registers a
volume that already exists, carries an immutable access mode, and is removed
either manually or when the last actor referencing it is deleted, according to
its delete trigger. Deleting the record also deletes the storage.

This adds the resource, its Postgres table and store methods, the
create/get/list/update/delete RPCs, and kubectl-ate commands. Nothing
references a volume yet; actor references arrive separately.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hajiler
hajiler force-pushed the shared-volumes/01-actor-volume-status branch from e57907a to 9256686 Compare October 13, 2026 15:59
@hajiler
hajiler force-pushed the shared-volumes/03-external-volume branch from b68483b to 1c24dc1 Compare October 13, 2026 15:59
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.

1 participant