1 import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
3 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
4 import { I18n } from '@ngx-translate/i18n-polyfill';
5 import * as _ from 'lodash';
6 import { Subscription } from 'rxjs';
8 import { IscsiService } from '../../../shared/api/iscsi.service';
9 import { ListWithDetails } from '../../../shared/classes/list-with-details.class';
10 import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
11 import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
12 import { TableComponent } from '../../../shared/datatable/table/table.component';
13 import { CellTemplate } from '../../../shared/enum/cell-template.enum';
14 import { Icons } from '../../../shared/enum/icons.enum';
15 import { CdTableAction } from '../../../shared/models/cd-table-action';
16 import { CdTableColumn } from '../../../shared/models/cd-table-column';
17 import { CdTableSelection } from '../../../shared/models/cd-table-selection';
18 import { FinishedTask } from '../../../shared/models/finished-task';
19 import { Permission } from '../../../shared/models/permissions';
20 import { Task } from '../../../shared/models/task';
21 import { CephReleaseNamePipe } from '../../../shared/pipes/ceph-release-name.pipe';
22 import { NotAvailablePipe } from '../../../shared/pipes/not-available.pipe';
23 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
24 import { ModalService } from '../../../shared/services/modal.service';
25 import { SummaryService } from '../../../shared/services/summary.service';
26 import { TaskListService } from '../../../shared/services/task-list.service';
27 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
28 import { IscsiTargetDiscoveryModalComponent } from '../iscsi-target-discovery-modal/iscsi-target-discovery-modal.component';
31 selector: 'cd-iscsi-target-list',
32 templateUrl: './iscsi-target-list.component.html',
33 styleUrls: ['./iscsi-target-list.component.scss'],
34 providers: [TaskListService]
36 export class IscsiTargetListComponent extends ListWithDetails implements OnInit, OnDestroy {
37 @ViewChild(TableComponent)
38 table: TableComponent;
40 available: boolean = undefined;
41 columns: CdTableColumn[];
43 modalRef: NgbModalRef;
44 permission: Permission;
45 selection = new CdTableSelection();
46 cephIscsiConfigVersion: number;
49 summaryDataSubscription: Subscription;
50 tableActions: CdTableAction[];
55 'iscsi/target/create': (metadata: object) => {
57 target_iqn: metadata['target_iqn']
63 private authStorageService: AuthStorageService,
65 private iscsiService: IscsiService,
66 private taskListService: TaskListService,
67 private cephReleaseNamePipe: CephReleaseNamePipe,
68 private notAvailablePipe: NotAvailablePipe,
69 private summaryservice: SummaryService,
70 private modalService: ModalService,
71 private taskWrapper: TaskWrapperService,
72 public actionLabels: ActionLabelsI18n
75 this.permission = this.authStorageService.getPermissions().iscsi;
81 routerLink: () => '/block/iscsi/targets/create',
82 name: this.actionLabels.CREATE
87 routerLink: () => `/block/iscsi/targets/edit/${this.selection.first().target_iqn}`,
88 name: this.actionLabels.EDIT,
89 disable: () => !this.selection.first() || !_.isUndefined(this.getDeleteDisableDesc()),
90 disableDesc: () => this.getEditDisableDesc()
95 click: () => this.deleteIscsiTargetModal(),
96 name: this.actionLabels.DELETE,
97 disable: () => !this.selection.first() || !_.isUndefined(this.getDeleteDisableDesc()),
98 disableDesc: () => this.getDeleteDisableDesc()
106 name: this.i18n('Target'),
109 cellTransformation: CellTemplate.executing
112 name: this.i18n('Portals'),
117 name: this.i18n('Images'),
122 name: this.i18n('# Sessions'),
123 prop: 'info.num_sessions',
124 pipe: this.notAvailablePipe,
129 this.iscsiService.status().subscribe((result: any) => {
130 this.available = result.available;
132 if (result.available) {
133 this.iscsiService.version().subscribe((res: any) => {
134 this.cephIscsiConfigVersion = res['ceph_iscsi_config_version'];
135 this.taskListService.init(
136 () => this.iscsiService.listTargets(),
137 (resp) => this.prepareResponse(resp),
138 (targets) => (this.targets = targets),
139 () => this.onFetchError(),
146 this.iscsiService.settings().subscribe((settings: any) => {
147 this.settings = settings;
150 this.summaryservice.subscribeOnce((summary) => {
151 const releaseName = this.cephReleaseNamePipe.transform(summary.version);
152 this.docsUrl = `http://docs.ceph.com/docs/${releaseName}/mgr/dashboard/#enabling-iscsi-management`;
153 this.status = result.message;
160 if (this.summaryDataSubscription) {
161 this.summaryDataSubscription.unsubscribe();
165 getEditDisableDesc(): string | undefined {
166 const first = this.selection.first();
167 if (first && first.cdExecuting) {
168 return first.cdExecuting;
170 if (first && _.isUndefined(first['info'])) {
171 return this.i18n('Unavailable gateway(s)');
177 getDeleteDisableDesc(): string | undefined {
178 const first = this.selection.first();
179 if (first && first.cdExecuting) {
180 return first.cdExecuting;
182 if (first && _.isUndefined(first['info'])) {
183 return this.i18n('Unavailable gateway(s)');
185 if (first && first['info'] && first['info']['num_sessions']) {
186 return this.i18n('Target has active sessions');
192 prepareResponse(resp: any): any[] {
193 resp.forEach((element: Record<string, any>) => {
194 element.cdPortals = element.portals.map(
195 (portal: Record<string, any>) => `${portal.host}:${portal.ip}`
197 element.cdImages = element.disks.map(
198 (disk: Record<string, any>) => `${disk.pool}/${disk.image}`
206 this.table.reset(); // Disable loading indicator.
209 itemFilter(entry: Record<string, any>, task: Task) {
210 return entry.target_iqn === task.metadata['target_iqn'];
213 taskFilter(task: Task) {
214 return ['iscsi/target/create', 'iscsi/target/edit', 'iscsi/target/delete'].includes(task.name);
217 updateSelection(selection: CdTableSelection) {
218 this.selection = selection;
221 deleteIscsiTargetModal() {
222 const target_iqn = this.selection.first().target_iqn;
224 this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
225 itemDescription: this.i18n('iSCSI target'),
226 itemNames: [target_iqn],
227 submitActionObservable: () =>
228 this.taskWrapper.wrapTaskAroundCall({
229 task: new FinishedTask('iscsi/target/delete', {
230 target_iqn: target_iqn
232 call: this.iscsiService.deleteTarget(target_iqn)
237 configureDiscoveryAuth() {
238 this.modalService.show(IscsiTargetDiscoveryModalComponent);