]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: tenanted bucket lifecycle management fix 62415/head
authorNaman Munet <naman.munet@ibm.com>
Thu, 20 Mar 2025 15:07:02 +0000 (20:37 +0530)
committerNaman Munet <naman.munet@ibm.com>
Mon, 24 Mar 2025 08:24:57 +0000 (13:54 +0530)
Fixes: https://tracker.ceph.com/issues/70588
Signed-off-by: Naman Munet <naman.munet@ibm.com>
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
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-lifecycle-list/rgw-bucket-lifecycle-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-tiering-form/rgw-bucket-tiering-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts
src/pybind/mgr/dashboard/openapi.yaml

index 746bd1c5d1a37665704dfa7a93668a8624b5c661..ccd98ab451b0cdbfa542d9c6924a0c32f47edcf4 100755 (executable)
@@ -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')
index 44a88c0ce482d5e586038414d692f0ac4c7bc444..c16e2a012ea0f08df0f7d502872ef9fa3877238b 100644 (file)
@@ -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(
index 48c368692aac0843dcce61302428d75092fceb62..f74065e8a0a4b4dbf5b4c8eabf48b085609ef54b 100644 (file)
@@ -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
     );
   });
 });
index db1191dc951cba5dd034e21d81741e92695b0f1c..dde30ad0e94734c2ce2ab661c8fde102f62d950f 100644 (file)
@@ -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: () => {
index b1b80dc199c3b9b389c44684d0cf4b921a0386e8..67e26757a40c7867a15f215815e9f2679f2cc1f5 100644 (file)
@@ -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 });
     });
index e1e5fab12dfa14c903aece231e85f1a463ccce96..1363bcec56c9eb77ba6af1439d06f26b9cb75aea 100755 (executable)
@@ -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':