]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
af27a265b88aa3d47bf00620229e00506b3aaddc
[ceph-ci.git] /
1 import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core';
2
3 import * as _ from 'lodash';
4 import { BsModalRef, BsModalService } from 'ngx-bootstrap';
5
6 import { RbdService } from '../../../shared/api/rbd.service';
7 import { ConfirmationModalComponent } from '../../../shared/components/confirmation-modal/confirmation-modal.component';
8 import { DeletionModalComponent } from '../../../shared/components/deletion-modal/deletion-modal.component';
9 import { CellTemplate } from '../../../shared/enum/cell-template.enum';
10 import { CdTableColumn } from '../../../shared/models/cd-table-column';
11 import { CdTableSelection } from '../../../shared/models/cd-table-selection';
12 import { ExecutingTask } from '../../../shared/models/executing-task';
13 import { FinishedTask } from '../../../shared/models/finished-task';
14 import { Permission } from '../../../shared/models/permissions';
15 import { CdDatePipe } from '../../../shared/pipes/cd-date.pipe';
16 import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
17 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
18 import { NotificationService } from '../../../shared/services/notification.service';
19 import { TaskManagerService } from '../../../shared/services/task-manager.service';
20 import { RbdSnapshotFormComponent } from '../rbd-snapshot-form/rbd-snapshot-form.component';
21 import { RbdSnapshotModel } from './rbd-snapshot.model';
22
23 @Component({
24   selector: 'cd-rbd-snapshot-list',
25   templateUrl: './rbd-snapshot-list.component.html',
26   styleUrls: ['./rbd-snapshot-list.component.scss']
27 })
28 export class RbdSnapshotListComponent implements OnInit, OnChanges {
29   @Input()
30   snapshots: RbdSnapshotModel[] = [];
31   @Input()
32   poolName: string;
33   @Input()
34   rbdName: string;
35   @Input()
36   executingTasks: ExecutingTask[] = [];
37
38   @ViewChild('nameTpl')
39   nameTpl: TemplateRef<any>;
40   @ViewChild('protectTpl')
41   protectTpl: TemplateRef<any>;
42   @ViewChild('rollbackTpl')
43   rollbackTpl: TemplateRef<any>;
44
45   permission: Permission;
46
47   data: RbdSnapshotModel[];
48
49   columns: CdTableColumn[];
50
51   modalRef: BsModalRef;
52
53   selection = new CdTableSelection();
54
55   constructor(
56     private authStorageService: AuthStorageService,
57     private modalService: BsModalService,
58     private dimlessBinaryPipe: DimlessBinaryPipe,
59     private cdDatePipe: CdDatePipe,
60     private rbdService: RbdService,
61     private taskManagerService: TaskManagerService,
62     private notificationService: NotificationService
63   ) {
64     this.permission = this.authStorageService.getPermissions().rbdImage;
65   }
66
67   ngOnInit() {
68     this.columns = [
69       {
70         name: 'Name',
71         prop: 'name',
72         cellTransformation: CellTemplate.executing,
73         flexGrow: 2
74       },
75       {
76         name: 'Size',
77         prop: 'size',
78         flexGrow: 1,
79         cellClass: 'text-right',
80         pipe: this.dimlessBinaryPipe
81       },
82       {
83         name: 'Provisioned',
84         prop: 'disk_usage',
85         flexGrow: 1,
86         cellClass: 'text-right',
87         pipe: this.dimlessBinaryPipe
88       },
89       {
90         name: 'State',
91         prop: 'is_protected',
92         flexGrow: 1,
93         cellClass: 'text-center',
94         cellTemplate: this.protectTpl
95       },
96       {
97         name: 'Created',
98         prop: 'timestamp',
99         flexGrow: 1,
100         pipe: this.cdDatePipe
101       }
102     ];
103   }
104
105   ngOnChanges() {
106     this.data = this.merge(this.snapshots, this.executingTasks);
107   }
108
109   private merge(snapshots: RbdSnapshotModel[], executingTasks: ExecutingTask[] = []) {
110     const resultSnapshots = _.clone(snapshots);
111     executingTasks.forEach((executingTask) => {
112       const snapshotExecuting = resultSnapshots.find((snapshot) => {
113         return snapshot.name === executingTask.metadata['snapshot_name'];
114       });
115       if (snapshotExecuting) {
116         if (executingTask.name === 'rbd/snap/delete') {
117           snapshotExecuting.cdExecuting = 'deleting';
118         } else if (executingTask.name === 'rbd/snap/edit') {
119           snapshotExecuting.cdExecuting = 'updating';
120         } else if (executingTask.name === 'rbd/snap/rollback') {
121           snapshotExecuting.cdExecuting = 'rolling back';
122         }
123       } else if (executingTask.name === 'rbd/snap/create') {
124         const rbdSnapshotModel = new RbdSnapshotModel();
125         rbdSnapshotModel.name = executingTask.metadata['snapshot_name'];
126         rbdSnapshotModel.cdExecuting = 'creating';
127         this.pushIfNotExists(resultSnapshots, rbdSnapshotModel);
128       }
129     });
130     return resultSnapshots;
131   }
132
133   private pushIfNotExists(resultSnapshots: RbdSnapshotModel[], rbdSnapshotModel: RbdSnapshotModel) {
134     const exists = resultSnapshots.some((resultSnapshot) => {
135       return resultSnapshot.name === rbdSnapshotModel.name;
136     });
137     if (!exists) {
138       resultSnapshots.push(rbdSnapshotModel);
139     }
140   }
141
142   private openSnapshotModal(taskName: string, oldSnapshotName: string = null) {
143     this.modalRef = this.modalService.show(RbdSnapshotFormComponent);
144     this.modalRef.content.poolName = this.poolName;
145     this.modalRef.content.imageName = this.rbdName;
146     if (oldSnapshotName) {
147       this.modalRef.content.setSnapName(this.selection.first().name);
148     }
149     this.modalRef.content.onSubmit.subscribe((snapshotName: string) => {
150       const executingTask = new ExecutingTask();
151       executingTask.name = taskName;
152       executingTask.metadata = { snapshot_name: snapshotName };
153       this.executingTasks.push(executingTask);
154       this.ngOnChanges();
155     });
156   }
157
158   openCreateSnapshotModal() {
159     this.openSnapshotModal('rbd/snap/create');
160   }
161
162   openEditSnapshotModal() {
163     this.openSnapshotModal('rbd/snap/edit', this.selection.first().name);
164   }
165
166   toggleProtection() {
167     const snapshotName = this.selection.first().name;
168     const isProtected = this.selection.first().is_protected;
169     const finishedTask = new FinishedTask();
170     finishedTask.name = 'rbd/snap/edit';
171     finishedTask.metadata = {
172       pool_name: this.poolName,
173       image_name: this.rbdName,
174       snapshot_name: snapshotName
175     };
176     this.rbdService
177       .protectSnapshot(this.poolName, this.rbdName, snapshotName, !isProtected)
178       .toPromise()
179       .then((resp) => {
180         const executingTask = new ExecutingTask();
181         executingTask.name = finishedTask.name;
182         executingTask.metadata = finishedTask.metadata;
183         this.executingTasks.push(executingTask);
184         this.ngOnChanges();
185         this.taskManagerService.subscribe(
186           finishedTask.name,
187           finishedTask.metadata,
188           (asyncFinishedTask: FinishedTask) => {
189             this.notificationService.notifyTask(asyncFinishedTask);
190           }
191         );
192       });
193   }
194
195   _asyncTask(task: string, taskName: string, snapshotName: string) {
196     const finishedTask = new FinishedTask();
197     finishedTask.name = taskName;
198     finishedTask.metadata = {
199       pool_name: this.poolName,
200       image_name: this.rbdName,
201       snapshot_name: snapshotName
202     };
203     this.rbdService[task](this.poolName, this.rbdName, snapshotName)
204       .toPromise()
205       .then(() => {
206         const executingTask = new ExecutingTask();
207         executingTask.name = finishedTask.name;
208         executingTask.metadata = finishedTask.metadata;
209         this.executingTasks.push(executingTask);
210         this.modalRef.hide();
211         this.ngOnChanges();
212         this.taskManagerService.subscribe(
213           executingTask.name,
214           executingTask.metadata,
215           (asyncFinishedTask: FinishedTask) => {
216             this.notificationService.notifyTask(asyncFinishedTask);
217           }
218         );
219       })
220       .catch((resp) => {
221         this.modalRef.content.stopLoadingSpinner();
222       });
223   }
224
225   rollbackModal() {
226     const snapshotName = this.selection.selected[0].name;
227     const initialState = {
228       titleText: 'RBD snapshot rollback',
229       buttonText: 'Rollback',
230       bodyTpl: this.rollbackTpl,
231       bodyData: {
232         snapName: `${this.poolName}/${this.rbdName}@${snapshotName}`
233       },
234       onSubmit: () => {
235         this._asyncTask('rollbackSnapshot', 'rbd/snap/rollback', snapshotName);
236       }
237     };
238
239     this.modalRef = this.modalService.show(ConfirmationModalComponent, { initialState });
240   }
241
242   deleteSnapshotModal() {
243     const snapshotName = this.selection.selected[0].name;
244     this.modalRef = this.modalService.show(DeletionModalComponent);
245     this.modalRef.content.setUp({
246       metaType: 'RBD snapshot',
247       pattern: snapshotName,
248       deletionMethod: () => this._asyncTask('deleteSnapshot', 'rbd/snap/delete', snapshotName),
249       modalRef: this.modalRef
250     });
251   }
252
253   updateSelection(selection: CdTableSelection) {
254     this.selection = selection;
255   }
256 }