1 import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core';
3 import * as _ from 'lodash';
4 import * as moment from 'moment';
5 import { BsModalRef, BsModalService } from 'ngx-bootstrap';
6 import { of } from 'rxjs';
8 import { RbdService } from '../../../shared/api/rbd.service';
9 import { ConfirmationModalComponent } from '../../../shared/components/confirmation-modal/confirmation-modal.component';
10 import { DeletionModalComponent } from '../../../shared/components/deletion-modal/deletion-modal.component';
11 import { CellTemplate } from '../../../shared/enum/cell-template.enum';
12 import { CdTableColumn } from '../../../shared/models/cd-table-column';
13 import { CdTableSelection } from '../../../shared/models/cd-table-selection';
14 import { ExecutingTask } from '../../../shared/models/executing-task';
15 import { FinishedTask } from '../../../shared/models/finished-task';
16 import { Permission } from '../../../shared/models/permissions';
17 import { CdDatePipe } from '../../../shared/pipes/cd-date.pipe';
18 import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
19 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
20 import { NotificationService } from '../../../shared/services/notification.service';
21 import { SummaryService } from '../../../shared/services/summary.service';
22 import { TaskListService } from '../../../shared/services/task-list.service';
23 import { TaskManagerService } from '../../../shared/services/task-manager.service';
24 import { RbdSnapshotFormComponent } from '../rbd-snapshot-form/rbd-snapshot-form.component';
25 import { RbdSnapshotModel } from './rbd-snapshot.model';
28 selector: 'cd-rbd-snapshot-list',
29 templateUrl: './rbd-snapshot-list.component.html',
30 styleUrls: ['./rbd-snapshot-list.component.scss'],
31 providers: [TaskListService]
33 export class RbdSnapshotListComponent implements OnInit, OnChanges {
35 snapshots: RbdSnapshotModel[] = [];
41 nameTpl: TemplateRef<any>;
42 @ViewChild('protectTpl')
43 protectTpl: TemplateRef<any>;
44 @ViewChild('rollbackTpl')
45 rollbackTpl: TemplateRef<any>;
47 permission: Permission;
49 data: RbdSnapshotModel[];
51 columns: CdTableColumn[];
55 selection = new CdTableSelection();
58 'rbd/snap/create': (metadata) => {
59 const model = new RbdSnapshotModel();
60 model.name = metadata['snapshot_name'];
66 private authStorageService: AuthStorageService,
67 private modalService: BsModalService,
68 private dimlessBinaryPipe: DimlessBinaryPipe,
69 private cdDatePipe: CdDatePipe,
70 private rbdService: RbdService,
71 private taskManagerService: TaskManagerService,
72 private notificationService: NotificationService,
73 private summaryService: SummaryService,
74 private taskListService: TaskListService
76 this.permission = this.authStorageService.getPermissions().rbdImage;
84 cellTransformation: CellTemplate.executing,
91 cellClass: 'text-right',
92 pipe: this.dimlessBinaryPipe
98 cellClass: 'text-right',
99 pipe: this.dimlessBinaryPipe
103 prop: 'is_protected',
105 cellClass: 'text-center',
106 cellTemplate: this.protectTpl
112 pipe: this.cdDatePipe
118 const itemFilter = (entry, task) => {
119 return entry.name === task.metadata['snapshot_name'];
122 const taskFilter = (task) => {
124 ['rbd/snap/create', 'rbd/snap/delete', 'rbd/snap/edit', 'rbd/snap/rollback'].includes(
127 this.poolName === task.metadata['pool_name'] &&
128 this.rbdName === task.metadata['image_name']
132 this.taskListService.init(
133 () => of(this.snapshots),
135 (items) => (this.data = items),
136 () => (this.data = this.snapshots),
143 private openSnapshotModal(taskName: string, snapName: string = null) {
144 this.modalRef = this.modalService.show(RbdSnapshotFormComponent);
145 this.modalRef.content.poolName = this.poolName;
146 this.modalRef.content.imageName = this.rbdName;
148 this.modalRef.content.setEditing();
150 // Auto-create a name for the snapshot: <image_name>_<timestamp_ISO_8601>
151 // https://en.wikipedia.org/wiki/ISO_8601
152 snapName = `${this.rbdName}-${moment()
154 .format('YYYYMMDD[T]HHmmss[Z]')}`;
156 this.modalRef.content.setSnapName(snapName);
157 this.modalRef.content.onSubmit.subscribe((snapshotName: string) => {
158 const executingTask = new ExecutingTask();
159 executingTask.name = taskName;
160 executingTask.metadata = {
161 image_name: this.rbdName,
162 pool_name: this.poolName,
163 snapshot_name: snapshotName
165 this.summaryService.addRunningTask(executingTask);
170 openCreateSnapshotModal() {
171 this.openSnapshotModal('rbd/snap/create');
174 openEditSnapshotModal() {
175 this.openSnapshotModal('rbd/snap/edit', this.selection.first().name);
179 const snapshotName = this.selection.first().name;
180 const isProtected = this.selection.first().is_protected;
181 const finishedTask = new FinishedTask();
182 finishedTask.name = 'rbd/snap/edit';
183 finishedTask.metadata = {
184 pool_name: this.poolName,
185 image_name: this.rbdName,
186 snapshot_name: snapshotName
189 .protectSnapshot(this.poolName, this.rbdName, snapshotName, !isProtected)
192 const executingTask = new ExecutingTask();
193 executingTask.name = finishedTask.name;
194 executingTask.metadata = finishedTask.metadata;
195 this.summaryService.addRunningTask(executingTask);
197 this.taskManagerService.subscribe(
199 finishedTask.metadata,
200 (asyncFinishedTask: FinishedTask) => {
201 this.notificationService.notifyTask(asyncFinishedTask);
207 _asyncTask(task: string, taskName: string, snapshotName: string) {
208 const finishedTask = new FinishedTask();
209 finishedTask.name = taskName;
210 finishedTask.metadata = {
211 pool_name: this.poolName,
212 image_name: this.rbdName,
213 snapshot_name: snapshotName
215 this.rbdService[task](this.poolName, this.rbdName, snapshotName)
218 const executingTask = new ExecutingTask();
219 executingTask.name = finishedTask.name;
220 executingTask.metadata = finishedTask.metadata;
221 this.summaryService.addRunningTask(executingTask);
222 this.modalRef.hide();
224 this.taskManagerService.subscribe(
226 executingTask.metadata,
227 (asyncFinishedTask: FinishedTask) => {
228 this.notificationService.notifyTask(asyncFinishedTask);
233 this.modalRef.content.stopLoadingSpinner();
238 const snapshotName = this.selection.selected[0].name;
239 const initialState = {
240 titleText: 'RBD snapshot rollback',
241 buttonText: 'Rollback',
242 bodyTpl: this.rollbackTpl,
244 snapName: `${this.poolName}/${this.rbdName}@${snapshotName}`
247 this._asyncTask('rollbackSnapshot', 'rbd/snap/rollback', snapshotName);
251 this.modalRef = this.modalService.show(ConfirmationModalComponent, { initialState });
254 deleteSnapshotModal() {
255 const snapshotName = this.selection.selected[0].name;
256 this.modalRef = this.modalService.show(DeletionModalComponent);
257 this.modalRef.content.setUp({
258 metaType: 'RBD snapshot',
259 pattern: snapshotName,
260 deletionMethod: () => this._asyncTask('deleteSnapshot', 'rbd/snap/delete', snapshotName),
261 modalRef: this.modalRef
265 updateSelection(selection: CdTableSelection) {
266 this.selection = selection;