From be4d533646ca2c09b040c34de6a6a56d11da77ae Mon Sep 17 00:00:00 2001 From: Afreen Date: Wed, 3 Apr 2024 07:45:32 +0530 Subject: [PATCH] mgr/dashboard: Fix NFS routing Fixes https://tracker.ceph.com/issues/65310 The NFS tab in object and File nav uses same route due to which both gets activated when one of them is clicked. Hence, this PR separates the routing for Object and File nav. Object-> NFS: /rgw/nfs File-> NFS: /cephfs/nfs Both routes use same NFS List and Form component but under different routes as mentioned above. Changes summary - updated route for File from "/fs" to "/cephfs/" to support both fs and nfs tabs. Since using `/fs` and `/fs/nfs` will activate both paths and it will be an undesirable user experience. - `getFsalRouteFromPath` helper function to set the storage backend from route. - removed `stoarge-backend` field from nfs form as now route decides teh storage backend - breadcrumbs redirect to respective navs - updated e2e tests - updated unit tests - changes list page of object-> nfs page to say Bucket instead of Path Signed-off-by: Afreen (cherry picked from commit 97359d6b1ee8133afcddf1f540b147c26723e24e) Conflicts: src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html --- .../frontend/cypress/e2e/common/urls.po.ts | 4 +- .../workflow/10-nfs-exports.e2e-spec.ts | 14 +- .../workflow/nfs/nfs-export.po.ts | 15 +- .../frontend/cypress/e2e/page-helper.po.ts | 4 +- .../frontend/src/app/app-routing.module.ts | 66 ++++---- .../cephfs-form/cephfs-form.component.ts | 6 +- .../cephfs-list/cephfs-list.component.ts | 2 +- .../src/app/ceph/nfs/models/nfs.fsal.ts | 6 +- .../ceph/nfs/nfs-form/nfs-form.component.html | 108 ++++--------- .../ceph/nfs/nfs-form/nfs-form.component.scss | 8 - .../nfs/nfs-form/nfs-form.component.spec.ts | 23 ++- .../ceph/nfs/nfs-form/nfs-form.component.ts | 151 ++++++------------ .../nfs/nfs-list/nfs-list.component.spec.ts | 10 +- .../ceph/nfs/nfs-list/nfs-list.component.ts | 17 +- .../frontend/src/app/ceph/nfs/nfs.module.ts | 1 + .../frontend/src/app/ceph/nfs/utils.ts | 7 + .../frontend/src/app/ceph/rgw/rgw.module.ts | 31 ++++ .../src/app/shared/api/nfs.service.ts | 6 +- 18 files changed, 220 insertions(+), 259 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/utils.ts diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/common/urls.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/common/urls.po.ts index 6f7316f98f5..970fc8ff509 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/common/urls.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/common/urls.po.ts @@ -42,7 +42,7 @@ export class UrlsCollection extends PageHelper { 'rgw daemons': { url: '#/rgw/daemon', id: 'cd-rgw-daemon-list' }, // CephFS - cephfs: { url: '#/cephfs', id: 'cd-cephfs-list' }, - 'create cephfs': { url: '#/cephfs/create', id: 'cd-cephfs-form' } + cephfs: { url: '#/cephfs/fs', id: 'cd-cephfs-list' }, + 'create cephfs': { url: '#/cephfs/fs/create', id: 'cd-cephfs-form' } }; } diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/10-nfs-exports.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/10-nfs-exports.e2e-spec.ts index fdd96d7e975..ff2e7581bb6 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/10-nfs-exports.e2e-spec.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/10-nfs-exports.e2e-spec.ts @@ -19,11 +19,11 @@ describe('nfsExport page', () => { beforeEach(() => { cy.login(); - nfsExport.navigateTo(); }); describe('breadcrumb test', () => { it('should open and show breadcrumb', () => { + nfsExport.navigateTo('rgw_index'); nfsExport.expectBreadcrumbText('NFS'); }); }); @@ -43,23 +43,24 @@ describe('nfsExport page', () => { buckets.navigateTo('create'); buckets.create(bucketName, 'dashboard'); - nfsExport.navigateTo(); + nfsExport.navigateTo('rgw_index'); nfsExport.existTableCell(rgwPseudo, false); - nfsExport.navigateTo('create'); + nfsExport.navigateTo('rgw_create'); nfsExport.create(backends[1], squash, client, rgwPseudo, bucketName); nfsExport.existTableCell(rgwPseudo); }); // @TODO: uncomment this when a CephFS volume can be created through Dashboard. // it('should create a nfs-export with CephFS backend', () => { - // nfsExport.navigateTo(); + // nfsExport.navigateTo('cephfs_index'); // nfsExport.existTableCell(fsPseudo, false); - // nfsExport.navigateTo('create'); + // nfsExport.navigateTo('cephfs_create'); // nfsExport.create(backends[0], squash, client, fsPseudo); // nfsExport.existTableCell(fsPseudo); // }); it('should show Clients', () => { + nfsExport.navigateTo('rgw_index'); nfsExport.clickTab('cd-nfs-details', rgwPseudo, 'Clients (1)'); cy.get('cd-nfs-details').within(() => { nfsExport.getTableCount('total').should('be.gte', 0); @@ -67,12 +68,13 @@ describe('nfsExport page', () => { }); it('should edit an export', () => { - nfsExport.editExport(rgwPseudo, editPseudo); + nfsExport.editExport(rgwPseudo, editPseudo, 'rgw_index'); nfsExport.existTableCell(editPseudo); }); it('should delete exports and bucket', () => { + nfsExport.navigateTo('rgw_index'); nfsExport.delete(editPseudo); buckets.navigateTo(); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/nfs/nfs-export.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/nfs/nfs-export.po.ts index c700ef0581d..3639eb9a8ab 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/nfs/nfs-export.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/orchestrator/workflow/nfs/nfs-export.po.ts @@ -3,21 +3,18 @@ import { PageHelper } from '../../../page-helper.po'; /* tslint:enable*/ const pages = { - index: { url: '#/nfs', id: 'cd-nfs-list' }, - create: { url: '#/nfs/create', id: 'cd-nfs-form' } + cephfs_index: { url: '#cephfs/nfs', id: 'cd-nfs-list' }, + cephfs_create: { url: '#cephfs/nfs/create', id: 'cd-nfs-form' }, + rgw_index: { url: '#rgw/nfs', id: 'cd-nfs-list' }, + rgw_create: { url: '#rgw/nfs/create', id: 'cd-nfs-form' } }; export class NFSPageHelper extends PageHelper { pages = pages; - - @PageHelper.restrictTo(pages.create.url) create(backend: string, squash: string, client: object, pseudo: string, rgwPath?: string) { this.selectOption('cluster_id', 'testnfs'); - // select a storage backend - this.selectOption('name', backend); if (backend === 'CephFS') { this.selectOption('fs_name', 'myfs'); - cy.get('#security_label').click({ force: true }); } else { cy.get('input[data-testid=rgw_path]').type(rgwPath); @@ -38,8 +35,8 @@ export class NFSPageHelper extends PageHelper { cy.get('cd-submit-button').click(); } - editExport(pseudo: string, editPseudo: string) { - this.navigateEdit(pseudo); + editExport(pseudo: string, editPseudo: string, url: string) { + this.navigateEdit(pseudo, true, true, url); cy.get('input[name=pseudo]').clear().type(editPseudo); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/page-helper.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/page-helper.po.ts index 2a16ff7e141..49144b25fbf 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/page-helper.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/page-helper.po.ts @@ -52,9 +52,9 @@ export abstract class PageHelper { /** * Navigates to the edit page */ - navigateEdit(name: string, select = true, breadcrumb = true) { + navigateEdit(name: string, select = true, breadcrumb = true, navigateTo: string = null) { if (select) { - this.navigateTo(); + this.navigateTo(navigateTo); this.getFirstTableCell(name).click(); } cy.contains('Creating...').should('not.exist'); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts index 2ba634fa25d..f861ad183a2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/app-routing.module.ts @@ -352,18 +352,48 @@ const routes: Routes = [ { path: 'cephfs', canActivate: [FeatureTogglesGuardService], - data: { breadcrumbs: 'File/File Systems' }, children: [ - { path: '', component: CephfsListComponent }, { - path: URLVerbs.CREATE, + path: 'fs', + component: CephfsListComponent, + data: { breadcrumbs: 'File/File Systems' } + }, + { + path: `fs/${URLVerbs.CREATE}`, component: CephfsVolumeFormComponent, data: { breadcrumbs: ActionLabels.CREATE } }, { - path: `${URLVerbs.EDIT}/:id`, + path: `fs/${URLVerbs.EDIT}/:id`, component: CephfsVolumeFormComponent, data: { breadcrumbs: ActionLabels.EDIT } + }, + { + path: 'nfs', + canActivateChild: [FeatureTogglesGuardService, ModuleStatusGuardService], + data: { + moduleStatusGuardConfig: { + uiApiPath: 'nfs-ganesha', + redirectTo: 'error', + section: 'nfs-ganesha', + section_info: 'NFS GANESHA', + header: 'NFS-Ganesha is not configured' + }, + breadcrumbs: 'File/NFS' + }, + children: [ + { path: '', component: NfsListComponent }, + { + path: URLVerbs.CREATE, + component: NfsFormComponent, + data: { breadcrumbs: ActionLabels.CREATE } + }, + { + path: `${URLVerbs.EDIT}/:cluster_id/:export_id`, + component: NfsFormComponent, + data: { breadcrumbs: ActionLabels.EDIT } + } + ] } ] }, @@ -403,34 +433,6 @@ const routes: Routes = [ data: { breadcrumbs: ActionLabels.EDIT } } ] - }, - // NFS - { - path: 'nfs', - canActivateChild: [FeatureTogglesGuardService, ModuleStatusGuardService], - data: { - moduleStatusGuardConfig: { - uiApiPath: 'nfs-ganesha', - redirectTo: 'error', - section: 'nfs-ganesha', - section_info: 'NFS GANESHA', - header: 'NFS-Ganesha is not configured' - }, - breadcrumbs: 'NFS' - }, - children: [ - { path: '', component: NfsListComponent }, - { - path: URLVerbs.CREATE, - component: NfsFormComponent, - data: { breadcrumbs: ActionLabels.CREATE } - }, - { - path: `${URLVerbs.EDIT}/:cluster_id/:export_id`, - component: NfsFormComponent, - data: { breadcrumbs: ActionLabels.EDIT } - } - ] } ] }, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-form/cephfs-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-form/cephfs-form.component.ts index dbbe522fa0a..0506c4c7734 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-form/cephfs-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-form/cephfs-form.component.ts @@ -68,7 +68,7 @@ export class CephfsVolumeFormComponent extends CdForm implements OnInit { private route: ActivatedRoute ) { super(); - this.editing = this.router.url.startsWith(`/cephfs/${URLVerbs.EDIT}`); + this.editing = this.router.url.startsWith(`/cephfs/fs/${URLVerbs.EDIT}`); this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE; this.resource = $localize`File System`; this.hosts = { @@ -176,7 +176,7 @@ export class CephfsVolumeFormComponent extends CdForm implements OnInit { this.form.setErrors({ cdSubmitButton: true }); }, complete: () => { - this.router.navigate([BASE_URL]); + this.router.navigate([`${BASE_URL}/fs`]); } }); } else { @@ -210,7 +210,7 @@ export class CephfsVolumeFormComponent extends CdForm implements OnInit { self.form.setErrors({ cdSubmitButton: true }); }, complete: () => { - this.router.navigate([BASE_URL]); + this.router.navigate([`${BASE_URL}/fs`]); } }); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts index 2957401d86a..748eeee0ee4 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-list/cephfs-list.component.ts @@ -27,7 +27,7 @@ import { map, switchMap } from 'rxjs/operators'; import { HealthService } from '~/app/shared/api/health.service'; import { CephfsAuthModalComponent } from '~/app/ceph/cephfs/cephfs-auth-modal/cephfs-auth-modal.component'; -const BASE_URL = 'cephfs'; +const BASE_URL = 'cephfs/fs'; @Component({ selector: 'cd-cephfs-list', diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/models/nfs.fsal.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/models/nfs.fsal.ts index f204ac6d8b6..cbdc44f3ca8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/models/nfs.fsal.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/models/nfs.fsal.ts @@ -1,5 +1,9 @@ +export enum SUPPORTED_FSAL { + CEPH = 'CEPH', + RGW = 'RGW' +} export interface NfsFSAbstractionLayer { - value: string; + value: SUPPORTED_FSAL; descr: string; disabled: boolean; } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html index f54361a5f7d..ae427886f0e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/nfs/nfs-form/nfs-form.component.html @@ -15,9 +15,6 @@ for="cluster_id"> Cluster - -

This is the ID of an NFS Service.

-
+ +

This is the ID of an NFS Service.

+
This field is required. @@ -46,42 +46,9 @@
- -
- -
- - This field is required. - {{ fsalAvailabilityError }} -
-
-
+ *ngIf="storageBackend === 'CEPH'"> @@ -112,7 +79,7 @@
+ *ngIf="storageBackend === 'CEPH'">