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
This commit is contained in:
@@ -156,6 +156,12 @@ spec:
|
||||
- actions
|
||||
type: object
|
||||
type: array
|
||||
retainOnDelete:
|
||||
description: |-
|
||||
RetainOnDelete keeps the dedicated RGW user (created when UserRef is empty)
|
||||
instead of deleting it when this BucketAccess is removed. Ignored when
|
||||
UserRef is set (that user is never managed here). Defaults to false.
|
||||
type: boolean
|
||||
secretName:
|
||||
description: |-
|
||||
SecretName is the Secret the operator writes credentials into for the
|
||||
|
||||
@@ -26,6 +26,9 @@ spec:
|
||||
- jsonPath: .status.policyPrincipals
|
||||
name: Grants
|
||||
type: integer
|
||||
- jsonPath: .status.adopted
|
||||
name: Adopted
|
||||
type: boolean
|
||||
- jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
@@ -58,6 +61,16 @@ spec:
|
||||
description: BucketName is the S3 bucket name. Defaults to metadata.name.
|
||||
Immutable.
|
||||
type: string
|
||||
managePolicy:
|
||||
default: true
|
||||
description: |-
|
||||
ManagePolicy controls whether the operator manages the bucket's S3 policy
|
||||
from BucketAccess grants. When true (the default) the operator reconciles
|
||||
its own statements while preserving any statements it does not own, so it
|
||||
is safe to adopt a bucket that already has a policy. Set to false to leave
|
||||
the bucket policy entirely untouched (BucketAccess grants then have no
|
||||
effect on this bucket).
|
||||
type: boolean
|
||||
objectLock:
|
||||
description: ObjectLock configures S3 object lock. Enabling it forces
|
||||
versioning on.
|
||||
@@ -144,6 +157,11 @@ spec:
|
||||
status:
|
||||
description: BucketStatus reports observed bucket state.
|
||||
properties:
|
||||
adopted:
|
||||
description: |-
|
||||
Adopted reports that the RGW bucket already existed when the operator
|
||||
first reconciled this resource (it was taken over, not created).
|
||||
type: boolean
|
||||
bucketID:
|
||||
description: BucketID is the RGW internal bucket instance id.
|
||||
type: string
|
||||
|
||||
@@ -23,6 +23,9 @@ spec:
|
||||
- jsonPath: .status.secretName
|
||||
name: Secret
|
||||
type: string
|
||||
- jsonPath: .status.adopted
|
||||
name: Adopted
|
||||
type: boolean
|
||||
- jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
@@ -90,6 +93,12 @@ spec:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
retainOnDelete:
|
||||
description: |-
|
||||
RetainOnDelete keeps the RGW user (and its keys) when the ObjectStoreUser
|
||||
resource is deleted, instead of removing it. Set this before adopting an
|
||||
existing user you may later want to hand back. Defaults to false.
|
||||
type: boolean
|
||||
secretName:
|
||||
description: |-
|
||||
SecretName is the Secret the operator writes the access/secret key into.
|
||||
@@ -97,8 +106,10 @@ spec:
|
||||
AWS_SECRET_ACCESS_KEY, BUCKET_HOST and the RGW uid.
|
||||
type: string
|
||||
suspended:
|
||||
description: Suspended, when true, suspends the user so its keys stop
|
||||
working.
|
||||
description: |-
|
||||
Suspended manages the user's suspended state: true suspends the user so
|
||||
its keys stop working, false resumes it. When unset the operator does not
|
||||
touch the suspended state (useful when adopting an existing user).
|
||||
type: boolean
|
||||
uid:
|
||||
description: UID is the RGW user id. Defaults to metadata.name. Immutable
|
||||
@@ -108,6 +119,11 @@ spec:
|
||||
status:
|
||||
description: ObjectStoreUserStatus reports observed user state.
|
||||
properties:
|
||||
adopted:
|
||||
description: |-
|
||||
Adopted reports that the RGW user already existed when the operator first
|
||||
reconciled this resource (it was taken over, not created).
|
||||
type: boolean
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
|
||||
+42
-2
@@ -157,6 +157,12 @@ spec:
|
||||
- actions
|
||||
type: object
|
||||
type: array
|
||||
retainOnDelete:
|
||||
description: |-
|
||||
RetainOnDelete keeps the dedicated RGW user (created when UserRef is empty)
|
||||
instead of deleting it when this BucketAccess is removed. Ignored when
|
||||
UserRef is set (that user is never managed here). Defaults to false.
|
||||
type: boolean
|
||||
secretName:
|
||||
description: |-
|
||||
SecretName is the Secret the operator writes credentials into for the
|
||||
@@ -290,6 +296,9 @@ spec:
|
||||
- jsonPath: .status.policyPrincipals
|
||||
name: Grants
|
||||
type: integer
|
||||
- jsonPath: .status.adopted
|
||||
name: Adopted
|
||||
type: boolean
|
||||
- jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
@@ -322,6 +331,16 @@ spec:
|
||||
description: BucketName is the S3 bucket name. Defaults to metadata.name.
|
||||
Immutable.
|
||||
type: string
|
||||
managePolicy:
|
||||
default: true
|
||||
description: |-
|
||||
ManagePolicy controls whether the operator manages the bucket's S3 policy
|
||||
from BucketAccess grants. When true (the default) the operator reconciles
|
||||
its own statements while preserving any statements it does not own, so it
|
||||
is safe to adopt a bucket that already has a policy. Set to false to leave
|
||||
the bucket policy entirely untouched (BucketAccess grants then have no
|
||||
effect on this bucket).
|
||||
type: boolean
|
||||
objectLock:
|
||||
description: ObjectLock configures S3 object lock. Enabling it forces
|
||||
versioning on.
|
||||
@@ -408,6 +427,11 @@ spec:
|
||||
status:
|
||||
description: BucketStatus reports observed bucket state.
|
||||
properties:
|
||||
adopted:
|
||||
description: |-
|
||||
Adopted reports that the RGW bucket already existed when the operator
|
||||
first reconciled this resource (it was taken over, not created).
|
||||
type: boolean
|
||||
bucketID:
|
||||
description: BucketID is the RGW internal bucket instance id.
|
||||
type: string
|
||||
@@ -519,6 +543,9 @@ spec:
|
||||
- jsonPath: .status.secretName
|
||||
name: Secret
|
||||
type: string
|
||||
- jsonPath: .status.adopted
|
||||
name: Adopted
|
||||
type: boolean
|
||||
- jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
@@ -586,6 +613,12 @@ spec:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
retainOnDelete:
|
||||
description: |-
|
||||
RetainOnDelete keeps the RGW user (and its keys) when the ObjectStoreUser
|
||||
resource is deleted, instead of removing it. Set this before adopting an
|
||||
existing user you may later want to hand back. Defaults to false.
|
||||
type: boolean
|
||||
secretName:
|
||||
description: |-
|
||||
SecretName is the Secret the operator writes the access/secret key into.
|
||||
@@ -593,8 +626,10 @@ spec:
|
||||
AWS_SECRET_ACCESS_KEY, BUCKET_HOST and the RGW uid.
|
||||
type: string
|
||||
suspended:
|
||||
description: Suspended, when true, suspends the user so its keys stop
|
||||
working.
|
||||
description: |-
|
||||
Suspended manages the user's suspended state: true suspends the user so
|
||||
its keys stop working, false resumes it. When unset the operator does not
|
||||
touch the suspended state (useful when adopting an existing user).
|
||||
type: boolean
|
||||
uid:
|
||||
description: UID is the RGW user id. Defaults to metadata.name. Immutable
|
||||
@@ -604,6 +639,11 @@ spec:
|
||||
status:
|
||||
description: ObjectStoreUserStatus reports observed user state.
|
||||
properties:
|
||||
adopted:
|
||||
description: |-
|
||||
Adopted reports that the RGW user already existed when the operator first
|
||||
reconciled this resource (it was taken over, not created).
|
||||
type: boolean
|
||||
conditions:
|
||||
items:
|
||||
description: Condition contains details for one aspect of the current
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# Adopting an existing radosgw user + bucket. The operator takes them over in
|
||||
# place: no recreation, existing keys reused, existing bucket policy preserved.
|
||||
# retainOnDelete keeps the RGW objects if these CRDs are later deleted.
|
||||
# See docs/adoption.md.
|
||||
apiVersion: ceph.unkin.net/v1alpha1
|
||||
kind: ObjectStoreUser
|
||||
metadata:
|
||||
name: legacy-owner
|
||||
namespace: default
|
||||
spec:
|
||||
# uid must match the existing RGW user id.
|
||||
uid: legacy-owner
|
||||
# Set maxBuckets to the existing user's limit (it otherwise defaults to 1000
|
||||
# and would be applied). Leave displayName/suspended unset to keep them as-is.
|
||||
maxBuckets: 1000
|
||||
retainOnDelete: true
|
||||
---
|
||||
apiVersion: ceph.unkin.net/v1alpha1
|
||||
kind: Bucket
|
||||
metadata:
|
||||
name: legacy-data
|
||||
namespace: default
|
||||
spec:
|
||||
# bucketName must match the existing bucket.
|
||||
bucketName: legacy-data
|
||||
ownerRef: legacy-owner
|
||||
retainOnDelete: true
|
||||
# managePolicy defaults to true: the operator merges its BucketAccess grants
|
||||
# into the existing policy, preserving statements it does not own. Set it to
|
||||
# false to leave the bucket policy entirely under manual control.
|
||||
managePolicy: true
|
||||
Reference in New Issue
Block a user