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