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 { CdTableSelection } from '../../../shared/models/cd-table-selection';
17 import { BooleanTextPipe } from '../../../shared/pipes/boolean-text.pipe';
18 import { IscsiBackstorePipe } from '../../../shared/pipes/iscsi-backstore.pipe';
21 selector: 'cd-iscsi-target-details',
22 templateUrl: './iscsi-target-details.component.html',
23 styleUrls: ['./iscsi-target-details.component.scss']
25 export class IscsiTargetDetailsComponent implements OnChanges, OnInit {
27 selection: CdTableSelection;
31 cephIscsiConfigVersion: number;
33 @ViewChild('highlightTpl', { static: true })
34 highlightTpl: TemplateRef<any>;
36 private detailTable: TableComponent;
37 @ViewChild('detailTable', { static: false })
38 set content(content: TableComponent) {
39 this.detailTable = content;
41 content.updateColumns();
45 @ViewChild('tree', { static: false }) tree: TreeComponent;
48 columns: CdTableColumn[];
55 treeOptions: ITreeOptions = {
56 useVirtualScroll: true,
59 click: this.onNodeSelected.bind(this)
66 private iscsiBackstorePipe: IscsiBackstorePipe,
67 private booleanTextPipe: BooleanTextPipe
74 name: this.i18n('Name'),
76 cellTemplate: this.highlightTpl
80 name: this.i18n('Current'),
82 cellTemplate: this.highlightTpl
86 name: this.i18n('Default'),
88 cellTemplate: this.highlightTpl
94 if (this.selection.hasSelection) {
95 this.selectedItem = this.selection.first();
99 this.data = undefined;
102 private generateTree() {
103 const target_meta = _.cloneDeep(this.selectedItem.target_controls);
104 // Target level authentication was introduced in ceph-iscsi config v11
105 if (this.cephIscsiConfigVersion > 10) {
106 _.extend(target_meta, _.cloneDeep(this.selectedItem.auth));
108 this.metadata = { root: target_meta };
112 this.selectedItem.cdExecuting
113 ? [Icons.large, Icons.spinner, Icons.spin]
114 : [Icons.large, Icons.bullseye],
119 expanded: _.join([Icons.large, Icons.user], ' '),
120 leaf: _.join([Icons.user], ' ')
123 expanded: _.join([Icons.large, Icons.users], ' '),
124 leaf: _.join([Icons.users], ' ')
127 expanded: _.join([Icons.large, Icons.disk], ' '),
128 leaf: _.join([Icons.disk], ' ')
131 expanded: _.join([Icons.large, Icons.server], ' '),
132 leaf: _.join([Icons.server], ' ')
136 const disks: any[] = [];
137 _.forEach(this.selectedItem.disks, (disk) => {
138 const cdId = 'disk_' + disk.pool + '_' + disk.image;
139 this.metadata[cdId] = {
140 controls: disk.controls,
141 backstore: disk.backstore
143 ['wwn', 'lun'].forEach((k) => {
145 this.metadata[cdId][k] = disk[k];
149 name: `${disk.pool}/${disk.image}`,
151 cdIcon: cssClasses.disks.leaf
155 const portals: any[] = [];
156 _.forEach(this.selectedItem.portals, (portal) => {
158 name: `${portal.host}:${portal.ip}`,
159 cdIcon: cssClasses.portals.leaf
163 const clients: any[] = [];
164 _.forEach(this.selectedItem.clients, (client) => {
165 const client_metadata = _.cloneDeep(client.auth);
167 _.extend(client_metadata, client.info);
168 delete client_metadata['state'];
169 _.forEach(Object.keys(client.info.state), (state) => {
170 client_metadata[state.toLowerCase()] = client.info.state[state];
173 this.metadata['client_' + client.client_iqn] = client_metadata;
175 const luns: any[] = [];
176 client.luns.forEach((lun: Record<string, any>) => {
178 name: `${lun.pool}/${lun.image}`,
179 cdId: 'disk_' + lun.pool + '_' + lun.image,
180 cdIcon: cssClasses.disks.leaf
186 status = Object.keys(client.info.state).includes('LOGGED_IN') ? 'logged_in' : 'logged_out';
189 name: client.client_iqn,
191 cdId: 'client_' + client.client_iqn,
193 cdIcon: cssClasses.initiators.leaf
197 const groups: any[] = [];
198 _.forEach(this.selectedItem.groups, (group) => {
199 const luns: any[] = [];
200 group.disks.forEach((disk: Record<string, any>) => {
202 name: `${disk.pool}/${disk.image}`,
203 cdId: 'disk_' + disk.pool + '_' + disk.image,
204 cdIcon: cssClasses.disks.leaf
208 const initiators: any[] = [];
209 group.members.forEach((member: string) => {
212 cdId: 'client_' + member
217 name: group.group_id,
218 cdIcon: cssClasses.groups.leaf,
223 cdIcon: cssClasses.disks.expanded
227 children: initiators,
228 cdIcon: cssClasses.initiators.expanded
236 name: this.selectedItem.target_iqn,
239 cdIcon: cssClasses.target.expanded,
245 cdIcon: cssClasses.disks.expanded
251 cdIcon: cssClasses.portals.expanded
257 cdIcon: cssClasses.initiators.expanded
263 cdIcon: cssClasses.groups.expanded
270 private format(value: any) {
271 if (typeof value === 'boolean') {
272 return this.booleanTextPipe.transform(value);
277 onNodeSelected(tree: TreeModel, node: TreeNode) {
278 TREE_ACTIONS.ACTIVATE(tree, node, true);
279 if (node.data.cdId) {
280 this.title = node.data.name;
281 const tempData = this.metadata[node.data.cdId] || {};
283 if (node.data.cdId === 'root') {
284 this.columns[2].isHidden = false;
285 this.data = _.map(this.settings.target_default_controls, (value, key) => {
286 value = this.format(value);
290 current: !_.isUndefined(tempData[key]) ? this.format(tempData[key]) : value
293 // Target level authentication was introduced in ceph-iscsi config v11
294 if (this.cephIscsiConfigVersion > 10) {
295 ['user', 'password', 'mutual_user', 'mutual_password'].forEach((key) => {
299 current: tempData[key]
303 } else if (node.data.cdId.toString().startsWith('disk_')) {
304 this.columns[2].isHidden = false;
305 this.data = _.map(this.settings.disk_default_controls[tempData.backstore], (value, key) => {
306 value = this.format(value);
310 current: !_.isUndefined(tempData.controls[key])
311 ? this.format(tempData.controls[key])
316 displayName: 'backstore',
317 default: this.iscsiBackstorePipe.transform(this.settings.default_backstore),
318 current: this.iscsiBackstorePipe.transform(tempData.backstore)
320 ['wwn', 'lun'].forEach((k) => {
330 this.columns[2].isHidden = true;
331 this.data = _.map(tempData, (value, key) => {
335 current: this.format(value)
340 this.data = undefined;
343 if (this.detailTable) {
344 this.detailTable.updateColumns();
349 this.tree.treeModel.expandAll();