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

ivandika 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 e0060a8f50 HDDS-11196. Improve SCM WebUI Display (#6960)
e0060a8f50 is described below

commit e0060a8f50fc8c919e08dbba2294b29d9fb5c84a
Author: slfan1989 <[email protected]>
AuthorDate: Tue Sep 17 18:07:44 2024 +0800

    HDDS-11196. Improve SCM WebUI Display (#6960)
---
 .../src/main/resources/webapps/static/ozone.css    |  4 ++
 .../resources/webapps/static/templates/jvm.html    |  2 +-
 .../hadoop/hdds/scm/node/SCMNodeManager.java       | 21 +++++++++
 .../apache/hadoop/hdds/scm/server/SCMMXBean.java   |  3 +-
 .../hdds/scm/server/StorageContainerManager.java   | 51 ++++++++++++++++++++--
 .../main/resources/webapps/scm/scm-overview.html   | 39 +++++++++++++++--
 .../src/main/resources/webapps/scm/scm.js          |  7 +++
 7 files changed, 118 insertions(+), 9 deletions(-)

diff --git a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css 
b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css
index e08e9c5206..389d9d78f2 100644
--- a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css
+++ b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.css
@@ -91,3 +91,7 @@ body {
 .om-roles-background {
     background-color: #dcfbcd!important;
 }
+
+.scm-roles-background {
+    background-color: #dcfbcd!important;
+}
\ No newline at end of file
diff --git 
a/hadoop-hdds/framework/src/main/resources/webapps/static/templates/jvm.html 
b/hadoop-hdds/framework/src/main/resources/webapps/static/templates/jvm.html
index c1f7d16aef..9706ebdf6b 100644
--- a/hadoop-hdds/framework/src/main/resources/webapps/static/templates/jvm.html
+++ b/hadoop-hdds/framework/src/main/resources/webapps/static/templates/jvm.html
@@ -21,6 +21,6 @@
     </tr>
     <tr>
         <th>Input arguments:</th>
-        <td>{{$ctrl.jmx.InputArguments}}</td>
+        <td><pre>{{$ctrl.jmx.InputArguments.join('\n')}}</pre></td>
     </tr>
 </table>
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
index fa8f316aa4..7121d8f7a9 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/SCMNodeManager.java
@@ -146,6 +146,8 @@ public class SCMNodeManager implements NodeManager {
   private static final String LASTHEARTBEAT = "LASTHEARTBEAT";
   private static final String USEDSPACEPERCENT = "USEDSPACEPERCENT";
   private static final String TOTALCAPACITY = "CAPACITY";
+  private static final String DNUUID = "UUID";
+  private static final String VERSION = "VERSION";
   /**
    * Constructs SCM machine Manager.
    */
@@ -447,6 +449,11 @@ public class SCMNodeManager implements NodeManager {
           processNodeReport(datanodeDetails, nodeReport);
           LOG.info("Updated datanode to: {}", dn);
           scmNodeEventPublisher.fireEvent(SCMEvents.NODE_ADDRESS_UPDATE, dn);
+        } else if (isVersionChange(oldNode.getVersion(), 
datanodeDetails.getVersion())) {
+          LOG.info("Update the version for registered datanode = {}, " +
+              "oldVersion = {}, newVersion = {}.",
+              datanodeDetails.getUuid(), oldNode.getVersion(), 
datanodeDetails.getVersion());
+          nodeStateManager.updateNode(datanodeDetails, layoutInfo);
         }
       } catch (NodeNotFoundException e) {
         LOG.error("Cannot find datanode {} from nodeStateManager",
@@ -508,6 +515,18 @@ public class SCMNodeManager implements NodeManager {
     return ipChanged || hostNameChanged;
   }
 
+  /**
+   * Check if the version has been updated.
+   *
+   * @param oldVersion datanode oldVersion
+   * @param newVersion datanode newVersion
+   * @return true means replacement is needed, while false means replacement 
is not needed.
+   */
+  private boolean isVersionChange(String oldVersion, String newVersion) {
+    final boolean versionChanged = !Objects.equals(oldVersion, newVersion);
+    return versionChanged;
+  }
+
   /**
    * Send heartbeat to indicate the datanode is alive and doing well.
    *
@@ -1136,6 +1155,8 @@ public class SCMNodeManager implements NodeManager {
       String nonScmUsedPerc = storagePercentage[1];
       map.put(USEDSPACEPERCENT,
           "Ozone: " + scmUsedPerc + "%, other: " + nonScmUsedPerc + "%");
+      map.put(DNUUID, dni.getUuidString());
+      map.put(VERSION, dni.getVersion());
       nodes.put(hostName, map);
     }
     return nodes;
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
index de609356b2..75a5193116 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
@@ -18,6 +18,7 @@
 
 package org.apache.hadoop.hdds.scm.server;
 
+import java.util.List;
 import java.util.Map;
 
 import org.apache.hadoop.hdds.annotation.InterfaceAudience;
@@ -72,7 +73,7 @@ public interface SCMMXBean extends ServiceRuntimeInfo {
 
   String getClusterId();
 
-  String getScmRatisRoles();
+  List<List<String>> getScmRatisRoles();
 
   /**
    * Primordial node is the node on which scm init operation is performed.
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
index 868e54f193..5f69d9fee2 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
@@ -171,6 +171,7 @@ import 
org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
 import 
org.apache.hadoop.security.authentication.client.AuthenticationException;
 import org.apache.hadoop.util.ReflectionUtils;
 import org.apache.ratis.protocol.RaftPeerId;
+import org.apache.ratis.server.RaftServer;
 import org.apache.ratis.util.ExitUtils;
 import org.apache.ratis.util.JvmPauseMonitor;
 import org.slf4j.Logger;
@@ -2131,10 +2132,54 @@ public final class StorageContainerManager extends 
ServiceRuntimeInfoImpl
   }
 
   @Override
-  public String getScmRatisRoles() {
+  public List<List<String>> getScmRatisRoles() {
     final SCMRatisServer server = getScmHAManager().getRatisServer();
-    return server != null ?
-        HddsUtils.format(server.getRatisRoles()) : "STANDALONE";
+
+    // If Ratis is disabled
+    if (server == null) {
+      return getRatisRolesException("Ratis is disabled");
+    }
+
+    // To attempt to find the SCM Leader,
+    // and if the Leader is not found
+    // return Leader is not found message.
+    RaftServer.Division division = server.getDivision();
+    RaftPeerId leaderId = division.getInfo().getLeaderId();
+    if (leaderId == null) {
+      return getRatisRolesException("No leader found");
+    }
+
+    // If the SCMRatisServer is stopped, return a service stopped message.
+    if (server.isStopped()) {
+      return getRatisRolesException("Server is shutting down");
+    }
+
+    // Attempt to retrieve role information.
+    try {
+      List<String> ratisRoles = server.getRatisRoles();
+      List<List<String>> result = new ArrayList<>();
+      for (String role : ratisRoles) {
+        String[] roleArr = role.split(":");
+        List<String> scmInfo = new ArrayList<>();
+        // Host Name
+        scmInfo.add(roleArr[0]);
+        // Node ID
+        scmInfo.add(roleArr[3]);
+        // Ratis Port
+        scmInfo.add(roleArr[1]);
+        // Role
+        scmInfo.add(roleArr[2]);
+        result.add(scmInfo);
+      }
+      return result;
+    } catch (Exception e) {
+      LOG.error("Failed to getRatisRoles.", e);
+      return getRatisRolesException("Exception Occurred, " + e.getMessage());
+    }
+  }
+
+  private static List<List<String>> getRatisRolesException(String 
exceptionString) {
+    return 
Collections.singletonList(Collections.singletonList(exceptionString));
   }
 
   /**
diff --git 
a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html 
b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html
index 3f825d4e25..0f233bf4ea 100644
--- a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html
+++ b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm-overview.html
@@ -140,6 +140,10 @@
                                         'sortdesc':(columnName == 'comstate' 
&& !reverse)}">Commisioned State</span> </th>
             <th ng-click = "columnSort('lastheartbeat')" 
class="nodeStatusInfo">  <span ng-class="{'sorting' : (columnName != 
'lastheartbeat'), 'sortasc' : (columnName == 'heartbeat' && !reverse),
                                         'sortdesc':(columnName == 
'lastheartbeat' && !reverse)}">Last Heartbeat</span> </th>
+            <th ng-click = "columnSort('uuid')" class="uuId" ><span 
ng-class="{'sorting' : (columnName != 'uuid'), 'sortasc' : (columnName == 
'uuid' && !reverse),
+                                        'sortdesc':(columnName == 'uuid' && 
!reverse)}">UUID</span></th>
+            <th ng-click = "columnSort('version')" class="version" ><span 
ng-class="{'sorting' : (columnName != 'version'), 'sortasc' : (columnName == 
'version' && !reverse),
+                                        'sortdesc':(columnName == 'version' && 
!reverse)}">Version</span></th>
         </tr>
     </thead>
     <tbody>
@@ -157,6 +161,8 @@
             <td>{{typestat.opstate}}</td>
             <td>{{typestat.comstate}}</td>
             <td>{{typestat.lastheartbeat}}</td>
+            <td>{{typestat.uuid}}</td>
+            <td>{{typestat.version}}</td>
        </tr>
     </tbody>
 </table>
@@ -210,10 +216,6 @@
         <td> Force Exit Safe Mode </td>
         <td>{{$ctrl.overview.jmx.SafeModeExitForceful}}</td>
     </tr>
-    <tr>
-        <td> SCM Roles (HA) </td>
-        <td>{{$ctrl.overview.jmx.ScmRatisRoles}}</td>
-    </tr>
     <tr ng-hide="!$ctrl.overview.jmx.PrimordialNode">
         <td> Primordial Node (HA) </td>
         <td>{{$ctrl.overview.jmx.PrimordialNode}}</td>
@@ -235,6 +237,35 @@
     </tbody>
 </table>
 
+<h2>SCM Roles (HA)</h2>
+<h4 ng-show="$ctrl.overview.jmx.ScmRatisRoles.length == 1 && 
$ctrl.overview.jmx.ScmRatisRoles[0].length == 
1">{{$ctrl.overview.jmx.ScmRatisRoles[0][0]}}</h4>
+<div ng-show="$ctrl.overview.jmx.ScmRatisRoles.length > 1">
+    <table class="table table-striped table-bordered" class="col-md-6">
+        <thead>
+        <tr>
+            <th>Host Name</th>
+            <th>Node ID</th>
+            <th>Ratis Port</th>
+            <th>Role</th>
+        </tr>
+        </thead>
+        <tbody ng-repeat="roles in $ctrl.overview.jmx.ScmRatisRoles">
+        <tr class="scm-roles-background" ng-if="$ctrl.role.Id == roles[1]">
+            <td>{{roles[0]}}</td>
+            <td>{{roles[1]}}</td>
+            <td>{{roles[2]}}</td>
+            <td>{{roles[3]}}</td>
+        </tr>
+        <tr ng-if="$ctrl.role.Id != roles[1]">
+            <td>{{roles[0]}}</td>
+            <td>{{roles[1]}}</td>
+            <td>{{roles[2]}}</td>
+            <td>{{roles[3]}}</td>
+        </tr>
+        </tbody>
+    </table>
+</div>
+
 <h2>Safemode rules statuses</h2>
 
 <table class="table table-bordered table-striped" class="col-md-6">
diff --git a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js 
b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
index 6fac684953..e00f8b8ede 100644
--- a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
+++ b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
@@ -56,6 +56,11 @@
                 }
             }
 
+            $http.get("jmx?qry=Ratis:service=RaftServer,group=*,id=*")
+                .then(function (result) {
+                    ctrl.role = result.data.beans[0];
+            });
+
             function get_protocol(URLScheme, value, baseProto, fallbackProto) {
                 let protocol = "unknown"
                 let port = -1;
@@ -95,6 +100,8 @@
                                     capacity: value && value.find((element) => 
element.key === "CAPACITY").value,
                                     comstate: value && value.find((element) => 
element.key === "COMSTATE").value,
                                     lastheartbeat: value && 
value.find((element) => element.key === "LASTHEARTBEAT").value,
+                                    uuid: value && value.find((element) => 
element.key === "UUID").value,
+                                    version: value && value.find((element) => 
element.key === "VERSION").value,
                                     port: portSpec.port,
                                     protocol: portSpec.proto
                                 }


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

Reply via email to