1 import { Component, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
3 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
4 import _ from 'lodash';
5 import { Subscription } from 'rxjs';
7 import { IscsiService } from '~/app/shared/api/iscsi.service';
8 import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
9 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
10 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
11 import { TableComponent } from '~/app/shared/datatable/table/table.component';
12 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
13 import { Icons } from '~/app/shared/enum/icons.enum';
14 import { CdTableAction } from '~/app/shared/models/cd-table-action';
15 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
16 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
17 import { FinishedTask } from '~/app/shared/models/finished-task';
18 import { Permission } from '~/app/shared/models/permissions';
19 import { Task } from '~/app/shared/models/task';
20 import { JoinPipe } from '~/app/shared/pipes/join.pipe';
21 import { NotAvailablePipe } from '~/app/shared/pipes/not-available.pipe';
22 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
23 import { ModalService } from '~/app/shared/services/modal.service';
24 import { TaskListService } from '~/app/shared/services/task-list.service';
25 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
26 import { IscsiTargetDiscoveryModalComponent } from '../iscsi-target-discovery-modal/iscsi-target-discovery-modal.component';
29 selector: 'cd-iscsi-target-list',
30 templateUrl: './iscsi-target-list.component.html',
31 styleUrls: ['./iscsi-target-list.component.scss'],
32 providers: [TaskListService]
34 export class IscsiTargetListComponent extends ListWithDetails implements OnInit, OnDestroy {
35 @ViewChild(TableComponent)
36 table: TableComponent;
38 available: boolean = undefined;
39 columns: CdTableColumn[];
40 modalRef: NgbModalRef;
41 permission: Permission;
42 selection = new CdTableSelection();
43 cephIscsiConfigVersion: number;
46 summaryDataSubscription: Subscription;
47 tableActions: CdTableAction[];
52 'iscsi/target/create': (metadata: object) => {
54 target_iqn: metadata['target_iqn']
60 private authStorageService: AuthStorageService,
61 private iscsiService: IscsiService,
62 private joinPipe: JoinPipe,
63 private taskListService: TaskListService,
64 private notAvailablePipe: NotAvailablePipe,
65 private modalService: ModalService,
66 private taskWrapper: TaskWrapperService,
67 public actionLabels: ActionLabelsI18n,
68 protected ngZone: NgZone
71 this.permission = this.authStorageService.getPermissions().iscsi;
77 routerLink: () => '/block/iscsi/targets/create',
78 name: this.actionLabels.CREATE
83 routerLink: () => `/block/iscsi/targets/edit/${this.selection.first().target_iqn}`,
84 name: this.actionLabels.EDIT,
85 disable: () => this.getEditDisableDesc()
90 click: () => this.deleteIscsiTargetModal(),
91 name: this.actionLabels.DELETE,
92 disable: () => this.getDeleteDisableDesc()
100 name: $localize`Target`,
103 cellTransformation: CellTemplate.executing
106 name: $localize`Portals`,
112 name: $localize`Images`,
118 name: $localize`# Sessions`,
119 prop: 'info.num_sessions',
120 pipe: this.notAvailablePipe,
125 this.iscsiService.status().subscribe((result: any) => {
126 this.available = result.available;
128 if (!result.available) {
129 this.status = result.message;
135 if (this.available) {
136 this.setTableRefreshTimeout();
137 this.iscsiService.version().subscribe((res: any) => {
138 this.cephIscsiConfigVersion = res['ceph_iscsi_config_version'];
140 this.taskListService.init(
141 () => this.iscsiService.listTargets(),
142 (resp) => this.prepareResponse(resp),
143 (targets) => (this.targets = targets),
144 () => this.onFetchError(),
150 this.iscsiService.settings().subscribe((settings: any) => {
151 this.settings = settings;
157 if (this.summaryDataSubscription) {
158 this.summaryDataSubscription.unsubscribe();
162 getEditDisableDesc(): string | boolean {
163 const first = this.selection.first();
165 if (first && first?.cdExecuting) {
166 return first.cdExecuting;
169 if (first && _.isUndefined(first?.['info'])) {
170 return $localize`Unavailable gateway(s)`;
176 getDeleteDisableDesc(): string | boolean {
177 const first = this.selection.first();
179 if (first?.cdExecuting) {
180 return first.cdExecuting;
183 if (first && _.isUndefined(first?.['info'])) {
184 return $localize`Unavailable gateway(s)`;
187 if (first && first?.['info']?.['num_sessions']) {
188 return $localize`Target has active sessions`;
194 prepareResponse(resp: any): any[] {
195 resp.forEach((element: Record<string, any>) => {
196 element.cdPortals = element.portals.map(
197 (portal: Record<string, any>) => `${portal.host}:${portal.ip}`
199 element.cdImages = element.disks.map(
200 (disk: Record<string, any>) => `${disk.pool}/${disk.image}`
208 this.table.reset(); // Disable loading indicator.
211 itemFilter(entry: Record<string, any>, task: Task) {
212 return entry.target_iqn === task.metadata['target_iqn'];
215 taskFilter(task: Task) {
216 return ['iscsi/target/create', 'iscsi/target/edit', 'iscsi/target/delete'].includes(task.name);
219 updateSelection(selection: CdTableSelection) {
220 this.selection = selection;
223 deleteIscsiTargetModal() {
224 const target_iqn = this.selection.first().target_iqn;
226 this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
227 itemDescription: $localize`iSCSI target`,
228 itemNames: [target_iqn],
229 submitActionObservable: () =>
230 this.taskWrapper.wrapTaskAroundCall({
231 task: new FinishedTask('iscsi/target/delete', {
232 target_iqn: target_iqn
234 call: this.iscsiService.deleteTarget(target_iqn)
239 configureDiscoveryAuth() {
240 this.modalService.show(IscsiTargetDiscoveryModalComponent);