1 import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core';
9 } from '@circlon/angular-tree-component';
10 import _ from 'lodash';
12 import { TableComponent } from '~/app/shared/datatable/table/table.component';
13 import { Icons } from '~/app/shared/enum/icons.enum';
14 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
15 import { BooleanTextPipe } from '~/app/shared/pipes/boolean-text.pipe';
16 import { IscsiBackstorePipe } from '~/app/shared/pipes/iscsi-backstore.pipe';
19 selector: 'cd-iscsi-target-details',
20 templateUrl: './iscsi-target-details.component.html',
21 styleUrls: ['./iscsi-target-details.component.scss']
23 export class IscsiTargetDetailsComponent implements OnChanges, OnInit {
29 cephIscsiConfigVersion: number;
31 @ViewChild('highlightTpl', { static: true })
32 highlightTpl: TemplateRef<any>;
34 private detailTable: TableComponent;
35 @ViewChild('detailTable')
36 set content(content: TableComponent) {
37 this.detailTable = content;
39 content.updateColumns();
43 @ViewChild('tree') tree: TreeComponent;
46 columns: CdTableColumn[];
53 treeOptions: ITreeOptions = {
54 useVirtualScroll: true,
57 click: this.onNodeSelected.bind(this)
63 private iscsiBackstorePipe: IscsiBackstorePipe,
64 private booleanTextPipe: BooleanTextPipe
71 name: $localize`Name`,
73 cellTemplate: this.highlightTpl
77 name: $localize`Current`,
79 cellTemplate: this.highlightTpl
83 name: $localize`Default`,
85 cellTemplate: this.highlightTpl
92 this.selectedItem = this.selection;
96 this.data = undefined;
99 private generateTree() {
100 const target_meta = _.cloneDeep(this.selectedItem.target_controls);
101 // Target level authentication was introduced in ceph-iscsi config v11
102 if (this.cephIscsiConfigVersion > 10) {
103 _.extend(target_meta, _.cloneDeep(this.selectedItem.auth));
105 this.metadata = { root: target_meta };
109 this.selectedItem.cdExecuting
110 ? [Icons.large, Icons.spinner, Icons.spin]
111 : [Icons.large, Icons.bullseye],
116 expanded: _.join([Icons.large, Icons.user], ' '),
117 leaf: _.join([Icons.user], ' ')
120 expanded: _.join([Icons.large, Icons.users], ' '),
121 leaf: _.join([Icons.users], ' ')
124 expanded: _.join([Icons.large, Icons.disk], ' '),
125 leaf: _.join([Icons.disk], ' ')
128 expanded: _.join([Icons.large, Icons.server], ' '),
129 leaf: _.join([Icons.server], ' ')
133 const disks: any[] = [];
134 _.forEach(this.selectedItem.disks, (disk) => {
135 const cdId = 'disk_' + disk.pool + '_' + disk.image;
136 this.metadata[cdId] = {
137 controls: disk.controls,
138 backstore: disk.backstore
140 ['wwn', 'lun'].forEach((k) => {
142 this.metadata[cdId][k] = disk[k];
146 name: `${disk.pool}/${disk.image}`,
148 cdIcon: cssClasses.disks.leaf
152 const portals: any[] = [];
153 _.forEach(this.selectedItem.portals, (portal) => {
155 name: `${portal.host}:${portal.ip}`,
156 cdIcon: cssClasses.portals.leaf
160 const clients: any[] = [];
161 _.forEach(this.selectedItem.clients, (client) => {
162 const client_metadata = _.cloneDeep(client.auth);
164 _.extend(client_metadata, client.info);
165 delete client_metadata['state'];
166 _.forEach(Object.keys(client.info.state), (state) => {
167 client_metadata[state.toLowerCase()] = client.info.state[state];
170 this.metadata['client_' + client.client_iqn] = client_metadata;
172 const luns: any[] = [];
173 client.luns.forEach((lun: Record<string, any>) => {
175 name: `${lun.pool}/${lun.image}`,
176 cdId: 'disk_' + lun.pool + '_' + lun.image,
177 cdIcon: cssClasses.disks.leaf
183 status = Object.keys(client.info.state).includes('LOGGED_IN') ? 'logged_in' : 'logged_out';
186 name: client.client_iqn,
188 cdId: 'client_' + client.client_iqn,
190 cdIcon: cssClasses.initiators.leaf
194 const groups: any[] = [];
195 _.forEach(this.selectedItem.groups, (group) => {
196 const luns: any[] = [];
197 group.disks.forEach((disk: Record<string, any>) => {
199 name: `${disk.pool}/${disk.image}`,
200 cdId: 'disk_' + disk.pool + '_' + disk.image,
201 cdIcon: cssClasses.disks.leaf
205 const initiators: any[] = [];
206 group.members.forEach((member: string) => {
209 cdId: 'client_' + member
214 name: group.group_id,
215 cdIcon: cssClasses.groups.leaf,
220 cdIcon: cssClasses.disks.expanded
224 children: initiators,
225 cdIcon: cssClasses.initiators.expanded
233 name: this.selectedItem.target_iqn,
236 cdIcon: cssClasses.target.expanded,
242 cdIcon: cssClasses.disks.expanded
248 cdIcon: cssClasses.portals.expanded
254 cdIcon: cssClasses.initiators.expanded
260 cdIcon: cssClasses.groups.expanded
267 private format(value: any) {
268 if (typeof value === 'boolean') {
269 return this.booleanTextPipe.transform(value);
274 onNodeSelected(tree: TreeModel, node: TreeNode) {
275 TREE_ACTIONS.ACTIVATE(tree, node, true);
276 if (node.data.cdId) {
277 this.title = node.data.name;
278 const tempData = this.metadata[node.data.cdId] || {};
280 if (node.data.cdId === 'root') {
281 this.detailTable?.toggleColumn({ prop: 'default', isHidden: true });
282 this.data = _.map(this.settings.target_default_controls, (value, key) => {
283 value = this.format(value);
287 current: !_.isUndefined(tempData[key]) ? this.format(tempData[key]) : value
290 // Target level authentication was introduced in ceph-iscsi config v11
291 if (this.cephIscsiConfigVersion > 10) {
292 ['user', 'password', 'mutual_user', 'mutual_password'].forEach((key) => {
296 current: tempData[key]
300 } else if (node.data.cdId.toString().startsWith('disk_')) {
301 this.detailTable?.toggleColumn({ prop: 'default', isHidden: true });
302 this.data = _.map(this.settings.disk_default_controls[tempData.backstore], (value, key) => {
303 value = this.format(value);
307 current: !_.isUndefined(tempData.controls[key])
308 ? this.format(tempData.controls[key])
313 displayName: 'backstore',
314 default: this.iscsiBackstorePipe.transform(this.settings.default_backstore),
315 current: this.iscsiBackstorePipe.transform(tempData.backstore)
317 ['wwn', 'lun'].forEach((k) => {
327 this.detailTable?.toggleColumn({ prop: 'default', isHidden: false });
328 this.data = _.map(tempData, (value, key) => {
332 current: this.format(value)
337 this.data = undefined;
340 this.detailTable?.updateColumns();
344 this.tree.treeModel.expandAll();