12 } from '@angular/core';
14 import _ from 'lodash';
15 import { Observable, Subscription } from 'rxjs';
16 import { take } from 'rxjs/operators';
18 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
19 import { DaemonService } from '~/app/shared/api/daemon.service';
20 import { HostService } from '~/app/shared/api/host.service';
21 import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
22 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
23 import { TableComponent } from '~/app/shared/datatable/table/table.component';
24 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
25 import { Icons } from '~/app/shared/enum/icons.enum';
26 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
27 import { CdTableAction } from '~/app/shared/models/cd-table-action';
28 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
29 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
30 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
31 import { Daemon } from '~/app/shared/models/daemon.interface';
32 import { Permissions } from '~/app/shared/models/permissions';
33 import { CephServiceSpec } from '~/app/shared/models/service.interface';
34 import { RelativeDatePipe } from '~/app/shared/pipes/relative-date.pipe';
35 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
36 import { NotificationService } from '~/app/shared/services/notification.service';
39 selector: 'cd-service-daemon-list',
40 templateUrl: './service-daemon-list.component.html',
41 styleUrls: ['./service-daemon-list.component.scss']
43 export class ServiceDaemonListComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
44 @ViewChild('statusTpl', { static: true })
45 statusTpl: TemplateRef<any>;
47 @ViewChild('listTpl', { static: true })
48 listTpl: TemplateRef<any>;
50 @ViewChildren('daemonsTable')
51 daemonsTableTpls: QueryList<TemplateRef<TableComponent>>;
60 hiddenColumns: string[] = [];
67 daemons: Daemon[] = [];
68 services: Array<CephServiceSpec> = [];
69 columns: CdTableColumn[] = [];
70 serviceColumns: CdTableColumn[] = [];
71 tableActions: CdTableAction[];
72 selection = new CdTableSelection();
73 permissions: Permissions;
75 hasOrchestrator = false;
78 private daemonsTable: TableComponent;
79 private daemonsTableTplsSub: Subscription;
80 private serviceSub: Subscription;
83 private hostService: HostService,
84 private cephServiceService: CephServiceService,
85 private orchService: OrchestratorService,
86 private relativeDatePipe: RelativeDatePipe,
87 public actionLabels: ActionLabelsI18n,
88 private authStorageService: AuthStorageService,
89 private daemonService: DaemonService,
90 private notificationService: NotificationService
94 this.permissions = this.authStorageService.getPermissions();
99 click: () => this.daemonAction('start'),
100 name: this.actionLabels.START,
101 disable: () => this.actionDisabled('start')
104 permission: 'update',
106 click: () => this.daemonAction('stop'),
107 name: this.actionLabels.STOP,
108 disable: () => this.actionDisabled('stop')
111 permission: 'update',
113 click: () => this.daemonAction('restart'),
114 name: this.actionLabels.RESTART,
115 disable: () => this.actionDisabled('restart')
118 permission: 'update',
120 click: () => this.daemonAction('redeploy'),
121 name: this.actionLabels.REDEPLOY,
122 disable: () => this.actionDisabled('redeploy')
127 name: $localize`Hostname`,
133 name: $localize`Daemon type`,
139 name: $localize`Daemon ID`,
145 name: $localize`Container ID`,
146 prop: 'container_id',
149 cellTransformation: CellTemplate.truncate,
150 customTemplateConfig: {
155 name: $localize`Container Image name`,
156 prop: 'container_image_name',
161 name: $localize`Container Image ID`,
162 prop: 'container_image_id',
165 cellTransformation: CellTemplate.truncate,
166 customTemplateConfig: {
171 name: $localize`Version`,
177 name: $localize`Status`,
181 cellTemplate: this.statusTpl
184 name: $localize`Last Refreshed`,
185 prop: 'last_refresh',
186 pipe: this.relativeDatePipe,
190 name: $localize`Daemon Events`,
193 cellTemplate: this.listTpl
197 this.serviceColumns = [
199 name: $localize`Service Name`,
200 prop: 'service_name',
205 name: $localize`Service Type`,
206 prop: 'service_type',
211 name: $localize`Service Events`,
214 cellTemplate: this.listTpl
218 this.orchService.status().subscribe((data: { available: boolean }) => {
219 this.hasOrchestrator = data.available;
220 this.showDocPanel = !data.available;
223 this.columns = this.columns.filter((col: any) => {
224 return !this.hiddenColumns.includes(col.prop);
229 if (!_.isUndefined(this.daemonsTable)) {
230 this.daemonsTable.reloadData();
235 this.daemonsTableTplsSub = this.daemonsTableTpls.changes.subscribe(
236 (tableRefs: QueryList<TableComponent>) => {
237 this.daemonsTable = tableRefs.first;
243 if (this.daemonsTableTplsSub) {
244 this.daemonsTableTplsSub.unsubscribe();
246 if (this.serviceSub) {
247 this.serviceSub.unsubscribe();
251 getStatusClass(row: Daemon): string {
254 '-1': 'badge-danger',
255 '0': 'badge-warning',
263 getDaemons(context: CdTableFetchDataContext) {
264 let observable: Observable<Daemon[]>;
266 observable = this.hostService.getDaemons(this.hostname);
267 } else if (this.serviceName) {
268 observable = this.cephServiceService.getDaemons(this.serviceName);
273 observable.subscribe(
274 (daemons: Daemon[]) => {
275 this.daemons = daemons;
276 this.sortDaemonEvents();
286 this.daemons.forEach((daemon: any) => {
287 daemon.events?.sort((event1: any, event2: any) => {
288 return new Date(event2.created).getTime() - new Date(event1.created).getTime();
292 getServices(context: CdTableFetchDataContext) {
293 this.serviceSub = this.cephServiceService.list(this.serviceName).subscribe(
294 (services: CephServiceSpec[]) => {
295 this.services = services;
304 trackByFn(_index: any, item: any) {
308 updateSelection(selection: CdTableSelection) {
309 this.selection = selection;
312 daemonAction(actionType: string) {
314 .action(this.selection.first()?.daemon_name, actionType)
318 this.notificationService.show(
319 NotificationType.success,
320 `Daemon ${actionType} scheduled`,
325 this.notificationService.show(
326 NotificationType.error,
327 'Daemon action failed',
334 actionDisabled(actionType: string) {
335 if (this.selection?.hasSelection) {
336 const daemon = this.selection.selected[0];
337 if (daemon.daemon_type === 'mon' || daemon.daemon_type === 'mgr') {
338 return true; // don't allow actions on mon and mgr, dashboard requires them.
340 switch (actionType) {
342 if (daemon.status_desc === 'running') {
347 if (daemon.status_desc === 'stopped') {
354 return true; // if no selection then disable everything