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
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 totrue/falseto manage it).email— left unchanged when empty.maxBuckets— defaults to1000and is always applied. If the existing user has a different limit you want to keep, setmaxBucketsto 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
cephrgwopprefix (and the legacy prefixesfull,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.BucketAccessgrants 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) |
Recommended adoption procedure
- Create an
ObjectStoreUserfor each owner, settingretainOnDelete: trueandmaxBucketsto the value you want. ConfirmADOPTED=true. - Create the
Bucket(withretainOnDelete: true) referencing that owner. WithmanagePolicy: true(default) the existing policy is preserved. - Optionally add
BucketAccessobjects to model existing grants; they merge into the policy. If you would rather keep managing the policy by hand, setmanagePolicy: falseon the Bucket. - To hand a resource back, delete its CRD — with
retainOnDelete: truethe RGW bucket/user is left untouched.