Skip to content

feat: add backup and restore commands to kubectl-documentdb plugin - #449

Open
WentingWu666666 wants to merge 2 commits into
documentdb:mainfrom
WentingWu666666:wentingwu/kubectl-plugin-backup-commands
Open

feat: add backup and restore commands to kubectl-documentdb plugin#449
WentingWu666666 wants to merge 2 commits into
documentdb:mainfrom
WentingWu666666:wentingwu/kubectl-plugin-backup-commands

Conversation

@WentingWu666666

@WentingWu666666 WentingWu666666 commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Closes #139

What

The kubectl documentdb plugin could inspect (status, events) and fail over (promote) clusters, but had no coverage for the backup lifecycle. Operators had to hand-write Backup, ScheduledBackup, and recovery-bootstrapped DocumentDB manifests.

This adds five commands:

Command Purpose
backup create Create a Backup for a DocumentDB, with --retention-days and an optional --wait
backup list List backups with phase, owning schedule, timings, expiry, and captured schema version
backup schedule create Create a ScheduledBackup with client-side cron validation
backup schedule list List schedules with last/next run
restore Create a new DocumentDB that bootstraps from an existing backup

Notable design points

  • restore never overwrites. It always creates a new DocumentDB. The source cluster's spec is cloned as unstructured data so unknown/future fields survive the round-trip, spec.clusterReplication is dropped (a restored cluster starts standalone), and spec.bootstrap.recovery.backup is injected. --dry-run prints the manifest instead of creating it, and --source-documentdb supplies a spec template for the DR case where the original cluster is gone.
  • Cron validation matches the operator exactly. backup schedule create validates with the same cron.ParseStandard call the ScheduledBackup controller uses, so anything the plugin accepts the operator accepts.
  • Terminal-phase logic is not reimplemented. --wait reuses preview.BackupStatus.IsDone() so the plugin and operator stay in lockstep as phases evolve. A skipped backup (standby cluster) exits non-zero under --wait.
  • Backups are correlated to their schedule via the scheduledbackup label the operator already sets, so backup list --scheduled-backup <name> works without extra API fields.
  • Fail-fast on typos. backup create / backup schedule create verify the target DocumentDB exists first, rather than leaving an orphaned resource the operator can only reject on reconcile.

Refactors

  • GVR helpers shared across commands moved into cmd/gvr.go; status.go and promote.go now use them.
  • The hand-rolled fake dynamic client used in tests gained Create, a label-selector-aware List, and per-Kind object keying (it previously keyed on namespace/name only, which collides once more than one resource type is in play).

CI

While validating this I found the documentdb-kubectl-plugin module has no test execution in CI at alltest-unit.yml is path-filtered to operator/src/**, so govulncheck was the only job that ever looked at the module. The plugin's pre-existing tests (and the ~24 added here) never ran on a PR.

This adds .github/workflows/test-kubectl-plugin.yml, which runs gofmt, go build, go vet, and race-enabled go test for the module. It is filtered on documentdb-kubectl-plugin/** plus operator/src/api/** (the plugin consumes api/preview through a replace directive, so API changes can break it). It is a separate workflow rather than new paths on test-unit.yml so plugin-only PRs do not needlessly spin up the operator and Helm jobs. Happy to fold it into test-unit.yml instead if maintainers prefer.

Dependencies

go.mod promotes four already-present indirect deps to direct (cloudnative-pg, robfig/cron, sigs.k8s.io/yaml). go.sum is unchanged — no new modules, no supply-chain delta.

Testing

  • ~24 new unit tests in cmd/backup_test.go and cmd/restore_test.go covering flag validation, spec cloning, the phase guard, dry-run, already-exists, status filtering, and both --wait paths.
  • gofmt -l, go build ./..., go vet ./..., go test -race -count=1 ./... all clean.
  • Smoke-tested the built binary's --help output and error paths (missing required flags, invalid cron).
  • Ran backup list / backup schedule list read-only against a live AKS cluster.
  • Validated the exact objects the plugin emits (Backup, ScheduledBackup, and the restore-shaped DocumentDB with bootstrap.recovery and no clusterReplication) against the real CRDs and validating webhook via kubectl apply --dry-run=server. All three accepted; nothing persisted.

Docs

Both copies of kubectl-plugin.md (documentdb-kubectl-plugin/ and docs/operator-public-documentation/preview/) are updated and remain byte-identical. CHANGELOG.md gets an [Unreleased] entry.

Open questions for reviewers

  1. Should restore be top-level (as here) or nested as backup restore?
  2. Under --wait, a skipped backup currently exits non-zero. Would you prefer a warning + exit 0?

The kubectl plugin could inspect and promote clusters but had no coverage
for the backup lifecycle, so operators had to hand-write Backup,
ScheduledBackup, and recovery-bootstrapped DocumentDB manifests.

Add:

- `backup create`  - creates a Backup for a DocumentDB, with an optional
  `--retention-days` override and `--wait` that polls until the backup
  reaches a terminal phase (exiting non-zero on failed/skipped).
- `backup list`    - lists backups with phase, owning schedule, start and
  stop times, expiry, and the captured schema version, filterable by
  `--documentdb`, `--scheduled-backup`, and `--status`.
- `backup schedule create|list` - manages ScheduledBackup resources. The
  cron expression is validated client-side with the same
  `cron.ParseStandard` call the operator uses, so accept/reject semantics
  match exactly.
- `restore` - creates a *new* DocumentDB that bootstraps from an existing
  backup. The source cluster's spec is cloned as unstructured data so
  unknown fields survive, `spec.clusterReplication` is dropped because a
  restored cluster starts standalone, and `spec.bootstrap.recovery.backup`
  is injected. `--dry-run` prints the manifest instead of creating it and
  `--source-documentdb` supplies a template when the original cluster is
  gone.

The GVR helpers shared by these commands move into cmd/gvr.go, and the
hand-rolled fake dynamic client used by the tests gains Create, a
label-selector-aware List, and per-Kind object keying so multiple resource
types can coexist in one fake.

Closes documentdb#139

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Wenting Wu <wentingwu@microsoft.com>
Copilot AI lite review requested due to automatic review settings August 26, 2026 13:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds backup lifecycle coverage to the kubectl documentdb plugin so operators can create/list backups and schedules, and restore a backup into a new DocumentDB without hand-authoring CR manifests. This fits into the repo’s day-two ops tooling by extending the existing plugin commands (status/events/promote) with backup/restore workflows.

Changes:

  • Introduces backup create|list, backup schedule create|list, and restore commands (including --wait / --dry-run flows).
  • Refactors shared GroupVersionResource construction into cmd/gvr.go and updates existing commands to use it.
  • Enhances the fake dynamic client to support Create and label-selector-aware List to enable broader unit test coverage; updates docs and changelog accordingly.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
documentdb-kubectl-plugin/kubectl-plugin.md Documents new backup/restore commands and flags for the plugin guide copy in the plugin module.
docs/operator-public-documentation/preview/kubectl-plugin.md Mirrors the plugin guide updates in public operator documentation.
documentdb-kubectl-plugin/go.mod Promotes existing indirect deps to direct deps to support new command implementation.
documentdb-kubectl-plugin/cmd/root.go Registers new backup and restore commands with the root CLI.
documentdb-kubectl-plugin/cmd/backup.go Implements backup create/list and scheduled backup create/list commands plus shared helpers.
documentdb-kubectl-plugin/cmd/restore.go Implements restore command that clones a source DocumentDB spec and injects bootstrap.recovery.backup.
documentdb-kubectl-plugin/cmd/gvr.go Centralizes GVR helpers for DocumentDB/Backup/ScheduledBackup resources.
documentdb-kubectl-plugin/cmd/status.go Switches DocumentDB GVR construction to the shared helper.
documentdb-kubectl-plugin/cmd/promote.go Switches DocumentDB GVR construction to the shared helper.
documentdb-kubectl-plugin/cmd/fake_dynamic_test.go Extends fake dynamic client to support Create, label selector List, and kind-scoped object keying.
documentdb-kubectl-plugin/cmd/backup_test.go Adds unit tests for backup and scheduled-backup commands, filtering, and --wait paths.
documentdb-kubectl-plugin/cmd/restore_test.go Adds unit tests for restore validation, spec cloning, dry-run, already-exists, and wait behavior.
CHANGELOG.md Adds an Unreleased entry describing the new kubectl backup/restore functionality and links to docs.
Suppressed comments (1)

documentdb-kubectl-plugin/cmd/backup.go:487

  • The validation allows --retention-days to be 0 (meaning "use the cluster default"), but this error message claims the value must be > 0. This is misleading for users who pass 0 explicitly.
	if o.retentionDays < 0 {
		return fmt.Errorf("--retention-days must be greater than zero, got %d", o.retentionDays)
	}

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +129 to +131
if o.retentionDays < 0 {
return fmt.Errorf("--retention-days must be greater than zero, got %d", o.retentionDays)
}
The kubectl-documentdb plugin is a separate Go module that falls outside
the path filters of test-unit.yml, so its tests were never executed in CI
-- govulncheck was the only job that looked at the module at all. Add a
workflow that runs gofmt, build, vet and the race-enabled unit tests for
it, filtered on the plugin directory plus operator/src/api (which the
plugin consumes through a replace directive).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Wenting Wu <wentingwu@microsoft.com>
@documentdb-triage-tool documentdb-triage-tool Bot added CI/CD dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation ecosystem enhancement New feature or request go Pull requests that update go code test labels Aug 26, 2026
@documentdb-triage-tool

Copy link
Copy Markdown

🤖 Auto-triaged by documentdb-triage-tool.

Applied: ecosystem, go, documentation, test, CI/CD, dependencies, enhancement
Project fields suggested: Component kubectl-plugin · Priority P2 · Effort XL · Status Needs Review
Confidence: 0.92 (mixed)

Reasoning

component from path globs (kubectl-plugin, docs, test, ci, dependencies); effort from diff stats (2146+24 LOC, 14 files); LLM: Adds five new backup/restore commands to the kubectl plugin, involving cross-cutting refactors of GVR helpers, test infrastructure, and new manifest generation logic — a substantial cross-file feature addition.

If a label is wrong, remove it manually and ping @patty-chow so the rules can be tuned. The bot will not re-label items that already have component labels.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation ecosystem enhancement New feature or request go Pull requests that update go code test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Commands for backup/restore in our kubectl extension

3 participants