]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Detailed error messages in rgw bucket name validation 41296/head
authorNizamudeen A <nia@redhat.com>
Sun, 25 Apr 2021 12:41:03 +0000 (18:11 +0530)
committerNizamudeen A <nia@redhat.com>
Wed, 12 May 2021 09:20:05 +0000 (14:50 +0530)
Explain the rgw bucket name constrains for each bucket name validation
errors.

Fixes: https://tracker.ceph.com/issues/50516
Signed-off-by: Nizamudeen A <nia@redhat.com>
(cherry picked from commit ab04e536684024c8d3613907d4bcd72fddf2ef20)

src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.po.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.html
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 6183ae25790cccd5fdbc0fe4a154e6eb3cd5b232..6950227aee97bb77a91aa3717122fd1b9be287d5 100644 (file)
@@ -129,7 +129,10 @@ export class BucketsPageHelper extends PageHelper {
       .and('have.class', 'ng-invalid');
 
     // Check that error message was printed under name input field
-    cy.get('#bid + .invalid-feedback').should('have.text', 'The value is not valid.');
+    cy.get('#bid + .invalid-feedback').should(
+      'have.text',
+      'Bucket names must be 3 to 63 characters long.'
+    );
 
     // Test invalid owner input
     // select some valid option. The owner drop down error message will not appear unless a valid user was selected at
index 310ec3d171f55485c770d789a671c31fb870fb47..be54ee84efb51ef048c8bb19a2c6a787dd0cc2c4 100644 (file)
             <span class="invalid-feedback"
                   *ngIf="bucketForm.showError('bid', frm, 'bucketNameExists')"
                   i18n>The chosen name is already in use.</span>
+            <span class="invalid-feedback"
+                  *ngIf="bucketForm.showError('bid', frm, 'containsUpperCase')"
+                  i18n>Bucket names must not contain uppercase characters or underscores.</span>
+            <span class="invalid-feedback"
+                  *ngIf="bucketForm.showError('bid', frm, 'lowerCaseOrNumber')"
+                  i18n>Each label must start and end with a lowercase letter or a number.</span>
+            <span class="invalid-feedback"
+                  *ngIf="bucketForm.showError('bid', frm, 'ipAddress')"
+                  i18n>Bucket names cannot be formatted as IP address.</span>
+            <span class="invalid-feedback"
+                  *ngIf="bucketForm.showError('bid', frm, 'onlyLowerCaseAndNumbers')"
+                  i18n>Bucket names can only contain lowercase letters, numbers, and hyphens.</span>
+            <span class="invalid-feedback"
+                  *ngIf="bucketForm.showError('bid', frm, 'shouldBeInRange')"
+                  i18n>Bucket names must be 3 to 63 characters long.</span>
           </div>
         </div>
 
index 82e1a1e47f2bfdc92662b8d03bf95801b221d98b..aa02c4cc0304cab166d08f41b2b37eefe3c3f0e2 100644 (file)
@@ -54,14 +54,14 @@ describe('RgwBucketFormComponent', () => {
   });
 
   describe('bucketNameValidator', () => {
-    const testValidator = (name: string, valid: boolean) => {
+    const testValidator = (name: string, valid: boolean, expectedError?: string) => {
       rgwBucketServiceGetSpy.and.returnValue(throwError('foo'));
       formHelper.setValue('bid', name, true);
-      tick(500);
+      tick();
       if (valid) {
         formHelper.expectValid('bid');
       } else {
-        formHelper.expectError('bid', 'bucketNameInvalid');
+        formHelper.expectError('bid', expectedError);
       }
     };
 
@@ -70,11 +70,14 @@ describe('RgwBucketFormComponent', () => {
     }));
 
     it('bucket names cannot be formatted as IP address', fakeAsync(() => {
-      testValidator('172.10.4.51', false);
+      const testIPs = ['1.1.1.01', '001.1.1.01', '127.0.0.1'];
+      for (const ip of testIPs) {
+        testValidator(ip, false, 'ipAddress');
+      }
     }));
 
     it('bucket name must be >= 3 characters long (1/2)', fakeAsync(() => {
-      testValidator('ab', false);
+      testValidator('ab', false, 'shouldBeInRange');
     }));
 
     it('bucket name must be >= 3 characters long (2/2)', fakeAsync(() => {
@@ -82,7 +85,7 @@ describe('RgwBucketFormComponent', () => {
     }));
 
     it('bucket name must be <= than 63 characters long (1/2)', fakeAsync(() => {
-      testValidator(_.repeat('a', 64), false);
+      testValidator(_.repeat('a', 64), false, 'shouldBeInRange');
     }));
 
     it('bucket name must be <= than 63 characters long (2/2)', fakeAsync(() => {
@@ -90,23 +93,31 @@ describe('RgwBucketFormComponent', () => {
     }));
 
     it('bucket names must not contain uppercase characters or underscores (1/2)', fakeAsync(() => {
-      testValidator('iAmInvalid', false);
+      testValidator('iAmInvalid', false, 'containsUpperCase');
+    }));
+
+    it('bucket names can only contain lowercase letters, numbers, and hyphens', fakeAsync(() => {
+      testValidator('$$$', false, 'onlyLowerCaseAndNumbers');
     }));
 
     it('bucket names must not contain uppercase characters or underscores (2/2)', fakeAsync(() => {
-      testValidator('i_am_invalid', false);
+      testValidator('i_am_invalid', false, 'containsUpperCase');
+    }));
+
+    it('bucket names must start and end with letters or numbers', fakeAsync(() => {
+      testValidator('abcd-', false, 'lowerCaseOrNumber');
     }));
 
     it('bucket names with invalid labels (1/3)', fakeAsync(() => {
-      testValidator('abc.1def.Ghi2', false);
+      testValidator('abc.1def.Ghi2', false, 'containsUpperCase');
     }));
 
     it('bucket names with invalid labels (2/3)', fakeAsync(() => {
-      testValidator('abc.1_xy', false);
+      testValidator('abc.1_xy', false, 'containsUpperCase');
     }));
 
     it('bucket names with invalid labels (3/3)', fakeAsync(() => {
-      testValidator('abc.*def', false);
+      testValidator('abc.*def', false, 'lowerCaseOrNumber');
     }));
 
     it('bucket names must be a series of one or more labels and can contain lowercase letters, numbers, and hyphens (1/3)', fakeAsync(() => {
index bde9390dcf310c4f330b67b7a53dd6df3e34d050..da3fb9f3e0b128a1279ab6e290b3c0e6916ad438 100644 (file)
@@ -250,19 +250,27 @@ export class RgwBucketFormComponent extends CdForm implements OnInit {
         return observableOf(null);
       }
       const constraints = [];
+      let errorName: string;
       // - Bucket names cannot be formatted as IP address.
       constraints.push(() => {
         const ipv4Rgx = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i;
         const ipv6Rgx = /^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i;
         const name = this.bucketForm.get('bid').value;
-        let notAnIP = true;
+        let notIP = true;
         if (ipv4Rgx.test(name) || ipv6Rgx.test(name)) {
-          notAnIP = false;
+          errorName = 'ipAddress';
+          notIP = false;
         }
-        return notAnIP;
+        return notIP;
       });
       // - Bucket names can be between 3 and 63 characters long.
-      constraints.push((name: string) => _.inRange(name.length, 3, 64));
+      constraints.push((name: string) => {
+        if (!_.inRange(name.length, 3, 64)) {
+          errorName = 'shouldBeInRange';
+          return false;
+        }
+        return true;
+      });
       // - Bucket names must not contain uppercase characters or underscores.
       // - Bucket names must start with a lowercase letter or number.
       // - Bucket names must be a series of one or more labels. Adjacent
@@ -274,14 +282,17 @@ export class RgwBucketFormComponent extends CdForm implements OnInit {
         return _.every(labels, (label) => {
           // Bucket names must not contain uppercase characters or underscores.
           if (label !== _.toLower(label) || label.includes('_')) {
+            errorName = 'containsUpperCase';
             return false;
           }
           // Bucket names can contain lowercase letters, numbers, and hyphens.
           if (!/[0-9a-z-]/.test(label)) {
+            errorName = 'onlyLowerCaseAndNumbers';
             return false;
           }
           // Each label must start and end with a lowercase letter or a number.
-          return _.every([0, label.length], (index) => {
+          return _.every([0, label.length - 1], (index) => {
+            errorName = 'lowerCaseOrNumber';
             return /[a-z]/.test(label[index]) || _.isInteger(_.parseInt(label[index]));
           });
         });
@@ -289,7 +300,20 @@ export class RgwBucketFormComponent extends CdForm implements OnInit {
       if (!_.every(constraints, (func: Function) => func(control.value))) {
         return observableTimer().pipe(
           map(() => {
-            return { bucketNameInvalid: true };
+            switch (errorName) {
+              case 'onlyLowerCaseAndNumbers':
+                return { onlyLowerCaseAndNumbers: true };
+              case 'shouldBeInRange':
+                return { shouldBeInRange: true };
+              case 'ipAddress':
+                return { ipAddress: true };
+              case 'containsUpperCase':
+                return { containsUpperCase: true };
+              case 'lowerCaseOrNumber':
+                return { lowerCaseOrNumber: true };
+              default:
+                return { bucketNameInvalid: true };
+            }
           })
         );
       }