From: Tiago Melo Date: Tue, 20 Oct 2020 10:20:17 +0000 (+0000) Subject: mgr/dashboard: RBD: Disable actions when name is not valid X-Git-Tag: v16.1.0~526^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e5141ca9759deb26bb73953b46da32ae60e97ffe;p=ceph.git mgr/dashboard: RBD: Disable actions when name is not valid Its possible to create RBD Images with invalid names using external tools and this can cause problems in the dashboard. We now check for the validity of each image name and disable all actions if the name is invalid. Fixes: https://tracker.ceph.com/issues/47785 Signed-off-by: Tiago Melo --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts index 3bcb822b49c9..0f07933abd3c 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts @@ -301,4 +301,38 @@ describe('RbdListComponent', () => { } }); }); + + const getActionDisable = (name: string) => + component.tableActions.find((o) => o.name === name).disable; + + const testActions = (selection: any, expected: string | boolean) => { + expect(getActionDisable('Edit')(selection)).toBe(expected); + expect(getActionDisable('Delete')(selection)).toBe(expected); + expect(getActionDisable('Copy')(selection)).toBe(expected); + expect(getActionDisable('Flatten')(selection)).toBeTruthy(); + expect(getActionDisable('Move to Trash')(selection)).toBe(expected); + }; + + it('should test TableActions with valid/invalid image name', () => { + component.selection.selected = [ + { + name: 'foobar', + pool_name: 'rbd', + snapshots: [] + } + ]; + testActions(component.selection, false); + + component.selection.selected = [ + { + name: 'foo/bar', + pool_name: 'rbd', + snapshots: [] + } + ]; + testActions( + component.selection, + `This RBD image has an invalid name and can't be managed by ceph.` + ); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts index 70be703fdf43..f8719ea7eeca 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts @@ -131,7 +131,8 @@ export class RbdListComponent extends ListWithDetails implements OnInit { permission: 'update', icon: Icons.edit, routerLink: () => this.urlBuilder.getEdit(getImageUri()), - name: this.actionLabels.EDIT + name: this.actionLabels.EDIT, + disable: this.getInvalidNameDisable }; const deleteAction: CdTableAction = { permission: 'delete', @@ -144,7 +145,7 @@ export class RbdListComponent extends ListWithDetails implements OnInit { permission: 'create', canBePrimary: (selection: CdTableSelection) => selection.hasSingleSelection, disable: (selection: CdTableSelection) => - !selection.hasSingleSelection || selection.first().cdExecuting, + this.getInvalidNameDisable(selection) || !!selection.first().cdExecuting, icon: Icons.copy, routerLink: () => `/block/rbd/copy/${getImageUri()}`, name: this.actionLabels.COPY @@ -152,7 +153,9 @@ export class RbdListComponent extends ListWithDetails implements OnInit { const flattenAction: CdTableAction = { permission: 'update', disable: (selection: CdTableSelection) => - !selection.hasSingleSelection || selection.first().cdExecuting || !selection.first().parent, + this.getInvalidNameDisable(selection) || + selection.first().cdExecuting || + !selection.first().parent, icon: Icons.flatten, click: () => this.flattenRbdModal(), name: this.actionLabels.FLATTEN @@ -163,8 +166,7 @@ export class RbdListComponent extends ListWithDetails implements OnInit { click: () => this.trashRbdModal(), name: this.actionLabels.TRASH, disable: (selection: CdTableSelection) => - !selection.first() || - !selection.hasSingleSelection || + this.getInvalidNameDisable(selection) || selection.first().image_format === RBDImageFormat.V1 }; this.tableActions = [ @@ -442,10 +444,16 @@ export class RbdListComponent extends ListWithDetails implements OnInit { return $localize`This RBD has cloned snapshots. Please delete related RBDs before deleting this RBD.`; } - return ( - !selection.first() || - !selection.hasSingleSelection || - this.hasClonedSnapshots(selection.first()) - ); + return this.getInvalidNameDisable(selection) || this.hasClonedSnapshots(selection.first()); + } + + getInvalidNameDisable(selection: CdTableSelection): string | boolean { + const first = selection.first(); + + if (first?.name?.match(/[@/]/)) { + return $localize`This RBD image has an invalid name and can't be managed by ceph.`; + } + + return !selection.first() || !selection.hasSingleSelection; } }