Skip to content

feat(admin): add bucket migration commands for on-demand migration - #366

Merged
overtrue merged 1 commit into
mainfrom
overtrue/issue-364-implementation-810c07
Sep 7, 2026
Merged

overtrue merged 1 commit into
mainfrom
overtrue/issue-364-implementation-810c07

Conversation

@overtrue

@overtrue overtrue commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Related issue

Closes #364.

Background

RustFS server ships On-Demand Migration: a bucket names an external S3-compatible source bucket, a GET that misses locally is served from the source and stored locally, and a background backfill job pulls the rest. The server side is complete; rc had no command surface for the /rustfs/admin/v3/on-demand-migration/{bucket} route family, so operators had to drive it with awscurl.

Solution

Adds rc admin bucket migration set|get|rm|status and rc admin bucket migration backfill start|cancel|status, following the existing core / s3 / cli layering.

  • core (crates/core/src/admin/on_demand_migration.rs): request and response types, the OnDemandMigrationApi trait, and local validation mirroring the server bounds. Every response field is optional with the server default, so an older server that omits fields still parses and unknown fields from a newer server are ignored. Credential values are dropped at the parsing boundary; only their presence survives.
  • s3 (crates/s3/src/admin/on_demand_migration.rs): SigV4 transport. The PUT body is held in zeroizing storage and handed to the HTTP client by ownership; responses are bounded and error bodies are credential-scrubbed. Status mapping: 400 OnDemandMigrationSourceUnreachable → network (3), other 400 → usage (2), 401/403 → auth (4), 404 with a known code → not found (5), any other 404 → unsupported (7) with server does not support on-demand migration, 409 → conflict (6), 501 → unsupported (7).
  • cli (crates/cli/src/commands/admin/bucket.rs): the secret is taken from --secret-key, then RC_ODM_SECRET_KEY, then a hidden prompt (human mode on a terminal only). The REDACTED placeholder is refused because set replaces the configuration wholesale. set --dry-run maps to PUT ...?dry-run=true. Human output renders one key/value table per document; a null served_by_source_ratio renders as an em dash, never zero. --watch refreshes a progress line until the backfill job reaches a terminal state, or streams one JSON record per refresh with --json.
  • Wire fixtures are vendored from rustfs/rustfs crates/madmin/fixtures/on_demand_migration/ at commit 1a88870809896c989465540b519afc74731d7f33, with provenance in a README. Parse and transport tests read those files rather than hand-written literals.
  • Output schema v3 gains the on_demand_migration family (data: {operation, bucket, result}) with success/empty/error fixtures. docs/reference/rc/admin.md and the README document the workflow, secret handling, output, and exit codes.

Deviation from the issue

The issue lists exit code 5 for a 409 backfill conflict. crates/cli/src/exit_code.rs is a protected contract where 5 is not-found and 6 is conflict, so a 409 exits 6 here. Changing that would need the Breaking Change process.

Tests

  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets -- -D warnings (zero warnings)
  • cargo test --workspace (all 64 test binaries pass)

New coverage: 11 core parse/validation tests against the vendored fixtures, 13 s3 transport tests against a local HTTP server (routes, query encoding, signed headers, plaintext body, status mapping, credential scrubbing), 11 cli unit tests (parsing, secret resolution, exit codes via a fake API, watch termination), 9 binary-level tests in crates/cli/tests/admin_bucket_migration.rs, plus help-contract and schema-contract cases.

Closes #364.

Add `rc admin bucket migration set|get|rm|status` and
`backfill start|cancel|status` for the RustFS On-Demand Migration admin
routes under /rustfs/admin/v3/on-demand-migration/{bucket}.

- core: request/response types with every response field optional and
  defaulted, credential values dropped at the parsing boundary, local
  validation mirroring the server bounds, and the OnDemandMigrationApi
  trait. Parse tests read the wire fixtures vendored from rustfs/rustfs
  (crates/madmin/fixtures/on_demand_migration, commit 1a888708).
- s3: SigV4 transport with the PUT body held in zeroizing storage,
  bounded responses, credential-scrubbed error bodies, and status
  mapping: 400 source-unreachable -> network (3), other 400 -> usage (2),
  401/403 -> auth (4), known 404 codes -> not found (5), other 404 ->
  unsupported (7, "server does not support on-demand migration"),
  409 -> conflict (6), 501 -> unsupported (7).
- cli: secret taken from --secret-key, RC_ODM_SECRET_KEY, or a hidden
  prompt; the REDACTED placeholder is refused because set replaces the
  configuration wholesale. Human tables render a null
  served_by_source_ratio as an em dash; --watch refreshes a progress
  line until the backfill job reaches a terminal state. JSON output uses
  schema v3 family on_demand_migration.
- docs, README, output schema v3, fixtures, help contract and binary
  tests updated.
@overtrue
overtrue merged commit 1c86126 into main Sep 7, 2026
15 of 17 checks passed
@overtrue
overtrue deleted the overtrue/issue-364-implementation-810c07 branch September 7, 2026 12:48
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.

Add rc commands for On-Demand Migration

1 participant