]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: fix bucket rate limit API on owner change 62764/head
authorNaman Munet <naman.munet@ibm.com>
Thu, 10 Apr 2025 11:40:02 +0000 (17:10 +0530)
committerNaman Munet <naman.munet@ibm.com>
Mon, 14 Apr 2025 08:08:32 +0000 (13:38 +0530)
Fixes: https://tracker.ceph.com/issues/70874
PR covers & fixes below scenarios:
Whenever we change the owner of bucket from non-tenanted to tenanted and
vice-versa with the rate-limit changes, there was issue in sending bucket name
Scenario 1: Changing the bucket owner from tenanted to non-tenanted
Scenario 2: Changing the bucket owner from non-tenanted to tenanted
Scenario 3: Keeping the owner(tenanted) same and changing only rate limit

Signed-off-by: Naman Munet <naman.munet@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.ts

index 0de5bbdef563c7e76c362121063a22e33cf75ff4..f72573e12a43ed40c23f9affd3a7e10da829c86d 100644 (file)
@@ -21,6 +21,8 @@ import { RgwBucketFormComponent } from './rgw-bucket-form.component';
 import { RgwRateLimitComponent } from '../rgw-rate-limit/rgw-rate-limit.component';
 import { CheckboxModule, SelectModule } from 'carbon-components-angular';
 import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { LoadingStatus } from '~/app/shared/forms/cd-form';
 
 describe('RgwBucketFormComponent', () => {
   let component: RgwBucketFormComponent;
@@ -30,6 +32,7 @@ describe('RgwBucketFormComponent', () => {
   let rgwBucketServiceGetSpy: jasmine.Spy;
   let enumerateSpy: jasmine.Spy;
   let formHelper: FormHelper;
+  let childComponent: RgwRateLimitComponent;
 
   configureTestBed({
     declarations: [RgwBucketFormComponent, RgwRateLimitComponent],
@@ -338,4 +341,90 @@ describe('RgwBucketFormComponent', () => {
     component.deleteTag(0);
     expect(updateValidationSpy).toHaveBeenCalled();
   });
+
+  describe('should call bucket ratelimit API with correct bucket name', () => {
+    beforeEach(() => {
+      component.loading = LoadingStatus.Ready;
+      fixture.detectChanges();
+      childComponent = fixture.debugElement.query(By.directive(RgwRateLimitComponent))
+        .componentInstance;
+    });
+    it('Scenario 1: tenanted owner with tenanted bucket name', () => {
+      const rateLimitSpy = spyOn(rgwBucketService, 'updateBucketRateLimit').and.returnValue(
+        observableOf([])
+      );
+      component.editing = true;
+      formHelper.setMultipleValues({
+        bid: 'tenant/bucket1',
+        owner: 'tenant$user1'
+      });
+      childComponent.form.patchValue({
+        rate_limit_enabled: true,
+        rate_limit_max_readOps: 100,
+        rate_limit_max_writeOps: 200,
+        rate_limit_max_readBytes: '10MB',
+        rate_limit_max_writeBytes: '20MB',
+        rate_limit_max_readOps_unlimited: true, // Unlimited
+        rate_limit_max_writeOps_unlimited: true, // Unlimited
+        rate_limit_max_readBytes_unlimited: true, // Unlimited
+        rate_limit_max_writeBytes_unlimited: true // Unlimited
+      });
+      childComponent.form.get('rate_limit_enabled').markAsDirty();
+      const rateLimitConfig = childComponent.getRateLimitFormValue();
+      component.updateBucketRateLimit();
+      expect(rateLimitSpy).toHaveBeenCalledWith('tenant/bucket1', rateLimitConfig);
+    });
+
+    it('Scenario 2: non tenanted owner with tenanted bucket name', () => {
+      const rateLimitSpy = spyOn(rgwBucketService, 'updateBucketRateLimit').and.returnValue(
+        observableOf([])
+      );
+      component.editing = true;
+      formHelper.setMultipleValues({
+        bid: 'tenant/bucket1',
+        owner: 'non_tenanted_user'
+      });
+      childComponent.form.patchValue({
+        rate_limit_enabled: true,
+        rate_limit_max_readOps: 100,
+        rate_limit_max_writeOps: 200,
+        rate_limit_max_readBytes: '10MB',
+        rate_limit_max_writeBytes: '20MB',
+        rate_limit_max_readOps_unlimited: true, // Unlimited
+        rate_limit_max_writeOps_unlimited: true, // Unlimited
+        rate_limit_max_readBytes_unlimited: true, // Unlimited
+        rate_limit_max_writeBytes_unlimited: true // Unlimited
+      });
+      childComponent.form.get('rate_limit_enabled').markAsDirty();
+      const rateLimitConfig = childComponent.getRateLimitFormValue();
+      component.updateBucketRateLimit();
+      expect(rateLimitSpy).toHaveBeenCalledWith('bucket1', rateLimitConfig);
+    });
+
+    it('Scenario 3: tenanted owner and with non-tenanted bucket name', () => {
+      const rateLimitSpy = spyOn(rgwBucketService, 'updateBucketRateLimit').and.returnValue(
+        observableOf([])
+      );
+      component.editing = true;
+      formHelper.setMultipleValues({
+        bid: 'bucket1',
+        owner: 'tenant$user1'
+      });
+      childComponent.form.patchValue({
+        rate_limit_enabled: true,
+        rate_limit_max_readOps: 100,
+        rate_limit_max_writeOps: 200,
+        rate_limit_max_readBytes: '10MB',
+        rate_limit_max_writeBytes: '20MB',
+        rate_limit_max_readOps_unlimited: true, // Unlimited
+        rate_limit_max_writeOps_unlimited: true, // Unlimited
+        rate_limit_max_readBytes_unlimited: true, // Unlimited
+        rate_limit_max_writeBytes_unlimited: true // Unlimited
+      });
+      childComponent.form.get('rate_limit_enabled').markAsDirty();
+      const rateLimitConfig = childComponent.getRateLimitFormValue();
+      component.updateBucketRateLimit();
+      expect(rateLimitSpy).toHaveBeenCalledWith('tenant/bucket1', rateLimitConfig);
+    });
+  });
 });
index c9c6954d2302693b3d54c30c00bf2960f7ceca43..468718214432a3786338eeb89c9cd2e81783075b 100644 (file)
@@ -412,17 +412,42 @@ export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewC
   }
 
   updateBucketRateLimit() {
+    /**
+     * Whenever we change the owner of bucket from non-tenanted to tenanted
+     * and vice-versa with the rate-limit changes there was issue in sending
+     * bucket name, hence the below logic caters to it.
+     *
+     * Scenario 1: Changing the bucket owner from tenanted to non-tenanted
+     * Scenario 2: Changing the bucket owner from non-tenanted to tenanted
+     * Scenario 3: Keeping the owner(tenanted) same and changing only rate limit
+     */
+    const owner = this.bucketForm.getValue('owner');
+    const bidInput = this.bucketForm.getValue('bid');
+
+    let bid: string;
+
+    const hasOwnerWithDollar = owner.includes('$');
+    const bidHasSlash = bidInput.includes('/');
+
+    if (bidHasSlash && hasOwnerWithDollar) {
+      bid = bidInput;
+    } else if (hasOwnerWithDollar) {
+      const ownerPrefix = owner.split('$')[0];
+      bid = `${ownerPrefix}/${bidInput}`;
+    } else if (bidHasSlash) {
+      bid = bidInput.split('/')[1];
+    } else {
+      bid = bidInput;
+    }
     // Check if bucket ratelimit has been modified.
     const rateLimitConfig: RgwRateLimitConfig = this.rateLimitComponent.getRateLimitFormValue();
     if (!!rateLimitConfig) {
-      this.rgwBucketService
-        .updateBucketRateLimit(this.bucketForm.getValue('bid'), rateLimitConfig)
-        .subscribe(
-          () => {},
-          (error: any) => {
-            this.notificationService.show(NotificationType.error, error);
-          }
-        );
+      this.rgwBucketService.updateBucketRateLimit(bid, rateLimitConfig).subscribe(
+        () => {},
+        (error: any) => {
+          this.notificationService.show(NotificationType.error, error);
+        }
+      );
     }
   }