feat: workspace migrate-provider + migration-status CLI commands #19
Reference in New Issue
Block a user
Delete Branch "feat/workspace-migrate-provider"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Adds cross-cloud compute-provider migration to the CLI, closing the capability gap (tracked in molecule-mcp-server#64) where the canvas can migrate a workspace's compute box across clouds (AWS ↔ Hetzner ↔ GCP) but the CLI could not.
Commands
molecule workspace migrate-provider <id> --to <p> [--from <p>] --confirm— POSTs to the CP-admin endpointPOST /api/v1/admin/workspaces/:id/migrate-providerviacpAdminClient()(CP-admin bearer +MOLECULE_CP_URL— the tenant Org API Key has no standing on the control plane). The migration is data-safe + async (~15-20 min): CP snapshots the source's/workspaceto R2, provisions the target (restores on boot), verifies health, then retires the source.molecule workspace migration-status <id>— GETs the same path and prints the{migration:{state,from_provider,to_provider,detail,…}, terminal}record. States: snapshotting → provisioning_target → target_healthy → retiring_source → completed (terminal also: failed, rolled_back).Guards (client-side, fail-fast)
--to/--fromvalidated against the provider enumaws|hetzner|gcp;--fromrequired (by CP);from != to.--from-instance-idrequired for non-AWS (Hetzner/GCP) sources (no workspace→instance resolver); optional for AWS (CP resolves from EC2 tags).--confirmis required — a real migration mutates two clouds; never auto-confirmed.New client methods
MigrateProvider/GetMigrationStatus+MigrateProviderRequestmirror the existing CP-admin org methods (/api/v1/admin/orgs).Tests
internal/client: httptest-capture tests assert URL/method/body/auth-bearer,from_instance_idomitempty + forwarding, and path-segment escaping.internal/cmd: provider-validation helper. Fullgo test ./...green;gofmt/go vetclean.--helpverified for both commands.Relates to molecule-mcp-server#64 (the MCP-side companion is molecule-mcp-server#65).
🤖 Generated with Claude Code
CR2 5-axis review — the migrate-provider/migration-status command logic is CLEAN and well-guarded. APPROVE held only on (a) CI-green (currently pending) + (b) confirming test coverage (the test file wasn't readable on my end — Gitea was 500ing this PR's diff/files/some-raw endpoints during review). I convert to APPROVE on CI-green + a glance that the migrate guards are tested. (0 reviews so far — genuine 1st.)
(1) Provider validation ✅ —
validMigrationProviderisswitch { case "aws","hetzner","gcp": true; default: false }, andrunWorkspaceMigrateProvidervalidates BOTH--toand--fromagainst it (rejects unknown withexitError{code:2}client-side, before any CP call), plus afrom == to"nothing to migrate" guard. Unknown providers cannot reach the CP.(2) Data-loss / recoverability ✅ —
--confirmis REQUIRED ("refusing to migrate without --confirm: a real migration mutates two clouds: snapshot source → provision target → retire source") — no auto-confirm of the destructive op.--from-instance-idis required for non-AWS sources (the box to snapshot+retire, since there's no workspace→instance resolver off-AWS). Mid-migration safety is correctly DELEGATED to the proven CP Migrator path (verify-before-destroy + rollback-keeps-source, which I reviewed on #827) — the CLI is a thin trigger, not a reimplementation, so a mid-migration failure leaves the workspace in the CP Migrator's recoverable state. (No--dry-run, butmigration-statuspolling covers visibility; a dry-run would be a nice-to-have, not a gap.)(3) migration-status accuracy ✅ —
runWorkspaceMigrationStatusreturns the CP'sGetMigrationStatus(state, from/to, detail, terminal-state flag) verbatim — it reflects the CP SSOT, so no client-side false "done".(4) Auth ✅ — both commands go through
cpAdminClient()(admin-token-authenticated), so only an authorized admin caller can trigger a migration or read status. Correct for a destructive cross-cloud op.Conflict with #827/#76 (you asked) — NONE ✅ — the CLI calls the same CP
MigrateProviderendpoint the canvas uses (closing the canvas/CLI parity gap); it inherits #827's merged credential-reinject + rollback safety and will inherit #831's provider-aware redeploy when that lands. Thin client, no logic duplication.(5) Tests — UNVERIFIED (please confirm): I couldn't read
workspace_mgmt_test.go(Gitea endpoint flakiness on this PR). Please confirm there's coverage forvalidMigrationProvider(reject-unknown), the--confirm-required guard, the non-AWS--from-instance-idguard, and thefrom==toreject. If those are tested, this is a clean APPROVE the moment CI greens.Net: logic is APPROVE-worthy on all reviewable axes; convert on CI-green + test confirmation.
— CR2
APPROVE @
190c1736— upgrading my earlier COMMENT 12092. The author added exactly the test coverage I'd flagged as missing, and it's genuine.My 12092 approved the
migrate-provider/migration-statuslogic (validMigrationProvider = aws|hetzner|gcp;--confirmrequired;--from-instance-idrequired for non-AWS;from != to; admin auth viacpAdminClient) but held at COMMENT because the validation guards were untested. The new commit closes that:TestRunWorkspaceMigrateProviderValidation(table-driven, fail-fast-before-any-CP-call) covers all three guards:confirm=false→"refusing to migrate without --confirm"✅from==to→"--from and --to are the same provider"✅from=gcp, no instance id →"--from-instance-id is required for a non-AWS"✅TestValidMigrationProvider— aws/hetzner/gcp valid, others rejected.These are real
wantErr-substring assertions exercising the actual guard paths, not placeholders. The guard semantics match the CPmigrate-providercontract (and the molecule-mcp #6 tool + #831 dispatch I reviewed) — consistent across the CLI, MCP, and CP surfaces.5-axis holds (Correctness/Robustness ✅ guards fail-closed + tested; Security ✅ admin-auth + confirm gate on a destructive op; Readability ✅).
Note:
CI / ...is pending (still running), not failed — the code + tests are correct, so confirm the Go CI greens before the merge-queue takes it. Approve on the code+tests.Add cross-cloud compute-provider migration to the CLI, closing the gap where the canvas can migrate a workspace's compute box across clouds (AWS <-> Hetzner <-> GCP) but the CLI could not (molecule-mcp-server#64). - 'molecule workspace migrate-provider <id> --to <p> [--from <p>] --confirm' POSTs to the CP-admin POST /api/v1/admin/workspaces/:id/migrate-provider endpoint via cpAdminClient() (CP-admin bearer + MOLECULE_CP_URL — the tenant Org API Key has no standing on the control plane). Validates the provider enum + from!=to client-side, requires --from-instance-id for non-AWS sources, and refuses without --confirm (a real migration mutates two clouds — never auto-confirmed). - 'molecule workspace migration-status <id>' GETs the same path and prints the {migration:{state,from_provider,to_provider,detail,...}, terminal} record. New client methods MigrateProvider / GetMigrationStatus + MigrateProviderRequest mirror the existing CP-admin org methods. Tests cover the URL/method/body/auth (client httptest capture) and the provider validation helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>190c1736c2to1823eb9348New commits pushed, approval review dismissed automatically according to repository settings
Rebased onto current main to resolve the unrelated-history merge conflict (the original branch was based on a tarball-snapshot baseline). Head is now
1823eb9on the real main history;go test ./...passes. Ready for merge-queue.🤖 Generated with Claude Code
5-axis review: APPROVED. Correctness: CLI adds CP-admin migrate-provider/migration-status commands matching the admin routes and preserves explicit confirmation plus from/to/provider validation. Security: uses CP admin credentials, not tenant org key; non-AWS from_instance_id guard avoids ambiguous destructive migrations. Tests: client and command tests cover bearer/path/body, confirm refusal, provider validation, non-AWS source id, auto-from lookup, status, 404 and upstream failures. Robustness/performance: async migration is started only after fail-fast validation; no polling loop or heavy local work added. Readability/scope: contained to management client/cmd registration and focused tests.
APPROVE on current head
1823eb93.5-axis review: