]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
01c373f1630155770dc838a9116fd1564c828316
[ceph-ci.git] /
1 import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
2
3 import { I18n } from '@ngx-translate/i18n-polyfill';
4 import * as _ from 'lodash';
5 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
6 import { Subscription } from 'rxjs';
7
8 import { IscsiService } from '../../../shared/api/iscsi.service';
9 import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
10 import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
11 import { TableComponent } from '../../../shared/datatable/table/table.component';
12 import { CellTemplate } from '../../../shared/enum/cell-template.enum';
13 import { Icons } from '../../../shared/enum/icons.enum';
14 import { CdTableAction } from '../../../shared/models/cd-table-action';
15 import { CdTableColumn } from '../../../shared/models/cd-table-column';
16 import { CdTableSelection } from '../../../shared/models/cd-table-selection';
17 import { FinishedTask } from '../../../shared/models/finished-task';
18 import { Permission } from '../../../shared/models/permissions';
19 import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe';
20 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
21 import { SummaryService } from '../../../shared/services/summary.service';
22 import { TaskListService } from '../../../shared/services/task-list.service';
23 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
24 import { IscsiTargetDiscoveryModalComponent } from '../iscsi-target-discovery-modal/iscsi-target-discovery-modal.component';
25
26 @Component({
27   selector: 'cd-iscsi-target-list',
28   templateUrl: './iscsi-target-list.component.html',
29   styleUrls: ['./iscsi-target-list.component.scss'],
30   providers: [TaskListService]
31 })
32 export class IscsiTargetListComponent implements OnInit, OnDestroy {
33   @ViewChild(TableComponent, { static: false })
34   table: TableComponent;
35
36   available: boolean = undefined;
37   columns: CdTableColumn[];
38   docsUrl: string;
39   modalRef: BsModalRef;
40   permission: Permission;
41   selection = new CdTableSelection();
42   settings: any;
43   status: string;
44   summaryDataSubscription: Subscription;
45   tableActions: CdTableAction[];
46   targets = [];
47   icons = Icons;
48
49   builders = {
50     'iscsi/target/create': (metadata) => {
51       return {
52         target_iqn: metadata['target_iqn']
53       };
54     }
55   };
56
57   constructor(
58     private authStorageService: AuthStorageService,
59     private i18n: I18n,
60     private iscsiService: IscsiService,
61     private taskListService: TaskListService,
62     private cephReleaseNamePipe: CephReleaseNamePipe,
63     private summaryservice: SummaryService,
64     private modalService: BsModalService,
65     private taskWrapper: TaskWrapperService,
66     public actionLabels: ActionLabelsI18n
67   ) {
68     this.permission = this.authStorageService.getPermissions().iscsi;
69
70     this.tableActions = [
71       {
72         permission: 'create',
73         icon: Icons.add,
74         routerLink: () => '/block/iscsi/targets/create',
75         name: this.actionLabels.CREATE
76       },
77       {
78         permission: 'update',
79         icon: Icons.edit,
80         routerLink: () => `/block/iscsi/targets/edit/${this.selection.first().target_iqn}`,
81         name: this.actionLabels.EDIT
82       },
83       {
84         permission: 'delete',
85         icon: Icons.destroy,
86         click: () => this.deleteIscsiTargetModal(),
87         name: this.actionLabels.DELETE,
88         disable: () => !this.selection.first() || !_.isUndefined(this.getDeleteDisableDesc()),
89         disableDesc: () => this.getDeleteDisableDesc()
90       }
91     ];
92   }
93
94   ngOnInit() {
95     this.columns = [
96       {
97         name: this.i18n('Target'),
98         prop: 'target_iqn',
99         flexGrow: 2,
100         cellTransformation: CellTemplate.executing
101       },
102       {
103         name: this.i18n('Portals'),
104         prop: 'cdPortals',
105         flexGrow: 2
106       },
107       {
108         name: this.i18n('Images'),
109         prop: 'cdImages',
110         flexGrow: 2
111       },
112       {
113         name: this.i18n('# Sessions'),
114         prop: 'info.num_sessions',
115         flexGrow: 1
116       }
117     ];
118
119     this.iscsiService.status().subscribe((result: any) => {
120       this.available = result.available;
121
122       if (result.available) {
123         this.taskListService.init(
124           () => this.iscsiService.listTargets(),
125           (resp) => this.prepareResponse(resp),
126           (targets) => (this.targets = targets),
127           () => this.onFetchError(),
128           this.taskFilter,
129           this.itemFilter,
130           this.builders
131         );
132
133         this.iscsiService.settings().subscribe((settings: any) => {
134           this.settings = settings;
135         });
136       } else {
137         const summary = this.summaryservice.getCurrentSummary();
138         const releaseName = this.cephReleaseNamePipe.transform(summary.version);
139         this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/#enabling-iscsi-management`;
140         this.status = result.message;
141       }
142     });
143   }
144
145   ngOnDestroy() {
146     if (this.summaryDataSubscription) {
147       this.summaryDataSubscription.unsubscribe();
148     }
149   }
150
151   getDeleteDisableDesc(): string | undefined {
152     const first = this.selection.first();
153     if (first && first['info'] && first['info']['num_sessions']) {
154       return this.i18n('Target has active sessions');
155     }
156   }
157
158   prepareResponse(resp: any): any[] {
159     resp.forEach((element) => {
160       element.cdPortals = element.portals.map((portal) => `${portal.host}:${portal.ip}`);
161       element.cdImages = element.disks.map((disk) => `${disk.pool}/${disk.image}`);
162     });
163
164     return resp;
165   }
166
167   onFetchError() {
168     this.table.reset(); // Disable loading indicator.
169   }
170
171   itemFilter(entry, task) {
172     return entry.target_iqn === task.metadata['target_iqn'];
173   }
174
175   taskFilter(task) {
176     return ['iscsi/target/create', 'iscsi/target/edit', 'iscsi/target/delete'].includes(task.name);
177   }
178
179   updateSelection(selection: CdTableSelection) {
180     this.selection = selection;
181   }
182
183   deleteIscsiTargetModal() {
184     const target_iqn = this.selection.first().target_iqn;
185
186     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
187       initialState: {
188         itemDescription: this.i18n('iSCSI'),
189         submitActionObservable: () =>
190           this.taskWrapper.wrapTaskAroundCall({
191             task: new FinishedTask('iscsi/target/delete', {
192               target_iqn: target_iqn
193             }),
194             call: this.iscsiService.deleteTarget(target_iqn)
195           })
196       }
197     });
198   }
199
200   configureDiscoveryAuth() {
201     this.modalService.show(IscsiTargetDiscoveryModalComponent, {});
202   }
203 }