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 { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
35 import { RelativeDatePipe } from '~/app/shared/pipes/relative-date.pipe';
36 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
37 import { NotificationService } from '~/app/shared/services/notification.service';
40 selector: 'cd-service-daemon-list',
41 templateUrl: './service-daemon-list.component.html',
42 styleUrls: ['./service-daemon-list.component.scss']
44 export class ServiceDaemonListComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
45 @ViewChild('statusTpl', { static: true })
46 statusTpl: TemplateRef<any>;
48 @ViewChild('listTpl', { static: true })
49 listTpl: TemplateRef<any>;
51 @ViewChildren('daemonsTable')
52 daemonsTableTpls: QueryList<TemplateRef<TableComponent>>;
65 daemons: Daemon[] = [];
66 services: Array<CephServiceSpec> = [];
67 columns: CdTableColumn[] = [];
68 serviceColumns: CdTableColumn[] = [];
69 tableActions: CdTableAction[];
70 selection = new CdTableSelection();
71 permissions: Permissions;
73 hasOrchestrator = false;
76 private daemonsTable: TableComponent;
77 private daemonsTableTplsSub: Subscription;
78 private serviceSub: Subscription;
81 private hostService: HostService,
82 private cephServiceService: CephServiceService,
83 private orchService: OrchestratorService,
84 private relativeDatePipe: RelativeDatePipe,
85 private dimlessBinaryPipe: DimlessBinaryPipe,
86 public actionLabels: ActionLabelsI18n,
87 private authStorageService: AuthStorageService,
88 private daemonService: DaemonService,
89 private notificationService: NotificationService
93 this.permissions = this.authStorageService.getPermissions();
98 click: () => this.daemonAction('start'),
99 name: this.actionLabels.START,
100 disable: () => this.actionDisabled('start')
103 permission: 'update',
105 click: () => this.daemonAction('stop'),
106 name: this.actionLabels.STOP,
107 disable: () => this.actionDisabled('stop')
110 permission: 'update',
112 click: () => this.daemonAction('restart'),
113 name: this.actionLabels.RESTART,
114 disable: () => this.actionDisabled('restart')
117 permission: 'update',
119 click: () => this.daemonAction('redeploy'),
120 name: this.actionLabels.REDEPLOY,
121 disable: () => this.actionDisabled('redeploy')
126 name: $localize`Hostname`,
132 name: $localize`Daemon type`,
138 name: $localize`Daemon ID`,
144 name: $localize`Container ID`,
145 prop: 'container_id',
148 cellTransformation: CellTemplate.truncate,
149 customTemplateConfig: {
154 name: $localize`Container Image name`,
155 prop: 'container_image_name',
160 name: $localize`Container Image ID`,
161 prop: 'container_image_id',
164 cellTransformation: CellTemplate.truncate,
165 customTemplateConfig: {
170 name: $localize`Version`,
176 name: $localize`Status`,
180 cellTemplate: this.statusTpl
183 name: $localize`Last Refreshed`,
184 prop: 'last_refresh',
185 pipe: this.relativeDatePipe,
189 name: $localize`Daemon Events`,
192 cellTemplate: this.listTpl
195 name: $localize`Memory Usage`,
196 prop: 'memory_usage',
198 pipe: this.dimlessBinaryPipe
201 name: $localize`CPU %`,
202 prop: 'cpu_percentage',
207 this.serviceColumns = [
209 name: $localize`Service Name`,
210 prop: 'service_name',
215 name: $localize`Service Type`,
216 prop: 'service_type',
221 name: $localize`Service Events`,
224 cellTemplate: this.listTpl
228 this.orchService.status().subscribe((data: { available: boolean }) => {
229 this.hasOrchestrator = data.available;
230 this.showDocPanel = !data.available;
235 if (!_.isUndefined(this.daemonsTable)) {
236 this.daemonsTable.reloadData();
241 this.daemonsTableTplsSub = this.daemonsTableTpls.changes.subscribe(
242 (tableRefs: QueryList<TableComponent>) => {
243 this.daemonsTable = tableRefs.first;
249 if (this.daemonsTableTplsSub) {
250 this.daemonsTableTplsSub.unsubscribe();
252 if (this.serviceSub) {
253 this.serviceSub.unsubscribe();
257 getStatusClass(row: Daemon): string {
260 '-1': 'badge-danger',
261 '0': 'badge-warning',
269 getDaemons(context: CdTableFetchDataContext) {
270 let observable: Observable<Daemon[]>;
272 observable = this.hostService.getDaemons(this.hostname);
273 } else if (this.serviceName) {
274 observable = this.cephServiceService.getDaemons(this.serviceName);
279 observable.subscribe(
280 (daemons: Daemon[]) => {
281 this.daemons = daemons;
282 this.sortDaemonEvents();
292 this.daemons.forEach((daemon: any) => {
293 daemon.events?.sort((event1: any, event2: any) => {
294 return new Date(event2.created).getTime() - new Date(event1.created).getTime();
298 getServices(context: CdTableFetchDataContext) {
299 this.serviceSub = this.cephServiceService.list(this.serviceName).subscribe(
300 (services: CephServiceSpec[]) => {
301 this.services = services;
310 trackByFn(_index: any, item: any) {
314 updateSelection(selection: CdTableSelection) {
315 this.selection = selection;
318 daemonAction(actionType: string) {
320 .action(this.selection.first()?.daemon_name, actionType)
324 this.notificationService.show(
325 NotificationType.success,
326 `Daemon ${actionType} scheduled`,
331 this.notificationService.show(
332 NotificationType.error,
333 'Daemon action failed',
340 actionDisabled(actionType: string) {
341 if (this.selection?.hasSelection) {
342 const daemon = this.selection.selected[0];
343 if (daemon.daemon_type === 'mon' || daemon.daemon_type === 'mgr') {
344 return true; // don't allow actions on mon and mgr, dashboard requires them.
346 switch (actionType) {
348 if (daemon.status_desc === 'running') {
353 if (daemon.status_desc === 'stopped') {
360 return true; // if no selection then disable everything