1 import { Component, OnDestroy, OnInit } from '@angular/core';
3 import _ from 'lodash';
4 import { Subscription } from 'rxjs';
6 import { PgCategoryService } from '~/app/ceph/shared/pg-category.service';
7 import { HealthService } from '~/app/shared/api/health.service';
8 import { CssHelper } from '~/app/shared/classes/css-helper';
9 import { Icons } from '~/app/shared/enum/icons.enum';
10 import { Permissions } from '~/app/shared/models/permissions';
11 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
12 import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
13 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
17 } from '~/app/shared/services/feature-toggles.service';
18 import { RefreshIntervalService } from '~/app/shared/services/refresh-interval.service';
21 selector: 'cd-health',
22 templateUrl: './health.component.html',
23 styleUrls: ['./health.component.scss']
25 export class HealthComponent implements OnInit, OnDestroy {
27 interval = new Subscription();
28 permissions: Permissions;
29 enabledFeature$: FeatureTogglesMap$;
36 this.cssHelper.propertyValue('chart-color-cyan'),
37 this.cssHelper.propertyValue('chart-color-purple')
43 rawCapacityChartConfig = {
47 this.cssHelper.propertyValue('chart-color-blue'),
48 this.cssHelper.propertyValue('chart-color-gray')
54 pgStatusChartConfig = {
61 private healthService: HealthService,
62 private authStorageService: AuthStorageService,
63 private pgCategoryService: PgCategoryService,
64 private featureToggles: FeatureTogglesService,
65 private refreshIntervalService: RefreshIntervalService,
66 private dimlessBinary: DimlessBinaryPipe,
67 private dimless: DimlessPipe,
68 private cssHelper: CssHelper
70 this.permissions = this.authStorageService.getPermissions();
71 this.enabledFeature$ = this.featureToggles.get();
75 this.interval = this.refreshIntervalService.intervalData$.subscribe(() => {
81 this.interval.unsubscribe();
85 this.healthService.getMinimalHealth().subscribe((data: any) => {
86 this.healthData = data;
90 prepareReadWriteRatio(chart: Record<string, any>) {
91 const ratioLabels = [];
95 this.healthData.client_perf.write_op_per_sec + this.healthData.client_perf.read_op_per_sec;
98 `${$localize`Reads`}: ${this.dimless.transform(
99 this.healthData.client_perf.read_op_per_sec
102 ratioData.push(this.calcPercentage(this.healthData.client_perf.read_op_per_sec, total));
104 `${$localize`Writes`}: ${this.dimless.transform(
105 this.healthData.client_perf.write_op_per_sec
108 ratioData.push(this.calcPercentage(this.healthData.client_perf.write_op_per_sec, total));
110 chart.labels = ratioLabels;
111 chart.dataset[0].data = ratioData;
112 chart.dataset[0].label = `${this.dimless.transform(total)}\n${$localize`IOPS`}`;
115 prepareClientThroughput(chart: Record<string, any>) {
116 const ratioLabels = [];
117 const ratioData = [];
120 this.healthData.client_perf.read_bytes_sec + this.healthData.client_perf.write_bytes_sec;
123 `${$localize`Reads`}: ${this.dimlessBinary.transform(
124 this.healthData.client_perf.read_bytes_sec
127 ratioData.push(this.calcPercentage(this.healthData.client_perf.read_bytes_sec, total));
129 `${$localize`Writes`}: ${this.dimlessBinary.transform(
130 this.healthData.client_perf.write_bytes_sec
133 ratioData.push(this.calcPercentage(this.healthData.client_perf.write_bytes_sec, total));
135 chart.labels = ratioLabels;
136 chart.dataset[0].data = ratioData;
137 chart.dataset[0].label = `${this.dimlessBinary
139 .replace(' ', '\n')}${$localize`/s`}`;
142 prepareRawUsage(chart: Record<string, any>, data: Record<string, any>) {
143 const percentAvailable = this.calcPercentage(
144 data.df.stats.total_bytes - data.df.stats.total_used_raw_bytes,
145 data.df.stats.total_bytes
147 const percentUsed = this.calcPercentage(
148 data.df.stats.total_used_raw_bytes,
149 data.df.stats.total_bytes
152 chart.dataset[0].data = [percentUsed, percentAvailable];
155 `${$localize`Used`}: ${this.dimlessBinary.transform(data.df.stats.total_used_raw_bytes)}`,
156 `${$localize`Avail.`}: ${this.dimlessBinary.transform(
157 data.df.stats.total_bytes - data.df.stats.total_used_raw_bytes
161 chart.dataset[0].label = `${percentUsed}%\nof ${this.dimlessBinary.transform(
162 data.df.stats.total_bytes
166 preparePgStatus(chart: Record<string, any>, data: Record<string, any>) {
167 const categoryPgAmount: Record<string, number> = {};
170 _.forEach(data.pg_info.statuses, (pgAmount, pgStatesText) => {
171 const categoryType = this.pgCategoryService.getTypeByStates(pgStatesText);
173 if (_.isUndefined(categoryPgAmount[categoryType])) {
174 categoryPgAmount[categoryType] = 0;
176 categoryPgAmount[categoryType] += pgAmount;
177 totalPgs += pgAmount;
180 for (const categoryType of this.pgCategoryService.getAllTypes()) {
181 if (_.isUndefined(categoryPgAmount[categoryType])) {
182 categoryPgAmount[categoryType] = 0;
186 chart.dataset[0].data = this.pgCategoryService
188 .map((categoryType) => this.calcPercentage(categoryPgAmount[categoryType], totalPgs));
191 `${$localize`Clean`}: ${this.dimless.transform(categoryPgAmount['clean'])}`,
192 `${$localize`Working`}: ${this.dimless.transform(categoryPgAmount['working'])}`,
193 `${$localize`Warning`}: ${this.dimless.transform(categoryPgAmount['warning'])}`,
194 `${$localize`Unknown`}: ${this.dimless.transform(categoryPgAmount['unknown'])}`
197 chart.dataset[0].label = `${totalPgs}\n${$localize`PGs`}`;
200 prepareObjects(chart: Record<string, any>, data: Record<string, any>) {
201 const objectCopies = data.pg_info.object_stats.num_object_copies;
204 data.pg_info.object_stats.num_objects_misplaced -
205 data.pg_info.object_stats.num_objects_degraded -
206 data.pg_info.object_stats.num_objects_unfound;
207 const healthyPercentage = this.calcPercentage(healthy, objectCopies);
208 const misplacedPercentage = this.calcPercentage(
209 data.pg_info.object_stats.num_objects_misplaced,
212 const degradedPercentage = this.calcPercentage(
213 data.pg_info.object_stats.num_objects_degraded,
216 const unfoundPercentage = this.calcPercentage(
217 data.pg_info.object_stats.num_objects_unfound,
222 `${$localize`Healthy`}: ${healthyPercentage}%`,
223 `${$localize`Misplaced`}: ${misplacedPercentage}%`,
224 `${$localize`Degraded`}: ${degradedPercentage}%`,
225 `${$localize`Unfound`}: ${unfoundPercentage}%`
228 chart.dataset[0].data = [
235 chart.dataset[0].label = `${this.dimless.transform(
236 data.pg_info.object_stats.num_objects
237 )}\n${$localize`objects`}`;
240 isClientReadWriteChartShowable() {
241 const readOps = this.healthData.client_perf.read_op_per_sec || 0;
242 const writeOps = this.healthData.client_perf.write_op_per_sec || 0;
244 return readOps + writeOps > 0;
247 private calcPercentage(dividend: number, divisor: number) {
248 if (!_.isNumber(dividend) || !_.isNumber(divisor) || divisor === 0) {
252 return Math.round((dividend / divisor) * 100);