This is an automated email from the ASF dual-hosted git repository.

erose 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 4cbf5ce0b8 HDDS-13101. Remove duplicate information in datanode list 
output (#8523)
4cbf5ce0b8 is described below

commit 4cbf5ce0b8f4bf4d25bc8444fd7c594615fdc1e5
Author: sreejasahithi <[email protected]>
AuthorDate: Thu Aug 7 20:54:35 2025 +0530

    HDDS-13101. Remove duplicate information in datanode list output (#8523)
---
 .../hdds/scm/cli/datanode/BasicDatanodeInfo.java   | 165 +++++++++++++++++++++
 .../hdds/scm/cli/datanode/ListInfoSubcommand.java  | 131 +++++-----------
 .../scm/cli/datanode/TestListInfoSubcommand.java   |   5 +-
 .../src/main/smoketest/admincli/datanode.robot     |   3 +-
 .../src/main/smoketest/balancer/testBalancer.robot |   2 +-
 5 files changed, 207 insertions(+), 99 deletions(-)

diff --git 
a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/BasicDatanodeInfo.java
 
b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/BasicDatanodeInfo.java
new file mode 100644
index 0000000000..4a925ffad5
--- /dev/null
+++ 
b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/BasicDatanodeInfo.java
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+package org.apache.hadoop.hdds.scm.cli.datanode;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+
+/**
+ * Represents filtered Datanode information for json use.
+ */
+public class BasicDatanodeInfo {
+  @JsonInclude(JsonInclude.Include.NON_NULL)
+  private Long used = null;
+  @JsonInclude(JsonInclude.Include.NON_NULL)
+  private Long capacity = null;
+  @JsonInclude(JsonInclude.Include.NON_NULL)
+  private Double percentUsed = null;
+  private final DatanodeDetails dn;
+  private final HddsProtos.NodeOperationalState opState;
+  private final HddsProtos.NodeState healthState;
+  
+  public BasicDatanodeInfo(DatanodeDetails dnDetails, 
HddsProtos.NodeOperationalState opState,
+      HddsProtos.NodeState healthState) {
+    this.dn = dnDetails;
+    this.opState = opState;
+    this.healthState = healthState;
+  }
+
+  public BasicDatanodeInfo(DatanodeDetails dnDetails, 
HddsProtos.NodeOperationalState opState,
+      HddsProtos.NodeState healthState, long used, long capacity, double 
percentUsed) {
+    this(dnDetails, opState, healthState);
+    this.used = used;
+    this.capacity = capacity;
+    this.percentUsed = percentUsed;
+  }
+  
+  @JsonProperty(index = 5)
+  public String getId() {
+    return dn.getUuidString();
+  }
+  
+  @JsonProperty(index = 10)
+  public String getHostName() {
+    return dn.getHostName();
+  }
+  
+  @JsonProperty(index = 15)
+  public String getIpAddress() {
+    return dn.getIpAddress();
+  }
+  
+  @JsonProperty(index = 20)
+  public List<DatanodeDetails.Port> getPorts() {
+    return dn.getPorts();
+  }
+
+  @JsonProperty(index = 25)
+  public long getSetupTime() {
+    return dn.getSetupTime();
+  }
+
+  @JsonProperty(index = 30)
+  public int getCurrentVersion() {
+    return dn.getCurrentVersion();
+  }
+
+  @JsonProperty(index = 35)
+  public HddsProtos.NodeOperationalState getOpState() {
+    return opState;
+  }
+
+  @JsonProperty(index = 40)
+  public HddsProtos.NodeOperationalState getPersistedOpState() {
+    return dn.getPersistedOpState();
+  }
+
+  @JsonProperty(index = 45)
+  public long getPersistedOpStateExpiryEpochSec() {
+    return dn.getPersistedOpStateExpiryEpochSec();
+  }
+  
+  @JsonProperty(index = 50)
+  public HddsProtos.NodeState getHealthState() {
+    return healthState;
+  }
+
+  @JsonProperty(index = 55)
+  public boolean isDecommissioned() {
+    return dn.isDecommissioned();
+  }
+  
+  @JsonProperty(index = 60)
+  public boolean isMaintenance() {
+    return dn.isMaintenance();
+  }
+  
+  @JsonProperty(index = 65)
+  public int getLevel() {
+    return dn.getLevel();
+  }
+  
+  @JsonProperty(index = 70)
+  public int getCost() {
+    return dn.getCost();
+  }
+  
+  @JsonProperty(index = 75)
+  public int getNumOfLeaves() {
+    return dn.getNumOfLeaves();
+  }
+  
+  @JsonProperty(index = 80)
+  public String getNetworkFullPath() {
+    return dn.getNetworkFullPath();
+  }
+  
+  @JsonProperty(index = 85)
+  public String getNetworkLocation() {
+    return dn.getNetworkLocation();
+  }
+  
+  @JsonProperty(index = 90)
+  public String getNetworkName() {
+    return dn.getNetworkName();
+  }
+  
+  @JsonProperty(index = 95)
+  public Long getUsed() {
+    return used;
+  }
+
+  @JsonProperty(index = 100)
+  public Long getCapacity() {
+    return capacity;
+  }
+
+  @JsonProperty(index = 105)
+  public Double getPercentUsed() {
+    return percentUsed;
+  }
+
+  @JsonIgnore
+  public DatanodeDetails getDatanodeDetails() {
+    return dn;
+  }
+}
diff --git 
a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/ListInfoSubcommand.java
 
b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/ListInfoSubcommand.java
index a30e91150e..49fb032d6c 100644
--- 
a/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/ListInfoSubcommand.java
+++ 
b/hadoop-ozone/cli-admin/src/main/java/org/apache/hadoop/hdds/scm/cli/datanode/ListInfoSubcommand.java
@@ -17,10 +17,10 @@
 
 package org.apache.hadoop.hdds.scm.cli.datanode;
 
-import com.fasterxml.jackson.annotation.JsonInclude;
 import com.google.common.base.Strings;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
@@ -88,26 +88,23 @@ public void execute(ScmClient scmClient) throws IOException 
{
     pipelines = scmClient.listPipelines();
     if (exclusiveNodeOptions != null && 
!Strings.isNullOrEmpty(exclusiveNodeOptions.getNodeId())) {
       HddsProtos.Node node = 
scmClient.queryNode(UUID.fromString(exclusiveNodeOptions.getNodeId()));
-      DatanodeWithAttributes dwa = new DatanodeWithAttributes(DatanodeDetails
-          .getFromProtoBuf(node.getNodeID()),
-          node.getNodeOperationalStates(0),
-          node.getNodeStates(0));
-      
+      BasicDatanodeInfo singleNodeInfo = new 
BasicDatanodeInfo(DatanodeDetails.getFromProtoBuf(node.getNodeID()),
+          node.getNodeOperationalStates(0), node.getNodeStates(0));
       if (json) {
-        List<DatanodeWithAttributes> singleList = 
Collections.singletonList(dwa);
-        
System.out.println(JsonUtils.toJsonStringWithDefaultPrettyPrinter(singleList));
+        List<BasicDatanodeInfo> dtoList = 
Collections.singletonList(singleNodeInfo);
+        
System.out.println(JsonUtils.toJsonStringWithDefaultPrettyPrinter(dtoList));
       } else {
-        printDatanodeInfo(dwa);
+        printDatanodeInfo(singleNodeInfo);
       }
       return;
     }
-    Stream<DatanodeWithAttributes> allNodes = getAllNodes(scmClient).stream();
+    Stream<BasicDatanodeInfo> allNodes = getAllNodes(scmClient).stream();
     if (exclusiveNodeOptions != null && 
!Strings.isNullOrEmpty(exclusiveNodeOptions.getIp())) {
-      allNodes = allNodes.filter(p -> p.getDatanodeDetails().getIpAddress()
+      allNodes = allNodes.filter(p -> p.getIpAddress()
           .compareToIgnoreCase(exclusiveNodeOptions.getIp()) == 0);
     }
     if (exclusiveNodeOptions != null && 
!Strings.isNullOrEmpty(exclusiveNodeOptions.getHostname())) {
-      allNodes = allNodes.filter(p -> p.getDatanodeDetails().getHostName()
+      allNodes = allNodes.filter(p -> p.getHostName()
           .compareToIgnoreCase(exclusiveNodeOptions.getHostname()) == 0);
     }
     if (!Strings.isNullOrEmpty(nodeOperationalState)) {
@@ -124,42 +121,49 @@ public void execute(ScmClient scmClient) throws 
IOException {
     }
     
     if (json) {
-      List<DatanodeWithAttributes> datanodeList = allNodes.collect(
-              Collectors.toList());
-      System.out.println(
-              JsonUtils.toJsonStringWithDefaultPrettyPrinter(datanodeList));
+      List<BasicDatanodeInfo> datanodeList = 
allNodes.collect(Collectors.toList());
+      
System.out.println(JsonUtils.toJsonStringWithDefaultPrettyPrinter(datanodeList));
     } else {
       allNodes.forEach(this::printDatanodeInfo);
     }
   }
 
-  private List<DatanodeWithAttributes> getAllNodes(ScmClient scmClient)
+  private List<BasicDatanodeInfo> getAllNodes(ScmClient scmClient)
       throws IOException {
 
     // If sorting is requested
     if (exclusiveNodeOptions != null && (exclusiveNodeOptions.mostUsed || 
exclusiveNodeOptions.leastUsed)) {
       boolean sortByMostUsed = exclusiveNodeOptions.mostUsed;
-      List<HddsProtos.DatanodeUsageInfoProto> usageInfos = 
scmClient.getDatanodeUsageInfo(sortByMostUsed, 
-          Integer.MAX_VALUE);
+      List<HddsProtos.DatanodeUsageInfoProto> usageInfos;
+      try {
+        usageInfos = scmClient.getDatanodeUsageInfo(sortByMostUsed, 
Integer.MAX_VALUE);
+      } catch (Exception e) {
+        System.err.println("Failed to get datanode usage info: " + 
e.getMessage());
+        return Collections.emptyList();
+      }
 
       return usageInfos.stream()
           .map(p -> {
-            String uuidStr = p.getNode().getUuid();
-            UUID parsedUuid = UUID.fromString(uuidStr);
-
             try {
+              String uuidStr = p.getNode().getUuid();
+              UUID parsedUuid = UUID.fromString(uuidStr);
               HddsProtos.Node node = scmClient.queryNode(parsedUuid);
               long capacity = p.getCapacity();
               long used = capacity - p.getRemaining();
               double percentUsed = (capacity > 0) ? (used * 100.0) / capacity 
: 0.0;
-              return new DatanodeWithAttributes(
+              return new BasicDatanodeInfo(
                   DatanodeDetails.getFromProtoBuf(node.getNodeID()),
                   node.getNodeOperationalStates(0),
                   node.getNodeStates(0),
                   used,
                   capacity,
                   percentUsed);
-            } catch (IOException e) {
+            } catch (Exception e) {
+              String reason = "Could not process info for an unknown datanode";
+              if (p != null && p.getNode() != null && 
!Strings.isNullOrEmpty(p.getNode().getUuid())) {
+                reason = "Could not process node info for " + 
p.getNode().getUuid();
+              }
+              System.err.printf("Error: %s: %s%n", reason, e.getMessage());
               return null;
             }
           })
@@ -170,17 +174,16 @@ private List<DatanodeWithAttributes> 
getAllNodes(ScmClient scmClient)
     List<HddsProtos.Node> nodes = scmClient.queryNode(null,
         null, HddsProtos.QueryScope.CLUSTER, "");
 
-    return nodes.stream()
-        .map(p -> new DatanodeWithAttributes(
+    return nodes.stream().map(p -> new BasicDatanodeInfo(
             DatanodeDetails.getFromProtoBuf(p.getNodeID()),
             p.getNodeOperationalStates(0), p.getNodeStates(0)))
-        .sorted((o1, o2) -> o1.healthState.compareTo(o2.healthState))
+        .sorted(Comparator.comparing(BasicDatanodeInfo::getHealthState))
         .collect(Collectors.toList());
   }
 
-  private void printDatanodeInfo(DatanodeWithAttributes dna) {
+  private void printDatanodeInfo(BasicDatanodeInfo dn) {
     StringBuilder pipelineListInfo = new StringBuilder();
-    DatanodeDetails datanode = dna.getDatanodeDetails();
+    DatanodeDetails datanode = dn.getDatanodeDetails();
     int relatedPipelineNum = 0;
     if (!pipelines.isEmpty()) {
       List<Pipeline> relatedPipelines = pipelines.stream().filter(
@@ -206,72 +209,14 @@ private void printDatanodeInfo(DatanodeWithAttributes 
dna) {
         " (" + datanode.getNetworkLocation() + "/" + datanode.getIpAddress()
         + "/" + datanode.getHostName() + "/" + relatedPipelineNum +
         " pipelines)");
-    System.out.println("Operational State: " + dna.getOpState());
-    System.out.println("Health State: " + dna.getHealthState());
+    System.out.println("Operational State: " + dn.getOpState());
+    System.out.println("Health State: " + dn.getHealthState());
     System.out.println("Related pipelines:\n" + pipelineListInfo);
 
-    if (dna.getUsed() != null && dna.getCapacity() != null && dna.getUsed() >= 
0 && dna.getCapacity() > 0) {
-      System.out.println("Capacity: " + dna.getCapacity());
-      System.out.println("Used: " + dna.getUsed());
-      System.out.printf("Percentage Used : %.2f%%%n%n", dna.getPercentUsed());
-    }
-  }
-
-  private static class DatanodeWithAttributes {
-    private DatanodeDetails datanodeDetails;
-    private HddsProtos.NodeOperationalState operationalState;
-    private HddsProtos.NodeState healthState;
-    @JsonInclude(JsonInclude.Include.NON_NULL)
-    private Long used = null;
-    @JsonInclude(JsonInclude.Include.NON_NULL)
-    private Long capacity = null;
-    @JsonInclude(JsonInclude.Include.NON_NULL)
-    private Double percentUsed = null;
-
-    DatanodeWithAttributes(DatanodeDetails dn,
-        HddsProtos.NodeOperationalState opState,
-        HddsProtos.NodeState healthState) {
-      this.datanodeDetails = dn;
-      this.operationalState = opState;
-      this.healthState = healthState;
-    }
-
-    DatanodeWithAttributes(DatanodeDetails dn,
-                           HddsProtos.NodeOperationalState opState,
-                           HddsProtos.NodeState healthState,
-                           long used,
-                           long capacity,
-                           double percentUsed) {
-      this.datanodeDetails = dn;
-      this.operationalState = opState;
-      this.healthState = healthState;
-      this.used = used;
-      this.capacity = capacity;
-      this.percentUsed = percentUsed;
-    }
-
-    public DatanodeDetails getDatanodeDetails() {
-      return datanodeDetails;
-    }
-
-    public HddsProtos.NodeOperationalState getOpState() {
-      return operationalState;
-    }
-
-    public HddsProtos.NodeState getHealthState() {
-      return healthState;
-    }
-
-    public Long getUsed() {
-      return used;
-    }
-    
-    public Long getCapacity() {
-      return capacity;
-    }
-    
-    public Double getPercentUsed() {
-      return percentUsed;
+    if (dn.getUsed() != null && dn.getCapacity() != null && dn.getUsed() >= 0 
&& dn.getCapacity() > 0) {
+      System.out.println("Capacity: " + dn.getCapacity());
+      System.out.println("Used: " + dn.getUsed());
+      System.out.printf("Percentage Used : %.2f%%%n%n", dn.getPercentUsed());
     }
   }
 }
diff --git 
a/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestListInfoSubcommand.java
 
b/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestListInfoSubcommand.java
index a63d0c925f..fd6834068e 100644
--- 
a/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestListInfoSubcommand.java
+++ 
b/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/hdds/scm/cli/datanode/TestListInfoSubcommand.java
@@ -207,9 +207,8 @@ public void testDataNodeByUuidOutput()
     assertEquals(1, root.size(), "Expected 1 node in JSON output");
 
     JsonNode node = root.get(0);
-    assertTrue(node.has("datanodeDetails"), "Missing datanodeDetails");
     String opState = node.get("opState").asText();
-    String uuid = node.get("datanodeDetails").get("uuid").asText();
+    String uuid = node.get("id").asText();
 
     assertEquals("IN_SERVICE", opState, "Expected opState IN_SERVICE but got: 
" + opState);
     assertEquals(nodes.get(0).getNodeID().getUuid(), uuid,
@@ -365,8 +364,6 @@ private List<HddsProtos.Node> getNodeDetails() {
       dnd.setIpAddress("1.2.3." + i + 1);
       dnd.setNetworkLocation("/default");
       dnd.setNetworkName("host" + i);
-      dnd.addPorts(HddsProtos.Port.newBuilder()
-          .setName("ratis").setValue(5678).build());
       dnd.setUuid(UUID.randomUUID().toString());
 
       HddsProtos.Node.Builder builder  = HddsProtos.Node.newBuilder();
diff --git a/hadoop-ozone/dist/src/main/smoketest/admincli/datanode.robot 
b/hadoop-ozone/dist/src/main/smoketest/admincli/datanode.robot
index d4e7e7a2b4..2795ae5ac4 100644
--- a/hadoop-ozone/dist/src/main/smoketest/admincli/datanode.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/admincli/datanode.robot
@@ -99,9 +99,10 @@ Incomplete command
 
 List datanodes as JSON
     ${output} =         Execute          ozone admin datanode list --json | jq 
-r '.'
-                        Should contain   ${output}    datanodeDetails
+                        Should contain   ${output}    id
                         Should contain   ${output}    healthState
                         Should contain   ${output}    opState
+                        Should contain   ${output}    persistedOpState
 
 Get usage info as JSON
     ${output} =         Execute          ozone admin datanode usageinfo -m 
--json | jq -r '.'
diff --git a/hadoop-ozone/dist/src/main/smoketest/balancer/testBalancer.robot 
b/hadoop-ozone/dist/src/main/smoketest/balancer/testBalancer.robot
index 999aecb2fc..0436348239 100644
--- a/hadoop-ozone/dist/src/main/smoketest/balancer/testBalancer.robot
+++ b/hadoop-ozone/dist/src/main/smoketest/balancer/testBalancer.robot
@@ -150,7 +150,7 @@ All container is closed
 
 Get Datanode Ozone Used Bytes Info
     [arguments]             ${uuid}
-    ${output} =    Execute    export DATANODES=$(ozone admin datanode list 
--json) && for datanode in $(echo "$\{DATANODES\}" | jq -r 
'.[].datanodeDetails.uuid'); do ozone admin datanode usageinfo 
--uuid=$\{datanode\} --json | jq '{(.[0].datanodeDetails.uuid) : 
.[0].ozoneUsed}'; done | jq -s add
+    ${output} =    Execute    export DATANODES=$(ozone admin datanode list 
--json) && for datanode in $(echo "$\{DATANODES\}" | jq -r '.[].id'); do ozone 
admin datanode usageinfo --uuid=$\{datanode\} --json | jq 
'{(.[0].datanodeDetails.uuid) : .[0].ozoneUsed}'; done | jq -s add
     ${result} =    Execute    echo '${output}' | jq '. | to_entries | .[] | 
select(.key == "${uuid}") | .value'
     [return]          ${result}
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to