]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | import { |
2 | AfterViewInit, | |
3 | Component, | |
4 | Input, | |
5 | OnChanges, | |
6 | OnDestroy, | |
7 | OnInit, | |
8 | QueryList, | |
9 | TemplateRef, | |
e306af50 | 10 | ViewChild, |
9f95a23c TL |
11 | ViewChildren |
12 | } from '@angular/core'; | |
9f95a23c | 13 | |
f67539c2 | 14 | import _ from 'lodash'; |
9f95a23c | 15 | import { Observable, Subscription } from 'rxjs'; |
20effc67 | 16 | import { take } from 'rxjs/operators'; |
f67539c2 TL |
17 | |
18 | import { CephServiceService } from '~/app/shared/api/ceph-service.service'; | |
20effc67 | 19 | import { DaemonService } from '~/app/shared/api/daemon.service'; |
f67539c2 TL |
20 | import { HostService } from '~/app/shared/api/host.service'; |
21 | import { OrchestratorService } from '~/app/shared/api/orchestrator.service'; | |
20effc67 | 22 | import { ActionLabelsI18n } from '~/app/shared/constants/app.constants'; |
f67539c2 TL |
23 | import { TableComponent } from '~/app/shared/datatable/table/table.component'; |
24 | import { CellTemplate } from '~/app/shared/enum/cell-template.enum'; | |
b3b6e05e | 25 | import { Icons } from '~/app/shared/enum/icons.enum'; |
20effc67 TL |
26 | import { NotificationType } from '~/app/shared/enum/notification-type.enum'; |
27 | import { CdTableAction } from '~/app/shared/models/cd-table-action'; | |
f67539c2 TL |
28 | import { CdTableColumn } from '~/app/shared/models/cd-table-column'; |
29 | import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context'; | |
20effc67 | 30 | import { CdTableSelection } from '~/app/shared/models/cd-table-selection'; |
f67539c2 | 31 | import { Daemon } from '~/app/shared/models/daemon.interface'; |
20effc67 | 32 | import { Permissions } from '~/app/shared/models/permissions'; |
b3b6e05e | 33 | import { CephServiceSpec } from '~/app/shared/models/service.interface'; |
f67539c2 | 34 | import { RelativeDatePipe } from '~/app/shared/pipes/relative-date.pipe'; |
20effc67 TL |
35 | import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; |
36 | import { NotificationService } from '~/app/shared/services/notification.service'; | |
9f95a23c TL |
37 | |
38 | @Component({ | |
39 | selector: 'cd-service-daemon-list', | |
40 | templateUrl: './service-daemon-list.component.html', | |
41 | styleUrls: ['./service-daemon-list.component.scss'] | |
42 | }) | |
43 | export class ServiceDaemonListComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy { | |
e306af50 TL |
44 | @ViewChild('statusTpl', { static: true }) |
45 | statusTpl: TemplateRef<any>; | |
46 | ||
b3b6e05e TL |
47 | @ViewChild('listTpl', { static: true }) |
48 | listTpl: TemplateRef<any>; | |
49 | ||
9f95a23c TL |
50 | @ViewChildren('daemonsTable') |
51 | daemonsTableTpls: QueryList<TemplateRef<TableComponent>>; | |
52 | ||
53 | @Input() | |
54 | serviceName?: string; | |
55 | ||
56 | @Input() | |
57 | hostname?: string; | |
58 | ||
b3b6e05e TL |
59 | @Input() |
60 | flag?: string; | |
61 | ||
62 | icons = Icons; | |
63 | ||
9f95a23c | 64 | daemons: Daemon[] = []; |
b3b6e05e | 65 | services: Array<CephServiceSpec> = []; |
9f95a23c | 66 | columns: CdTableColumn[] = []; |
b3b6e05e | 67 | serviceColumns: CdTableColumn[] = []; |
20effc67 TL |
68 | tableActions: CdTableAction[]; |
69 | selection = new CdTableSelection(); | |
70 | permissions: Permissions; | |
9f95a23c TL |
71 | |
72 | hasOrchestrator = false; | |
adb31ebb | 73 | showDocPanel = false; |
9f95a23c TL |
74 | |
75 | private daemonsTable: TableComponent; | |
76 | private daemonsTableTplsSub: Subscription; | |
b3b6e05e | 77 | private serviceSub: Subscription; |
9f95a23c TL |
78 | |
79 | constructor( | |
9f95a23c TL |
80 | private hostService: HostService, |
81 | private cephServiceService: CephServiceService, | |
f67539c2 | 82 | private orchService: OrchestratorService, |
20effc67 TL |
83 | private relativeDatePipe: RelativeDatePipe, |
84 | public actionLabels: ActionLabelsI18n, | |
85 | private authStorageService: AuthStorageService, | |
86 | private daemonService: DaemonService, | |
87 | private notificationService: NotificationService | |
9f95a23c TL |
88 | ) {} |
89 | ||
90 | ngOnInit() { | |
20effc67 TL |
91 | this.permissions = this.authStorageService.getPermissions(); |
92 | this.tableActions = [ | |
93 | { | |
94 | permission: 'update', | |
95 | icon: Icons.start, | |
96 | click: () => this.daemonAction('start'), | |
97 | name: this.actionLabels.START, | |
98 | disable: () => this.actionDisabled('start') | |
99 | }, | |
100 | { | |
101 | permission: 'update', | |
102 | icon: Icons.stop, | |
103 | click: () => this.daemonAction('stop'), | |
104 | name: this.actionLabels.STOP, | |
105 | disable: () => this.actionDisabled('stop') | |
106 | }, | |
107 | { | |
108 | permission: 'update', | |
109 | icon: Icons.restart, | |
110 | click: () => this.daemonAction('restart'), | |
111 | name: this.actionLabels.RESTART, | |
112 | disable: () => this.actionDisabled('restart') | |
113 | }, | |
114 | { | |
115 | permission: 'update', | |
116 | icon: Icons.deploy, | |
117 | click: () => this.daemonAction('redeploy'), | |
118 | name: this.actionLabels.REDEPLOY, | |
119 | disable: () => this.actionDisabled('redeploy') | |
120 | } | |
121 | ]; | |
9f95a23c TL |
122 | this.columns = [ |
123 | { | |
f67539c2 | 124 | name: $localize`Hostname`, |
9f95a23c | 125 | prop: 'hostname', |
b3b6e05e | 126 | flexGrow: 2, |
9f95a23c TL |
127 | filterable: true |
128 | }, | |
129 | { | |
f67539c2 | 130 | name: $localize`Daemon type`, |
9f95a23c TL |
131 | prop: 'daemon_type', |
132 | flexGrow: 1, | |
133 | filterable: true | |
134 | }, | |
135 | { | |
f67539c2 | 136 | name: $localize`Daemon ID`, |
9f95a23c TL |
137 | prop: 'daemon_id', |
138 | flexGrow: 1, | |
139 | filterable: true | |
140 | }, | |
141 | { | |
f67539c2 | 142 | name: $localize`Container ID`, |
9f95a23c | 143 | prop: 'container_id', |
b3b6e05e | 144 | flexGrow: 2, |
1911f103 TL |
145 | filterable: true, |
146 | cellTransformation: CellTemplate.truncate, | |
147 | customTemplateConfig: { | |
148 | length: 12 | |
149 | } | |
9f95a23c TL |
150 | }, |
151 | { | |
f67539c2 | 152 | name: $localize`Container Image name`, |
9f95a23c TL |
153 | prop: 'container_image_name', |
154 | flexGrow: 3, | |
155 | filterable: true | |
156 | }, | |
157 | { | |
f67539c2 | 158 | name: $localize`Container Image ID`, |
9f95a23c | 159 | prop: 'container_image_id', |
b3b6e05e | 160 | flexGrow: 2, |
1911f103 TL |
161 | filterable: true, |
162 | cellTransformation: CellTemplate.truncate, | |
163 | customTemplateConfig: { | |
164 | length: 12 | |
165 | } | |
9f95a23c TL |
166 | }, |
167 | { | |
f67539c2 | 168 | name: $localize`Version`, |
9f95a23c TL |
169 | prop: 'version', |
170 | flexGrow: 1, | |
171 | filterable: true | |
172 | }, | |
173 | { | |
f67539c2 | 174 | name: $localize`Status`, |
9f95a23c TL |
175 | prop: 'status_desc', |
176 | flexGrow: 1, | |
e306af50 TL |
177 | filterable: true, |
178 | cellTemplate: this.statusTpl | |
9f95a23c TL |
179 | }, |
180 | { | |
f67539c2 | 181 | name: $localize`Last Refreshed`, |
9f95a23c | 182 | prop: 'last_refresh', |
f67539c2 | 183 | pipe: this.relativeDatePipe, |
b3b6e05e TL |
184 | flexGrow: 1 |
185 | }, | |
186 | { | |
187 | name: $localize`Daemon Events`, | |
188 | prop: 'events', | |
189 | flexGrow: 5, | |
190 | cellTemplate: this.listTpl | |
191 | } | |
192 | ]; | |
193 | ||
194 | this.serviceColumns = [ | |
195 | { | |
196 | name: $localize`Service Name`, | |
197 | prop: 'service_name', | |
198 | flexGrow: 2, | |
199 | filterable: true | |
200 | }, | |
201 | { | |
202 | name: $localize`Service Type`, | |
203 | prop: 'service_type', | |
204 | flexGrow: 1, | |
205 | filterable: true | |
206 | }, | |
207 | { | |
208 | name: $localize`Service Events`, | |
209 | prop: 'events', | |
210 | flexGrow: 5, | |
211 | cellTemplate: this.listTpl | |
9f95a23c TL |
212 | } |
213 | ]; | |
214 | ||
215 | this.orchService.status().subscribe((data: { available: boolean }) => { | |
216 | this.hasOrchestrator = data.available; | |
adb31ebb | 217 | this.showDocPanel = !data.available; |
9f95a23c TL |
218 | }); |
219 | } | |
220 | ||
221 | ngOnChanges() { | |
222 | if (!_.isUndefined(this.daemonsTable)) { | |
223 | this.daemonsTable.reloadData(); | |
224 | } | |
225 | } | |
226 | ||
227 | ngAfterViewInit() { | |
228 | this.daemonsTableTplsSub = this.daemonsTableTpls.changes.subscribe( | |
229 | (tableRefs: QueryList<TableComponent>) => { | |
230 | this.daemonsTable = tableRefs.first; | |
231 | } | |
232 | ); | |
233 | } | |
234 | ||
235 | ngOnDestroy() { | |
236 | if (this.daemonsTableTplsSub) { | |
237 | this.daemonsTableTplsSub.unsubscribe(); | |
238 | } | |
b3b6e05e TL |
239 | if (this.serviceSub) { |
240 | this.serviceSub.unsubscribe(); | |
241 | } | |
9f95a23c TL |
242 | } |
243 | ||
f67539c2 | 244 | getStatusClass(row: Daemon): string { |
e306af50 TL |
245 | return _.get( |
246 | { | |
247 | '-1': 'badge-danger', | |
248 | '0': 'badge-warning', | |
249 | '1': 'badge-success' | |
250 | }, | |
f67539c2 | 251 | row.status, |
e306af50 TL |
252 | 'badge-dark' |
253 | ); | |
254 | } | |
255 | ||
9f95a23c TL |
256 | getDaemons(context: CdTableFetchDataContext) { |
257 | let observable: Observable<Daemon[]>; | |
258 | if (this.hostname) { | |
259 | observable = this.hostService.getDaemons(this.hostname); | |
260 | } else if (this.serviceName) { | |
261 | observable = this.cephServiceService.getDaemons(this.serviceName); | |
262 | } else { | |
263 | this.daemons = []; | |
264 | return; | |
265 | } | |
266 | observable.subscribe( | |
267 | (daemons: Daemon[]) => { | |
268 | this.daemons = daemons; | |
20effc67 | 269 | this.sortDaemonEvents(); |
9f95a23c TL |
270 | }, |
271 | () => { | |
272 | this.daemons = []; | |
273 | context.error(); | |
274 | } | |
275 | ); | |
276 | } | |
b3b6e05e | 277 | |
20effc67 TL |
278 | 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(); | |
282 | }); | |
283 | }); | |
284 | } | |
b3b6e05e TL |
285 | getServices(context: CdTableFetchDataContext) { |
286 | this.serviceSub = this.cephServiceService.list(this.serviceName).subscribe( | |
287 | (services: CephServiceSpec[]) => { | |
288 | this.services = services; | |
289 | }, | |
290 | () => { | |
291 | this.services = []; | |
292 | context.error(); | |
293 | } | |
294 | ); | |
295 | } | |
296 | ||
297 | trackByFn(_index: any, item: any) { | |
298 | return item.created; | |
299 | } | |
20effc67 TL |
300 | |
301 | updateSelection(selection: CdTableSelection) { | |
302 | this.selection = selection; | |
303 | } | |
304 | ||
305 | daemonAction(actionType: string) { | |
306 | this.daemonService | |
307 | .action(this.selection.first()?.daemon_name, actionType) | |
308 | .pipe(take(1)) | |
309 | .subscribe({ | |
310 | next: (resp) => { | |
311 | this.notificationService.show( | |
312 | NotificationType.success, | |
313 | `Daemon ${actionType} scheduled`, | |
314 | resp.body.toString() | |
315 | ); | |
316 | }, | |
317 | error: (resp) => { | |
318 | this.notificationService.show( | |
319 | NotificationType.error, | |
320 | 'Daemon action failed', | |
321 | resp.body.toString() | |
322 | ); | |
323 | } | |
324 | }); | |
325 | } | |
326 | ||
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. | |
332 | } | |
333 | switch (actionType) { | |
334 | case 'start': | |
335 | if (daemon.status_desc === 'running') { | |
336 | return true; | |
337 | } | |
338 | break; | |
339 | case 'stop': | |
340 | if (daemon.status_desc === 'stopped') { | |
341 | return true; | |
342 | } | |
343 | break; | |
344 | } | |
345 | return false; | |
346 | } | |
347 | return true; // if no selection then disable everything | |
348 | } | |
9f95a23c | 349 | } |