Files
kandev/docs/plans/kubernetes-executor/task-02-lifecycle.md
T
2026-09-02 13:50:03 +00:00

73 lines
3.9 KiB
Markdown

---
id: "02-lifecycle"
title: "Kubernetes lifecycle and recovery"
status: completed
wave: 2
depends_on: ["01-backend-foundation"]
plan: "plan.md"
spec: "../../specs/kubernetes-executor/spec.md"
---
# Task 02: Kubernetes lifecycle and recovery
- **Acceptance:** CreateInstance provisions/verifies storage and Pod, injects
agentctl/config/auth through exec, binds a loopback forward, and completes the
existing health/nonce handshake.
- **Acceptance:** restart/reconnect verifies exact Pod/PVC UIDs and ownership
labels, rotates local forwarding, and surfaces deterministic remote status.
Exact-Pod reconnect is independent of the current profile row; replacement
of a missing retained Pod uses the recorded non-secret workload snapshot,
even after that profile is edited or deleted.
- **Acceptance:** ordinary stop preserves resources; terminal/forced cleanup is
idempotent, fails closed, and never deletes an existing claim.
- **Verification:** `cd apps/backend && go test -race ./internal/agent/runtime/lifecycle/...`
- **Files likely touched:** `apps/backend/internal/agent/runtime/lifecycle/executor_kubernetes*.go`,
`executor_backend.go`, `manager_launch.go`, liveness/status files, and adjacent tests.
- **Dependencies:** Task 01.
- **Parallelism:** parallel-safe with Tasks 03 and 04 after Task 01; owns
lifecycle files and metadata allowlists.
- **Inputs:** spec State machine/Persistence/Failure modes; ADR exact identity
rules; Docker and SSH reconnect/cleanup patterns.
## Results
Implemented the real Kubernetes lifecycle behind the existing
`ExecutorBackend` boundary. Fresh launch now composes and admission-validates
the exact Pod/PVC, persists provisional and admitted identities before later
fallible phases, materializes agentctl/auth/config/skills through exec, starts
a loopback-only WebSocket-primary/SPDY-fallback forward, and completes the
managed health/nonce handshake. The streaming transport honors Kubernetes REST
auth, proxy, TLS, and custom dial hooks; cancellation closes a blocked
handshake without coupling a successful upgraded stream to its deadline.
The live Kind launch also established the secret-store boundary used by that
bootstrap: lifecycle internals receive the raw store so private
`kandev-runtime:*` nonce/auth records can be materialized, while SSH, Sprites,
credential providers, and other user-visible consumers receive the filtered
`UserVisibleStore`. This keeps runtime-only records inaccessible through public
secret surfaces without blocking managed Kubernetes startup.
Reconnect, restart, active refresh, model switch, and sibling-session reuse use
the recorded six-field resource identity and immutable workload snapshot.
Exact UID/resource-version and complete ownership-label checks guard deletion.
Ordinary stop retains resources, terminal cleanup preserves durable inventory
when teardown fails, existing claims are never deleted, and restart recovery
can reconstruct cleanup without an in-memory execution.
Verification completed on 2026-08-24:
- `cd apps/backend && golangci-lint run ./...` passed with `0 issues` after
behavior-preserving complexity, duplication, nesting, constant, and test-file
refactors.
- `cd apps/backend && go test -race ./internal/agent/runtime/lifecycle/...`
passed (`lifecycle` 43.627 seconds; `lifecycle/skill` 1.052 seconds).
- `cd apps/backend && go test -race ./internal/agent/kubernetes -count=1`
passed, including blocked WebSocket/SPDY cancellation, post-upgrade survival,
REST custom-dial preservation, and cancellation/detach race coverage.
- `cd apps/backend && go test ./internal/orchestrator/...` and
`go test ./internal/backendapp -run 'Test.*Kubernetes' -count=1` passed.
- `cd apps/backend && go test ./internal/backendapp -run
'TestLifecycleSecretStoresSeparateRuntimeAndUserCredentialSecrets|Test.*Kubernetes'
-count=1` passed after the live Kind secret-store correction.
- `gofmt`, `go mod tidy -diff`, `go mod verify`, and `git diff --check` passed.