[UI] Brokers Dashboard
This commit is contained in:
parent
88335f94a8
commit
74b0c000da
8 changed files with 209 additions and 50 deletions
|
@ -1,11 +1,15 @@
|
|||
import React from 'react';
|
||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||
import { ClusterId } from 'types';
|
||||
import { ClusterId, BrokerMetrics, ZooKeeperStatus } from 'types';
|
||||
import useInterval from 'lib/hooks/useInterval';
|
||||
import formatBytes from 'lib/utils/formatBytes';
|
||||
import cx from 'classnames';
|
||||
|
||||
interface Props {
|
||||
interface Props extends BrokerMetrics {
|
||||
clusterId: string;
|
||||
isFetched: boolean;
|
||||
minDiskUsage: number;
|
||||
maxDiskUsage: number;
|
||||
fetchBrokers: (clusterId: ClusterId) => void;
|
||||
fetchBrokerMetrics: (clusterId: ClusterId) => void;
|
||||
}
|
||||
|
@ -13,6 +17,17 @@ interface Props {
|
|||
const Topics: React.FC<Props> = ({
|
||||
clusterId,
|
||||
isFetched,
|
||||
brokerCount,
|
||||
activeControllers,
|
||||
zooKeeperStatus,
|
||||
onlinePartitionCount,
|
||||
offlinePartitionCount,
|
||||
underReplicatedPartitionCount,
|
||||
diskUsageDistribution,
|
||||
minDiskUsage,
|
||||
maxDiskUsage,
|
||||
networkPoolUsage,
|
||||
requestPoolUsage,
|
||||
fetchBrokers,
|
||||
fetchBrokerMetrics,
|
||||
}) => {
|
||||
|
@ -27,8 +42,129 @@ const Topics: React.FC<Props> = ({
|
|||
useInterval(() => { fetchBrokerMetrics(clusterId); }, 5000);
|
||||
|
||||
if (isFetched) {
|
||||
const [minDiskUsageValue, minDiskUsageSize] = formatBytes(minDiskUsage);
|
||||
const [maxDiskUsageValue, maxDiskUsageSize] = formatBytes(maxDiskUsage);
|
||||
|
||||
return (
|
||||
<div>Brokers of {clusterId}</div>
|
||||
<div className="section">
|
||||
<div className="box">
|
||||
<h5 className="title is-5">Uptime</h5>
|
||||
<div className="level">
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Total Brokers</p>
|
||||
<p className="title">{brokerCount}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Active Controllers</p>
|
||||
<p className="title">{activeControllers}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Zookeeper Status</p>
|
||||
<p className="title">
|
||||
{zooKeeperStatus === ZooKeeperStatus.online ? (
|
||||
<span className="tag is-primary">Online</span>
|
||||
) : (
|
||||
<span className="tag is-danger">Offline</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="box">
|
||||
<h5 className="title is-5">Partitions</h5>
|
||||
<div className="level">
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Online</p>
|
||||
<p>
|
||||
<span className={cx('title', {'has-text-danger': offlinePartitionCount !== 0})}>
|
||||
{onlinePartitionCount}
|
||||
</span>
|
||||
<span className="subtitle"> of {onlinePartitionCount + offlinePartitionCount}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Under Replicated</p>
|
||||
<p className="title">{underReplicatedPartitionCount}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">In Sync Replicas</p>
|
||||
<p className="title has-text-grey-lighter">Soon</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Out of Sync Replicas</p>
|
||||
<p className="title has-text-grey-lighter">Soon</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="box">
|
||||
<h5 className="title is-5">Disk</h5>
|
||||
<div className="level">
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Max usage</p>
|
||||
<p>
|
||||
<span className="title">{maxDiskUsageValue}</span>
|
||||
<span className="subtitle"> {maxDiskUsageSize}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Min Usage</p>
|
||||
<p>
|
||||
<span className="title">{minDiskUsageValue}</span>
|
||||
<span className="subtitle"> {minDiskUsageSize}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Distribution</p>
|
||||
<p className="title">{diskUsageDistribution}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="box">
|
||||
<h5 className="title is-5">System</h5>
|
||||
<div className="level">
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Network pool usage</p>
|
||||
<p className="title">
|
||||
{Math.round(networkPoolUsage * 10000) / 100}
|
||||
<span className="subtitle">%</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item level-left">
|
||||
<div>
|
||||
<p className="heading">Request pool usage</p>
|
||||
<p className="title">
|
||||
{Math.round(requestPoolUsage * 10000) / 100}
|
||||
<span className="subtitle">%</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
fetchBrokerMetrics,
|
||||
} from 'redux/reducers/brokers/thunks';
|
||||
import Brokers from './Brokers';
|
||||
import { getIsBrokerListFetched } from 'redux/reducers/brokers/selectors';
|
||||
import * as brokerSelectors from 'redux/reducers/brokers/selectors';
|
||||
import { RootState, ClusterId } from 'types';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
|
@ -15,8 +15,19 @@ interface RouteProps {
|
|||
interface OwnProps extends RouteComponentProps<RouteProps> { }
|
||||
|
||||
const mapStateToProps = (state: RootState, { match: { params: { clusterId } }}: OwnProps) => ({
|
||||
isFetched: getIsBrokerListFetched(state),
|
||||
isFetched: brokerSelectors.getIsBrokerListFetched(state),
|
||||
clusterId,
|
||||
brokerCount: brokerSelectors.getBrokerCount(state),
|
||||
zooKeeperStatus: brokerSelectors.getZooKeeperStatus(state),
|
||||
activeControllers: brokerSelectors.getActiveControllers(state),
|
||||
networkPoolUsage: brokerSelectors.getNetworkPoolUsage(state),
|
||||
requestPoolUsage: brokerSelectors.getRequestPoolUsage(state),
|
||||
onlinePartitionCount: brokerSelectors.getOnlinePartitionCount(state),
|
||||
offlinePartitionCount: brokerSelectors.getOfflinePartitionCount(state),
|
||||
underReplicatedPartitionCount: brokerSelectors.getUnderReplicatedPartitionCount(state),
|
||||
diskUsageDistribution: brokerSelectors.getDiskUsageDistribution(state),
|
||||
minDiskUsage: brokerSelectors.getMinDiskUsage(state),
|
||||
maxDiskUsage: brokerSelectors.getMaxDiskUsage(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
|
|
|
@ -18,7 +18,6 @@ const List: React.FC<Props> = ({
|
|||
const items = showInternal ? topics : externalTopics;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="section">
|
||||
<div className="box">
|
||||
<div className="field">
|
||||
|
@ -55,7 +54,6 @@ const List: React.FC<Props> = ({
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
BASE_PARAMS,
|
||||
} from 'lib/constants';
|
||||
|
||||
export const getBrokers = (clusterId: ClusterId): Promise<{ brokers: Broker[] }> =>
|
||||
export const getBrokers = (clusterId: ClusterId): Promise<Broker[]> =>
|
||||
fetch(`${BASE_URL}/clusters/${clusterId}/brokers`, { ...BASE_PARAMS })
|
||||
.then(res => res.json());
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ export const initialState: BrokersState = {
|
|||
networkPoolUsage: 0,
|
||||
requestPoolUsage: 0,
|
||||
onlinePartitionCount: 0,
|
||||
underReplicatedPartitionCount: 0,
|
||||
offlinePartitionCount: 0,
|
||||
underReplicatedPartitionCount: 0,
|
||||
diskUsageDistribution: undefined,
|
||||
};
|
||||
|
||||
|
|
|
@ -13,8 +13,22 @@ export const getIsBrokerListFetched = createSelector(
|
|||
|
||||
const getBrokerList = createSelector(brokersState, ({ items }) => items);
|
||||
|
||||
export const getTotalBrokers = createSelector(
|
||||
getIsBrokerListFetched,
|
||||
export const getBrokerCount = createSelector(brokersState, ({ brokerCount }) => brokerCount);
|
||||
export const getZooKeeperStatus = createSelector(brokersState, ({ zooKeeperStatus }) => zooKeeperStatus);
|
||||
export const getActiveControllers = createSelector(brokersState, ({ activeControllers }) => activeControllers);
|
||||
export const getNetworkPoolUsage = createSelector(brokersState, ({ networkPoolUsage }) => networkPoolUsage);
|
||||
export const getRequestPoolUsage = createSelector(brokersState, ({ requestPoolUsage }) => requestPoolUsage);
|
||||
export const getOnlinePartitionCount = createSelector(brokersState, ({ onlinePartitionCount }) => onlinePartitionCount);
|
||||
export const getOfflinePartitionCount = createSelector(brokersState, ({ offlinePartitionCount }) => offlinePartitionCount);
|
||||
export const getDiskUsageDistribution = createSelector(brokersState, ({ diskUsageDistribution }) => diskUsageDistribution);
|
||||
export const getUnderReplicatedPartitionCount = createSelector(brokersState, ({ underReplicatedPartitionCount }) => underReplicatedPartitionCount);
|
||||
|
||||
export const getMinDiskUsage = createSelector(
|
||||
getBrokerList,
|
||||
(isFetched, brokers) => (isFetched && brokers !== undefined ? brokers.length : undefined),
|
||||
(brokers) => Math.min(...brokers.map(({ segmentSize }) => segmentSize)),
|
||||
);
|
||||
|
||||
export const getMaxDiskUsage = createSelector(
|
||||
getBrokerList,
|
||||
(brokers) => Math.max(...brokers.map(({ segmentSize }) => segmentSize)),
|
||||
);
|
||||
|
|
|
@ -9,8 +9,8 @@ import { PromiseThunk, ClusterId } from 'types';
|
|||
export const fetchBrokers = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => {
|
||||
dispatch(fetchBrokersAction.request());
|
||||
try {
|
||||
const { brokers } = await getBrokers(clusterId);
|
||||
dispatch(fetchBrokersAction.success(brokers));
|
||||
const payload = await getBrokers(clusterId);
|
||||
dispatch(fetchBrokersAction.success(payload));
|
||||
} catch (e) {
|
||||
dispatch(fetchBrokersAction.failure());
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface Broker {
|
|||
bytesOutPerSec: number;
|
||||
};
|
||||
|
||||
export enum ZooKeeperStatus { online, offline };
|
||||
export enum ZooKeeperStatus { offline, online };
|
||||
|
||||
export interface BrokerDiskUsage {
|
||||
brokerId: BrokerId;
|
||||
|
@ -22,8 +22,8 @@ export interface BrokerMetrics {
|
|||
networkPoolUsage: number;
|
||||
requestPoolUsage: number;
|
||||
onlinePartitionCount: number;
|
||||
underReplicatedPartitionCount: number;
|
||||
offlinePartitionCount: number;
|
||||
underReplicatedPartitionCount: number;
|
||||
diskUsageDistribution?: string;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue