Support adopting existing radosgw buckets and users #5

Merged
benvin merged 1 commits from benvin/safe-adoption into main 2026-07-25 10:17:01 +10:00
Owner

Why

The operator assumed it created every user/bucket it managed, so taking over pre-existing radosgw state was unsafe: reconciling an existing user could overwrite its attributes, reconciling an existing bucket wiped its policy, and deleting a CRD always deleted the underlying RGW object (only Bucket had retainOnDelete). This makes adoption first-class — take over in place, and hand back without destroying anything.

Answers the questions from the request: creating CRDs for existing resources is now a safe noop on existence (keys reused, policy preserved), and deletion can orphan instead of destroy.

Changes

  • Orphan on deleteretainOnDelete added to ObjectStoreUser and BucketAccess (dedicated users), symmetric with Bucket. Deleting the CRD drops the finalizer and leaves the RGW object.
  • Non-destructive policy — the operator marks its statements with a cephrgwop* Sid and now merges: it preserves statements it does not own and reconciles only its own (MergeBucketPolicy + GetBucketPolicy). Adopting a bucket with a hand-written policy keeps it. New Bucket.spec.managePolicy (default true) opts out of policy management entirely. Legacy (unprefixed) operator sids are still recognised so upgrades don't duplicate statements.
  • Non-destructive user attributesDisplayName only sent when non-empty; suspended is now an optional *bool (unset = leave as-is). maxBuckets still defaults to 1000 (documented as an adoption consideration).
  • Adoption visibilitystatus.adopted (+ ADOPTED printcolumn) on ObjectStoreUser/Bucket, true when the RGW object pre-existed. Detection is keyed off the status identity field so a Pending owner-wait doesn't mislabel it.
  • regenerate CRDs/deepcopy; add docs/adoption.md + config/samples/05-adoption.yaml; cover merge/foreign-preservation/idempotence in policy_test.go.

Reserved statement ids

The cephrgwop prefix (and legacy full/custom/raw/readonly*/readwrite*) are treated as operator-owned — don't name your own policy statements with them. Documented in docs/adoption.md.

Verification

gofmt, go vet, go build ./..., go test -race ./... pass; CGO_ENABLED=0 binary builds; CRDs regenerated with controller-gen v0.17.3.

https://claude.ai/code/session_016CEncETbf8cvy1PhsHfFHM

## Why The operator assumed it created every user/bucket it managed, so taking over **pre-existing** radosgw state was unsafe: reconciling an existing user could overwrite its attributes, reconciling an existing bucket **wiped its policy**, and deleting a CRD always deleted the underlying RGW object (only `Bucket` had `retainOnDelete`). This makes adoption first-class — take over in place, and hand back without destroying anything. Answers the questions from the request: creating CRDs for existing resources is now a safe noop on existence (keys reused, policy preserved), and deletion can orphan instead of destroy. ## Changes - **Orphan on delete** — `retainOnDelete` added to `ObjectStoreUser` and `BucketAccess` (dedicated users), symmetric with `Bucket`. Deleting the CRD drops the finalizer and leaves the RGW object. - **Non-destructive policy** — the operator marks its statements with a `cephrgwop*` `Sid` and now **merges**: it preserves statements it does not own and reconciles only its own (`MergeBucketPolicy` + `GetBucketPolicy`). Adopting a bucket with a hand-written policy keeps it. New `Bucket.spec.managePolicy` (default `true`) opts out of policy management entirely. Legacy (unprefixed) operator sids are still recognised so upgrades don't duplicate statements. - **Non-destructive user attributes** — `DisplayName` only sent when non-empty; `suspended` is now an optional `*bool` (unset = leave as-is). `maxBuckets` still defaults to 1000 (documented as an adoption consideration). - **Adoption visibility** — `status.adopted` (+ `ADOPTED` printcolumn) on `ObjectStoreUser`/`Bucket`, true when the RGW object pre-existed. Detection is keyed off the status identity field so a `Pending` owner-wait doesn't mislabel it. - regenerate CRDs/deepcopy; add `docs/adoption.md` + `config/samples/05-adoption.yaml`; cover merge/foreign-preservation/idempotence in `policy_test.go`. ## Reserved statement ids The `cephrgwop` prefix (and legacy `full`/`custom`/`raw`/`readonly*`/`readwrite*`) are treated as operator-owned — don't name your own policy statements with them. Documented in `docs/adoption.md`. ## Verification `gofmt`, `go vet`, `go build ./...`, `go test -race ./...` pass; `CGO_ENABLED=0` binary builds; CRDs regenerated with controller-gen v0.17.3. https://claude.ai/code/session_016CEncETbf8cvy1PhsHfFHM
unkinben added 1 commit 2026-07-25 00:15:11 +10:00
Support adopting existing radosgw buckets and users
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
54d3e38223
The operator previously assumed it created every user and bucket it managed:
reconciling an existing resource could overwrite its user attributes or wipe its
bucket policy, and deleting a CRD always deleted the underlying RGW object (only
Bucket had retainOnDelete). That made taking over pre-existing radosgw state
unsafe. Make adoption first-class.

- add retainOnDelete to ObjectStoreUser and BucketAccess (dedicated users), so
  deleting the CRD orphans the RGW user instead of deleting it (symmetric with
  Bucket)
- merge bucket policy instead of replacing it: the operator marks its own
  statements with a cephrgwop* Sid and preserves any statement it does not own,
  so adopting a bucket with a hand-written policy keeps it; add Bucket
  managePolicy (default true) to opt out of policy management entirely
- only reconcile user attributes the spec sets: DisplayName when non-empty and
  Suspended is now an optional *bool, so adopting a user does not reset them
- record adoption: ObjectStoreUser/Bucket status.adopted (+ printcolumn) is true
  when the RGW object already existed on first reconcile
- add GetBucketPolicy + MergeBucketPolicy; keyed adoption detection off the
  status identity field so a Pending owner wait does not mislabel it
- regenerate CRDs/deepcopy; add docs/adoption.md and
  config/samples/05-adoption.yaml; cover the merge in policy_test.go

Claude-Session: https://claude.ai/code/session_016CEncETbf8cvy1PhsHfFHM
benvin merged commit 9bbaa2b8ba into main 2026-07-25 10:17:01 +10:00
benvin deleted branch benvin/safe-adoption 2026-07-25 10:17:01 +10:00
Sign in to join this conversation.