Files
cephrgw-operator/docs/adoption.md
T
unkinben 54d3e38223
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Support adopting existing radosgw buckets and users
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
2026-07-25 00:15:10 +10:00

3.5 KiB

Adopting existing radosgw buckets and users

The operator can take over buckets and users that already exist in radosgw: write CRDs that match them and it manages them in place instead of recreating them. It can also hand them back without deleting the underlying RGW objects.

What happens when you create a CRD for an existing resource

CRD On adoption
ObjectStoreUser The user is not recreated and its existing keys are reused (never rotated). status.adopted becomes true. Attributes are only changed if the spec sets them (see below).
Bucket The bucket is not recreated. status.adopted becomes true. Versioning/tags/quota are only touched if the spec sets them. The policy is merged, not overwritten (see below).
BucketAccess Adds the grant's statement to the bucket policy and (for a dedicated user) reuses that user's keys.

status.adopted is also shown in kubectl get osu / kubectl get bkt under the ADOPTED column.

User attributes

To avoid clobbering an adopted user, the operator only sends attributes you set:

  • displayName — left unchanged when empty.
  • suspended — left unchanged when unset (it is an optional *bool; set it explicitly to true/false to manage it).
  • email — left unchanged when empty.
  • maxBucketsdefaults to 1000 and is always applied. If the existing user has a different limit you want to keep, set maxBuckets to match (or to the value you want).

Bucket policy is merged, not replaced

The operator owns only the policy statements it writes — they carry a cephrgwop… statement id. On every reconcile it preserves statements it does not own and reconciles only its own. So adopting a bucket that already has a hand-written policy keeps that policy; your BucketAccess grants are added alongside it.

  • Reserve the cephrgwop prefix (and the legacy prefixes full, custom, raw, readonly*, readwrite*) for the operator — do not name your own statements with them, or they will be treated as operator-owned and replaced.
  • To have the operator never touch a bucket's policy, set spec.managePolicy: false. BucketAccess grants then have no effect on that bucket.

What happens when you delete the CRD

By default, deleting a CRD deletes the underlying RGW resource. Opt out per resource to orphan it instead (the finalizer is dropped, the RGW object is left in place):

CRD Default on delete Keep the RGW object
ObjectStoreUser deletes the RGW user + keys spec.retainOnDelete: true
Bucket deletes the (empty) bucket spec.retainOnDelete: true (and never set purgeOnDelete)
BucketAccess (dedicated user) deletes the dedicated user spec.retainOnDelete: true
BucketAccess (userRef) only drops the policy statement n/a (never manages that user)
  1. Create an ObjectStoreUser for each owner, setting retainOnDelete: true and maxBuckets to the value you want. Confirm ADOPTED=true.
  2. Create the Bucket (with retainOnDelete: true) referencing that owner. With managePolicy: true (default) the existing policy is preserved.
  3. Optionally add BucketAccess objects to model existing grants; they merge into the policy. If you would rather keep managing the policy by hand, set managePolicy: false on the Bucket.
  4. To hand a resource back, delete its CRD — with retainOnDelete: true the RGW bucket/user is left untouched.