editRetentionPolicies('snap_schedule_retention_add', retention_to_add)
return f'Retention policies for snapshot schedule on path {path} updated successfully'
+
+ @RESTController.Resource('DELETE')
+ def delete_snapshot(self, fs: str, path: str, schedule: str, start: str):
+ error_code, _, err = mgr.remote('snap_schedule',
+ 'snap_schedule_rm',
+ path,
+ schedule,
+ start,
+ fs,
+ None,
+ None)
+ if error_code != 0:
+ raise DashboardException(
+ f'Failed to delete snapshot schedule for path {path}: {err}'
+ )
+
+ return f'Snapshot schedule for path {path} deleted successfully'
+
+ @RESTController.Resource('POST')
+ def deactivate(self, fs: str, path: str, schedule: str, start: str):
+ error_code, _, err = mgr.remote('snap_schedule',
+ 'snap_schedule_deactivate',
+ path,
+ schedule,
+ start,
+ fs,
+ None,
+ None)
+ if error_code != 0:
+ raise DashboardException(
+ f'Failed to deactivate snapshot schedule for path {path}: {err}'
+ )
+
+ return f'Snapshot schedule for path {path} deactivated successfully'
+
+ @RESTController.Resource('POST')
+ def activate(self, fs: str, path: str, schedule: str, start: str):
+ error_code, _, err = mgr.remote('snap_schedule',
+ 'snap_schedule_activate',
+ path,
+ schedule,
+ start,
+ fs,
+ None,
+ None)
+ if error_code != 0:
+ raise DashboardException(
+ f'Failed to activate snapshot schedule for path {path}: {err}'
+ )
+
+ return f'Snapshot schedule for path {path} activated successfully'
[permission]="permissions.cephfs"
[selection]="selection"
class="btn-group"
- [tableActions]="tableActions"
+ [tableActions]="tableActions$ | async"
>
</cd-table-actions>
</div>
import { NotificationService } from '~/app/shared/services/notification.service';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
-import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
import { CephfsSnapshotscheduleFormComponent } from '../cephfs-snapshotschedule-form/cephfs-snapshotschedule-form.component';
+import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
+import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
+import { FinishedTask } from '~/app/shared/models/finished-task';
@Component({
selector: 'cd-cephfs-snapshotschedule-list',
snapScheduleModuleStatus$ = new BehaviorSubject<boolean>(false);
moduleServiceListSub!: Subscription;
columns: CdTableColumn[] = [];
- tableActions: CdTableAction[] = [];
+ tableActions$ = new BehaviorSubject<CdTableAction[]>([]);
context!: CdTableFetchDataContext;
selection = new CdTableSelection();
permissions!: Permissions;
errorMessage: string = '';
selectedName: string = '';
icons = Icons;
+ tableActions: CdTableAction[] = [
+ {
+ name: this.actionLabels.CREATE,
+ permission: 'create',
+ icon: Icons.add,
+ click: () => this.openModal(false)
+ },
+ {
+ name: this.actionLabels.EDIT,
+ permission: 'update',
+ icon: Icons.edit,
+ click: () => this.openModal(true)
+ },
+ {
+ name: this.actionLabels.DELETE,
+ permission: 'delete',
+ icon: Icons.trash,
+ click: () => this.deleteSnapshotSchedule()
+ }
+ ];
MODULE_NAME = 'snap_schedule';
ENABLE_MODULE_TIMER = 2 * 1000;
private modalService: ModalService,
private mgrModuleService: MgrModuleService,
private notificationService: NotificationService,
- private actionLables: ActionLabelsI18n
+ private actionLabels: ActionLabelsI18n,
+ private taskWrapper: TaskWrapperService
) {
super();
this.permissions = this.authStorageService.getPermissions();
{ prop: 'created', name: $localize`Created`, cellTransformation: CellTemplate.timeAgo }
];
- this.tableActions = [
- {
- name: this.actionLables.CREATE,
- permission: 'create',
- icon: Icons.add,
- click: () => this.openModal(false)
- },
- {
- name: this.actionLables.EDIT,
- permission: 'update',
- icon: Icons.edit,
- click: () => this.openModal(true)
- }
- ];
+ this.tableActions$.next(this.tableActions);
}
ngOnDestroy(): void {
updateSelection(selection: CdTableSelection) {
this.selection = selection;
+ if (!this.selection.hasSelection) return;
+ const isActive = this.selection.first()?.active;
+
+ this.tableActions$.next([
+ ...this.tableActions,
+ {
+ name: isActive ? this.actionLabels.DEACTIVATE : this.actionLabels.ACTIVATE,
+ permission: 'update',
+ icon: isActive ? Icons.warning : Icons.success,
+ click: () =>
+ isActive ? this.deactivateSnapshotSchedule() : this.activateSnapshotSchedule()
+ }
+ ]);
}
openModal(edit = false) {
}
);
}
+
+ deactivateSnapshotSchedule() {
+ const { path, start, fs, schedule } = this.selection.first();
+
+ this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
+ itemDescription: $localize`snapshot schedule`,
+ actionDescription: this.actionLabels.DEACTIVATE,
+ submitActionObservable: () =>
+ this.taskWrapper.wrapTaskAroundCall({
+ task: new FinishedTask('cephfs/snapshot/schedule/deactivate', {
+ path
+ }),
+ call: this.snapshotScheduleService.deactivate({
+ path,
+ schedule,
+ start,
+ fs
+ })
+ })
+ });
+ }
+
+ activateSnapshotSchedule() {
+ const { path, start, fs, schedule } = this.selection.first();
+
+ this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
+ itemDescription: $localize`snapshot schedule`,
+ actionDescription: this.actionLabels.ACTIVATE,
+ submitActionObservable: () =>
+ this.taskWrapper.wrapTaskAroundCall({
+ task: new FinishedTask('cephfs/snapshot/schedule/activate', {
+ path
+ }),
+ call: this.snapshotScheduleService.activate({
+ path,
+ schedule,
+ start,
+ fs
+ })
+ })
+ });
+ }
+
+ deleteSnapshotSchedule() {
+ const { path, start, fs, schedule } = this.selection.first();
+
+ this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
+ itemDescription: $localize`snapshot schedule`,
+ submitActionObservable: () =>
+ this.taskWrapper.wrapTaskAroundCall({
+ task: new FinishedTask('cephfs/snapshot/schedule/' + URLVerbs.DELETE, {
+ path
+ }),
+ call: this.snapshotScheduleService.delete({
+ path,
+ schedule,
+ start,
+ fs
+ })
+ })
+ });
+ }
}
return this.http.post(`${this.baseURL}/snapshot/schedule`, data, { observe: 'response' });
}
- update(data: Record<string, any>): Observable<any> {
+ update({ fs, path, ...rest }: Record<string, any>): Observable<any> {
return this.http.put(
- `${this.baseURL}/snapshot/schedule/${data.fs}/${encodeURIComponent(data.path)}`,
- data,
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(path)}`,
+ rest,
{ observe: 'response' }
);
}
+ activate({ fs, path, ...rest }: Record<string, any>): Observable<any> {
+ return this.http.post(
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(path)}/activate`,
+ rest,
+ { observe: 'response' }
+ );
+ }
+
+ deactivate({ fs, path, ...rest }: Record<string, any>): Observable<any> {
+ return this.http.post(
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(path)}/deactivate`,
+ rest,
+ { observe: 'response' }
+ );
+ }
+
+ delete({ fs, path, schedule, start }: Record<string, any>): Observable<any> {
+ return this.http.delete(
+ `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(
+ path
+ )}/delete_snapshot?schedule=${schedule}&start=${encodeURIComponent(start)}`
+ );
+ }
+
checkScheduleExists(
path: string,
fs: string,
IMPORT: any;
MIGRATE: string;
START_UPGRADE: string;
+ ACTIVATE: string;
+ DEACTIVATE: string;
constructor() {
/* Create a new item */
this.DEMOTE = $localize`Demote`;
this.START_UPGRADE = $localize`Start Upgrade`;
+
+ this.ACTIVATE = $localize`Activate`;
+ this.DEACTIVATE = $localize`Deactivate`;
}
}
delete: new TaskMessageOperation($localize`Deleting`, $localize`delete`, $localize`Deleted`),
add: new TaskMessageOperation($localize`Adding`, $localize`add`, $localize`Added`),
remove: new TaskMessageOperation($localize`Removing`, $localize`remove`, $localize`Removed`),
- import: new TaskMessageOperation($localize`Importing`, $localize`import`, $localize`Imported`)
+ import: new TaskMessageOperation($localize`Importing`, $localize`import`, $localize`Imported`),
+ activate: new TaskMessageOperation(
+ $localize`Importing`,
+ $localize`activate`,
+ $localize`Activated`
+ ),
+ deactivate: new TaskMessageOperation(
+ $localize`Importing`,
+ $localize`deactivate`,
+ $localize`Deactivated`
+ )
};
rbd = {
),
'cephfs/snapshot/schedule/edit': this.newTaskMessage(this.commonOperations.update, (metadata) =>
this.snapshotSchedule(metadata)
+ ),
+ 'cephfs/snapshot/schedule/delete': this.newTaskMessage(
+ this.commonOperations.delete,
+ (metadata) => this.snapshotSchedule(metadata)
+ ),
+ 'cephfs/snapshot/schedule/activate': this.newTaskMessage(
+ this.commonOperations.activate,
+ (metadata) => this.snapshotSchedule(metadata)
+ ),
+ 'cephfs/snapshot/schedule/deactivate': this.newTaskMessage(
+ this.commonOperations.deactivate,
+ (metadata) => this.snapshotSchedule(metadata)
)
};
- jwt: []
tags:
- CephFSSnapshotSchedule
+ /api/cephfs/snapshot/schedule/{fs}/{path}/activate:
+ post:
+ parameters:
+ - in: path
+ name: fs
+ required: true
+ schema:
+ type: string
+ - in: path
+ name: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ properties:
+ schedule:
+ type: string
+ start:
+ type: string
+ required:
+ - schedule
+ - start
+ type: object
+ responses:
+ '201':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Resource created.
+ '202':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Operation is still executing. Please check the task queue.
+ '400':
+ description: Operation exception. Please check the response body for details.
+ '401':
+ description: Unauthenticated access. Please login first.
+ '403':
+ description: Unauthorized access. Please check your permissions.
+ '500':
+ description: Unexpected error. Please check the response body for the stack
+ trace.
+ security:
+ - jwt: []
+ tags:
+ - CephFSSnapshotSchedule
+ /api/cephfs/snapshot/schedule/{fs}/{path}/deactivate:
+ post:
+ parameters:
+ - in: path
+ name: fs
+ required: true
+ schema:
+ type: string
+ - in: path
+ name: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/json:
+ schema:
+ properties:
+ schedule:
+ type: string
+ start:
+ type: string
+ required:
+ - schedule
+ - start
+ type: object
+ responses:
+ '201':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Resource created.
+ '202':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Operation is still executing. Please check the task queue.
+ '400':
+ description: Operation exception. Please check the response body for details.
+ '401':
+ description: Unauthenticated access. Please login first.
+ '403':
+ description: Unauthorized access. Please check your permissions.
+ '500':
+ description: Unexpected error. Please check the response body for the stack
+ trace.
+ security:
+ - jwt: []
+ tags:
+ - CephFSSnapshotSchedule
+ /api/cephfs/snapshot/schedule/{fs}/{path}/delete_snapshot:
+ delete:
+ parameters:
+ - in: path
+ name: fs
+ required: true
+ schema:
+ type: string
+ - in: path
+ name: path
+ required: true
+ schema:
+ type: string
+ - in: query
+ name: schedule
+ required: true
+ schema:
+ type: string
+ - in: query
+ name: start
+ required: true
+ schema:
+ type: string
+ responses:
+ '202':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Operation is still executing. Please check the task queue.
+ '204':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Resource deleted.
+ '400':
+ description: Operation exception. Please check the response body for details.
+ '401':
+ description: Unauthenticated access. Please login first.
+ '403':
+ description: Unauthorized access. Please check your permissions.
+ '500':
+ description: Unexpected error. Please check the response body for the stack
+ trace.
+ security:
+ - jwt: []
+ tags:
+ - CephFSSnapshotSchedule
/api/cephfs/subvolume:
post:
parameters: []