Skip to content

Commit

Permalink
Changes to Capacity Metrics in OCS Persistent Storage Dashboard
Browse files Browse the repository at this point in the history
 - Add Raw Capacity Card in Dashboard
 - Remove Avaiable Metric from Breakdown Card
 - Rename Capacity Breakdown Card
 - Add Info Tip to Capacity Breakdown Card
  • Loading branch information
bipuladh committed Dec 3, 2020
1 parent 1910f99 commit 40fcc35
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"Projects": "Projects",
"Storage Classes": "Storage Classes",
"Pods": "Pods",
"Capacity breakdown": "Capacity breakdown",
"Used Capacity Breakdown": "Used Capacity Breakdown",
"This card shows the used capacity for Usable storage, broken-down by different kubernetes resources. Usable storage is all the data that can be stored in the system after decreasing the replication policies.": "This card shows the used capacity for Usable storage, broken-down by different kubernetes resources. Usable storage is all the data that can be stored in the system after decreasing the replication policies.",
"{{metricType}}": "{{metricType}}",
"Break By Dropdown": "Break By Dropdown",
"Details": "Details",
Expand All @@ -23,6 +24,11 @@
"Mode": "Mode",
"Version": "Version",
"Inventory": "Inventory",
"Raw Capacity": "Raw Capacity",
"Used": "Used",
"Available versus Used Capacity": "Available versus Used Capacity",
"Used of {{capacity}}": "Used of {{capacity}}",
"Not Available": "Not Available",
"Status": "Status",
"OCS Cluster": "OCS Cluster",
"Data Resiliency": "Data Resiliency",
Expand All @@ -41,6 +47,7 @@
"Latency": "Latency",
"Throughput": "Throughput",
"Recovery": "Recovery",
"Capacity breakdown": "Capacity breakdown",
"Requested capacity": "Requested capacity",
"Persistent Storage": "Persistent Storage",
"Storage": "Storage",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import { useTranslation } from 'react-i18next';
import * as _ from 'lodash';
import { Select, SelectProps } from '@patternfly/react-core';
import { humanizeBinaryBytes } from '@console/internal/components/utils';
import { humanizeBinaryBytes, FieldLevelHelp } from '@console/internal/components/utils';
import {
DashboardItemProps,
withDashboardResources,
Expand Down Expand Up @@ -48,8 +48,7 @@ const BreakdownCard: React.FC<DashboardItemProps> = ({
const top5SortedMetricsData = sortInstantVectorStats(top6MetricsData);
const top5MetricsStats = getStackChartStats(top5SortedMetricsData, humanize);
const metricTotal = _.get(results[1], 'data.result[0].value[1]');
const cephAvailable = _.get(results[2], 'data.result[0].value[1]');
const cephUsed = _.get(results[3], 'data.result[0].value[1]');
const cephUsed = _.get(results[2], 'data.result[0].value[1]');

const handleMetricsChange: SelectProps['onSelect'] = (_e, breakdown) => {
setMetricType(breakdown as string);
Expand All @@ -75,7 +74,14 @@ const BreakdownCard: React.FC<DashboardItemProps> = ({
return (
<DashboardCard>
<DashboardCardHeader>
<DashboardCardTitle>{t('ceph-storage-plugin~Capacity breakdown')}</DashboardCardTitle>
<DashboardCardTitle>
{t('ceph-storage-plugin~Used Capacity Breakdown')}
<FieldLevelHelp>
{t(
'ceph-storage-plugin~This card shows the used capacity for Usable storage, broken-down by different kubernetes resources. Usable storage is all the data that can be stored in the system after decreasing the replication policies.',
)}
</FieldLevelHelp>
</DashboardCardTitle>
<div className="ceph-capacity-breakdown-card__header">
<Select
className="ceph-capacity-breakdown-card-header__dropdown"
Expand All @@ -98,7 +104,6 @@ const BreakdownCard: React.FC<DashboardItemProps> = ({
hasLoadError={queriesLoadError}
metricTotal={metricTotal}
top5MetricsStats={top5MetricsStats}
capacityAvailable={cephAvailable}
capacityUsed={cephUsed}
metricModel={model}
humanize={humanize}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@import '../../../../../../console-shared/src/styles/skeleton-screen.scss';

.ceph-raw-usage {
&__container {
display: flex;
width: 100%;
margin-top: var(--pf-global--spacer--md);
}
&__legend {
flex-grow: 1;
padding-top: var(--pf-global--spacer--md);
}
&__chart {
flex-grow: 0.5;
max-height: 180px;
}
&--error {
margin-top: var(--pf-global--spacer--xs);
margin-bottom: var(--pf-global--spacer--xs);
width: 100%;
text-align: center;
}
}

.ceph-raw-card-legend {
&__container {
margin-bottom: 1em;
flex: 1 1 0;
display: flex;
}
&__color-square {
width: 15px;
height: 15px;
}
&__title {
margin-left: 6px;
line-height: 15px;
font-weight: bold;
&--pad {
padding-right: 30px;
}
}
&__index-block {
display: flex;
}
&__value-block {
display: flex;
flex-direction: row-reverse;
flex-grow: 0.25;
}
&__text {
line-height: 15px;
font-weight: bold;
}
}

/* Styles related to lodaing state */

.skeleton-activity {
animation: $skeleton-animation;
background: $skeleton-color;
opacity: 0;
border-radius: 6px;
margin: 0.5rem 0.7em 0.5rem 0.7em;
height: 30px;
&::after {
background-repeat: no-repeat;
content: '';
display: block;
height: 100%;
width: 100%;
}
}

.ceph-raw-usage-loading {
&__legend {
flex-grow: 1;
}
&-legend__item {
min-width: 1em;
max-width: 18em;
flex-grow: 0.5;
min-height: 1em;
max-height: 2em;
}
&__chart {
flex-grow: 1;
min-width: 5em;
max-width: 10em;
min-height: 8em;
max-height: 10em;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import * as React from 'react';
import classNames from 'classnames';
import { compose } from 'redux';
import { useTranslation } from 'react-i18next';
import { ChartDonut, ChartLabel } from '@patternfly/react-charts';
import { usePrometheusQueries } from '@console/shared/src/components/dashboard/utilization-card/prometheus-hook';
import DashboardCard from '@console/shared/src/components/dashboard/dashboard-card/DashboardCard';
import DashboardCardTitle from '@console/shared/src/components/dashboard/dashboard-card/DashboardCardTitle';
import DashboardCardBody from '@console/shared/src/components/dashboard/dashboard-card/DashboardCardBody';
import DashboardCardHeader from '@console/shared/src/components/dashboard/dashboard-card/DashboardCardHeader';
import { humanizeBinaryBytes } from '@console/internal/components/utils';
import { getInstantVectorStats } from '@console/internal/components/graphs/utils';
import { CAPACITY_INFO_QUERIES } from '../../../../constants/queries';
import './raw-capacity-card.scss';

const queries = (() => Object.values(CAPACITY_INFO_QUERIES))();
const colorScale = ['#0166cc', '#d6d6d6'];

// Enchance instantVectorStats to directly parse the values (else loading state won't be accurate)
const parser = compose((val) => val?.[0]?.y, getInstantVectorStats);

const RawCapacityCard: React.FC = React.memo(() => {
const [values, loading, loadError] = usePrometheusQueries(queries, parser as any);
const { t } = useTranslation();

const totalCapacityMetric = values?.[0];
const usedCapacityMetric = values?.[1];

const totalCapacity = humanizeBinaryBytes(totalCapacityMetric);
const availableCapacity = humanizeBinaryBytes(
totalCapacityMetric - usedCapacityMetric,
null,
totalCapacity?.unit,
);
const usedCapacity = humanizeBinaryBytes(usedCapacityMetric, null, totalCapacity?.unit);

// Adjusted units
const usedCapacityAdjusted = humanizeBinaryBytes(usedCapacityMetric);
const availableCapacityAdjusted = humanizeBinaryBytes(totalCapacityMetric - usedCapacityMetric);

const donutData = [
{ x: 'Used', y: usedCapacity.value, string: usedCapacityAdjusted.string },
{
x: 'Available',
y: availableCapacity.value,
string: availableCapacityAdjusted.string,
},
];

return (
<DashboardCard>
<DashboardCardHeader>
<DashboardCardTitle>{t('ceph-storage-plugin~Raw Capacity')}</DashboardCardTitle>
</DashboardCardHeader>
<DashboardCardBody className="ceph-raw-usage__container">
{!loading && !loadError && (
<>
<div className="ceph-raw-usage__item ceph-raw-usage__legend">
<ChartLegend
fill={colorScale[0]}
title={t('ceph-storage-plugin~Used')}
text={usedCapacityAdjusted.string}
titleClassName="ceph-raw-card-legend__title--pad"
/>
<ChartLegend
fill={colorScale[1]}
title={t('ceph-storage-plugin~Available')}
text={availableCapacityAdjusted.string}
/>
</div>
<div className="ceph-raw-usage__item ceph-raw-usage__chart">
<ChartDonut
ariaDesc={t('ceph-storage-plugin~Available versus Used Capacity')}
ariaTitle={t('ceph-storage-plugin~Available versus Used Capacity')}
height={150}
width={150}
data={donutData}
labels={({ datum }) => `${datum.string}`}
title={usedCapacityAdjusted.string}
subTitle={t('ceph-storage-plugin~Used of {{capacity}}', {
capacity: totalCapacity,
})}
colorScale={colorScale}
padding={{ top: 0, bottom: 0, left: 0, right: 0 }}
constrainToVisibleArea
subTitleComponent={
<ChartLabel dy={5} style={{ fill: `var(--pf-global--palette--black-500)` }} />
}
/>
</div>
</>
)}
{!loadError && loading && <LoadingCardBody />}
{loadError && !loading && <ErrorCardBody />}
</DashboardCardBody>
</DashboardCard>
);
});

const LoadingCardBody: React.FC = () => (
<div className="ceph-raw-usage__container">
<div className="ceph-raw-usage-loading__legend">
<div className="ceph-raw-usage-loading-legend__item skeleton-activity" />
<div className="ceph-raw-usage-loading-legend__item skeleton-activity" />
</div>
<div className="ceph-raw-usage-loading__chart skeleton-activity" />
</div>
);

const ErrorCardBody: React.FC = () => {
const { t } = useTranslation();
return (
<>
<div className="ceph-raw-usage--error text-muted">
{t('ceph-storage-plugin~Not Available')}
</div>
</>
);
};

const ChartLegend: React.FC<ChartLegendProps> = ({ fill, title, text, titleClassName }) => (
<div className="ceph-raw-card-legend__container">
<div className="ceph-raw-card-legend__index-block">
<div className="ceph-raw-card-legend__color-square" style={{ backgroundColor: fill }} />
<div className={classNames('ceph-raw-card-legend__title', titleClassName)}>{title}</div>
</div>
<div className="ceph-raw-card-legend__value-block">
<div className="ceph-raw-card-legend__text">{text}</div>
</div>
</div>
);

type ChartLegendProps = {
fill: string;
text: string;
title: string;
titleClassName?: string;
};

export default RawCapacityCard;
14 changes: 8 additions & 6 deletions frontend/packages/ceph-storage-plugin/src/constants/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export enum StorageDashboardQuery {
CEPH_CAPACITY_AVAILABLE = 'CEPH_CAPACITY_AVAILABLE',
POOL_CAPACITY_RATIO = 'POOL_CAPACITY_RATIO',
POOL_SAVED_CAPACITY = 'POOL_SAVED_CAPACITY',
// Capacity Info Card
RAW_CAPACITY_TOTAL = 'RAW_TOTAL_CAPACITY',
RAW_CAPACITY_USED = 'RAW_CAPACITY_USED',
}

export const INDEPENDENT_UTILIZATION_QUERIES = {
Expand Down Expand Up @@ -70,6 +73,11 @@ export const CAPACITY_USAGE_QUERIES = {
'sum((kubelet_volume_stats_used_bytes * on (namespace,persistentvolumeclaim) group_right() kube_pod_spec_volumes_persistentvolumeclaims_info) * on (namespace,persistentvolumeclaim) group_left(storageclass, provisioner) (kube_persistentvolumeclaim_info * on (storageclass) group_left(provisioner) kube_storageclass_info {provisioner=~"(.*rbd.csi.ceph.com)|(.*cephfs.csi.ceph.com)|(ceph.rook.io/block)"}))',
};

export const CAPACITY_INFO_QUERIES = {
[StorageDashboardQuery.RAW_CAPACITY_TOTAL]: 'ceph_cluster_total_bytes',
[StorageDashboardQuery.RAW_CAPACITY_USED]: 'ceph_cluster_total_used_raw_bytes',
};

export const CAPACITY_BREAKDOWN_QUERIES = {
[StorageDashboardQuery.PROJECTS_TOTAL_USED]:
'sum(sum(kubelet_volume_stats_used_bytes * on (namespace,persistentvolumeclaim) group_left(storageclass, provisioner) (kube_persistentvolumeclaim_info * on (storageclass) group_left(provisioner) kube_storageclass_info {provisioner=~"(.*rbd.csi.ceph.com)|(.*cephfs.csi.ceph.com)|(ceph.rook.io/block)"})) by (namespace))',
Expand Down Expand Up @@ -107,8 +115,6 @@ export const breakdownQueryMap = {
})))`,
[StorageDashboardQuery.PROJECTS_TOTAL_USED]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.PROJECTS_TOTAL_USED],
[StorageDashboardQuery.CEPH_CAPACITY_AVAILABLE]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.CEPH_CAPACITY_AVAILABLE],
[StorageDashboardQuery.CEPH_CAPACITY_USED]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.CEPH_CAPACITY_USED],
},
Expand All @@ -122,8 +128,6 @@ export const breakdownQueryMap = {
})))`,
[StorageDashboardQuery.STORAGE_CLASSES_TOTAL_USED]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.STORAGE_CLASSES_TOTAL_USED],
[StorageDashboardQuery.CEPH_CAPACITY_AVAILABLE]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.CEPH_CAPACITY_AVAILABLE],
[StorageDashboardQuery.CEPH_CAPACITY_USED]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.CEPH_CAPACITY_USED],
},
Expand All @@ -137,8 +141,6 @@ export const breakdownQueryMap = {
})))`,
[StorageDashboardQuery.PODS_TOTAL_USED]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.PODS_TOTAL_USED],
[StorageDashboardQuery.CEPH_CAPACITY_AVAILABLE]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.CEPH_CAPACITY_AVAILABLE],
[StorageDashboardQuery.CEPH_CAPACITY_USED]:
CAPACITY_BREAKDOWN_QUERIES[StorageDashboardQuery.CEPH_CAPACITY_USED],
},
Expand Down
14 changes: 14 additions & 0 deletions frontend/packages/ceph-storage-plugin/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ const plugin: Plugin<ConsumedExtensions> = [
required: [CEPH_FLAG],
},
},
{
type: 'Dashboards/Card',
properties: {
tab: 'persistent-storage',
position: GridPosition.MAIN,
loader: () =>
import(
'./components/dashboard-page/storage-dashboard/raw-capacity-card/raw-capacity-card' /* webpackChunkName: "raw-capacity-card" */
).then((m) => m.default),
},
flags: {
required: [CEPH_FLAG],
},
},
{
type: 'Dashboards/Card',
properties: {
Expand Down

0 comments on commit 40fcc35

Please sign in to comment.