From e5141ca9759deb26bb73953b46da32ae60e97ffe Mon Sep 17 00:00:00 2001 From: Tiago Melo Date: Tue, 20 Oct 2020 10:20:17 +0000 Subject: [PATCH] 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 --- .../block/rbd-list/rbd-list.component.spec.ts | 34 +++++++++++++++++++ .../ceph/block/rbd-list/rbd-list.component.ts | 28 +++++++++------ 2 files changed, 52 insertions(+), 10 deletions(-) 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 3bcb822b49c..0f07933abd3 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 70be703fdf4..f8719ea7eec 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; } } -- 2.47.3