Skip to content
This repository has been archived by the owner on Apr 28, 2020. It is now read-only.

Commit

Permalink
Added top consumer card for storage dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
gnehapk committed Apr 12, 2019
1 parent 59589e3 commit 691f862
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/components/StorageOverview/StorageOverview.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import OCSHealthConnected from './OCSHealth/Health';
import { CapacityConnected } from './Capacity/Capacity';
import EventsConnected from './Events/Events';
import { UtilizationConnected } from './Utilization/Utilization';
import TopConsumersConnected from './TopConsumers/TopConsumers';

const MainCards = () => (
<GridItem lg={6} md={12} sm={12}>
Expand All @@ -22,6 +23,9 @@ const MainCards = () => (
<GridItem span={6}>
<CapacityConnected />
</GridItem>
<GridItem span={12}>
<TopConsumersConnected />
</GridItem>
</Grid>
</GridItem>
);
Expand Down
105 changes: 105 additions & 0 deletions src/components/StorageOverview/TopConsumers/TopConsumers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import PropTypes from 'prop-types';

import { LineChart, Row, Col } from 'patternfly-react';

import { InlineLoading } from '../../Loading';

import {
DashboardCard,
DashboardCardBody,
DashboardCardHeader,
DashboardCardTitle,
} from '../../Dashboard/DashboardCard';
import { StorageOverviewContext } from '../StorageOverviewContext/StorageOverviewContext';
import { getTopConsumerVectorStats } from '../../../selectors';

const TopConsumersBody = ({ stats }) => {
let results = 'Not data available';

if (stats.length) {
const columnsConf = getTopConsumerVectorStats(stats);
const { columns, unit } = columnsConf;
const formatTime = x => {
const dt = new Date(x);

let hrs = dt.getHours();
hrs = hrs > 9 ? `${hrs}` : `0${hrs}`;

let mins = dt.getMinutes();
mins = mins > 9 ? `${mins}` : `0${mins}`;

return `${hrs}:${mins}`;
};

results = (
<Row>
<Col lg={12} md={12} sm={12} xs={12}>
<LineChart
className="kubevirt-top-consumers__body"
id="line-chart"
data={{
x: 'x',
columns,
type: 'line',
}}
axis={{
y: {
label: {
text: `Used Capacity(${unit})`,
position: 'outer-top',
},
min: 0,
padding: {
bottom: 3,
},
},
x: {
tick: {
format: formatTime,
fit: true,
values: [...columns[0].slice(1)],
},
},
}}
/>
</Col>
</Row>
);
}

return <div>{results}</div>;
};

export const TopConsumers = ({ stats, LoadingComponent, loaded }) => (
<DashboardCard>
<DashboardCardHeader>
<DashboardCardTitle>Top Projects by Used Capacity</DashboardCardTitle>
</DashboardCardHeader>
<DashboardCardBody isLoading={!loaded} LoadingComponent={LoadingComponent}>
<TopConsumersBody stats={stats} />
</DashboardCardBody>
</DashboardCard>
);

TopConsumersBody.propTypes = {
stats: PropTypes.array.isRequired,
};

TopConsumers.defaultProps = {
stats: [],
loaded: false,
LoadingComponent: InlineLoading,
};

TopConsumers.propTypes = {
stats: PropTypes.array,
loaded: PropTypes.bool,
LoadingComponent: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
};

const TopConsumersConnected = () => (
<StorageOverviewContext.Consumer>{props => <TopConsumers {...props} />}</StorageOverviewContext.Consumer>
);

export default TopConsumersConnected;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { TopConsumers } from '../TopConsumers';

export const TopConsumerStats = {
stats: [
{
metric: {
namespace: 'openshift-namespace',
},
values: [
[1554797100, '46161920'],
[1554797400, '46161920'],
[1554797700, '46161920'],
[1554798000, '46161920'],
[1554798300, '46161920'],
[1554798600, '46161920'],
],
},
],
loaded: true,
};

export default [
{
component: TopConsumers,
props: { ...TopConsumerStats },
},
{
component: TopConsumers,
name: 'Loading top consumers',
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { render } from 'enzyme';

import { TopConsumers } from '../TopConsumers';
import { TopConsumerStats } from '../fixtures/TopConsumers.fixture';

const testTopConsumersOverview = () => <TopConsumers {...TopConsumerStats} />;

describe('<TopConsumers />', () => {
it('renders correctly', () => {
const component = render(testTopConsumersOverview());
expect(component).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<TopConsumers /> renders correctly 1`] = `
<div
class="card-pf kubevirt-dashboard__card"
>
<div
class="card-pf-heading kubevirt-dashboard__card-heading"
>
<h2
class="card-pf-title"
>
Top Projects by Used Capacity
</h2>
</div>
<div
class="card-pf-body"
>
<div>
<div
class="row"
>
<div
class="col-lg-12 col-md-12 col-sm-12 col-xs-12"
>
<div
class=" kubevirt-top-consumers__body"
/>
</div>
</div>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { persistentVolumeClaims } from '../../../tests/mocks/persistentVolumeCla
import { persistentVolumes } from '../../../tests/mocks/persistentVolume';
import { osdDisksCount } from '../../../tests/mocks/disks';

import { TopConsumerStats } from '../TopConsumers/fixtures/TopConsumers.fixture';

export const nodes = [localhostNode];
export const pvcs = persistentVolumeClaims;
export const pvs = persistentVolumes;
Expand All @@ -38,6 +40,7 @@ export default [
diskStats,
eventsData,
...utilizationStats,
...TopConsumerStats,
},
},
{
Expand Down
41 changes: 39 additions & 2 deletions src/selectors/prometheus/selectors.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { get } from 'lodash';
import { get, forEach } from 'lodash';

import { parseNumber } from '../../utils';
import { parseNumber, formatBytes } from '../../utils';

export const getConsumers = (results, nameLabel, formatLabel) => {
const result = get(results, 'data.result');
Expand Down Expand Up @@ -28,3 +28,40 @@ export const getLastUtilizationStat = response => {
const history = getUtilizationVectorStats(response);
return history ? history[history.length - 1] : null;
};

export const getTopConsumerVectorStats = result => {
let maxVal = 0;

forEach(result, namespace => {
forEach(namespace.values, value => {
maxVal = Math.max(maxVal, parseInt(value[1], 10));
});
});

const maxCapacityConveretd = { ...formatBytes(maxVal) };

const yAxisData = result.map(r => [
r.metric.namespace,
...r.values.map(array => formatBytes(array[1], maxCapacityConveretd.unit, 2).value),
]);

let largestLengthArray = 0;
let largestLengthArrayIndex = 0;

// timestamps count and values are not same for all the namespaces. Hence, finding the largest length array and taking its timestamps value as x-axis point
forEach(result, (namespace, index) => {
const len = namespace.values.length;
if (len > largestLengthArray) {
largestLengthArray = len;
largestLengthArrayIndex = index;
}
});
const xAxisData = ['x', ...result[largestLengthArrayIndex].values.map(array => new Date(array[0] * 1000))];

const stats = {
columns: [xAxisData, ...yAxisData],
unit: maxCapacityConveretd.unit,
};

return stats;
};

0 comments on commit 691f862

Please sign in to comment.