]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts
a3bd264c6843507d1766d802b1c1d293372ae11c
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / dashboard-v3 / dashboard / dashboard-v3.component.ts
1 import { Component, OnDestroy, OnInit } from '@angular/core';
2
3 import _ from 'lodash';
4 import { Observable, Subscription, timer } from 'rxjs';
5 import { take } from 'rxjs/operators';
6 import moment from 'moment';
7
8 import { HealthService } from '~/app/shared/api/health.service';
9 import { OsdService } from '~/app/shared/api/osd.service';
10 import { PrometheusService } from '~/app/shared/api/prometheus.service';
11 import { Promqls as queries } from '~/app/shared/enum/dashboard-promqls.enum';
12 import { Icons } from '~/app/shared/enum/icons.enum';
13 import { DashboardDetails } from '~/app/shared/models/cd-details';
14 import { Permissions } from '~/app/shared/models/permissions';
15 import { AlertmanagerAlert } from '~/app/shared/models/prometheus-alerts';
16 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
17 import {
18 FeatureTogglesMap$,
19 FeatureTogglesService
20 } from '~/app/shared/services/feature-toggles.service';
21 import { RefreshIntervalService } from '~/app/shared/services/refresh-interval.service';
22 import { SummaryService } from '~/app/shared/services/summary.service';
23 import { PrometheusListHelper } from '~/app/shared/helpers/prometheus-list-helper';
24 import { PrometheusAlertService } from '~/app/shared/services/prometheus-alert.service';
25 import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
26
27 @Component({
28 selector: 'cd-dashboard-v3',
29 templateUrl: './dashboard-v3.component.html',
30 styleUrls: ['./dashboard-v3.component.scss']
31 })
32 export class DashboardV3Component extends PrometheusListHelper implements OnInit, OnDestroy {
33 detailsCardData: DashboardDetails = {};
34 osdSettingsService: any;
35 osdSettings: any;
36 interval = new Subscription();
37 permissions: Permissions;
38 enabledFeature$: FeatureTogglesMap$;
39 color: string;
40 capacityService: any;
41 capacity: any;
42 healthData$: Observable<Object>;
43 prometheusAlerts$: Observable<AlertmanagerAlert[]>;
44
45 icons = Icons;
46 showAlerts = false;
47 flexHeight = true;
48 simplebar = {
49 autoHide: false
50 };
51 textClass: string;
52 borderClass: string;
53 alertType: string;
54 alerts: AlertmanagerAlert[];
55 healthData: any;
56 categoryPgAmount: Record<string, number> = {};
57 totalPgs = 0;
58 queriesResults: any = {
59 USEDCAPACITY: '',
60 IPS: '',
61 OPS: '',
62 READLATENCY: '',
63 WRITELATENCY: '',
64 READCLIENTTHROUGHPUT: '',
65 WRITECLIENTTHROUGHPUT: '',
66 RECOVERYBYTES: ''
67 };
68 timerGetPrometheusDataSub: Subscription;
69 timerTime = 30000;
70 readonly lastHourDateObject = {
71 start: moment().unix() - 3600,
72 end: moment().unix(),
73 step: 12
74 };
75
76 constructor(
77 private summaryService: SummaryService,
78 private orchestratorService: OrchestratorService,
79 private osdService: OsdService,
80 private authStorageService: AuthStorageService,
81 private featureToggles: FeatureTogglesService,
82 private healthService: HealthService,
83 public prometheusService: PrometheusService,
84 private refreshIntervalService: RefreshIntervalService,
85 public prometheusAlertService: PrometheusAlertService
86 ) {
87 super(prometheusService);
88 this.permissions = this.authStorageService.getPermissions();
89 this.enabledFeature$ = this.featureToggles.get();
90 }
91
92 ngOnInit() {
93 super.ngOnInit();
94 this.interval = this.refreshIntervalService.intervalData$.subscribe(() => {
95 this.getHealth();
96 this.getCapacityCardData();
97 });
98 this.getPrometheusData(this.lastHourDateObject);
99 this.getDetailsCardData();
100 }
101
102 ngOnDestroy() {
103 this.interval.unsubscribe();
104 if (this.timerGetPrometheusDataSub) {
105 this.timerGetPrometheusDataSub.unsubscribe();
106 }
107 }
108
109 getHealth() {
110 this.healthService.getMinimalHealth().subscribe((data: any) => {
111 this.healthData = data;
112 });
113 }
114
115 toggleAlertsWindow(type: string, isToggleButton: boolean = false) {
116 this.triggerPrometheusAlerts();
117 if (isToggleButton) {
118 this.showAlerts = !this.showAlerts;
119 this.flexHeight = !this.flexHeight;
120 } else if (
121 !this.showAlerts ||
122 (this.alertType === type && type !== 'danger') ||
123 (this.alertType !== 'warning' && type === 'danger')
124 ) {
125 this.showAlerts = !this.showAlerts;
126 this.flexHeight = !this.flexHeight;
127 }
128
129 type === 'danger' ? (this.alertType = 'critical') : (this.alertType = type);
130 this.textClass = `text-${type}`;
131 this.borderClass = `border-${type}`;
132 }
133
134 getDetailsCardData() {
135 this.healthService.getClusterFsid().subscribe((data: string) => {
136 this.detailsCardData.fsid = data;
137 });
138 this.orchestratorService.getName().subscribe((data: string) => {
139 this.detailsCardData.orchestrator = data;
140 });
141 this.summaryService.subscribe((summary) => {
142 const version = summary.version.replace('ceph version ', '').split(' ');
143 this.detailsCardData.cephVersion =
144 version[0] + ' ' + version.slice(2, version.length).join(' ');
145 });
146 }
147
148 getCapacityCardData() {
149 this.osdSettingsService = this.osdService
150 .getOsdSettings()
151 .pipe(take(1))
152 .subscribe((data: any) => {
153 this.osdSettings = data;
154 });
155 this.capacityService = this.healthService.getClusterCapacity().subscribe((data: any) => {
156 this.capacity = data;
157 });
158 }
159
160 triggerPrometheusAlerts() {
161 this.prometheusService.ifAlertmanagerConfigured(() => {
162 this.prometheusService.getAlerts().subscribe((alerts) => {
163 this.alerts = alerts;
164 });
165 });
166 }
167
168 getPrometheusData(selectedTime: any) {
169 this.prometheusService.ifPrometheusConfigured(() => {
170 if (this.timerGetPrometheusDataSub) {
171 this.timerGetPrometheusDataSub.unsubscribe();
172 }
173 this.timerGetPrometheusDataSub = timer(0, this.timerTime).subscribe(() => {
174 selectedTime = this.updateTimeStamp(selectedTime);
175
176 for (const queryName in queries) {
177 if (queries.hasOwnProperty(queryName)) {
178 const query = queries[queryName];
179 let interval = selectedTime.step;
180
181 if (query.includes('rate') && selectedTime.step < 20) {
182 interval = 20;
183 } else if (query.includes('rate')) {
184 interval = selectedTime.step * 2;
185 }
186
187 const intervalAdjustedQuery = query.replace(/\[(.*?)\]/g, `[${interval}s]`);
188
189 this.prometheusService
190 .getPrometheusData({
191 params: intervalAdjustedQuery,
192 start: selectedTime['start'],
193 end: selectedTime['end'],
194 step: selectedTime['step']
195 })
196 .subscribe((data: any) => {
197 if (data.result.length) {
198 this.queriesResults[queryName] = data.result[0].values;
199 }
200 });
201 }
202 }
203 });
204 });
205 }
206
207 private updateTimeStamp(selectedTime: any): any {
208 let formattedDate = {};
209 const date: number = selectedTime['start'] + this.timerTime / 1000;
210 const dateNow: number = selectedTime['end'] + this.timerTime / 1000;
211 formattedDate = {
212 start: date,
213 end: dateNow,
214 step: selectedTime['step']
215 };
216 return formattedDate;
217 }
218 }