]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
d0eed6a72c77ed11cf3f77badafdac443056bbb8
[ceph-ci.git] /
1 import { Component, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
2
3 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
4 import _ from 'lodash';
5 import { Subscription } from 'rxjs';
6
7 import { IscsiService } from '~/app/shared/api/iscsi.service';
8 import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
9 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
10 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
11 import { TableComponent } from '~/app/shared/datatable/table/table.component';
12 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
13 import { Icons } from '~/app/shared/enum/icons.enum';
14 import { CdTableAction } from '~/app/shared/models/cd-table-action';
15 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
16 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
17 import { FinishedTask } from '~/app/shared/models/finished-task';
18 import { Permission } from '~/app/shared/models/permissions';
19 import { Task } from '~/app/shared/models/task';
20 import { JoinPipe } from '~/app/shared/pipes/join.pipe';
21 import { NotAvailablePipe } from '~/app/shared/pipes/not-available.pipe';
22 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
23 import { ModalService } from '~/app/shared/services/modal.service';
24 import { TaskListService } from '~/app/shared/services/task-list.service';
25 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
26 import { IscsiTargetDiscoveryModalComponent } from '../iscsi-target-discovery-modal/iscsi-target-discovery-modal.component';
27
28 @Component({
29   selector: 'cd-iscsi-target-list',
30   templateUrl: './iscsi-target-list.component.html',
31   styleUrls: ['./iscsi-target-list.component.scss'],
32   providers: [TaskListService]
33 })
34 export class IscsiTargetListComponent extends ListWithDetails implements OnInit, OnDestroy {
35   @ViewChild(TableComponent)
36   table: TableComponent;
37
38   available: boolean = undefined;
39   columns: CdTableColumn[];
40   modalRef: NgbModalRef;
41   permission: Permission;
42   selection = new CdTableSelection();
43   cephIscsiConfigVersion: number;
44   settings: any;
45   status: string;
46   summaryDataSubscription: Subscription;
47   tableActions: CdTableAction[];
48   targets: any[] = [];
49   icons = Icons;
50
51   builders = {
52     'iscsi/target/create': (metadata: object) => {
53       return {
54         target_iqn: metadata['target_iqn']
55       };
56     }
57   };
58
59   constructor(
60     private authStorageService: AuthStorageService,
61     private iscsiService: IscsiService,
62     private joinPipe: JoinPipe,
63     private taskListService: TaskListService,
64     private notAvailablePipe: NotAvailablePipe,
65     private modalService: ModalService,
66     private taskWrapper: TaskWrapperService,
67     public actionLabels: ActionLabelsI18n,
68     protected ngZone: NgZone
69   ) {
70     super(ngZone);
71     this.permission = this.authStorageService.getPermissions().iscsi;
72
73     this.tableActions = [
74       {
75         permission: 'create',
76         icon: Icons.add,
77         routerLink: () => '/block/iscsi/targets/create',
78         name: this.actionLabels.CREATE
79       },
80       {
81         permission: 'update',
82         icon: Icons.edit,
83         routerLink: () => `/block/iscsi/targets/edit/${this.selection.first().target_iqn}`,
84         name: this.actionLabels.EDIT,
85         disable: () => this.getEditDisableDesc()
86       },
87       {
88         permission: 'delete',
89         icon: Icons.destroy,
90         click: () => this.deleteIscsiTargetModal(),
91         name: this.actionLabels.DELETE,
92         disable: () => this.getDeleteDisableDesc()
93       }
94     ];
95   }
96
97   ngOnInit() {
98     this.columns = [
99       {
100         name: $localize`Target`,
101         prop: 'target_iqn',
102         flexGrow: 2,
103         cellTransformation: CellTemplate.executing
104       },
105       {
106         name: $localize`Portals`,
107         prop: 'cdPortals',
108         pipe: this.joinPipe,
109         flexGrow: 2
110       },
111       {
112         name: $localize`Images`,
113         prop: 'cdImages',
114         pipe: this.joinPipe,
115         flexGrow: 2
116       },
117       {
118         name: $localize`# Sessions`,
119         prop: 'info.num_sessions',
120         pipe: this.notAvailablePipe,
121         flexGrow: 1
122       }
123     ];
124
125     this.iscsiService.status().subscribe((result: any) => {
126       this.available = result.available;
127
128       if (!result.available) {
129         this.status = result.message;
130       }
131     });
132   }
133
134   getTargets() {
135     if (this.available) {
136       this.setTableRefreshTimeout();
137       this.iscsiService.version().subscribe((res: any) => {
138         this.cephIscsiConfigVersion = res['ceph_iscsi_config_version'];
139       });
140       this.taskListService.init(
141         () => this.iscsiService.listTargets(),
142         (resp) => this.prepareResponse(resp),
143         (targets) => (this.targets = targets),
144         () => this.onFetchError(),
145         this.taskFilter,
146         this.itemFilter,
147         this.builders
148       );
149
150       this.iscsiService.settings().subscribe((settings: any) => {
151         this.settings = settings;
152       });
153     }
154   }
155
156   ngOnDestroy() {
157     if (this.summaryDataSubscription) {
158       this.summaryDataSubscription.unsubscribe();
159     }
160   }
161
162   getEditDisableDesc(): string | boolean {
163     const first = this.selection.first();
164
165     if (first && first?.cdExecuting) {
166       return first.cdExecuting;
167     }
168
169     if (first && _.isUndefined(first?.['info'])) {
170       return $localize`Unavailable gateway(s)`;
171     }
172
173     return !first;
174   }
175
176   getDeleteDisableDesc(): string | boolean {
177     const first = this.selection.first();
178
179     if (first?.cdExecuting) {
180       return first.cdExecuting;
181     }
182
183     if (first && _.isUndefined(first?.['info'])) {
184       return $localize`Unavailable gateway(s)`;
185     }
186
187     if (first && first?.['info']?.['num_sessions']) {
188       return $localize`Target has active sessions`;
189     }
190
191     return !first;
192   }
193
194   prepareResponse(resp: any): any[] {
195     resp.forEach((element: Record<string, any>) => {
196       element.cdPortals = element.portals.map(
197         (portal: Record<string, any>) => `${portal.host}:${portal.ip}`
198       );
199       element.cdImages = element.disks.map(
200         (disk: Record<string, any>) => `${disk.pool}/${disk.image}`
201       );
202     });
203
204     return resp;
205   }
206
207   onFetchError() {
208     this.table.reset(); // Disable loading indicator.
209   }
210
211   itemFilter(entry: Record<string, any>, task: Task) {
212     return entry.target_iqn === task.metadata['target_iqn'];
213   }
214
215   taskFilter(task: Task) {
216     return ['iscsi/target/create', 'iscsi/target/edit', 'iscsi/target/delete'].includes(task.name);
217   }
218
219   updateSelection(selection: CdTableSelection) {
220     this.selection = selection;
221   }
222
223   deleteIscsiTargetModal() {
224     const target_iqn = this.selection.first().target_iqn;
225
226     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
227       itemDescription: $localize`iSCSI target`,
228       itemNames: [target_iqn],
229       submitActionObservable: () =>
230         this.taskWrapper.wrapTaskAroundCall({
231           task: new FinishedTask('iscsi/target/delete', {
232             target_iqn: target_iqn
233           }),
234           call: this.iscsiService.deleteTarget(target_iqn)
235         })
236     });
237   }
238
239   configureDiscoveryAuth() {
240     this.modalService.show(IscsiTargetDiscoveryModalComponent);
241   }
242 }