]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
29af2bd2ae891c33865fb9750cb12c302a5b0f27
[ceph.git] /
1 import { Component, Inject } from '@angular/core';
2
3 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
4 import { SortDirection, SortPropDir } from '@swimlane/ngx-datatable';
5 import { Observable, Subscriber } from 'rxjs';
6
7 import { PrometheusListHelper } from '~/app/ceph/cluster/prometheus/prometheus-list-helper';
8 import { SilenceFormComponent } from '~/app/ceph/cluster/prometheus/silence-form/silence-form.component';
9 import { PrometheusService } from '~/app/shared/api/prometheus.service';
10 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
11 import { ActionLabelsI18n, SucceededActionLabelsI18n } from '~/app/shared/constants/app.constants';
12 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
13 import { Icons } from '~/app/shared/enum/icons.enum';
14 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
15 import { AlertmanagerSilence } from '~/app/shared/models/alertmanager-silence';
16 import { CdTableAction } from '~/app/shared/models/cd-table-action';
17 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
18 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
19 import { Permission } from '~/app/shared/models/permissions';
20 import { PrometheusRule } from '~/app/shared/models/prometheus-alerts';
21 import { CdDatePipe } from '~/app/shared/pipes/cd-date.pipe';
22 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
23 import { ModalService } from '~/app/shared/services/modal.service';
24 import { NotificationService } from '~/app/shared/services/notification.service';
25 import { PrometheusSilenceMatcherService } from '~/app/shared/services/prometheus-silence-matcher.service';
26 import { URLBuilderService } from '~/app/shared/services/url-builder.service';
27
28 const BASE_URL = 'monitoring/silences';
29
30 @Component({
31   providers: [
32     { provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) },
33     SilenceFormComponent
34   ],
35   selector: 'cd-silences-list',
36   templateUrl: './silence-list.component.html',
37   styleUrls: ['./silence-list.component.scss']
38 })
39 export class SilenceListComponent extends PrometheusListHelper {
40   silences: AlertmanagerSilence[] = [];
41   columns: CdTableColumn[];
42   tableActions: CdTableAction[];
43   permission: Permission;
44   selection = new CdTableSelection();
45   modalRef: NgbModalRef;
46   customCss = {
47     'badge badge-danger': 'active',
48     'badge badge-warning': 'pending',
49     'badge badge-default': 'expired'
50   };
51   sorts: SortPropDir[] = [{ prop: 'endsAt', dir: SortDirection.desc }];
52   rules: PrometheusRule[];
53   visited: boolean;
54
55   constructor(
56     private authStorageService: AuthStorageService,
57     private cdDatePipe: CdDatePipe,
58     private modalService: ModalService,
59     private notificationService: NotificationService,
60     private urlBuilder: URLBuilderService,
61     private actionLabels: ActionLabelsI18n,
62     private succeededLabels: SucceededActionLabelsI18n,
63     private silenceFormComponent: SilenceFormComponent,
64     private silenceMatcher: PrometheusSilenceMatcherService,
65     @Inject(PrometheusService) prometheusService: PrometheusService
66   ) {
67     super(prometheusService);
68     this.permission = this.authStorageService.getPermissions().prometheus;
69     const selectionExpired = (selection: CdTableSelection) =>
70       selection.first() && selection.first().status && selection.first().status.state === 'expired';
71     this.tableActions = [
72       {
73         permission: 'create',
74         icon: Icons.add,
75         routerLink: () => this.urlBuilder.getCreate(),
76         canBePrimary: (selection: CdTableSelection) => !selection.hasSingleSelection,
77         name: this.actionLabels.CREATE
78       },
79       {
80         permission: 'create',
81         canBePrimary: (selection: CdTableSelection) =>
82           selection.hasSingleSelection && selectionExpired(selection),
83         disable: (selection: CdTableSelection) =>
84           !selection.hasSingleSelection ||
85           selection.first().cdExecuting ||
86           (selection.first().cdExecuting && selectionExpired(selection)) ||
87           !selectionExpired(selection),
88         icon: Icons.copy,
89         routerLink: () => this.urlBuilder.getRecreate(this.selection.first().id),
90         name: this.actionLabels.RECREATE
91       },
92       {
93         permission: 'update',
94         icon: Icons.edit,
95         canBePrimary: (selection: CdTableSelection) =>
96           selection.hasSingleSelection && !selectionExpired(selection),
97         disable: (selection: CdTableSelection) =>
98           !selection.hasSingleSelection ||
99           selection.first().cdExecuting ||
100           (selection.first().cdExecuting && !selectionExpired(selection)) ||
101           selectionExpired(selection),
102         routerLink: () => this.urlBuilder.getEdit(this.selection.first().id),
103         name: this.actionLabels.EDIT
104       },
105       {
106         permission: 'delete',
107         icon: Icons.trash,
108         canBePrimary: (selection: CdTableSelection) =>
109           selection.hasSingleSelection && !selectionExpired(selection),
110         disable: (selection: CdTableSelection) =>
111           !selection.hasSingleSelection ||
112           selection.first().cdExecuting ||
113           selectionExpired(selection),
114         click: () => this.expireSilence(),
115         name: this.actionLabels.EXPIRE
116       }
117     ];
118     this.columns = [
119       {
120         name: $localize`ID`,
121         prop: 'id',
122         flexGrow: 3
123       },
124       {
125         name: $localize`Alerts Silenced`,
126         prop: 'silencedAlerts',
127         flexGrow: 3,
128         cellTransformation: CellTemplate.badge
129       },
130       {
131         name: $localize`Created by`,
132         prop: 'createdBy',
133         flexGrow: 2
134       },
135       {
136         name: $localize`Started`,
137         prop: 'startsAt',
138         pipe: this.cdDatePipe
139       },
140       {
141         name: $localize`Updated`,
142         prop: 'updatedAt',
143         pipe: this.cdDatePipe
144       },
145       {
146         name: $localize`Ends`,
147         prop: 'endsAt',
148         pipe: this.cdDatePipe
149       },
150       {
151         name: $localize`Status`,
152         prop: 'status.state',
153         cellTransformation: CellTemplate.classAdding
154       }
155     ];
156   }
157
158   refresh() {
159     this.prometheusService.ifAlertmanagerConfigured(() => {
160       this.prometheusService.getSilences().subscribe(
161         (silences) => {
162           this.silences = silences;
163           const activeSilences = silences.filter(
164             (silence: AlertmanagerSilence) => silence.status.state !== 'expired'
165           );
166           this.getAlerts(activeSilences);
167         },
168         () => {
169           this.prometheusService.disableAlertmanagerConfig();
170         }
171       );
172     });
173   }
174
175   updateSelection(selection: CdTableSelection) {
176     this.selection = selection;
177   }
178
179   getAlerts(silences: any) {
180     const rules = this.silenceFormComponent.getRules();
181     silences.forEach((silence: any) => {
182       silence.matchers.forEach((matcher: any) => {
183         this.rules = this.silenceMatcher.getMatchedRules(matcher, rules);
184         const alertNames: string[] = [];
185         for (const rule of this.rules) {
186           alertNames.push(rule.name);
187         }
188         silence.silencedAlerts = alertNames;
189       });
190     });
191   }
192
193   expireSilence() {
194     const id = this.selection.first().id;
195     const i18nSilence = $localize`Silence`;
196     const applicationName = 'Prometheus';
197     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
198       itemDescription: i18nSilence,
199       itemNames: [id],
200       actionDescription: this.actionLabels.EXPIRE,
201       submitActionObservable: () =>
202         new Observable((observer: Subscriber<any>) => {
203           this.prometheusService.expireSilence(id).subscribe(
204             () => {
205               this.notificationService.show(
206                 NotificationType.success,
207                 `${this.succeededLabels.EXPIRED} ${i18nSilence} ${id}`,
208                 undefined,
209                 undefined,
210                 applicationName
211               );
212             },
213             (resp) => {
214               resp['application'] = applicationName;
215               observer.error(resp);
216             },
217             () => {
218               observer.complete();
219               this.refresh();
220             }
221           );
222         })
223     });
224   }
225 }