]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard : Restrict create storage class with existing name 67843/head
authorAbhishek Desai <abhishek.desai1@ibm.com>
Tue, 17 Mar 2026 10:18:46 +0000 (15:48 +0530)
committerAbhishek Desai <abhishek.desai1@ibm.com>
Wed, 1 Apr 2026 06:31:54 +0000 (12:01 +0530)
fixes :
Signed-off-by: Abhishek Desai <abhishek.desai1@ibm.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-storage-class-form/rgw-storage-class-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-storage-class-form/rgw-storage-class-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-storage-class-form/rgw-storage-class-form.component.ts

index 1c0de9c9889d6561743cbad7dc50114245805460..ddd7ac68bcca4752e24d66daaf57858f1c5ec269 100644 (file)
       </div>
       @if( isTierMatch(TIER_TYPE.LOCAL )){
         <ng-container *ngTemplateOutlet="storageClassField"></ng-container>
-        <div class="form-item">
+        <div class="form-item clipboard">
         <cd-alert-panel type="info"
                         [showTitle]="false"
                         spacingClass="mb-2"
   <cds-text-label labelInputID="storage_class"
                   i18n
                   [disabled]="editing"
-                  [invalid]="storageClassForm.controls.storage_class.invalid && storageClassForm.controls.storage_class.dirty"
+                  [invalid]="storageClass.isInvalid"
                   [invalidText]="storageClassError"
                   >Name
     <input cdsText
+           cdValidate
+           #storageClass="cdValidate"
            type="text"
            id="storage_class"
            formControlName="storage_class"
-           [invalid]="storageClassForm.showError('storage_class', formDir, 'required')"/>
+           [invalid]="storageClass.isInvalid"/>
   </cds-text-label>
   <ng-template #storageClassError>
+    @if (storageClassForm.showError('storage_class', formDir, 'required')) {
     <span class="invalid-feedback"
-          *ngIf="storageClassForm.showError('storage_class', formDir, 'required')"
           i18n>This field is required.</span>
+    } @else if (storageClassForm.showError('storage_class', formDir, 'uniqueName')) {
+    <span class="invalid-feedback"
+          i18n>The Storage Class name is already in use.</span>
+    }
   </ng-template>
 </ng-template>
index 1e0f852672dbd11e74a2bc731419b59bde37814f..3d50c6ea3cd69f062138b974df963b4d5fbc856b 100644 (file)
@@ -126,6 +126,22 @@ describe('RgwStorageClassFormComponent', () => {
     expect(component).toBeTruthy();
   });
 
+  it('should mark duplicate storage class names as invalid', () => {
+    component.existingStorageClasses = [
+      {
+        storage_class: 'storageClass1',
+        placement_target: 'placement1',
+        zonegroup_name: 'zonegroup1'
+      }
+    ];
+
+    const control = component.storageClassForm.get('storage_class');
+    control.setValue('storageClass1');
+    control.updateValueAndValidity();
+
+    expect(control.hasError('uniqueName')).toBe(true);
+  });
+
   it('should set required validators for CLOUD_TIER fields', () => {
     (component as any).updateValidatorsBasedOnStorageClass(TIER_TYPE_DISPLAY.CLOUD_TIER);
     const requiredFields = ['region', 'target_endpoint', 'access_key', 'secret_key', 'target_path'];
index 59f04068eb4e5b75ef496148d2095a94a9c36e82..acb5eebd71dd183ea557b998f1d342c24faf470d 100644 (file)
@@ -100,6 +100,7 @@ export class RgwStorageClassFormComponent extends CdForm implements OnInit {
   defaultZonegroup: ZoneGroup;
   zoneGroupDetails: ZoneGroupDetails;
   storageClassInfo: StorageClass;
+  existingStorageClasses: StorageClass[] = [];
   tierTargetInfo: TierTarget;
   glacierStorageClassDetails: S3Glacier;
   allowReadThrough: boolean = false;
@@ -438,7 +439,14 @@ export class RgwStorageClassFormComponent extends CdForm implements OnInit {
     });
     this.storageClassForm = this.formBuilder.group({
       storage_class: new FormControl('', {
-        validators: [Validators.required]
+        validators: [
+          Validators.required,
+          CdValidators.custom('uniqueName', (storageClassName: string) => {
+            return this.existingStorageClasses.some(
+              (storageClass: StorageClass) => storageClass.storage_class === storageClassName
+            );
+          })
+        ]
       }),
       zonegroup: new FormControl(this.selectedZoneGroup, {
         validators: [Validators.required]
@@ -513,6 +521,8 @@ export class RgwStorageClassFormComponent extends CdForm implements OnInit {
       this.rgwZoneGroupService.getAllZonegroupsInfo().subscribe(
         (data: ZoneGroupDetails) => {
           this.zoneGroupDetails = data;
+          this.existingStorageClasses = BucketTieringUtils.filterAndMapTierTargets(data);
+          this.storageClassForm.get('storage_class')?.updateValueAndValidity({ emitEvent: false });
           this.zonegroupNames = [];
           this.zones = [];
           if (data.zonegroups && data.zonegroups.length > 0) {