1 import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core';
3 import { I18n } from '@ngx-translate/i18n-polyfill';
10 } from 'angular-tree-component';
11 import * as _ from 'lodash';
13 import { TableComponent } from '../../../shared/datatable/table/table.component';
14 import { Icons } from '../../../shared/enum/icons.enum';
15 import { CdTableColumn } from '../../../shared/models/cd-table-column';
16 import { BooleanTextPipe } from '../../../shared/pipes/boolean-text.pipe';
17 import { IscsiBackstorePipe } from '../../../shared/pipes/iscsi-backstore.pipe';
20 selector: 'cd-iscsi-target-details',
21 templateUrl: './iscsi-target-details.component.html',
22 styleUrls: ['./iscsi-target-details.component.scss']
24 export class IscsiTargetDetailsComponent implements OnChanges, OnInit {
30 cephIscsiConfigVersion: number;
32 @ViewChild('highlightTpl', { static: true })
33 highlightTpl: TemplateRef<any>;
35 private detailTable: TableComponent;
36 @ViewChild('detailTable')
37 set content(content: TableComponent) {
38 this.detailTable = content;
40 content.updateColumns();
44 @ViewChild('tree') tree: TreeComponent;
47 columns: CdTableColumn[];
54 treeOptions: ITreeOptions = {
55 useVirtualScroll: true,
58 click: this.onNodeSelected.bind(this)
65 private iscsiBackstorePipe: IscsiBackstorePipe,
66 private booleanTextPipe: BooleanTextPipe
73 name: this.i18n('Name'),
75 cellTemplate: this.highlightTpl
79 name: this.i18n('Current'),
81 cellTemplate: this.highlightTpl
85 name: this.i18n('Default'),
87 cellTemplate: this.highlightTpl
94 this.selectedItem = this.selection;
98 this.data = undefined;
101 private generateTree() {
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));
107 this.metadata = { root: target_meta };
111 this.selectedItem.cdExecuting
112 ? [Icons.large, Icons.spinner, Icons.spin]
113 : [Icons.large, Icons.bullseye],
118 expanded: _.join([Icons.large, Icons.user], ' '),
119 leaf: _.join([Icons.user], ' ')
122 expanded: _.join([Icons.large, Icons.users], ' '),
123 leaf: _.join([Icons.users], ' ')
126 expanded: _.join([Icons.large, Icons.disk], ' '),
127 leaf: _.join([Icons.disk], ' ')
130 expanded: _.join([Icons.large, Icons.server], ' '),
131 leaf: _.join([Icons.server], ' ')
135 const disks: any[] = [];
136 _.forEach(this.selectedItem.disks, (disk) => {
137 const cdId = 'disk_' + disk.pool + '_' + disk.image;
138 this.metadata[cdId] = {
139 controls: disk.controls,
140 backstore: disk.backstore
142 ['wwn', 'lun'].forEach((k) => {
144 this.metadata[cdId][k] = disk[k];
148 name: `${disk.pool}/${disk.image}`,
150 cdIcon: cssClasses.disks.leaf
154 const portals: any[] = [];
155 _.forEach(this.selectedItem.portals, (portal) => {
157 name: `${portal.host}:${portal.ip}`,
158 cdIcon: cssClasses.portals.leaf
162 const clients: any[] = [];
163 _.forEach(this.selectedItem.clients, (client) => {
164 const client_metadata = _.cloneDeep(client.auth);
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];
172 this.metadata['client_' + client.client_iqn] = client_metadata;
174 const luns: any[] = [];
175 client.luns.forEach((lun: Record<string, any>) => {
177 name: `${lun.pool}/${lun.image}`,
178 cdId: 'disk_' + lun.pool + '_' + lun.image,
179 cdIcon: cssClasses.disks.leaf
185 status = Object.keys(client.info.state).includes('LOGGED_IN') ? 'logged_in' : 'logged_out';
188 name: client.client_iqn,
190 cdId: 'client_' + client.client_iqn,
192 cdIcon: cssClasses.initiators.leaf
196 const groups: any[] = [];
197 _.forEach(this.selectedItem.groups, (group) => {
198 const luns: any[] = [];
199 group.disks.forEach((disk: Record<string, any>) => {
201 name: `${disk.pool}/${disk.image}`,
202 cdId: 'disk_' + disk.pool + '_' + disk.image,
203 cdIcon: cssClasses.disks.leaf
207 const initiators: any[] = [];
208 group.members.forEach((member: string) => {
211 cdId: 'client_' + member
216 name: group.group_id,
217 cdIcon: cssClasses.groups.leaf,
222 cdIcon: cssClasses.disks.expanded
226 children: initiators,
227 cdIcon: cssClasses.initiators.expanded
235 name: this.selectedItem.target_iqn,
238 cdIcon: cssClasses.target.expanded,
244 cdIcon: cssClasses.disks.expanded
250 cdIcon: cssClasses.portals.expanded
256 cdIcon: cssClasses.initiators.expanded
262 cdIcon: cssClasses.groups.expanded
269 private format(value: any) {
270 if (typeof value === 'boolean') {
271 return this.booleanTextPipe.transform(value);
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] || {};
282 if (node.data.cdId === 'root') {
283 this.columns[2].isHidden = false;
284 this.data = _.map(this.settings.target_default_controls, (value, key) => {
285 value = this.format(value);
289 current: !_.isUndefined(tempData[key]) ? this.format(tempData[key]) : value
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) => {
298 current: tempData[key]
302 } else if (node.data.cdId.toString().startsWith('disk_')) {
303 this.columns[2].isHidden = false;
304 this.data = _.map(this.settings.disk_default_controls[tempData.backstore], (value, key) => {
305 value = this.format(value);
309 current: !_.isUndefined(tempData.controls[key])
310 ? this.format(tempData.controls[key])
315 displayName: 'backstore',
316 default: this.iscsiBackstorePipe.transform(this.settings.default_backstore),
317 current: this.iscsiBackstorePipe.transform(tempData.backstore)
319 ['wwn', 'lun'].forEach((k) => {
329 this.columns[2].isHidden = true;
330 this.data = _.map(tempData, (value, key) => {
334 current: this.format(value)
339 this.data = undefined;
342 if (this.detailTable) {
343 this.detailTable.updateColumns();
348 this.tree.treeModel.expandAll();