This is an automated email from the ASF dual-hosted git repository.
arafat2198 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 b891f7c295 HDDS-10517. Recon - Add a UI component for showing DN
decommissioning detailed status and info (#6724)
b891f7c295 is described below
commit b891f7c29513280e1e9f32af89ac4d1caa84aaa0
Author: Smita <[email protected]>
AuthorDate: Wed Aug 7 11:54:44 2024 +0530
HDDS-10517. Recon - Add a UI component for showing DN decommissioning
detailed status and info (#6724)
---
.../webapps/recon/ozone-recon-web/api/db.json | 199 ++++++++++++++++++++-
.../webapps/recon/ozone-recon-web/api/routes.json | 2 +
.../src/components/overviewCard/overviewCard.tsx | 6 +-
.../src/views/datanodes/datanodes.tsx | 81 +++++++--
.../src/views/datanodes/decommissionSummary.tsx | 121 +++++++++++++
.../src/views/overview/overview.tsx | 32 +++-
6 files changed, 414 insertions(+), 27 deletions(-)
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 12b4297fec..5416ca7f00 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
@@ -94,7 +94,7 @@
},
{
"hostname": "localhost1.storage.enterprise.com",
- "uuid": "b5907812-a5f2-11ea-bb37-0242ac130011",
+ "uuid": "4712ba3d-4bb2-477a-9211-d9b50c013055",
"state": "HEALTHY",
"opState": "DECOMMISSIONING",
"lastHeartbeat": 1574724876059,
@@ -162,7 +162,7 @@
},
{
"hostname": "localhost3.storage.enterprise.com",
- "uuid": "b5907812-a5f2-11ea-bb37-0242ac130013",
+ "uuid": "4712ba3d-4bb2-477a-9211-d9b50c013056",
"state": "HEALTHY",
"opState": "ENTERING_MAINTENANCE",
"lastHeartbeat": 1574724876059,
@@ -6747,6 +6747,201 @@
],
"status": "OK"
},
+ "decommissioninfo": {
+ "DatanodesDecommissionInfo":[
+ {
+ "datanodeDetails": {
+ "level": 3,
+ "parent": null,
+ "cost": 0,
+ "uuid": "4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "uuidString": "4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "ipAddress": "172.18.0.13",
+ "hostName": "ozone-ha-datanode-6.ozone-ha_default",
+
+ "certSerialId": null,
+ "version": null,
+ "setupTime": 0,
+ "revision": null,
+ "buildDate": null,
+ "persistedOpState": "IN_SERVICE",
+ "persistedOpStateExpiryEpochSec": 0,
+ "initialVersion": 0,
+ "currentVersion": 1,
+ "decommissioned": false,
+ "maintenance": false,
+ "ipAddressAsByteString": {
+ "string": "172.18.0.13",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ },
+ "hostNameAsByteString": {
+ "string": "ozone-ha-datanode-6.ozone-ha_default",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ },
+ "networkName": "4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "networkLocation": "/default-rack",
+ "networkFullPath":
"/default-rack/4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "numOfLeaves": 1,
+ "networkNameAsByteString": {
+ "string": "4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ },
+ "networkLocationAsByteString": {
+ "string": "/default-rack",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ }
+ },
+ "metrics": null,
+ "containers": {}
+ },
+ {
+ "datanodeDetails": {
+ "level": 3,
+ "parent": null,
+ "cost": 0,
+ "uuid": "4712ba3d-4bb2-477a-9211-d9b50c013056",
+ "uuidString": "4712ba3d-4bb2-477a-9211-d9b50c013056",
+ "ipAddress": "172.18.0.13",
+ "hostName": "ozone-ha-datanode-6.ozone-ha_default",
+ "certSerialId": null,
+ "version": null,
+ "setupTime": 0,
+ "revision": null,
+ "buildDate": null,
+ "persistedOpState": "IN_SERVICE",
+ "persistedOpStateExpiryEpochSec": 0,
+ "initialVersion": 0,
+ "currentVersion": 1,
+ "decommissioned": false,
+ "maintenance": false,
+ "networkName": "4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "networkLocation": "/default-rack",
+ "networkFullPath":
"/default-rack/4712ba3d-4bb2-477a-9211-d9b50c013055",
+ "numOfLeaves": 1
+ },
+ "metrics": null,
+ "containers": {}
+ }
+ ]
+ },
+ "DatanodesDecommissionInfo": {
+ "DatanodesDecommissionInfo": [
+ {
+ "datanodeDetails": {
+ "level": 3,
+ "parent": null,
+ "cost": 0,
+ "uuid": "adc72ef9-0850-49d7-935d-e5a4e0d5be3c",
+ "uuidString": "adc72ef9-0850-49d7-935d-e5a4e0d5be3c",
+ "ipAddress": "172.18.0.10",
+ "hostName": "ozone-ha-datanode-2.ozone-ha_default",
+ "ports": [
+ {
+ "name": "HTTP",
+ "value": 9882
+ },
+ {
+ "name": "CLIENT_RPC",
+ "value": 19864
+ },
+ {
+ "name": "REPLICATION",
+ "value": 9886
+ },
+ {
+ "name": "RATIS",
+ "value": 9858
+ },
+ {
+ "name": "RATIS_ADMIN",
+ "value": 9857
+ },
+ {
+ "name": "RATIS_SERVER",
+ "value": 9856
+ },
+ {
+ "name": "RATIS_DATASTREAM",
+ "value": 9855
+ },
+ {
+ "name": "STANDALONE",
+ "value": 9859
+ }
+ ],
+ "certSerialId": null,
+ "version": null,
+ "setupTime": 0,
+ "revision": null,
+ "buildDate": null,
+ "persistedOpState": "DECOMMISSIONING",
+ "persistedOpStateExpiryEpochSec": 0,
+ "initialVersion": 0,
+ "currentVersion": 1,
+ "decommissioned": true,
+ "maintenance": false,
+ "ipAddressAsByteString": {
+ "string": "172.18.0.10",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ },
+ "hostNameAsByteString": {
+ "string": "ozone-ha-datanode-2.ozone-ha_default",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ },
+ "networkName": "adc72ef9-0850-49d7-935d-e5a4e0d5be3c",
+ "networkLocation": "/default-rack",
+ "networkFullPath":
"/default-rack/adc72ef9-0850-49d7-935d-e5a4e0d5be3c",
+ "numOfLeaves": 1,
+ "networkNameAsByteString": {
+ "string": "adc72ef9-0850-49d7-935d-e5a4e0d5be3c",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ },
+ "networkLocationAsByteString": {
+ "string": "/default-rack",
+ "bytes": {
+ "validUtf8": true,
+ "empty": false
+ }
+ }
+ },
+ "metrics": {
+ "decommissionStartTime": "23/05/2024 07:28:35 UTC",
+ "numOfUnclosedPipelines": 2,
+ "numOfUnderReplicatedContainers": 0.0,
+ "numOfUnclosedContainers": 0.0
+ },
+ "containers": {
+ "UnderReplicated": [],
+ "UnClosed": [
+ "#6",
+ "#10",
+ "#17"
+ ]
+ }
+ }
+ ]
+ },
"datanodesRemove": {
"selectedRowKeys": [
"b5907812-a5f2-11ea-bb37-0242ac130011"
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 7f3c86684b..e094f2b6ea 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
@@ -51,5 +51,7 @@
"/containers/mismatch/deleted?limit=*": "/deleted",
"/keys/deletePending/dirs?limit=*": "/dirdeletePending",
+ "/datanodes/decommission/info": "/decommissioninfo",
+ "/datanodes/decommission/info/datanode?uuid=*": "/DatanodesDecommissionInfo",
"/datanodes/remove": "/datanodesRemove"
}
\ No newline at end of file
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
index 78ba56e548..c8e19db14c 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
@@ -27,7 +27,8 @@ import {
FolderOpenOutlined,
FileTextOutlined,
QuestionCircleOutlined,
- DeleteOutlined
+ DeleteOutlined,
+ HourglassOutlined
} from '@ant-design/icons';
import { RouteComponentProps } from 'react-router';
import { withRouter, Link } from 'react-router-dom';
@@ -70,7 +71,8 @@ const IconSelector = ({ iconType, ...extras }: { iconType:
string }) => {
'inbox': <InboxOutlined {...extras} />,
'folder-open': <FolderOpenOutlined {...extras} />,
'file-text': <FileTextOutlined {...extras} />,
- 'delete': <DeleteOutlined {...extras} />
+ 'delete': <DeleteOutlined {...extras} />,
+ 'hourglass': <HourglassOutlined {...extras} />
}
const selectIcon = (type: string) => {
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/datanodes.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/datanodes.tsx
index c4c9bf129c..47fe41dd7b 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/datanodes.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/datanodes.tsx
@@ -48,10 +48,10 @@ import { ColumnSearch } from '@/utils/columnSearch';
import { ReplicationIcon } from '@/utils/themeIcons';
import { AutoReloadHelper } from '@/utils/autoReloadHelper';
import { AxiosGetHelper, AxiosPutHelper } from '@/utils/axiosRequestHelper';
+import DecommissionSummary from './decommissionSummary';
import './datanodes.less';
-
interface IDatanodeResponse {
hostname: string;
state: DatanodeState;
@@ -190,7 +190,6 @@ const COLUMNS = [
render: (text: DatanodeOpState) => renderDatanodeOpState(text),
sorter: (a: IDatanode, b: IDatanode) => a.opState.localeCompare(b.opState)
},
-
{
title: 'Uuid',
dataIndex: 'uuid',
@@ -198,7 +197,14 @@ const COLUMNS = [
isVisible: true,
isSearchable: true,
sorter: (a: IDatanode, b: IDatanode) => a.uuid.localeCompare(b.uuid),
- defaultSortOrder: 'ascend' as const
+ defaultSortOrder: 'ascend' as const,
+ render: (uuid: IDatanode, record: IDatanode) => {
+ return (
+ //1. Compare Decommission Api's UUID with all UUID in table and show
Decommission Summary
+ (decommissionUuids && decommissionUuids.includes(record.uuid) &&
record.opState !== 'DECOMMISSIONED') ?
+ <DecommissionSummary uuid={uuid} record={record} /> :
<span>{uuid}</span>
+ );
+ }
},
{
title: 'Storage Capacity',
@@ -356,6 +362,17 @@ const defaultColumns: IOption[] = COLUMNS.map(column => ({
}));
let cancelSignal: AbortController;
+let cancelDecommissionSignal: AbortController;
+let decommissionUuids: string | string[] =[];
+const COLUMN_UPDATE_DECOMMISSIONING = 'DECOMMISSIONING';
+
+type DatanodeDetails = {
+ uuid: string;
+}
+
+type DatanodeDecomissionInfo = {
+datanodeDetails: DatanodeDetails
+}
export class Datanodes extends React.Component<Record<string, object>,
IDatanodesState> {
autoReload: AutoReloadHelper;
@@ -389,24 +406,34 @@ export class Datanodes extends
React.Component<Record<string, object>, IDatanode
return selectedColumns;
};
- _loadData = () => {
- this.setState(prevState => ({
- loading: true,
- selectedColumns: this._getSelectedColumns(prevState.selectedColumns)
- }));
-
- const { request, controller } = AxiosGetHelper('/api/v1/datanodes',
cancelSignal);
- cancelSignal = controller;
- request.then(response => {
- const datanodesResponse: IDatanodesResponse = response.data;
+ _loadData = async () => {
+ // Need to call decommission API on each interval to get updated status
before datanode API to compare UUID's
+ // update Operation State Column in table Manually before rendering
+ try {
+ let decomissionResponse = await this._loadDecommisionAPI();
+ decommissionUuids =
decomissionResponse.data?.DatanodesDecommissionInfo?.map((item:
DatanodeDecomissionInfo) => item.datanodeDetails.uuid);
+ }
+ catch (error: any)
+ {
+ this.setState({
+ loading: false
+ });
+ decommissionUuids = [];
+ showDataFetchError(error.toString());
+ }
+ try {
+ // Call Datanode API Synchronously after completing Decommission API to
render Operation Status Column
+ let datanodeApiResponse = await this._loadDataNodeAPI();
+ const datanodesResponse: IDatanodesResponse = datanodeApiResponse.data;
const totalCount = datanodesResponse.totalCount;
const datanodes: IDatanodeResponse[] = datanodesResponse.datanodes;
const dataSource: IDatanode[] = datanodes && datanodes.map(datanode => {
+ let decommissionCondition = decommissionUuids &&
decommissionUuids.includes(datanode.uuid) && datanode.opState !==
'DECOMMISSIONED';
return {
hostname: datanode.hostname,
uuid: datanode.uuid,
state: datanode.state,
- opState: datanode.opState,
+ opState: decommissionCondition ? COLUMN_UPDATE_DECOMMISSIONING :
datanode.opState,
lastHeartbeat: datanode.lastHeartbeat,
storageUsed: datanode.storageReport.used,
storageTotal: datanode.storageReport.capacity,
@@ -423,19 +450,40 @@ export class Datanodes extends
React.Component<Record<string, object>, IDatanode
networkLocation: datanode.networkLocation
};
});
-
this.setState({
loading: false,
dataSource,
totalCount,
lastUpdated: Number(moment())
});
- }).catch(error => {
+ }
+ catch (error: any) {
this.setState({
loading: false
});
+ decommissionUuids = [];
showDataFetchError(error.toString());
+ }
+ };
+
+ _loadDecommisionAPI = async () => {
+ this.setState({
+ loading: true
});
+ decommissionUuids = [];
+ const { request, controller } = await
AxiosGetHelper('/api/v1/datanodes/decommission/info', cancelDecommissionSignal);
+ cancelDecommissionSignal = controller;
+ return request
+ };
+
+ _loadDataNodeAPI = async () => {
+ this.setState(prevState => ({
+ loading: true,
+ selectedColumns: this._getSelectedColumns(prevState.selectedColumns)
+ }));
+ const { request, controller } = await AxiosGetHelper('/api/v1/datanodes',
cancelSignal);
+ cancelSignal = controller;
+ return request;
};
removeDatanode = async (selectedRowKeys: any) => {
@@ -462,6 +510,7 @@ export class Datanodes extends
React.Component<Record<string, object>, IDatanode
componentWillUnmount(): void {
this.autoReload.stopPolling();
cancelSignal && cancelSignal.abort();
+ cancelDecommissionSignal && cancelDecommissionSignal.abort();
}
onShowSizeChange = (current: number, pageSize: number) => {
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/decommissionSummary.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/decommissionSummary.tsx
new file mode 100644
index 0000000000..28527c0816
--- /dev/null
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/datanodes/decommissionSummary.tsx
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { Descriptions, Popover, Tooltip } from 'antd';
+import { InfoCircleOutlined } from '@ant-design/icons';
+import { withRouter } from 'react-router-dom';
+import { RouteComponentProps } from 'react-router';
+import axios from 'axios';
+import { showDataFetchError } from '@/utils/common';
+
+interface IDecommissionSummaryProps extends RouteComponentProps<object> {
+ uuid: string;
+ isLoading: boolean;
+ summaryData: string[];
+ record: string[];
+}
+
+class DecommissionSummary extends React.Component<IDecommissionSummaryProps> {
+ constructor(props = {}) {
+ super(props);
+ this.state = {
+ uuid: this.props.uuid,
+ record: this.props.record,
+ isLoading: false,
+ summaryData: []
+ };
+ }
+
+ componentDidMount(): void {
+ this.setState({
+ isLoading: true
+ });
+ if (this.state?.record && this.state?.summaryData) {
+ this.fetchDecommissionSummary(this.state.uuid);
+ }
+ }
+
+ fetchDecommissionSummary = async (selectedUuid: any) => {
+ try {
+ const datanodeEndpoint =
`/api/v1/datanodes/decommission/info/datanode?uuid=${selectedUuid}`;
+ let infoDatanodeResponse = await axios.get(datanodeEndpoint);
+ let DatanodesDecommissionInfo = [];
+ DatanodesDecommissionInfo =
infoDatanodeResponse?.data?.DatanodesDecommissionInfo[0];
+ this.setState({
+ loading: false,
+ summaryData: DatanodesDecommissionInfo
+ });
+ }
+ catch (error) {
+ this.setState({
+ loading: false,
+ summaryData: []
+ });
+ showDataFetchError(error.toString());
+ }
+ };
+
+ render() {
+ const { summaryData, uuid } = this.state;
+ let content;
+
+ if ( summaryData && summaryData.length !== 0 && summaryData !== null &&
summaryData !== undefined && summaryData.datanodeDetails) {
+ const { datanodeDetails, containers, metrics } = summaryData;
+ content = (
+ <Descriptions size="small" bordered column={1} title={`Decommission
Status: DECOMMISSIONING`}>
+ <Descriptions.Item label="Datanode">
<b>{datanodeDetails.uuid}</b></Descriptions.Item>
+ <Descriptions.Item
label="Location">({datanodeDetails.networkLocation}/{datanodeDetails.ipAddress}/{datanodeDetails.hostname})</Descriptions.Item>
+ {metrics !== null && metrics !== undefined &&
Object.keys(metrics).length !== 0 &&
+ <>
+ {<Descriptions.Item label="Decommissioning Started
at">{metrics.decommissionStartTime}</Descriptions.Item>}
+ {<Descriptions.Item label="No. of Unclosed
Pipelines">{metrics.numOfUnclosedPipelines}</Descriptions.Item>}
+ {<Descriptions.Item label="No. of Unclosed
Containers">{metrics.numOfUnclosedContainers}</Descriptions.Item>}
+ {<Descriptions.Item label="No. of Under-Replicated
Containers">{metrics.numOfUnderReplicatedContainers}</Descriptions.Item>}
+ </>
+ }
+ {
+ containers && Object.keys(containers).length !== 0 &&
+ <>
+ {containers.UnderReplicated && containers.UnderReplicated.length
> 0 && <Descriptions.Item
label="Under-Replicated">{containers.UnderReplicated}</Descriptions.Item>}
+ {containers.UnClosed && containers.UnClosed.length > 0 &&
<Descriptions.Item label="Unclosed">{containers.UnClosed}</Descriptions.Item>}
+ </>
+ }
+ </Descriptions>
+ );
+ }
+ // Need to check summarydata is not empty
+ return (
+ <>
+ { (summaryData && summaryData.length !== 0) ?
+ <>
+ <Tooltip title="Detailed Summary of Decomssioned Records.">
+ <InfoCircleOutlined />
+ </Tooltip>
+ <Popover content={content} placement="top" trigger="hover">
+ {uuid}
+ </Popover>
+ </> : uuid
+ }
+ </>
+
+ );
+ }
+}
+
+export default withRouter(DecommissionSummary);
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
index bb2e5e02f2..a83d12408b 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
@@ -73,6 +73,7 @@ interface IOverviewState {
deletePendingSummarytotalUnrepSize: number | string;
deletePendingSummarytotalRepSize: number | string;
deletePendingSummarytotalDeletedKeys: number | string;
+ decommissionInfoCount: number | string;
scmServiceId: string;
omServiceId: string;
}
@@ -111,7 +112,8 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
openSummarytotalOpenKeys: 0,
deletePendingSummarytotalUnrepSize: 0,
deletePendingSummarytotalRepSize: 0,
- deletePendingSummarytotalDeletedKeys: 0
+ deletePendingSummarytotalDeletedKeys: 0,
+ decommissionInfoCount: 0
};
this.autoReload = new AutoReloadHelper(this._loadData);
}
@@ -131,7 +133,8 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
'/api/v1/clusterState',
'/api/v1/task/status',
'/api/v1/keys/open/summary',
- '/api/v1/keys/deletePending/summary'
+ '/api/v1/keys/deletePending/summary',
+ '/api/v1/datanodes/decommission/info'
], cancelOverviewSignal);
cancelOverviewSignal = controller;
@@ -139,13 +142,15 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
clusterStateResponse: Awaited<Promise<any>>,
taskstatusResponse: Awaited<Promise<any>>,
openResponse: Awaited<Promise<any>>,
- deletePendingResponse: Awaited<Promise<any>>
+ deletePendingResponse: Awaited<Promise<any>>,
+ decommissionResponse: Awaited<Promise<any>>
) => {
let responseError = [
clusterStateResponse,
taskstatusResponse,
openResponse,
- deletePendingResponse
+ deletePendingResponse,
+ decommissionResponse
].filter((resp) => resp.status === 'rejected');
if (responseError.length !== 0) {
@@ -186,8 +191,8 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
taskName: 'N/A', lastUpdatedTimestamp: 0, lastUpdatedSeqNumber: 0
}];
const missingContainersCount = clusterState.missingContainers;
- const omDBDeltaObject = taskStatus && taskStatus.find((item: any) =>
item.taskName === 'OmDeltaRequest');
- const omDBFullObject = taskStatus && taskStatus.find((item: any) =>
item.taskName === 'OmSnapshotRequest');
+ const omDBDeltaObject = taskStatus && taskStatus.find((item:any) =>
item.taskName === 'OmDeltaRequest');
+ const omDBFullObject = taskStatus && taskStatus.find((item:any) =>
item.taskName === 'OmSnapshotRequest');
this.setState({
loading: false,
@@ -212,6 +217,7 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
deletePendingSummarytotalUnrepSize:
deletePendingResponse.value?.data?.totalUnreplicatedDataSize,
deletePendingSummarytotalRepSize:
deletePendingResponse.value?.data?.totalReplicatedDataSize,
deletePendingSummarytotalDeletedKeys:
deletePendingResponse.value?.data?.totalDeletedKeys,
+ decommissionInfoCount:
decommissionResponse.value?.data?.DatanodesDecommissionInfo.length,
scmServiceId: clusterState.scmServiceId,
omServiceId: clusterState.omServiceId
});
@@ -267,10 +273,12 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
const { loading, datanodes, pipelines, storageReport, containers, volumes,
buckets, openSummarytotalUnrepSize, openSummarytotalRepSize,
openSummarytotalOpenKeys,
deletePendingSummarytotalUnrepSize, deletePendingSummarytotalRepSize,
deletePendingSummarytotalDeletedKeys,
keys, missingContainersCount, lastRefreshed, lastUpdatedOMDBDelta,
lastUpdatedOMDBFull,
- omStatus, openContainers, deletedContainers, scmServiceId, omServiceId }
= this.state;
+ omStatus, openContainers, deletedContainers, scmServiceId, omServiceId,
decommissionInfoCount } = this.state;
let openKeysError: boolean = false;
let pendingDeleteKeysError: boolean = false;
+ let decommissionInfoError: boolean = false;
+
if ([
openSummarytotalRepSize,
openSummarytotalUnrepSize,
@@ -280,6 +288,12 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
openKeysError = true;
}
+ if ([decommissionInfoCount].some(
+ (data) => data === undefined
+ )) {
+ decommissionInfoError = true;
+ }
+
if ([
deletePendingSummarytotalRepSize,
deletePendingSummarytotalUnrepSize,
@@ -427,6 +441,10 @@ export class Overview extends
React.Component<Record<string, object>, IOverviewS
<OverviewCard title="OM Service" loading={loading}
data={omServiceId} icon='file-text' linkToUrl='/Om' />
</Col>
}
+ <Col xs={24} sm={18} md={12} lg={12} xl={6}>
+ <OverviewCard loading={loading} title='Decommissioning Datanodes
Summary' data={decommissionInfoCount !== undefined ?
decommissionInfoCount.toString() : 'NA'} icon='hourglass'
+ linkToUrl='/Datanodes' error={decommissionInfoError} />
+ </Col>
</Row>
</div>
);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]