Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,7 @@ body {
.om-roles-background {
background-color: #dcfbcd!important;
}

.scm-roles-background {
background-color: #dcfbcd!important;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -447,6 +449,8 @@ public RegisteredCommand register(
processNodeReport(datanodeDetails, nodeReport);
LOG.info("Updated datanode to: {}", dn);
scmNodeEventPublisher.fireEvent(SCMEvents.NODE_ADDRESS_UPDATE, dn);
} else if (isVersionChange(oldNode.getVersion(), datanodeDetails.getVersion())) {
nodeStateManager.updateNode(datanodeDetails, layoutInfo);
Comment thread
ivandika3 marked this conversation as resolved.
}
} catch (NodeNotFoundException e) {
LOG.error("Cannot find datanode {} from nodeStateManager",
Expand Down Expand Up @@ -508,6 +512,18 @@ private boolean updateDnsToUuidMap(
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 ipChanged = !Objects.equals(oldVersion, newVersion);
return ipChanged;
}
Comment thread
ivandika3 marked this conversation as resolved.

/**
* Send heartbeat to indicate the datanode is alive and doing well.
*
Expand Down Expand Up @@ -1136,6 +1152,8 @@ public Map<String, Map<String, String>> getNodeStatusInfo() {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,6 +75,8 @@ public interface SCMMXBean extends ServiceRuntimeInfo {

String getScmRatisRoles();

List<List<String>> getRatisRoles();
Comment thread
ivandika3 marked this conversation as resolved.
Outdated

/**
* Primordial node is the node on which scm init operation is performed.
* @return hostname of primordialNode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,12 @@
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.proto.RaftProtos;
import org.apache.ratis.protocol.RaftPeer;
import org.apache.ratis.protocol.RaftPeerId;
import org.apache.ratis.server.DivisionInfo;
import org.apache.ratis.server.RaftServer;
import org.apache.ratis.thirdparty.com.google.protobuf.ByteString;
import org.apache.ratis.util.ExitUtils;
import org.apache.ratis.util.JvmPauseMonitor;
import org.slf4j.Logger;
Expand Down Expand Up @@ -2137,6 +2142,74 @@ public String getScmRatisRoles() {
HddsUtils.format(server.getRatisRoles()) : "STANDALONE";
}

@Override
public List<List<String>> getRatisRoles() {
final SCMRatisServer server = getScmHAManager().getRatisServer();

// If Ratis is enabled
if (server != null) {
Comment thread
slfan1989 marked this conversation as resolved.
Outdated

// 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();
RaftPeer leader = getLeader(division);
if (leader == 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());
}
}

// If Ratis is not enabled, we will throw an exception directly.
return getRatisRolesException("Ratis is disabled");
}

public RaftPeer getLeader(RaftServer.Division division) {
if (division.getInfo().isLeader()) {
return division.getPeer();
} else {
DivisionInfo info = division.getInfo();
RaftProtos.RoleInfoProto roleInfoProto = info.getRoleInfoProto();
RaftProtos.FollowerInfoProto followerInfo = roleInfoProto.getFollowerInfo();
RaftProtos.ServerRpcProto leaderInfo = followerInfo.getLeaderInfo();
RaftProtos.RaftPeerProto peerLeaderId = leaderInfo.getId();
ByteString leaderId = peerLeaderId.getId();
return leaderId.isEmpty() ? null :
division.getRaftConf().getPeer(RaftPeerId.valueOf(leaderId));
}
}
Comment thread
slfan1989 marked this conversation as resolved.
Outdated

private static List<List<String>> getRatisRolesException(String exceptionString) {
return Collections.singletonList(Collections.singletonList(exceptionString));
}

/**
* @return hostname of primordialNode
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ <h2>Node Status</h2>
'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>
Expand All @@ -157,6 +161,8 @@ <h2>Node Status</h2>
<td>{{typestat.opstate}}</td>
<td>{{typestat.comstate}}</td>
<td>{{typestat.lastheartbeat}}</td>
<td>{{typestat.uuid}}</td>
<td>{{typestat.version}}</td>
</tr>
</tbody>
</table>
Expand Down Expand Up @@ -210,10 +216,6 @@ <h2>Status</h2>
<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>
Expand All @@ -235,6 +237,34 @@ <h2>Meta-Data Volume Information</h2>
</tbody>
</table>

<h2 ng-show="$ctrl.overview.jmx.RatisRoles.length > 1">SCM Roles (HA)</h2>
Comment thread
ivandika3 marked this conversation as resolved.
Outdated
<div ng-show="$ctrl.overview.jmx.RatisRoles.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.RatisRoles">
<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">
Expand Down
7 changes: 7 additions & 0 deletions hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}
Expand Down