Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/test-kubectl-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Build, vet and unit-test the kubectl-documentdb plugin.
#
# The plugin lives in its own Go module (documentdb-kubectl-plugin/) which is
# outside the path filters of test-unit.yml, so its tests were never executed
# in CI. This workflow gives the module the same build/vet/test treatment the
# operator module gets.
#
# The plugin imports the operator's api/preview package through a `replace`
# directive, so changes under operator/src/api/ can break it; those paths are
# included in the filter.

name: Unit Test - kubectl plugin

on:
push:
branches: [main]
paths:
- 'documentdb-kubectl-plugin/**'
- 'operator/src/api/**'
- '.github/workflows/test-kubectl-plugin.yml'
pull_request:
branches: [main]
paths:
- 'documentdb-kubectl-plugin/**'
- 'operator/src/api/**'
- '.github/workflows/test-kubectl-plugin.yml'

permissions:
contents: read

jobs:
kubectl-plugin-test:
name: Build and Test kubectl Plugin
runs-on: ubuntu-22.04
timeout-minutes: 10
defaults:
run:
working-directory: documentdb-kubectl-plugin

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: documentdb-kubectl-plugin/go.mod
cache-dependency-path: documentdb-kubectl-plugin/go.sum

- name: Download dependencies
run: go mod download

- name: Check formatting
run: |
unformatted=$(gofmt -l .)
if [ -n "$unformatted" ]; then
echo "The following files are not gofmt'd:"
echo "$unformatted"
exit 1
fi

- name: Build
run: go build ./...

- name: Run go vet
run: go vet ./...

- name: Run unit tests
run: go test -v -race -count=1 -timeout 10m ./...

- name: Test Summary
if: always()
run: |
echo "## kubectl Plugin Test Results" >> "$GITHUB_STEP_SUMMARY"
echo "✅ kubectl plugin build, vet and unit tests completed" >> "$GITHUB_STEP_SUMMARY"
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [Unreleased]

### Major Features
- **Backup and restore commands in `kubectl documentdb`**: The kubectl plugin now covers the backup lifecycle end to end. `kubectl documentdb backup create` starts an on-demand backup (with `--retention-days` and an optional `--wait` that exits non-zero on a failed or skipped backup), `kubectl documentdb backup list` shows running/completed/failed/skipped backups with their owning schedule, expiry, and captured schema version, and `kubectl documentdb backup schedule create|list` manages `ScheduledBackup` resources with client-side cron validation. `kubectl documentdb restore` creates a new DocumentDB that bootstraps from an existing backup by cloning the source cluster's spec, dropping `spec.clusterReplication`, and setting `spec.bootstrap.recovery.backup`; use `--dry-run` to review the manifest first. See the [kubectl plugin guide](docs/operator-public-documentation/preview/kubectl-plugin.md). Resolves [#139](https://github.com/documentdb/documentdb-kubernetes-operator/issues/139).
- **Fail-fast ImageVolume capability check**: The operator now depends on the Kubernetes [ImageVolume](https://kubernetes.io/docs/concepts/storage/volumes/#image) feature to mount the DocumentDB extension into PostgreSQL pods. Instead of gating on a Kubernetes version number, the validating webhook performs a capability probe (a server-side dry-run) when a `DocumentDB` is created and **rejects the resource with an actionable error if ImageVolume is unavailable**, so you find out immediately instead of waiting for pods that never become ready. ImageVolume is GA (on by default) in Kubernetes **1.35+**; on **1.33/1.34** it is beta and must be enabled via the `ImageVolume` feature gate on a containerd/CRI-O runtime. The Helm chart's `kubeVersion` floor is relaxed to `>= 1.33.0-0` accordingly. See [Before you start](docs/operator-public-documentation/preview/getting-started/before-you-start.md).

## [0.3.0] - 2026-07-15
Expand Down
79 changes: 77 additions & 2 deletions docs/operator-public-documentation/preview/kubectl-plugin.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# kubectl-documentdb Plugin

The `kubectl documentdb` plugin provides operational tooling for Azure Cosmos DB for MongoDB (DocumentDB) deployments managed by this operator. It targets day-two operations such as status inspection, event triage, and primary promotion workflows.
The `kubectl documentdb` plugin provides operational tooling for Azure Cosmos DB for MongoDB (DocumentDB) deployments managed by this operator. It targets day-two operations such as status inspection, event triage, backup and restore, and primary promotion workflows.

## Installation

Expand All @@ -26,17 +26,88 @@ Copy `bin/kubectl-documentdb` onto your `PATH` (renaming is not required). Verif
| `kubectl documentdb status` | Collects cluster-wide health information for a DocumentDB CR across all member clusters. |
| `kubectl documentdb events` | Streams Kubernetes events scoped to a DocumentDB CR, optionally following new events. |
| `kubectl documentdb promote` | Switches the primary cluster in a fleet by patching `spec.clusterReplication.primary` and waiting for convergence. |
| `kubectl documentdb backup create` | Starts an on-demand backup by creating a `Backup` resource. |
| `kubectl documentdb backup list` | Lists running, completed, failed, and skipped backups. |
| `kubectl documentdb backup schedule create` | Creates a recurring backup schedule by creating a `ScheduledBackup` resource. |
| `kubectl documentdb backup schedule list` | Lists backup schedules with their last and next run times. |
| `kubectl documentdb restore` | Creates a new DocumentDB cluster that bootstraps from an existing backup. |

Run `kubectl documentdb <command> --help` to review all flags. Key options include:

- `--documentdb`: (required) name of the `DocumentDB` custom resource.
- `--documentdb`: name of the `DocumentDB` custom resource. Required by `status`, `events`, `promote`, `backup create`, and `backup schedule create`; optional as a filter on `backup list` and `backup schedule list`.
- `--namespace/-n`: namespace containing the resource. Defaults to `documentdb-preview-ns` for all commands.
- `--context`: kubeconfig context to use for hub-level operations (defaults to the current context).
- `--show-connections`: include connection strings in `status` output.
- `--follow/-f`: follow mode for `events` (enabled by default).
- `--since`: limit historical events to a relative duration (for example `--since=1h`).
- `--target-cluster`: target cluster name for `promote` (required).
- `--hub-context` and `--cluster-context`: override hub and target kubeconfig contexts when promoting.
- `--retention-days`: per-backup retention override for `backup create` and `backup schedule create`. Defaults to the cluster's `spec.backup.retentionDays`.
- `--status`: phase filter for `backup list` (`all`, `running`, `completed`, `failed`, `skipped`).
- `--wait`, `--wait-timeout`, and `--poll-interval`: block until a backup or restore reaches a terminal state.

## Backup and Restore

`backup` and `restore` operate on the `Backup`, `ScheduledBackup`, and `DocumentDB` custom resources in a single cluster, so they use `--context` (not `--hub-context`).

### Taking a backup

```bash
# Start a backup and return immediately
kubectl documentdb backup create --documentdb sample

# Start a backup, keep it for 7 days, and block until it finishes
kubectl documentdb backup create --documentdb sample --retention-days 7 --wait
```

The backup name defaults to `<documentdb>-<UTC timestamp>`; override it with `--name`. The command verifies the DocumentDB exists before creating the `Backup`, so a typo fails immediately instead of leaving a resource the operator can only reject later.

Backups are taken from the primary cluster only. In a multi-region deployment a `Backup` created against a standby is marked `skipped` by the operator, and `--wait` reports that as an error.

### Listing backups

```bash
# Every backup in the namespace
kubectl documentdb backup list

# Only the backups of one cluster that are still running
kubectl documentdb backup list --documentdb sample --status running

# Only the backups produced by a given schedule
kubectl documentdb backup list --scheduled-backup nightly
```

The table reports phase, the owning schedule (if any), start/stop/expiry times, and the DocumentDB schema version captured at backup time. Newest backups are listed first.

### Scheduling backups

```bash
# Back up every day at 02:00, keeping each backup for 14 days
kubectl documentdb backup schedule create --documentdb sample --schedule "0 2 * * *" --retention-days 14

kubectl documentdb backup schedule list --documentdb sample
```

The schedule name defaults to `<documentdb>-schedule`. Cron expressions are validated locally with the same parser the operator uses, so an invalid expression is rejected before the resource is created.

### Restoring

```bash
# Preview the manifest that would be created
kubectl documentdb restore --from-backup sample-20260101-020000 --name sample-restored --dry-run

# Create the restored cluster and wait for it to become healthy
kubectl documentdb restore --from-backup sample-20260101-020000 --name sample-restored --wait
```

`restore` builds a **new** DocumentDB resource; it never overwrites an existing cluster. The new spec is cloned from the DocumentDB the backup was taken from, so storage, resources, and version settings carry over, with two deliberate changes:

- `spec.bootstrap.recovery.backup.name` is set to the backup being restored.
- `spec.clusterReplication` is dropped, because the restored cluster starts standalone.

Use `--source-documentdb` when the original cluster no longer exists and you want to use another cluster's spec as the template. By default only `completed` backups can be restored; `--allow-incomplete-backup` overrides that guard.

A restore must target a binary at or above the schema version recorded on the backup. The command prints the backup's schema version so you can check this before the operator rejects the restore.

## Kubeconfig Expectations

Expand All @@ -49,12 +120,16 @@ The plugin never modifies kubeconfig files; it only reads them through `client-g
- **Status** prints a table containing cluster role, phase, pod readiness, service endpoints, and any retrieval errors per member cluster. Pass `--show-connections` to include the hub-reported primary connection string.
- **Events** prints the latest matching events immediately and switches to watch mode while `--follow` remains true.
- **Promote** patches the DocumentDB resource in the fleet hub, then (unless `--skip-wait` is used) polls both the hub and the target cluster until the reconciliation reports the desired primary cluster.
- **Backup** prints the created resource name and, with `--wait`, exits non-zero when the backup ends in `failed` or `skipped` so it can be used in scripts.
- **Restore** prints the rendered manifest with `--dry-run`, otherwise creates the DocumentDB and reports the backup's schema version.

## Troubleshooting

- Ensure the operator has already synchronized status for the target resource; otherwise `status` may report unknown phases.
- If you see context lookup errors, verify the context name exists via `kubectl config get-contexts` and matches the cluster list entry.
- Promotion waits until `status.status` reports a healthy phase on both hub and target contexts. Use `--poll-interval` and `--wait-timeout` to tune.
- A backup stuck before `running` usually means no default `VolumeSnapshotClass` exists. Check `kubectl documentdb events --documentdb <name>` for the operator's warning.
- `restore` reports `source DocumentDB ... not found` when the original cluster has been deleted. Pass `--source-documentdb` to point at another cluster whose spec should be used as the template.

## Contributing

Expand Down
Loading
Loading