This is an automated email from the ASF dual-hosted git repository.
siyao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new ae59f8ae5f HDDS-7248. Recon: Expand the container status page to show
all unhealthy container states (#3837)
ae59f8ae5f is described below
commit ae59f8ae5f2149ba1a7749bd3073803345333742
Author: smitajoshi12 <[email protected]>
AuthorDate: Fri Oct 21 12:41:45 2022 +0530
HDDS-7248. Recon: Expand the container status page to show all unhealthy
container states (#3837)
---
.../hadoop/ozone/recon/api/ContainerEndpoint.java | 1 +
.../webapps/recon/ozone-recon-web/api/db.json | 330 ++++++++++++++++++++-
.../webapps/recon/ozone-recon-web/api/routes.json | 8 +-
.../src/components/navBar/navBar.tsx | 5 +
.../views/missingContainers/missingContainers.tsx | 227 +++++++++-----
5 files changed, 502 insertions(+), 69 deletions(-)
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
index 0832700e96..ce8cc70589 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
@@ -242,6 +242,7 @@ public class ContainerEndpoint {
*/
@GET
@Path("/missing")
+ @Deprecated
public Response getMissingContainers(
@DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
int limit
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
index 04036416f4..1639302e23 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
@@ -1260,5 +1260,333 @@
"lastUpdatedTimestamp": 1663421094507,
"lastUpdatedSeqNumber": 0
}
- ]
+ ],
+ "containerUnhealthyMissing": {
+ "missingCount": 0,
+ "underReplicatedCount": 1,
+ "overReplicatedCount": 0,
+ "misReplicatedCount": 0,
+ "containers": [
+ {
+ "containerID": 1,
+ "containerState": "MISSING",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 3,
+ "actualReplicaCount": 0,
+ "replicaDeltaCount": 3,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 2,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_missing1",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_missing2",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_missing3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ },
+ {
+ "containerID": 2,
+ "containerState": "MISSING",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 3,
+ "actualReplicaCount": 0,
+ "replicaDeltaCount": 3,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 3,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_missing1",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_missing2",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_missing3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ }
+ ]
+ },
+ "containerUnhealthyUnderReplicated": {
+ "missingCount": 0,
+ "underReplicatedCount": 1,
+ "overReplicatedCount": 0,
+ "misReplicatedCount": 0,
+ "containers": [
+ {
+ "containerID": 2,
+ "containerState": "UNDER_REPLICATED",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 3,
+ "actualReplicaCount": 2,
+ "replicaDeltaCount": 1,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 2,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_UnderReplicated2",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_underreplicated2",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_underreplicated2",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ },
+ {
+ "containerID": 3,
+ "containerState": "UNDER_REPLICATED",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 4,
+ "actualReplicaCount": 2,
+ "replicaDeltaCount": 2,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 3,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_underreplicated3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_underreplicated3",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_underreplicated3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ }
+ ]
+ },
+ "containerUnhealthyOverReplicated": {
+ "missingCount": 0,
+ "underReplicatedCount": 1,
+ "overReplicatedCount": 0,
+ "misReplicatedCount": 0,
+ "containers": [
+ {
+ "containerID": 2,
+ "containerState": "OVER_REPLICATED",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 3,
+ "actualReplicaCount": 2,
+ "replicaDeltaCount": 1,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 2,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_overreplicated2",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_overreplicated22",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_overreplicated2",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ },
+ {
+ "containerID": 3,
+ "containerState": "OVER_REPLICATED",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 4,
+ "actualReplicaCount": 2,
+ "replicaDeltaCount": 2,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 3,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_overreplicated3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_overreplicated3",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_overreplicated3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ }
+ ]
+ },
+ "containerUnhealthyMisReplicated": {
+ "missingCount": 0,
+ "underReplicatedCount": 1,
+ "overReplicatedCount": 0,
+ "misReplicatedCount": 0,
+ "containers": [
+ {
+ "containerID": 2,
+ "containerState": "MIS_REPLICATED",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 3,
+ "actualReplicaCount": 2,
+ "replicaDeltaCount": 1,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 2,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_misreplicated2",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_misreplicated2",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 2,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_misreplicated2",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ },
+ {
+ "containerID": 3,
+ "containerState": "MIS_REPLICATED",
+ "unhealthySince": 1665590446222,
+ "expectedReplicaCount": 4,
+ "actualReplicaCount": 2,
+ "replicaDeltaCount": 2,
+ "reason": null,
+ "keys": 1,
+ "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+ "replicas": [
+ {
+ "containerId": 3,
+ "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+ "datanodeHost": "ozone_datanode_2.ozone_misreplicated3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590397315,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+ "datanodeHost": "ozone_datanode_3.ozone_misreplicated3",
+ "firstSeenTime": 1665588176616,
+ "lastSeenTime": 1665590392293,
+ "lastBcsId": 2
+ },
+ {
+ "containerId": 3,
+ "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+ "datanodeHost": "ozone_datanode_1.ozone_misreplicated3",
+ "firstSeenTime": 1665588176660,
+ "lastSeenTime": 1665590272289,
+ "lastBcsId": 0
+ }
+ ]
+ }
+ ]
+ }
}
\ No newline at end of file
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
index 4aa303fe29..0b0a4bb9d6 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
@@ -1,7 +1,6 @@
{
"/api/v1/*": "/$1",
"/containers/:id/keys": "/keys",
- "/containers/missing": "/missingContainers",
"/utilization/fileCount": "/fileSizeCounts",
"/namespace/du?path=/&files=true": "/root",
"/namespace/du?path=/vol:id&files=true": "/volume",
@@ -23,5 +22,10 @@
"/namespace/du?path=/clunky&files=true": "/clunky",
"/namespace/summary?path=*": "/metadata",
"/namespace/quota?path=*": "/quota",
- "/task/status": "/taskStatus"
+ "/task/status": "/taskStatus",
+ "/containers/missing": "/missingContainers",
+ "/containers/unhealthy/MISSING": "/containerUnhealthyMissing",
+ "/containers/unhealthy/UNDER_REPLICATED":
"/containerUnhealthyUnderReplicated",
+ "/containers/unhealthy/OVER_REPLICATED": "/containerUnhealthyOverReplicated",
+ "/containers/unhealthy/MIS_REPLICATED": "/containerUnhealthyMisReplicated"
}
\ No newline at end of file
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
index acc0550404..d381e8e4d4 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
@@ -66,6 +66,11 @@ class NavBar extends React.Component<INavBarProps> {
<span>Pipelines</span>
<Link to='/Pipelines'/>
</Menu.Item>
+ <Menu.Item key='/Containers'>
+ <Icon type='container'/>
+ <span>Containers</span>
+ <Link to='/Containers'/>
+ </Menu.Item>
<Menu.Item key='/Insights'>
<Icon type='bar-chart'/>
<span>Insights</span>
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
index 6a6dca304d..c6a76b5b97 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
@@ -18,7 +18,7 @@
import React from 'react';
import axios from 'axios';
-import {Icon, Table, Tooltip} from 'antd';
+import {Icon, Table, Tooltip, Tabs} from 'antd';
import {PaginationConfig} from 'antd/lib/pagination';
import filesize from 'filesize';
import moment from 'moment';
@@ -26,6 +26,7 @@ import {showDataFetchError, timeFormat} from 'utils/common';
import './missingContainers.less';
const size = filesize.partial({standard: 'iec'});
+const {TabPane} = Tabs;
interface IMissingContainerResponse {
containerID: number;
@@ -35,6 +36,19 @@ interface IMissingContainerResponse {
pipelineID: string;
}
+interface IContainerResponse {
+ containerID: number;
+ containerState: string;
+ unhealthySince: string;
+ expectedReplicaCount: number;
+ actualReplicaCount: number;
+ replicaDeltaCount: number;
+ reason: string;
+ keys: number;
+ pipelineID: string;
+ replicas: IContainerReplicas[];
+}
+
export interface IContainerReplica {
containerId: number;
datanodeHost: string;
@@ -42,11 +56,28 @@ export interface IContainerReplica {
lastReportTimestamp: number;
}
+export interface IContainerReplicas {
+ containerId: number;
+ datanodeUuid: string;
+ datanodeHost: string;
+ firstSeenTime: number;
+ lastSeenTime: number;
+ lastBcsId: number;
+}
+
export interface IMissingContainersResponse {
totalCount: number;
containers: IMissingContainerResponse[];
}
+interface IUnhealthyContainersResponse {
+ missingCount: number;
+ underReplicatedCount: number;
+ overReplicatedCount: number;
+ misReplicatedCount: number;
+ containers: IContainerResponse[];
+}
+
interface IKeyResponse {
Volume: string;
Bucket: string;
@@ -63,30 +94,79 @@ interface IContainerKeysResponse {
keys: IKeyResponse[];
}
-const COLUMNS = [
+const KEY_TABLE_COLUMNS = [
+ {
+ title: 'Volume',
+ dataIndex: 'Volume',
+ key: 'Volume'
+ },
+ {
+ title: 'Bucket',
+ dataIndex: 'Bucket',
+ key: 'Bucket'
+ },
+ {
+ title: 'Key',
+ dataIndex: 'Key',
+ key: 'Key'
+ },
+ {
+ title: 'Size',
+ dataIndex: 'DataSize',
+ key: 'DataSize',
+ render: (dataSize: number) => <div>{size(dataSize)}</div>
+ },
+ {
+ title: 'Date Created',
+ dataIndex: 'CreationTime',
+ key: 'CreationTime',
+ render: (date: string) => moment(date).format('lll')
+ },
+ {
+ title: 'Date Modified',
+ dataIndex: 'ModificationTime',
+ key: 'ModificationTime',
+ render: (date: string) => moment(date).format('lll')
+ }
+];
+
+const CONTAINER_TAB_COLUMNS = [
{
title: 'Container ID',
dataIndex: 'containerID',
key: 'containerID',
- sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) =>
a.containerID - b.containerID
+ sorter: (a: IContainerResponse, b: IContainerResponse) => a.containerID -
b.containerID
},
{
title: 'No. of Keys',
dataIndex: 'keys',
key: 'keys',
- sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) =>
a.keys - b.keys
+ sorter: (a: IContainerResponse, b: IContainerResponse) => a.keys - b.keys
+ },
+ {
+ title: 'Active/Expected Replica(s)',
+ dataIndex: 'expectedReplicaCount',
+ key: 'expectedReplicaCount',
+ render: (expectedReplicaCount: number, record: IContainerResponse) => {
+ const actualReplicaCount = record.actualReplicaCount;
+ return (
+ <span>
+ {actualReplicaCount} / {expectedReplicaCount}
+ </span>
+ );
+ }
},
{
title: 'Datanodes',
dataIndex: 'replicas',
key: 'replicas',
- render: (replicas: IContainerReplica[]) => (
+ render: (replicas: IContainerReplicas[]) => (
<div>
- {replicas.map(replica => {
+ {replicas && replicas.map(replica => {
const tooltip = (
<div>
- <div>First Report Time:
{timeFormat(replica.firstReportTimestamp)}</div>
- <div>Last Report Time:
{timeFormat(replica.lastReportTimestamp)}</div>
+ <div>First Report Time: {timeFormat(replica.firstSeenTime)}</div>
+ <div>Last Report Time: {timeFormat(replica.lastSeenTime)}</div>
</div>
);
return (
@@ -111,50 +191,14 @@ const COLUMNS = [
title: 'Pipeline ID',
dataIndex: 'pipelineID',
key: 'pipelineID',
- sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) =>
a.pipelineID.localeCompare(b.pipelineID)
- },
- {
- title: 'Missing Since',
- dataIndex: 'missingSince',
- key: 'missingSince',
- render: (missingSince: number) => timeFormat(missingSince),
- sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) =>
a.missingSince - b.missingSince
- }
-];
-
-const KEY_TABLE_COLUMNS = [
- {
- title: 'Volume',
- dataIndex: 'Volume',
- key: 'Volume'
- },
- {
- title: 'Bucket',
- dataIndex: 'Bucket',
- key: 'Bucket'
- },
- {
- title: 'Key',
- dataIndex: 'Key',
- key: 'Key'
- },
- {
- title: 'Size',
- dataIndex: 'DataSize',
- key: 'DataSize',
- render: (dataSize: number) => <div>{size(dataSize)}</div>
+ sorter: (a: IContainerResponse, b: IContainerResponse) =>
a.pipelineID.localeCompare(b.pipelineID)
},
{
- title: 'Date Created',
- dataIndex: 'CreationTime',
- key: 'CreationTime',
- render: (date: string) => moment(date).format('lll')
- },
- {
- title: 'Date Modified',
- dataIndex: 'ModificationTime',
- key: 'ModificationTime',
- render: (date: string) => moment(date).format('lll')
+ title: 'Unhealthy Since',
+ dataIndex: 'unhealthySince',
+ key: 'unhealthySince',
+ render: (unhealthySince: number) => timeFormat(unhealthySince),
+ sorter: (a: IContainerResponse, b: IContainerResponse) => a.unhealthySince
- b.unhealthySince
}
];
@@ -171,7 +215,10 @@ interface IExpandedRowState {
interface IMissingContainersState {
loading: boolean;
- dataSource: IMissingContainerResponse[];
+ missingDataSource: IContainerResponse[];
+ underReplicatedDataSource: IContainerResponse[];
+ overReplicatedDataSource: IContainerResponse[];
+ misReplicatedDataSource: IContainerResponse[];
totalCount: number;
expandedRowData: IExpandedRow;
}
@@ -181,7 +228,10 @@ export class MissingContainers extends
React.Component<Record<string, object>, I
super(props);
this.state = {
loading: false,
- dataSource: [],
+ missingDataSource: [],
+ underReplicatedDataSource: [],
+ overReplicatedDataSource: [],
+ misReplicatedDataSource: [],
totalCount: 0,
expandedRowData: {}
};
@@ -192,16 +242,36 @@ export class MissingContainers extends
React.Component<Record<string, object>, I
this.setState({
loading: true
});
- axios.get('/api/v1/containers/missing').then(response => {
- const missingContainersResponse: IMissingContainersResponse =
response.data;
- const totalCount = missingContainersResponse.totalCount;
- const missingContainers: IMissingContainerResponse[] =
missingContainersResponse.containers;
+
+ axios.all([
+ axios.get('/api/v1/containers/unhealthy/MISSING'),
+ axios.get('/api/v1/containers/unhealthy/UNDER_REPLICATED'),
+ axios.get('/api/v1/containers/unhealthy/OVER_REPLICATED'),
+ axios.get('/api/v1/containers/unhealthy/MIS_REPLICATED')
+ ]).then(axios.spread((missingContainersResponse, underReplicatedResponse,
overReplicatedResponse, misReplicatedResponse, allReplicatedResponse) => {
+
+ const missingContainersResponseData: IUnhealthyContainersResponse =
missingContainersResponse.data;
+ const totalCount = missingContainersResponseData.missingCount;
+ const missingContainers: IContainerResponse[] =
missingContainersResponseData.containers;
+
+ const underReplicatedResponseData: IUnhealthyContainersResponse =
underReplicatedResponse.data;
+ const uContainers: IContainerResponse[] =
underReplicatedResponseData.containers;
+
+ const overReplicatedResponseData: IUnhealthyContainersResponse =
overReplicatedResponse.data;
+ const oContainers: IContainerResponse[] =
overReplicatedResponseData.containers;
+
+ const misReplicatedResponseData: IUnhealthyContainersResponse =
misReplicatedResponse.data;
+ const mContainers: IContainerResponse[] =
misReplicatedResponseData.containers;
+
this.setState({
loading: false,
- dataSource: missingContainers,
+ missingDataSource: missingContainers,
+ underReplicatedDataSource: uContainers,
+ overReplicatedDataSource: oContainers,
+ misReplicatedDataSource: mContainers,
totalCount
});
- }).catch(error => {
+ })).catch(error => {
this.setState({
loading: false
});
@@ -212,7 +282,7 @@ export class MissingContainers extends
React.Component<Record<string, object>, I
onShowSizeChange = (current: number, pageSize: number) => {
console.log(current, pageSize);
};
-
+
onRowExpandClick = (expanded: boolean, record: IMissingContainerResponse) =>
{
if (expanded) {
this.setState(({expandedRowData}) => {
@@ -270,7 +340,7 @@ export class MissingContainers extends
React.Component<Record<string, object>, I
};
render() {
- const {dataSource, loading, totalCount} = this.state;
+ const {missingDataSource, loading, underReplicatedDataSource,
overReplicatedDataSource, misReplicatedDataSource} = this.state;
const paginationConfig: PaginationConfig = {
showTotal: (total: number, range) => `${range[0]}-${range[1]} of
${total} missing containers`,
showSizeChanger: true,
@@ -279,14 +349,39 @@ export class MissingContainers extends
React.Component<Record<string, object>, I
return (
<div className='missing-containers-container'>
<div className='page-header'>
- Missing Containers ({totalCount})
+ Containers
</div>
<div className='content-div'>
- <Table
- expandRowByClick dataSource={dataSource} columns={COLUMNS}
- loading={loading}
- pagination={paginationConfig} rowKey='containerID'
- expandedRowRender={this.expandedRowRender}
onExpand={this.onRowExpandClick}/>
+ <Tabs defaultActiveKey='1'>
+ <TabPane key='1' tab="Missing">
+ <Table
+ expandRowByClick dataSource={missingDataSource}
columns={CONTAINER_TAB_COLUMNS}
+ loading={loading}
+ pagination={paginationConfig} rowKey='containerID'
+ expandedRowRender={this.expandedRowRender}
onExpand={this.onRowExpandClick}/>
+ </TabPane>
+ <TabPane key='2' tab='Under-Replicated'>
+ <Table
+ expandRowByClick dataSource={underReplicatedDataSource}
columns={CONTAINER_TAB_COLUMNS}
+ loading={loading}
+ pagination={paginationConfig} rowKey='containerID'
+ expandedRowRender={this.expandedRowRender}
onExpand={this.onRowExpandClick}/>
+ </TabPane>
+ <TabPane key='3' tab='Over-Replicated'>
+ <Table
+ expandRowByClick dataSource={overReplicatedDataSource}
columns={CONTAINER_TAB_COLUMNS}
+ loading={loading}
+ pagination={paginationConfig} rowKey='containerID'
+ expandedRowRender={this.expandedRowRender}
onExpand={this.onRowExpandClick}/>
+ </TabPane>
+ <TabPane key='4' tab='Mis-Replicated'>
+ <Table
+ expandRowByClick dataSource={misReplicatedDataSource}
columns={CONTAINER_TAB_COLUMNS}
+ loading={loading}
+ pagination={paginationConfig} rowKey='containerID'
+ expandedRowRender={this.expandedRowRender}
onExpand={this.onRowExpandClick}/>
+ </TabPane>
+ </Tabs>
</div>
</div>
);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]