Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1830095: Update Control Plane status logic to include no. of not healthy compo… #5344

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -18,14 +18,15 @@ const ControlPlanePopup: React.FC<PrometheusHealthPopupProps> = ({ responses })
<StatusPopupSection firstColumn="Components" secondColumn="Response rate">
{responses.map(({ response, error }, index) => {
const health = getControlPlaneComponentHealth(response, error);
let icon: React.ReactNode;
if (health.state === HealthState.LOADING) {
icon = <div className="skeleton-health" />;
} else if (health.state !== HealthState.NOT_AVAILABLE) {
icon = healthStateMapping[health.state].icon;
}
const icon =
health.state === HealthState.LOADING ? (
<div className="skeleton-health" />
) : (
healthStateMapping[health.state].icon
);
const value = health.message || healthStateMapping[health.state]?.message;
return (
<Status key={titles[index]} value={health.message} icon={icon}>
<Status key={titles[index]} value={value} icon={icon}>
{titles[index]}
</Status>
);
Expand Down
Expand Up @@ -8,7 +8,7 @@ import {
} from '@console/plugin-sdk';
import {
HealthState,
operatorHealthPriority,
healthPriority,
} from '@console/shared/src/components/dashboard/status-card/states';
import { coFetch } from '@console/internal/co-fetch';
import {
Expand All @@ -22,6 +22,7 @@ import {
import { PrometheusResponse } from '@console/internal/components/graphs';
import { humanizePercentage } from '@console/internal/components/utils/units';
import { getOperatorsStatus } from '@console/shared/src/components/dashboard/status-card/state-utils';
import { pluralize } from '@patternfly/react-core';

export const fetchK8sHealth = async (url: string) => {
const response = await coFetch(url);
Expand All @@ -48,18 +49,20 @@ export const getControlPlaneComponentHealth = (
response: PrometheusResponse,
error,
): SubsystemHealth => {
if (
error ||
(response &&
response.status === 'success' &&
_.isNil(_.get(response, 'data.result[0].value[1]')))
) {
return { state: HealthState.NOT_AVAILABLE, message: 'Not available' };
if (error) {
return {
state: HealthState.NOT_AVAILABLE,
message: healthPriority[HealthState.NOT_AVAILABLE].message,
};
}
if (!response) {
return { state: HealthState.LOADING };
}
const perc = humanizePercentage(_.get(response, 'data.result[0].value[1]'));
const value = response.data?.result?.[0]?.value?.[1];
if (_.isNil(value)) {
return { state: HealthState.UNKNOWN, message: healthPriority[HealthState.UNKNOWN].message };
}
const perc = humanizePercentage(value);
if (perc.value > 90) {
return { state: HealthState.OK, message: perc.string };
}
Expand All @@ -69,7 +72,18 @@ export const getControlPlaneComponentHealth = (
return { state: HealthState.ERROR, message: perc.string };
};

const errorStates = [HealthState.WARNING, HealthState.ERROR, HealthState.NOT_AVAILABLE];
const getWorstStatus = (
componentsHealth: SubsystemHealth[],
): { state: HealthState; message: string; count: number } => {
const withPriority = componentsHealth.map((h) => healthPriority[h.state]);
const mostImportantState = Math.max(...withPriority.map(({ priority }) => priority));
const worstStatuses = withPriority.filter(({ priority }) => priority === mostImportantState);
return {
state: worstStatuses[0].health,
message: worstStatuses[0].message,
count: worstStatuses.length,
};
};

export const getControlPlaneHealth: PrometheusHealthHandler = (responses) => {
const componentsHealth = responses.map(({ response, error }) =>
Expand All @@ -78,30 +92,32 @@ export const getControlPlaneHealth: PrometheusHealthHandler = (responses) => {
if (componentsHealth.some((c) => c.state === HealthState.LOADING)) {
return { state: HealthState.LOADING };
}
const errComponents = componentsHealth.filter(({ state }) => errorStates.includes(state));
if (errComponents.length) {
return {
state: errComponents.length === 4 ? HealthState.NOT_AVAILABLE : HealthState.WARNING,
message: errComponents.length === 4 ? null : `${errComponents.length} components degraded`,
};
}
return { state: HealthState.OK };
const worstStatus = getWorstStatus(componentsHealth);

return {
state: worstStatus.state,
message: worstStatus.message
? worstStatus.count === 4
? worstStatus.message
: `${pluralize(worstStatus.count, 'component')} ${worstStatus.message.toLowerCase()}`
: null,
};
};

export const getClusterOperatorStatusPriority: GetOperatorStatusPriority<ClusterOperator> = (
co,
) => {
const status = getClusterOperatorStatus(co);
if (status === OperatorStatus.Degraded) {
return { ...operatorHealthPriority[HealthState.WARNING], title: status };
return { ...healthPriority[HealthState.WARNING], title: status };
}
if (status === OperatorStatus.Unknown) {
return { ...operatorHealthPriority[HealthState.UNKNOWN], title: status };
return { ...healthPriority[HealthState.UNKNOWN], title: status };
}
if (status === OperatorStatus.Updating) {
return { ...operatorHealthPriority[HealthState.UPDATING], title: status };
return { ...healthPriority[HealthState.UPDATING], title: status };
}
return { ...operatorHealthPriority[HealthState.OK], title: status };
return { ...healthPriority[HealthState.OK], title: status };
};

export const getClusterOperatorHealthStatus: GetOperatorsWithStatuses<ClusterOperator> = (
Expand Down
Expand Up @@ -5,7 +5,7 @@ import {
OperatorHealth,
GetOperatorStatusPriority,
} from '@console/plugin-sdk';
import { operatorHealthPriority, HealthState } from './states';
import { healthPriority, HealthState } from './states';

export const getMostImportantStatuses = (
operatorStatuses: OperatorStatusWithResources[],
Expand All @@ -21,7 +21,7 @@ export const getOperatorsStatus = <R extends K8sResourceCommon>(
if (!operators.length) {
return {
status: {
...operatorHealthPriority[HealthState.OK],
...healthPriority[HealthState.OK],
title: 'Available',
},
operators: [],
Expand Down Expand Up @@ -62,7 +62,7 @@ export const getOperatorsHealthState = (
return { health: HealthState.LOADING, detailMessage: undefined };
}
const sortedStatuses = healthStatuses.sort(
(a, b) => operatorHealthPriority[b.health].priority - operatorHealthPriority[a.health].priority,
(a, b) => healthPriority[b.health].priority - healthPriority[a.health].priority,
);
const groupedStatuses = _.groupBy(sortedStatuses, (s) => s.health);
const statusKeys = Object.keys(groupedStatuses);
Expand All @@ -87,8 +87,8 @@ export const getOperatorsHealthState = (

return {
health: HealthState[statusKeys[0]],
detailMessage: operatorHealthPriority[statusKeys[0]].message
? `${finalCount} ${operatorHealthPriority[statusKeys[0]].message}`
detailMessage: healthPriority[statusKeys[0]].message
? `${finalCount} ${healthPriority[statusKeys[0]].message.toLowerCase()}`
: undefined,
};
};
Expand Up @@ -49,11 +49,8 @@ export const healthStateMapping: { [key in HealthStateMappingKeys]: HealthStateM
},
};

export const operatorHealthPriority: {
[key in HealthStateMappingKeys]: {
priority: number;
health: HealthState;
} & HealthStateMappingValues;
export const healthPriority: {
[key in HealthStateMappingKeys]: PriorityHealthState;
} = {
[HealthState.OK]: {
priority: 0,
Expand Down Expand Up @@ -92,6 +89,11 @@ export const operatorHealthPriority: {
},
};

export type PriorityHealthState = {
priority: number;
health: HealthState;
} & HealthStateMappingValues;

type HealthStateMappingKeys = Exclude<keyof typeof HealthState, 'LOADING'>;

export type HealthStateMappingValues = {
Expand Down
@@ -1,7 +1,7 @@
import * as _ from 'lodash';
import {
HealthState,
operatorHealthPriority,
healthPriority,
} from '@console/shared/src/components/dashboard/status-card/states';
import { OperatorStatusPriority, GetOperatorsWithStatuses } from '@console/plugin-sdk';
import { getOperatorsStatus } from '@console/shared/src/components/dashboard/status-card/state-utils';
Expand Down Expand Up @@ -36,12 +36,12 @@ const getOperatorStatus = (
subscriptionStatus.status === SubscriptionState.SubscriptionStateUpgradePending
) {
return {
...operatorHealthPriority[HealthState.UPDATING],
...healthPriority[HealthState.UPDATING],
title: subscriptionStatus.title,
};
}
return {
...operatorHealthPriority[operatorHealth],
...healthPriority[operatorHealth],
title: csvStatus.title,
};
};
Expand Down