From 107abda71d5127b4170a8a1aac0bb84d9043c73f Mon Sep 17 00:00:00 2001 From: Naman Munet Date: Thu, 20 Mar 2025 20:37:02 +0530 Subject: [PATCH] mgr/dashboard: tenanted bucket lifecycle management fix Fixes: https://tracker.ceph.com/issues/70588 Signed-off-by: Naman Munet Before: As the tenant was not passed in lifecycle calls made through bucket details > tiering tab, & also account_id was not resolved to the user of the bucket, hence not able to manage the Tiering configuration lifecycle changes After: Account_id is resolved to user_id and tenant is additionally passed to the lifecycle API so as to handle the tenanted bucket scenario --- src/pybind/mgr/dashboard/controllers/rgw.py | 9 +++++++-- .../rgw-bucket-lifecycle-list.component.ts | 9 +++++++-- .../rgw-bucket-tiering-form.component.spec.ts | 4 +++- .../rgw-bucket-tiering-form.component.ts | 8 +++++--- .../frontend/src/app/shared/api/rgw-bucket.service.ts | 10 ++++++---- src/pybind/mgr/dashboard/openapi.yaml | 7 +++++++ 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index 746bd1c5d1a37..ccd98ab451b0c 100755 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -726,13 +726,18 @@ class RgwBucket(RgwRESTController): @RESTController.Collection(method='PUT', path='/lifecycle') @allow_empty_body def set_lifecycle_policy(self, bucket_name: str = '', lifecycle: str = '', daemon_name=None, - owner=None): + owner=None, tenant=None): + owner = self._get_owner(owner) + bucket_name = RgwBucket.get_s3_bucket_name(bucket_name, tenant) if lifecycle == '{}': return self._delete_lifecycle(bucket_name, daemon_name, owner) return self._set_lifecycle(bucket_name, lifecycle, daemon_name, owner) @RESTController.Collection(method='GET', path='/lifecycle') - def get_lifecycle_policy(self, bucket_name: str = '', daemon_name=None, owner=None): + def get_lifecycle_policy(self, bucket_name: str = '', daemon_name=None, owner=None, + tenant=None): + owner = self._get_owner(owner) + bucket_name = RgwBucket.get_s3_bucket_name(bucket_name, tenant) return self._get_lifecycle(bucket_name, daemon_name, owner) @Endpoint(method='GET', path='/ratelimit') diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-lifecycle-list/rgw-bucket-lifecycle-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-lifecycle-list/rgw-bucket-lifecycle-list.component.ts index 44a88c0ce482d..c16e2a012ea0f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-lifecycle-list/rgw-bucket-lifecycle-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-lifecycle-list/rgw-bucket-lifecycle-list.component.ts @@ -95,7 +95,7 @@ export class RgwBucketLifecycleListComponent implements OnInit { loadLifecyclePolicies(context: CdTableFetchDataContext) { const allLifecycleRules$ = this.rgwBucketService - .getLifecycle(this.bucket.bucket, this.bucket.owner) + .getLifecycle(this.bucket.bucket, this.bucket.owner, this.bucket.tenant) .pipe( tap((lifecycle: Lifecycle) => { this.lifecycleRuleList = lifecycle; @@ -145,7 +145,12 @@ export class RgwBucketLifecycleListComponent implements OnInit { submitLifecycleConfig(rules: any) { this.rgwBucketService - .setLifecycle(this.bucket.bucket, JSON.stringify(rules), this.bucket.owner) + .setLifecycle( + this.bucket.bucket, + JSON.stringify(rules), + this.bucket.owner, + this.bucket.tenant + ) .subscribe({ next: () => { this.notificationService.show( diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.spec.ts index 48c368692aac0..f74065e8a0a4b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.spec.ts @@ -62,6 +62,7 @@ describe('RgwBucketTieringFormComponent', () => { it('should call setLifecyclePolicy function', () => { component.ngOnInit(); + component.bucket.tenant = ''; component.tieringForm.setValue({ name: 'test', storageClass: 'CLOUD', @@ -80,7 +81,8 @@ describe('RgwBucketTieringFormComponent', () => { expect(setLifecycleSpy).toHaveBeenCalledWith( 'bucket1', JSON.stringify(component.configuredLifecycle.LifecycleConfiguration), - 'dashboard' + 'dashboard', + component.bucket.tenant ); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.ts index db1191dc951cb..dde30ad0e9473 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.ts @@ -56,7 +56,7 @@ export class RgwBucketTieringFormComponent extends CdForm implements OnInit { ngOnInit() { this.rgwBucketService - .getLifecycle(this.bucket.bucket, this.bucket.owner) + .getLifecycle(this.bucket.bucket, this.bucket.owner, this.bucket.tenant) .subscribe((lifecycle: Lifecycle) => { if (lifecycle === null) { lifecycle = { LifecycleConfiguration: { Rule: [] } }; @@ -235,7 +235,8 @@ export class RgwBucketTieringFormComponent extends CdForm implements OnInit { .setLifecycle( this.bucket.bucket, JSON.stringify(this.configuredLifecycle.LifecycleConfiguration), - this.bucket.owner + this.bucket.owner, + this.bucket.tenant ) .subscribe({ next: () => { @@ -262,7 +263,8 @@ export class RgwBucketTieringFormComponent extends CdForm implements OnInit { .setLifecycle( this.bucket.bucket, JSON.stringify(this.configuredLifecycle.LifecycleConfiguration), - this.bucket.owner + this.bucket.owner, + this.bucket.tenant ) .subscribe({ next: () => { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts index b1b80dc199c3b..67e26757a40c7 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts @@ -250,22 +250,24 @@ export class RgwBucketService extends ApiClient { }); } - setLifecycle(bucket_name: string, lifecycle: string, owner: string) { + setLifecycle(bucket_name: string, lifecycle: string, owner: string, tenant: string) { return this.rgwDaemonService.request((params: HttpParams) => { params = params.appendAll({ bucket_name: bucket_name, lifecycle: lifecycle, - owner: owner + owner: owner, + tenant: tenant }); return this.http.put(`${this.url}/lifecycle`, null, { params: params }); }); } - getLifecycle(bucket_name: string, owner: string) { + getLifecycle(bucket_name: string, owner: string, tenant: string) { return this.rgwDaemonService.request((params: HttpParams) => { params = params.appendAll({ bucket_name: bucket_name, - owner: owner + owner: owner, + tenant: tenant }); return this.http.get(`${this.url}/lifecycle`, { params: params }); }); diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index e1e5fab12dfa1..1363bcec56c9e 100755 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -11607,6 +11607,11 @@ paths: name: owner schema: type: string + - allowEmptyValue: true + in: query + name: tenant + schema: + type: string responses: '200': content: @@ -11643,6 +11648,8 @@ paths: type: string owner: type: string + tenant: + type: string type: object responses: '200': -- 2.39.5