Skip to content

Commit

Permalink
Changed CRD fetching to Prometheus
Browse files Browse the repository at this point in the history
  • Loading branch information
bond95 committed Sep 22, 2020
1 parent 20e34e7 commit 4ec3d93
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -1,82 +1,91 @@
import * as React from 'react';
import * as _ from 'lodash';
import { ChartDonut, ChartLegend, ChartLabel } from '@patternfly/react-charts';
import { WatchK8sResults } from '@console/internal/components/utils/k8s-watch-hook';
import { ClusterVersionKind } from '@console/internal/module/k8s';
import { InsightsOperator } from './status';
import { riskIcons, colorScale, legendColorScale, riskSorting } from './mappers';
import { riskIcons, colorScale, legendColorScale, riskSorting, mapMetrics } from './mappers';
import { PrometheusHealthPopupProps } from '@console/plugin-sdk';
import './style.scss';

const DataComponent: React.FC<DataComponentProps> = ({ x, y, datum }) => {
const Icon = riskIcons[datum.id];
return <Icon x={x} y={y - 5} fill={legendColorScale[datum.id]} />;
};

export const InsightsPopup: React.FC<InsightsPopupProps> = ({ insightsReport, clusterVersion }) => {
const resource = insightsReport.data;
const clusterId = _.get(clusterVersion, 'data.spec.clusterID', '');
const riskEntries = Object.entries(resource.spec).sort(
export const InsightsPopup: React.FC<PrometheusHealthPopupProps> = ({ responses, k8sResult }) => {
const resource = mapMetrics(responses[0].response);
const clusterId = _.get(k8sResult, 'data.spec.clusterID', '');
const riskEntries = Object.entries(resource).sort(
([k1], [k2]) => riskSorting[k1] - riskSorting[k2],
);

return (
<div className="co-status-popup__row">
<div className="co-insights__box">
<div className="co-status-popup__section">
Insights identifies and prioritizes risks to security, performance, availability, and
stability of your clusters.
</div>
<div className="co-status-popup__section">
<div>
<ChartDonut
data={riskEntries.map(([k, v]) => ({
label: `${v} ${k}`,
x: k,
y: v,
}))}
title={`${Object.values(resource.spec).reduce((acc, cur) => acc + cur, 0)}`}
subTitle="Total issues"
legendData={Object.entries(resource.spec).map(([k, v]) => ({ name: `${k}: ${v}` }))}
legendOrientation="vertical"
width={300}
height={150}
colorScale={colorScale}
constrainToVisibleArea
legendPosition="left"
legendComponent={
<ChartLegend
title="Total Risk"
titleComponent={<ChartLabel style={{ fontWeight: 'bold' }} />}
data={riskEntries.map(([k, v]) => ({
name: `${v} ${k}`,
id: k,
}))}
dataComponent={<DataComponent />}
/>
}
padding={{
bottom: 20,
left: 145,
right: 20, // Adjusted to accommodate legend
top: 0,
}}
/>
</div>
{riskEntries.length > 0 && (
<div>
<ChartDonut
data={riskEntries.map(([k, v]) => ({
label: `${v} ${k}`,
x: k,
y: v,
}))}
title={`${Object.values(resource).reduce((acc, cur) => acc + cur, 0)}`}
subTitle="Total issues"
legendData={Object.entries(resource).map(([k, v]) => ({ name: `${k}: ${v}` }))}
legendOrientation="vertical"
width={300}
height={150}
colorScale={colorScale}
constrainToVisibleArea
legendPosition="left"
legendComponent={
<ChartLegend
title="Total Risk"
titleComponent={<ChartLabel style={{ fontWeight: 'bold' }} />}
data={riskEntries.map(([k, v]) => ({
name: `${v} ${k}`,
id: k,
}))}
dataComponent={<DataComponent />}
/>
}
padding={{
bottom: 20,
left: 145,
right: 20, // Adjusted to accommodate legend
top: 0,
}}
/>
</div>
)}
{riskEntries.length === 0 && (
<div className="co-insights__no-rules">No Insights data to display.</div>
)}
</div>
<div className="co-status-popup__section co-status-popup__row">
<div style={{ fontWeight: 'bold' }}>Fixable issues</div>
<div>
<a href={`https://cloud.redhat.com/openshift/details/${clusterId}`}>
View all in OpenShift Cluster Manager
<div className="co-status-popup__section">
{riskEntries.length > 0 && (
<>
<div style={{ fontWeight: 'bold' }}>Fixable issues</div>
<div>
<a href={`https://cloud.redhat.com/openshift/details/${clusterId}`}>
View all in OpenShift Cluster Manager
</a>
</div>
</>
)}
{riskEntries.length === 0 && (
<a href="https://docs.openshift.com/container-platform/latest/support/getting-support.html">
More about Insights
</a>
</div>
)}
</div>
</div>
);
};

export type InsightsPopupProps = WatchK8sResults<{
insightsReport: InsightsOperator;
clusterVersion: ClusterVersionKind;
}>;
export type DataComponentProps = {
x?: number;
y?: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/camelcase */
import * as _ from 'lodash';

import {
global_palette_blue_50,
global_palette_blue_300,
Expand Down Expand Up @@ -36,3 +38,24 @@ export const riskSorting = {
important: 2,
critical: 3,
};

type Metrics = {
critical?: number;
important?: number;
low?: number;
moderate?: number;
};

export const mapMetrics = (response) => {
const values: Metrics = {};
for (let i = 0; i < response.data.result.length; i++) {
const value = response.data?.result?.[i]?.value?.[1];
if (_.isNil(value)) {
return null;
}
const metricName = response.data?.result?.[i]?.metric?.metric;
values[metricName] = value;
}

return values;
};
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
import { ResourceHealthHandler } from '@console/plugin-sdk';
import * as _ from 'lodash';
import { PrometheusHealthHandler, SubsystemHealth } from '@console/plugin-sdk';
import { HealthState } from '@console/shared/src/components/dashboard/status-card/states';
import { K8sResourceCommon } from '@console/internal/module/k8s';
import { PrometheusResponse } from '@console/internal/components/graphs';
import { mapMetrics } from './mappers';

export type InsightsOperator = {
spec: {
critical: number;
important: number;
low: number;
moderate: number;
};
} & K8sResourceCommon;

export const getClusterInsightsStatus: ResourceHealthHandler<{
insightsReport: InsightsOperator;
}> = ({ insightsReport }) => {
const { data, loaded, loadError } = insightsReport;

if (loadError) {
return { state: HealthState.UNKNOWN, message: 'Not available' };
export const getClusterInsightsComponentStatus = (
response: PrometheusResponse,
error,
): SubsystemHealth => {
if (error) {
return {
state: HealthState.NOT_AVAILABLE,
message: 'Not available',
};
}
if (!loaded) {
return { state: HealthState.LOADING, message: 'Scanning in progress' };
if (!response) {
return { state: HealthState.LOADING };
}
const values = mapMetrics(response);
if (_.isNil(values)) {
return { state: HealthState.UNKNOWN, message: 'Not available' };
}
const issuesNumber = Object.values(data.spec).reduce((acc, cur) => acc + cur, 0);
const issuesNumber = Object.values(values).reduce((acc, cur) => acc + cur, 0);
const issueStr = `${issuesNumber} issues found`;
if (data.spec.critical > 0) {
if (values.critical > 0) {
return { state: HealthState.ERROR, message: issueStr };
}
if (issuesNumber > 0) {
return { state: HealthState.WARNING, message: issueStr };
}
return { state: HealthState.OK, message: issueStr };
};

export const getClusterInsightsStatus: PrometheusHealthHandler = (responses, cluster) => {
const componentHealth = getClusterInsightsComponentStatus(
responses[0].response,
responses[0].error,
);
if (componentHealth.state === HealthState.LOADING || !_.get(cluster, 'loaded')) {
return { state: HealthState.LOADING };
}

return componentHealth;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.co-insights__box {
.co-insights__no-rules {
color: var(--pf-global--Color--200);
}
}
43 changes: 12 additions & 31 deletions frontend/packages/insights-plugin/src/plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,33 @@
import {
Plugin,
DashboardsOverviewHealthResourceSubsystem,
DashboardsOverviewHealthPrometheusSubsystem,
ModelFeatureFlag,
} from '@console/plugin-sdk';
import { ClusterVersionModel } from '@console/internal/models';
import { referenceForModel } from '@console/internal/module/k8s';
import { getClusterInsightsStatus } from './components/InsightsPopup/status';
import * as models from './models';

type ConsumedExtensions = DashboardsOverviewHealthResourceSubsystem<any> | ModelFeatureFlag;

const FLAG_INSIGHTS = 'INSIGHTS';
type ConsumedExtensions = ModelFeatureFlag | DashboardsOverviewHealthPrometheusSubsystem;

const plugin: Plugin<ConsumedExtensions> = [
{
type: 'FeatureFlag/Model',
properties: {
model: models.InsightsModel,
flag: FLAG_INSIGHTS,
},
},
{
type: 'Dashboards/Overview/Health/Resource',
type: 'Dashboards/Overview/Health/Prometheus',
properties: {
title: 'Insights',
resources: {
insightsReport: {
kind: referenceForModel(models.InsightsModel),
namespaced: false,
name: 'report-overview-object',
isList: false,
},
clusterVersion: {
kind: referenceForModel(ClusterVersionModel),
namespaced: false,
name: 'version',
isList: false,
},
},
queries: ["health_statuses_insights{metric=~'low|moderate|important|critical'}"],
healthHandler: getClusterInsightsStatus,
popupTitle: 'Insights Status',
additionalResource: {
kind: referenceForModel(ClusterVersionModel),
namespaced: false,
name: 'version',
isList: false,
prop: 'cluster',
},
popupComponent: () =>
import('./components/InsightsPopup/index' /* webpackChunkName: "insights-plugin" */).then(
(m) => m.InsightsPopup,
),
},
flags: {
required: [FLAG_INSIGHTS],
popupTitle: 'Insights',
},
},
];
Expand Down

0 comments on commit 4ec3d93

Please sign in to comment.