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 c77a627324e..369f97de6cf 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 @@ -153,6 +153,13 @@ export class RbdListComponent extends ListWithDetails implements OnInit { name: this.actionLabels.DELETE, disable: (selection: CdTableSelection) => this.getDeleteDisableDesc(selection) }; + const resyncAction: CdTableAction = { + permission: 'update', + icon: Icons.refresh, + click: () => this.resyncRbdModal(), + name: this.actionLabels.RESYNC, + disable: (selection: CdTableSelection) => this.getResyncDisableDesc(selection) + }; const copyAction: CdTableAction = { permission: 'create', canBePrimary: (selection: CdTableSelection) => selection.hasSingleSelection, @@ -200,6 +207,7 @@ export class RbdListComponent extends ListWithDetails implements OnInit { editAction, copyAction, flattenAction, + resyncAction, deleteAction, moveAction, removeSchedulingAction @@ -411,6 +419,26 @@ export class RbdListComponent extends ListWithDetails implements OnInit { }); } + resyncRbdModal() { + const poolName = this.selection.first().pool_name; + const namespace = this.selection.first().namespace; + const imageName = this.selection.first().name; + const imageSpec = new ImageSpec(poolName, namespace, imageName); + + this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, { + itemDescription: 'RBD', + itemNames: [imageSpec], + actionDescription: 'resync', + submitActionObservable: () => + this.taskWrapper.wrapTaskAroundCall({ + task: new FinishedTask('rbd/edit', { + image_spec: imageSpec.toString() + }), + call: this.rbdService.update(imageSpec, { resync: true }) + }) + }); + } + trashRbdModal() { const initialState = { poolName: this.selection.first().pool_name, @@ -533,6 +561,19 @@ export class RbdListComponent extends ListWithDetails implements OnInit { return this.getInvalidNameDisable(selection) || this.hasClonedSnapshots(selection.first()); } + getResyncDisableDesc(selection: CdTableSelection): string | boolean { + const first = selection.first(); + + if (first && this.imageIsPrimary(first)) { + return $localize`Primary RBD cannot be resynced`; + } + + return this.getInvalidNameDisable(selection); + } + + imageIsPrimary(image: object) { + return image['primary']; + } getInvalidNameDisable(selection: CdTableSelection): string | boolean { const first = selection.first(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts index 9e1c42963bd..d78620a89b2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/constants/app.constants.ts @@ -134,6 +134,7 @@ export class ActionLabelsI18n { STOP: string; REDEPLOY: string; RESTART: string; + RESYNC: string; constructor() { /* Create a new item */ @@ -190,7 +191,7 @@ export class ActionLabelsI18n { this.START_DRAIN = $localize`Start Drain`; this.STOP_DRAIN = $localize`Stop Drain`; - + this.RESYNC = $localize`Resync`; /* Prometheus wording */ this.RECREATE = $localize`Recreate`; this.EXPIRE = $localize`Expire`;