]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: nfs export enhancement for CEPHFS 58475/head
authorAvan Thakkar <athakkar@redhat.com>
Thu, 27 Jun 2024 10:06:42 +0000 (15:36 +0530)
committerAvan Thakkar <athakkar@redhat.com>
Tue, 9 Jul 2024 08:43:20 +0000 (14:13 +0530)
Fixes: https://tracker.ceph.com/issues/66718
Signed-off-by: Avan Thakkar <athakkar@redhat.com>
(cherry picked from commit 69a45db9c3cc9ed4ac36e7f2d6db78bd7940530b)

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 fcd87833f85fce42a5f563060165378e5594333a..7183808e19f177cb87d1b9eebed2df47dcf7340c 100644 (file)
@@ -826,6 +826,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 1ab3ed173ce81f2138b9752392f19562a7f25239..a83091a2c39a14c26618abf00162ec2df1d174ac 100644 (file)
@@ -90,7 +90,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="nfsForm.getValue('name') === 'CEPH'">
index 62efec423d36aac61f13cf28988ce0e64ccbbcdc..3273468bb4b10be00fddf4527c25fdbc823fef8b 100644 (file)
@@ -96,13 +96,15 @@ describe('NfsFormComponent', () => {
       access_type: 'RW',
       clients: [],
       cluster_id: 'mynfs',
-      fsal: { fs_name: 'a', name: 'CEPH' },
+      fsal: { fs_name: '', name: 'CEPH' },
       path: '/',
       protocolNfsv4: true,
       pseudo: '',
       sec_label_xattr: 'security.selinux',
       security_label: false,
       squash: 'no_root_squash',
+      subvolume: '',
+      subvolume_group: '',
       transportTCP: true,
       transportUDP: true
     });
index 540b7bfe64bee69b4d8df3168507564c6770715d..438c01a7370caf492591bb93a661f03a83d01898 100644 (file)
@@ -28,6 +28,8 @@ import { CdHttpErrorResponse } from '~/app/shared/services/api-interceptor.servi
 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 { CephfsSubvolumeService } from '~/app/shared/api/cephfs-subvolume.service';
+import { CephfsSubvolumeGroupService } from '~/app/shared/api/cephfs-subvolume-group.service';
 
 @Component({
   selector: 'cd-nfs-form',
@@ -61,6 +63,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),
@@ -81,6 +87,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,
@@ -138,6 +146,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('', {
@@ -155,7 +206,11 @@ export class NfsFormComponent extends CdForm implements OnInit {
           ]
         })
       }),
-      path: new UntypedFormControl('/'),
+      subvolume_group: new UntypedFormControl(''),
+      subvolume: new UntypedFormControl(''),
+      path: new UntypedFormControl('/', {
+        validators: [Validators.required]
+      }),
       protocolNfsv4: new UntypedFormControl(true),
       pseudo: new UntypedFormControl('', {
         validators: [
@@ -253,13 +308,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
-        }
-      });
-    }
   }
 
   fsalChangeHandler() {
@@ -470,6 +518,9 @@ export class NfsFormComponent extends CdForm implements OnInit {
       delete requestModel.fsal.fs_name;
     }
 
+    delete requestModel.subvolume;
+    delete requestModel.subvolume_group;
+
     requestModel.protocols = [];
     if (requestModel.protocolNfsv4) {
       requestModel.protocols.push(4);