]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: nfs export enhancement for CEPHFS 58303/head
authorAvan Thakkar <athakkar@redhat.com>
Thu, 27 Jun 2024 10:06:42 +0000 (15:36 +0530)
committerAvan Thakkar <athakkar@redhat.com>
Fri, 5 Jul 2024 13:53:59 +0000 (19:23 +0530)
Fixes: https://tracker.ceph.com/issues/66718
Signed-off-by: Avan Thakkar <athakkar@redhat.com>
src/pybind/mgr/dashboard/controllers/cephfs.py
src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.spec.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.ts

index 4210746fbd1ffc16ec4bd16717a32d0ba126167c..6ba2b2380b8d23816880c050fbf7d37884cbba53 100644 (file)
@@ -842,6 +842,15 @@ class CephFSSubvolumeGroups(RESTController):
                         f'Failed to get info for subvolume group {group["name"]}: {err}'
                     )
                 group['info'] = json.loads(out)
+
+                error_code, out, err = mgr.remote('volumes', '_cmd_fs_subvolumegroup_getpath',
+                                                  None, {'vol_name': vol_name,
+                                                         'group_name': group['name']})
+                if error_code != 0:
+                    raise DashboardException(
+                        f'Failed to get path for subvolume group {group["name"]}: {err}'
+                    )
+                group['info']['path'] = out
         return subvolume_groups
 
     @RESTController.Resource('GET')
index ae427886f0e2c33625e1ce2cdaf9f4ba1c3d31fa..01350b4def4a84cb48bf1477f6af309ccc82c5ee 100644 (file)
@@ -57,7 +57,7 @@
                       formControlName="fs_name"
                       name="fs_name"
                       id="fs_name"
-                      (change)="pathChangeHandler()">
+                      (change)="volumeChangeHandler()">
                 <option *ngIf="allFsNames === null"
                         value=""
                         i18n>Loading...</option>
           </div>
         </div>
 
+        <div class="form-group row"
+             *ngIf="storageBackend === 'CEPH'">
+          <label class="cd-col-form-label"
+                 for="subvolume_group"
+                 i18n>Subvolume Group</label>
+          <div class="cd-col-form-input">
+            <select class="form-select"
+                    formControlName="subvolume_group"
+                    name="subvolume_group"
+                    id="subvolume_group"
+                    (change)="getSubVol()">
+              <option *ngIf="allsubvolgrps === null"
+                      value=""
+                      i18n>Loading...</option>
+              <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length === 0"
+                      value=""
+                      i18n>-- No CephFS subvolume group available --</option>
+              <option *ngIf="allsubvolgrps !== null && allsubvolgrps.length > 0"
+                      value=""
+                      i18n>-- Select the CephFS subvolume group --</option>
+              <option *ngFor="let subvol_grp of allsubvolgrps"
+                      [value]="subvol_grp.name">{{ subvol_grp.name }}</option>
+            </select>
+          </div>
+        </div>
+
+      <div class="form-group row"
+           *ngIf="storageBackend === 'CEPH'">
+        <label class="cd-col-form-label"
+               for="subvolume"
+               i18n>Subvolume</label>
+        <div class="cd-col-form-input">
+          <select class="form-select"
+                  formControlName="subvolume"
+                  name="subvolume"
+                  id="subvolume"
+                  (change)="getPath()">
+            <option *ngIf="allsubvols === null"
+                    value=""
+                    i18n>Loading...</option>
+            <option *ngIf="allsubvols !== null && allsubvols.length === 0"
+                    value=""
+                    i18n>-- No CephFS subvolume available --</option>
+            <option *ngIf="allsubvols !== null && allsubvols.length > 0"
+                    value=""
+                    i18n>-- Select the CephFS subvolume --</option>
+            <option *ngFor="let subvolume of allsubvols"
+                    [value]="subvolume.name">{{ subvolume.name }}</option>
+          </select>
+        </div>
+      </div>
+
         <!-- Path -->
         <div class="form-group row"
              *ngIf="storageBackend === 'CEPH'">
index e6fc6e8ddff30accad1bc90e40f3397c62707bc3..7f88c6486843f586d5339826aa5ff2d01ff3e92d 100644 (file)
@@ -91,7 +91,7 @@ describe('NfsFormComponent', () => {
       access_type: 'RW',
       clients: [],
       cluster_id: 'mynfs',
-      fsal: { fs_name: 'a', name: 'CEPH' },
+      fsal: { fs_name: '', name: 'CEPH' },
       path: '/',
       protocolNfsv4: true,
       protocolNfsv3: true,
@@ -99,6 +99,8 @@ describe('NfsFormComponent', () => {
       sec_label_xattr: 'security.selinux',
       security_label: false,
       squash: 'no_root_squash',
+      subvolume: '',
+      subvolume_group: '',
       transportTCP: true,
       transportUDP: true
     });
index 98ef5c85914207b4f676fdd2fd005ce8787cddc9..f43067f231d913027604216807f2f0b4cc153c5c 100644 (file)
@@ -29,6 +29,8 @@ import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
 import { NfsFormClientComponent } from '../nfs-form-client/nfs-form-client.component';
 import { getFsalFromRoute, getPathfromFsal } from '../utils';
+import { CephfsSubvolumeService } from '~/app/shared/api/cephfs-subvolume.service';
+import { CephfsSubvolumeGroupService } from '~/app/shared/api/cephfs-subvolume-group.service';
 
 @Component({
   selector: 'cd-nfs-form',
@@ -63,6 +65,10 @@ export class NfsFormComponent extends CdForm implements OnInit {
   action: string;
   resource: string;
 
+  allsubvolgrps: any[] = [];
+  allsubvols: any[] = [];
+  fsPath: string = null;
+
   pathDataSource = (text$: Observable<string>) => {
     return text$.pipe(
       debounceTime(200),
@@ -83,6 +89,8 @@ export class NfsFormComponent extends CdForm implements OnInit {
   constructor(
     private authStorageService: AuthStorageService,
     private nfsService: NfsService,
+    private subvolService: CephfsSubvolumeService,
+    private subvolgrpService: CephfsSubvolumeGroupService,
     private route: ActivatedRoute,
     private router: Router,
     private rgwBucketService: RgwBucketService,
@@ -139,6 +147,49 @@ export class NfsFormComponent extends CdForm implements OnInit {
     });
   }
 
+  volumeChangeHandler() {
+    this.pathChangeHandler();
+    const fs_name = this.nfsForm.getValue('fsal').fs_name;
+    this.getSubVolGrp(fs_name);
+  }
+
+  getSubVol() {
+    this.getPath();
+    const fs_name = this.nfsForm.getValue('fsal').fs_name;
+    const subvolgrp = this.nfsForm.getValue('subvolume_group');
+    return this.subvolService.get(fs_name, subvolgrp).subscribe((data: any) => {
+      this.allsubvols = data;
+    });
+  }
+
+  getSubVolGrp(fs_name: string) {
+    return this.subvolgrpService.get(fs_name).subscribe((data: any) => {
+      this.allsubvolgrps = data;
+    });
+  }
+
+  getFsPath(volList: any[], value: string) {
+    const match = volList.find((vol) => vol.name === value);
+    if (match) {
+      return match.info.path;
+    }
+  }
+
+  getPath() {
+    const subvol = this.nfsForm.getValue('subvolume');
+    if (subvol === '') {
+      const subvolGroup = this.nfsForm.getValue('subvolume_group');
+      this.fsPath = this.getFsPath(this.allsubvolgrps, subvolGroup);
+    } else {
+      this.fsPath = this.getFsPath(this.allsubvols, subvol);
+    }
+    this.nfsForm.patchValue({
+      path: this.fsPath
+    });
+
+    this.pathChangeHandler();
+  }
+
   createForm() {
     this.nfsForm = new CdFormGroup({
       cluster_id: new UntypedFormControl('', {
@@ -156,6 +207,8 @@ export class NfsFormComponent extends CdForm implements OnInit {
           ]
         })
       }),
+      subvolume_group: new UntypedFormControl(''),
+      subvolume: new UntypedFormControl(''),
       path: new UntypedFormControl('/', {
         validators: [Validators.required]
       }),
@@ -266,13 +319,6 @@ export class NfsFormComponent extends CdForm implements OnInit {
 
   resolveFilesystems(filesystems: any[]) {
     this.allFsNames = filesystems;
-    if (!this.isEdit && filesystems.length > 0) {
-      this.nfsForm.patchValue({
-        fsal: {
-          fs_name: filesystems[0].name
-        }
-      });
-    }
   }
 
   resolveRealms(realms: string[]) {
@@ -439,6 +485,9 @@ export class NfsFormComponent extends CdForm implements OnInit {
       delete requestModel.fsal.fs_name;
     }
 
+    delete requestModel.subvolume;
+    delete requestModel.subvolume_group;
+
     requestModel.protocols = [];
     if (requestModel.protocolNfsv3) {
       requestModel.protocols.push(3);