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