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>>;
64 daemons: Daemon[] = [];
65 services: Array<CephServiceSpec> = [];
66 columns: CdTableColumn[] = [];
67 serviceColumns: CdTableColumn[] = [];
68 tableActions: CdTableAction[];
69 selection = new CdTableSelection();
70 permissions: Permissions;
72 hasOrchestrator = false;
75 private daemonsTable: TableComponent;
76 private daemonsTableTplsSub: Subscription;
77 private serviceSub: Subscription;
80 private hostService: HostService,
81 private cephServiceService: CephServiceService,
82 private orchService: OrchestratorService,
83 private relativeDatePipe: RelativeDatePipe,
84 public actionLabels: ActionLabelsI18n,
85 private authStorageService: AuthStorageService,
86 private daemonService: DaemonService,
87 private notificationService: NotificationService
91 this.permissions = this.authStorageService.getPermissions();
96 click: () => this.daemonAction('start'),
97 name: this.actionLabels.START,
98 disable: () => this.actionDisabled('start')
101 permission: 'update',
103 click: () => this.daemonAction('stop'),
104 name: this.actionLabels.STOP,
105 disable: () => this.actionDisabled('stop')
108 permission: 'update',
110 click: () => this.daemonAction('restart'),
111 name: this.actionLabels.RESTART,
112 disable: () => this.actionDisabled('restart')
115 permission: 'update',
117 click: () => this.daemonAction('redeploy'),
118 name: this.actionLabels.REDEPLOY,
119 disable: () => this.actionDisabled('redeploy')
124 name: $localize`Hostname`,
130 name: $localize`Daemon type`,
136 name: $localize`Daemon ID`,
142 name: $localize`Container ID`,
143 prop: 'container_id',
146 cellTransformation: CellTemplate.truncate,
147 customTemplateConfig: {
152 name: $localize`Container Image name`,
153 prop: 'container_image_name',
158 name: $localize`Container Image ID`,
159 prop: 'container_image_id',
162 cellTransformation: CellTemplate.truncate,
163 customTemplateConfig: {
168 name: $localize`Version`,
174 name: $localize`Status`,
178 cellTemplate: this.statusTpl
181 name: $localize`Last Refreshed`,
182 prop: 'last_refresh',
183 pipe: this.relativeDatePipe,
187 name: $localize`Daemon Events`,
190 cellTemplate: this.listTpl
194 this.serviceColumns = [
196 name: $localize`Service Name`,
197 prop: 'service_name',
202 name: $localize`Service Type`,
203 prop: 'service_type',
208 name: $localize`Service Events`,
211 cellTemplate: this.listTpl
215 this.orchService.status().subscribe((data: { available: boolean }) => {
216 this.hasOrchestrator = data.available;
217 this.showDocPanel = !data.available;
222 if (!_.isUndefined(this.daemonsTable)) {
223 this.daemonsTable.reloadData();
228 this.daemonsTableTplsSub = this.daemonsTableTpls.changes.subscribe(
229 (tableRefs: QueryList<TableComponent>) => {
230 this.daemonsTable = tableRefs.first;
236 if (this.daemonsTableTplsSub) {
237 this.daemonsTableTplsSub.unsubscribe();
239 if (this.serviceSub) {
240 this.serviceSub.unsubscribe();
244 getStatusClass(row: Daemon): string {
247 '-1': 'badge-danger',
248 '0': 'badge-warning',
256 getDaemons(context: CdTableFetchDataContext) {
257 let observable: Observable<Daemon[]>;
259 observable = this.hostService.getDaemons(this.hostname);
260 } else if (this.serviceName) {
261 observable = this.cephServiceService.getDaemons(this.serviceName);
266 observable.subscribe(
267 (daemons: Daemon[]) => {
268 this.daemons = daemons;
269 this.sortDaemonEvents();
279 this.daemons.forEach((daemon: any) => {
280 daemon.events?.sort((event1: any, event2: any) => {
281 return new Date(event2.created).getTime() - new Date(event1.created).getTime();
285 getServices(context: CdTableFetchDataContext) {
286 this.serviceSub = this.cephServiceService.list(this.serviceName).subscribe(
287 (services: CephServiceSpec[]) => {
288 this.services = services;
297 trackByFn(_index: any, item: any) {
301 updateSelection(selection: CdTableSelection) {
302 this.selection = selection;
305 daemonAction(actionType: string) {
307 .action(this.selection.first()?.daemon_name, actionType)
311 this.notificationService.show(
312 NotificationType.success,
313 `Daemon ${actionType} scheduled`,
318 this.notificationService.show(
319 NotificationType.error,
320 'Daemon action failed',
327 actionDisabled(actionType: string) {
328 if (this.selection?.hasSelection) {
329 const daemon = this.selection.selected[0];
330 if (daemon.daemon_type === 'mon' || daemon.daemon_type === 'mgr') {
331 return true; // don't allow actions on mon and mgr, dashboard requires them.
333 switch (actionType) {
335 if (daemon.status_desc === 'running') {
340 if (daemon.status_desc === 'stopped') {
347 return true; // if no selection then disable everything