]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; |
2 | ||
3 | import { I18n } from '@ngx-translate/i18n-polyfill'; | |
92f5a8d4 | 4 | import * as _ from 'lodash'; |
11fdf7f2 TL |
5 | import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; |
6 | import { Subscription } from 'rxjs'; | |
7 | ||
8 | import { IscsiService } from '../../../shared/api/iscsi.service'; | |
e306af50 | 9 | import { ListWithDetails } from '../../../shared/classes/list-with-details.class'; |
11fdf7f2 | 10 | import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component'; |
eafe8130 | 11 | import { ActionLabelsI18n } from '../../../shared/constants/app.constants'; |
11fdf7f2 TL |
12 | import { TableComponent } from '../../../shared/datatable/table/table.component'; |
13 | import { CellTemplate } from '../../../shared/enum/cell-template.enum'; | |
9f95a23c | 14 | import { Icons } from '../../../shared/enum/icons.enum'; |
11fdf7f2 TL |
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'; | |
9f95a23c TL |
19 | import { Permission } from '../../../shared/models/permissions'; |
20 | import { Task } from '../../../shared/models/task'; | |
92f5a8d4 | 21 | import { NotAvailablePipe } from '../../../shared/pipes/not-available.pipe'; |
11fdf7f2 | 22 | import { AuthStorageService } from '../../../shared/services/auth-storage.service'; |
11fdf7f2 TL |
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 | }) | |
e306af50 | 33 | export class IscsiTargetListComponent extends ListWithDetails implements OnInit, OnDestroy { |
9f95a23c | 34 | @ViewChild(TableComponent, { static: false }) |
11fdf7f2 TL |
35 | table: TableComponent; |
36 | ||
37 | available: boolean = undefined; | |
38 | columns: CdTableColumn[]; | |
11fdf7f2 | 39 | modalRef: BsModalRef; |
9f95a23c | 40 | permission: Permission; |
11fdf7f2 | 41 | selection = new CdTableSelection(); |
eafe8130 | 42 | cephIscsiConfigVersion: number; |
11fdf7f2 TL |
43 | settings: any; |
44 | status: string; | |
45 | summaryDataSubscription: Subscription; | |
46 | tableActions: CdTableAction[]; | |
9f95a23c TL |
47 | targets: any[] = []; |
48 | icons = Icons; | |
11fdf7f2 TL |
49 | |
50 | builders = { | |
9f95a23c | 51 | 'iscsi/target/create': (metadata: object) => { |
11fdf7f2 TL |
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, | |
92f5a8d4 | 63 | private notAvailablePipe: NotAvailablePipe, |
11fdf7f2 | 64 | private modalService: BsModalService, |
eafe8130 TL |
65 | private taskWrapper: TaskWrapperService, |
66 | public actionLabels: ActionLabelsI18n | |
11fdf7f2 | 67 | ) { |
e306af50 | 68 | super(); |
9f95a23c | 69 | this.permission = this.authStorageService.getPermissions().iscsi; |
11fdf7f2 TL |
70 | |
71 | this.tableActions = [ | |
72 | { | |
73 | permission: 'create', | |
9f95a23c | 74 | icon: Icons.add, |
eafe8130 TL |
75 | routerLink: () => '/block/iscsi/targets/create', |
76 | name: this.actionLabels.CREATE | |
11fdf7f2 TL |
77 | }, |
78 | { | |
79 | permission: 'update', | |
9f95a23c | 80 | icon: Icons.edit, |
11fdf7f2 | 81 | routerLink: () => `/block/iscsi/targets/edit/${this.selection.first().target_iqn}`, |
92f5a8d4 | 82 | name: this.actionLabels.EDIT, |
f6b5b4d7 | 83 | disable: () => !this.selection.first() || !_.isUndefined(this.getEditDisableDesc()), |
92f5a8d4 | 84 | disableDesc: () => this.getEditDisableDesc() |
11fdf7f2 TL |
85 | }, |
86 | { | |
87 | permission: 'delete', | |
9f95a23c | 88 | icon: Icons.destroy, |
11fdf7f2 | 89 | click: () => this.deleteIscsiTargetModal(), |
92f5a8d4 TL |
90 | name: this.actionLabels.DELETE, |
91 | disable: () => !this.selection.first() || !_.isUndefined(this.getDeleteDisableDesc()), | |
92 | disableDesc: () => this.getDeleteDisableDesc() | |
11fdf7f2 TL |
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', | |
92f5a8d4 | 118 | pipe: this.notAvailablePipe, |
11fdf7f2 TL |
119 | flexGrow: 1 |
120 | } | |
121 | ]; | |
122 | ||
123 | this.iscsiService.status().subscribe((result: any) => { | |
124 | this.available = result.available; | |
125 | ||
126 | if (result.available) { | |
eafe8130 TL |
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 | }); | |
11fdf7f2 TL |
139 | |
140 | this.iscsiService.settings().subscribe((settings: any) => { | |
141 | this.settings = settings; | |
142 | }); | |
143 | } else { | |
11fdf7f2 TL |
144 | this.status = result.message; |
145 | } | |
146 | }); | |
147 | } | |
148 | ||
149 | ngOnDestroy() { | |
150 | if (this.summaryDataSubscription) { | |
151 | this.summaryDataSubscription.unsubscribe(); | |
152 | } | |
153 | } | |
154 | ||
92f5a8d4 TL |
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 | } | |
9f95a23c TL |
163 | |
164 | return undefined; | |
92f5a8d4 TL |
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 | } | |
9f95a23c TL |
178 | |
179 | return undefined; | |
92f5a8d4 TL |
180 | } |
181 | ||
11fdf7f2 | 182 | prepareResponse(resp: any): any[] { |
9f95a23c TL |
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 | ); | |
11fdf7f2 TL |
190 | }); |
191 | ||
192 | return resp; | |
193 | } | |
194 | ||
195 | onFetchError() { | |
196 | this.table.reset(); // Disable loading indicator. | |
197 | } | |
198 | ||
9f95a23c | 199 | itemFilter(entry: Record<string, any>, task: Task) { |
11fdf7f2 TL |
200 | return entry.target_iqn === task.metadata['target_iqn']; |
201 | } | |
202 | ||
9f95a23c | 203 | taskFilter(task: Task) { |
11fdf7f2 TL |
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: { | |
eafe8130 TL |
216 | itemDescription: this.i18n('iSCSI target'), |
217 | itemNames: [target_iqn], | |
11fdf7f2 TL |
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 | } |