Skip to content

Commit

Permalink
Merge pull request #5344 from rawagner/control_plane_status
Browse files Browse the repository at this point in the history
Bug 1830095: Update Control Plane status logic to include no. of not healthy compo…
  • Loading branch information
openshift-merge-robot committed May 12, 2020
2 parents 5a3a9f8 + 692b688 commit ad4c9ae
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 42 deletions.
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

0 comments on commit ad4c9ae

Please sign in to comment.