]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core'; |
2 | ||
3 | import { I18n } from '@ngx-translate/i18n-polyfill'; | |
9f95a23c TL |
4 | import { |
5 | ITreeOptions, | |
9f95a23c TL |
6 | TreeComponent, |
7 | TreeModel, | |
e306af50 TL |
8 | TreeNode, |
9 | TREE_ACTIONS | |
9f95a23c | 10 | } from 'angular-tree-component'; |
11fdf7f2 | 11 | import * as _ from 'lodash'; |
11fdf7f2 TL |
12 | |
13 | import { TableComponent } from '../../../shared/datatable/table/table.component'; | |
9f95a23c | 14 | import { Icons } from '../../../shared/enum/icons.enum'; |
11fdf7f2 | 15 | import { CdTableColumn } from '../../../shared/models/cd-table-column'; |
eafe8130 | 16 | import { BooleanTextPipe } from '../../../shared/pipes/boolean-text.pipe'; |
11fdf7f2 TL |
17 | import { IscsiBackstorePipe } from '../../../shared/pipes/iscsi-backstore.pipe'; |
18 | ||
19 | @Component({ | |
20 | selector: 'cd-iscsi-target-details', | |
21 | templateUrl: './iscsi-target-details.component.html', | |
22 | styleUrls: ['./iscsi-target-details.component.scss'] | |
23 | }) | |
24 | export class IscsiTargetDetailsComponent implements OnChanges, OnInit { | |
25 | @Input() | |
e306af50 | 26 | selection: any; |
11fdf7f2 TL |
27 | @Input() |
28 | settings: any; | |
eafe8130 TL |
29 | @Input() |
30 | cephIscsiConfigVersion: number; | |
11fdf7f2 | 31 | |
9f95a23c | 32 | @ViewChild('highlightTpl', { static: true }) |
11fdf7f2 TL |
33 | highlightTpl: TemplateRef<any>; |
34 | ||
35 | private detailTable: TableComponent; | |
9f95a23c | 36 | @ViewChild('detailTable', { static: false }) |
11fdf7f2 TL |
37 | set content(content: TableComponent) { |
38 | this.detailTable = content; | |
39 | if (content) { | |
40 | content.updateColumns(); | |
41 | } | |
42 | } | |
43 | ||
9f95a23c TL |
44 | @ViewChild('tree', { static: false }) tree: TreeComponent; |
45 | ||
46 | icons = Icons; | |
11fdf7f2 TL |
47 | columns: CdTableColumn[]; |
48 | data: any; | |
49 | metadata: any = {}; | |
50 | selectedItem: any; | |
51 | title: string; | |
9f95a23c TL |
52 | |
53 | nodes: any[] = []; | |
54 | treeOptions: ITreeOptions = { | |
55 | useVirtualScroll: true, | |
56 | actionMapping: { | |
57 | mouse: { | |
58 | click: this.onNodeSelected.bind(this) | |
59 | } | |
60 | } | |
61 | }; | |
11fdf7f2 | 62 | |
eafe8130 TL |
63 | constructor( |
64 | private i18n: I18n, | |
65 | private iscsiBackstorePipe: IscsiBackstorePipe, | |
66 | private booleanTextPipe: BooleanTextPipe | |
67 | ) {} | |
11fdf7f2 TL |
68 | |
69 | ngOnInit() { | |
70 | this.columns = [ | |
71 | { | |
72 | prop: 'displayName', | |
73 | name: this.i18n('Name'), | |
eafe8130 | 74 | flexGrow: 1, |
11fdf7f2 TL |
75 | cellTemplate: this.highlightTpl |
76 | }, | |
77 | { | |
78 | prop: 'current', | |
79 | name: this.i18n('Current'), | |
80 | flexGrow: 1, | |
81 | cellTemplate: this.highlightTpl | |
82 | }, | |
83 | { | |
84 | prop: 'default', | |
85 | name: this.i18n('Default'), | |
86 | flexGrow: 1, | |
87 | cellTemplate: this.highlightTpl | |
88 | } | |
89 | ]; | |
90 | } | |
91 | ||
92 | ngOnChanges() { | |
e306af50 TL |
93 | if (this.selection) { |
94 | this.selectedItem = this.selection; | |
11fdf7f2 TL |
95 | this.generateTree(); |
96 | } | |
97 | ||
98 | this.data = undefined; | |
99 | } | |
100 | ||
101 | private generateTree() { | |
eafe8130 TL |
102 | const target_meta = _.cloneDeep(this.selectedItem.target_controls); |
103 | // Target level authentication was introduced in ceph-iscsi config v11 | |
104 | if (this.cephIscsiConfigVersion > 10) { | |
105 | _.extend(target_meta, _.cloneDeep(this.selectedItem.auth)); | |
106 | } | |
107 | this.metadata = { root: target_meta }; | |
11fdf7f2 TL |
108 | const cssClasses = { |
109 | target: { | |
9f95a23c TL |
110 | expanded: _.join( |
111 | this.selectedItem.cdExecuting | |
112 | ? [Icons.large, Icons.spinner, Icons.spin] | |
113 | : [Icons.large, Icons.bullseye], | |
114 | ' ' | |
115 | ) | |
11fdf7f2 TL |
116 | }, |
117 | initiators: { | |
9f95a23c TL |
118 | expanded: _.join([Icons.large, Icons.user], ' '), |
119 | leaf: _.join([Icons.user], ' ') | |
11fdf7f2 TL |
120 | }, |
121 | groups: { | |
9f95a23c TL |
122 | expanded: _.join([Icons.large, Icons.users], ' '), |
123 | leaf: _.join([Icons.users], ' ') | |
11fdf7f2 TL |
124 | }, |
125 | disks: { | |
9f95a23c TL |
126 | expanded: _.join([Icons.large, Icons.disk], ' '), |
127 | leaf: _.join([Icons.disk], ' ') | |
11fdf7f2 TL |
128 | }, |
129 | portals: { | |
9f95a23c TL |
130 | expanded: _.join([Icons.large, Icons.server], ' '), |
131 | leaf: _.join([Icons.server], ' ') | |
11fdf7f2 TL |
132 | } |
133 | }; | |
134 | ||
9f95a23c | 135 | const disks: any[] = []; |
11fdf7f2 | 136 | _.forEach(this.selectedItem.disks, (disk) => { |
9f95a23c TL |
137 | const cdId = 'disk_' + disk.pool + '_' + disk.image; |
138 | this.metadata[cdId] = { | |
11fdf7f2 TL |
139 | controls: disk.controls, |
140 | backstore: disk.backstore | |
141 | }; | |
eafe8130 TL |
142 | ['wwn', 'lun'].forEach((k) => { |
143 | if (k in disk) { | |
9f95a23c | 144 | this.metadata[cdId][k] = disk[k]; |
eafe8130 TL |
145 | } |
146 | }); | |
11fdf7f2 | 147 | disks.push({ |
9f95a23c TL |
148 | name: `${disk.pool}/${disk.image}`, |
149 | cdId: cdId, | |
150 | cdIcon: cssClasses.disks.leaf | |
11fdf7f2 TL |
151 | }); |
152 | }); | |
153 | ||
9f95a23c | 154 | const portals: any[] = []; |
11fdf7f2 | 155 | _.forEach(this.selectedItem.portals, (portal) => { |
9f95a23c TL |
156 | portals.push({ |
157 | name: `${portal.host}:${portal.ip}`, | |
158 | cdIcon: cssClasses.portals.leaf | |
159 | }); | |
11fdf7f2 TL |
160 | }); |
161 | ||
9f95a23c | 162 | const clients: any[] = []; |
11fdf7f2 | 163 | _.forEach(this.selectedItem.clients, (client) => { |
494da23a | 164 | const client_metadata = _.cloneDeep(client.auth); |
eafe8130 TL |
165 | if (client.info) { |
166 | _.extend(client_metadata, client.info); | |
167 | delete client_metadata['state']; | |
168 | _.forEach(Object.keys(client.info.state), (state) => { | |
169 | client_metadata[state.toLowerCase()] = client.info.state[state]; | |
170 | }); | |
171 | } | |
494da23a | 172 | this.metadata['client_' + client.client_iqn] = client_metadata; |
11fdf7f2 | 173 | |
9f95a23c TL |
174 | const luns: any[] = []; |
175 | client.luns.forEach((lun: Record<string, any>) => { | |
11fdf7f2 | 176 | luns.push({ |
9f95a23c TL |
177 | name: `${lun.pool}/${lun.image}`, |
178 | cdId: 'disk_' + lun.pool + '_' + lun.image, | |
179 | cdIcon: cssClasses.disks.leaf | |
11fdf7f2 TL |
180 | }); |
181 | }); | |
182 | ||
eafe8130 TL |
183 | let status = ''; |
184 | if (client.info) { | |
185 | status = Object.keys(client.info.state).includes('LOGGED_IN') ? 'logged_in' : 'logged_out'; | |
186 | } | |
11fdf7f2 | 187 | clients.push({ |
9f95a23c | 188 | name: client.client_iqn, |
eafe8130 | 189 | status: status, |
9f95a23c TL |
190 | cdId: 'client_' + client.client_iqn, |
191 | children: luns, | |
192 | cdIcon: cssClasses.initiators.leaf | |
11fdf7f2 TL |
193 | }); |
194 | }); | |
195 | ||
9f95a23c | 196 | const groups: any[] = []; |
11fdf7f2 | 197 | _.forEach(this.selectedItem.groups, (group) => { |
9f95a23c TL |
198 | const luns: any[] = []; |
199 | group.disks.forEach((disk: Record<string, any>) => { | |
11fdf7f2 | 200 | luns.push({ |
9f95a23c TL |
201 | name: `${disk.pool}/${disk.image}`, |
202 | cdId: 'disk_' + disk.pool + '_' + disk.image, | |
203 | cdIcon: cssClasses.disks.leaf | |
11fdf7f2 TL |
204 | }); |
205 | }); | |
206 | ||
9f95a23c TL |
207 | const initiators: any[] = []; |
208 | group.members.forEach((member: string) => { | |
11fdf7f2 | 209 | initiators.push({ |
9f95a23c TL |
210 | name: member, |
211 | cdId: 'client_' + member | |
11fdf7f2 TL |
212 | }); |
213 | }); | |
214 | ||
215 | groups.push({ | |
9f95a23c TL |
216 | name: group.group_id, |
217 | cdIcon: cssClasses.groups.leaf, | |
11fdf7f2 TL |
218 | children: [ |
219 | { | |
9f95a23c | 220 | name: 'Disks', |
11fdf7f2 | 221 | children: luns, |
9f95a23c | 222 | cdIcon: cssClasses.disks.expanded |
11fdf7f2 TL |
223 | }, |
224 | { | |
9f95a23c | 225 | name: 'Initiators', |
11fdf7f2 | 226 | children: initiators, |
9f95a23c | 227 | cdIcon: cssClasses.initiators.expanded |
11fdf7f2 TL |
228 | } |
229 | ] | |
230 | }); | |
231 | }); | |
232 | ||
9f95a23c TL |
233 | this.nodes = [ |
234 | { | |
235 | name: this.selectedItem.target_iqn, | |
236 | cdId: 'root', | |
237 | isExpanded: true, | |
238 | cdIcon: cssClasses.target.expanded, | |
239 | children: [ | |
240 | { | |
241 | name: 'Disks', | |
242 | isExpanded: true, | |
243 | children: disks, | |
244 | cdIcon: cssClasses.disks.expanded | |
245 | }, | |
246 | { | |
247 | name: 'Portals', | |
248 | isExpanded: true, | |
249 | children: portals, | |
250 | cdIcon: cssClasses.portals.expanded | |
251 | }, | |
252 | { | |
253 | name: 'Initiators', | |
254 | isExpanded: true, | |
255 | children: clients, | |
256 | cdIcon: cssClasses.initiators.expanded | |
257 | }, | |
258 | { | |
259 | name: 'Groups', | |
260 | isExpanded: true, | |
261 | children: groups, | |
262 | cdIcon: cssClasses.groups.expanded | |
11fdf7f2 | 263 | } |
9f95a23c TL |
264 | ] |
265 | } | |
266 | ]; | |
11fdf7f2 TL |
267 | } |
268 | ||
9f95a23c | 269 | private format(value: any) { |
eafe8130 TL |
270 | if (typeof value === 'boolean') { |
271 | return this.booleanTextPipe.transform(value); | |
272 | } | |
273 | return value; | |
274 | } | |
275 | ||
9f95a23c TL |
276 | onNodeSelected(tree: TreeModel, node: TreeNode) { |
277 | TREE_ACTIONS.ACTIVATE(tree, node, true); | |
278 | if (node.data.cdId) { | |
279 | this.title = node.data.name; | |
280 | const tempData = this.metadata[node.data.cdId] || {}; | |
11fdf7f2 | 281 | |
9f95a23c | 282 | if (node.data.cdId === 'root') { |
11fdf7f2 TL |
283 | this.columns[2].isHidden = false; |
284 | this.data = _.map(this.settings.target_default_controls, (value, key) => { | |
eafe8130 | 285 | value = this.format(value); |
11fdf7f2 TL |
286 | return { |
287 | displayName: key, | |
288 | default: value, | |
eafe8130 | 289 | current: !_.isUndefined(tempData[key]) ? this.format(tempData[key]) : value |
11fdf7f2 TL |
290 | }; |
291 | }); | |
eafe8130 TL |
292 | // Target level authentication was introduced in ceph-iscsi config v11 |
293 | if (this.cephIscsiConfigVersion > 10) { | |
294 | ['user', 'password', 'mutual_user', 'mutual_password'].forEach((key) => { | |
295 | this.data.push({ | |
296 | displayName: key, | |
297 | default: null, | |
298 | current: tempData[key] | |
299 | }); | |
300 | }); | |
301 | } | |
9f95a23c | 302 | } else if (node.data.cdId.toString().startsWith('disk_')) { |
11fdf7f2 TL |
303 | this.columns[2].isHidden = false; |
304 | this.data = _.map(this.settings.disk_default_controls[tempData.backstore], (value, key) => { | |
eafe8130 | 305 | value = this.format(value); |
11fdf7f2 TL |
306 | return { |
307 | displayName: key, | |
308 | default: value, | |
eafe8130 TL |
309 | current: !_.isUndefined(tempData.controls[key]) |
310 | ? this.format(tempData.controls[key]) | |
311 | : value | |
11fdf7f2 TL |
312 | }; |
313 | }); | |
314 | this.data.push({ | |
315 | displayName: 'backstore', | |
316 | default: this.iscsiBackstorePipe.transform(this.settings.default_backstore), | |
317 | current: this.iscsiBackstorePipe.transform(tempData.backstore) | |
318 | }); | |
eafe8130 TL |
319 | ['wwn', 'lun'].forEach((k) => { |
320 | if (k in tempData) { | |
321 | this.data.push({ | |
322 | displayName: k, | |
323 | default: undefined, | |
324 | current: tempData[k] | |
325 | }); | |
326 | } | |
327 | }); | |
11fdf7f2 TL |
328 | } else { |
329 | this.columns[2].isHidden = true; | |
330 | this.data = _.map(tempData, (value, key) => { | |
331 | return { | |
332 | displayName: key, | |
333 | default: undefined, | |
eafe8130 | 334 | current: this.format(value) |
11fdf7f2 TL |
335 | }; |
336 | }); | |
337 | } | |
338 | } else { | |
339 | this.data = undefined; | |
340 | } | |
341 | ||
342 | if (this.detailTable) { | |
343 | this.detailTable.updateColumns(); | |
344 | } | |
345 | } | |
9f95a23c TL |
346 | |
347 | onUpdateData() { | |
348 | this.tree.treeModel.expandAll(); | |
349 | } | |
11fdf7f2 | 350 | } |