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