blob: 288a5d2c50d5581be66f87cf6c18228df08cf69c [file] [log] [blame]
/**
* 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.yarn.client.cli;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingArgumentException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.hadoop.classification.InterfaceAudience.Private;
import org.apache.hadoop.classification.InterfaceStability.Unstable;
import org.apache.hadoop.util.ToolRunner;
import org.apache.hadoop.yarn.api.records.NodeId;
import org.apache.hadoop.yarn.api.records.NodeReport;
import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.util.ConverterUtils;
@Private
@Unstable
public class NodeCLI extends YarnCLI {
private static final String NODES_PATTERN = "%16s\t%15s\t%17s\t%28s" +
System.getProperty("line.separator");
private static final String NODE_STATE_CMD = "states";
private static final String NODE_ALL = "all";
private static final String NODE_SHOW_DETAILS = "showDetails";
public static void main(String[] args) throws Exception {
NodeCLI cli = new NodeCLI();
cli.setSysOutPrintStream(System.out);
cli.setSysErrPrintStream(System.err);
int res = ToolRunner.run(cli, args);
cli.stop();
System.exit(res);
}
@Override
public int run(String[] args) throws Exception {
Options opts = new Options();
opts.addOption(HELP_CMD, false, "Displays help for all commands.");
opts.addOption(STATUS_CMD, true, "Prints the status report of the node.");
opts.addOption(LIST_CMD, false, "List all running nodes. " +
"Supports optional use of -states to filter nodes " +
"based on node state, all -all to list all nodes, " +
"-showDetails to display more details about each node.");
Option nodeStateOpt = new Option(NODE_STATE_CMD, true,
"Works with -list to filter nodes based on input comma-separated " +
"list of node states. " + getAllValidNodeStates());
nodeStateOpt.setValueSeparator(',');
nodeStateOpt.setArgs(Option.UNLIMITED_VALUES);
nodeStateOpt.setArgName("States");
opts.addOption(nodeStateOpt);
Option allOpt = new Option(NODE_ALL, false,
"Works with -list to list all nodes.");
opts.addOption(allOpt);
Option showDetailsOpt = new Option(NODE_SHOW_DETAILS, false,
"Works with -list to show more details about each node.");
opts.addOption(showDetailsOpt);
opts.getOption(STATUS_CMD).setArgName("NodeId");
if (args != null && args.length > 0) {
for (int i = args.length - 1; i >= 0; i--) {
if (args[i].equalsIgnoreCase("-" + NODE_ALL)) {
args[i] = "-" + NODE_ALL;
}
}
}
int exitCode = -1;
CommandLine cliParser = null;
try {
cliParser = new GnuParser().parse(opts, args);
} catch (MissingArgumentException ex) {
sysout.println("Missing argument for options");
printUsage(opts);
return exitCode;
}
if (cliParser.hasOption("status")) {
if (args.length != 2) {
printUsage(opts);
return exitCode;
}
printNodeStatus(cliParser.getOptionValue("status"));
} else if (cliParser.hasOption("list")) {
Set<NodeState> nodeStates = new HashSet<NodeState>();
if (cliParser.hasOption(NODE_ALL)) {
for (NodeState state : NodeState.values()) {
nodeStates.add(state);
}
} else if (cliParser.hasOption(NODE_STATE_CMD)) {
String[] types = cliParser.getOptionValues(NODE_STATE_CMD);
if (types != null) {
for (String type : types) {
if (!type.trim().isEmpty()) {
try {
nodeStates.add(NodeState.valueOf(
org.apache.hadoop.util.StringUtils.toUpperCase(
type.trim())));
} catch (IllegalArgumentException ex) {
sysout.println("The node state " + type + " is invalid.");
sysout.println(getAllValidNodeStates());
return exitCode;
}
}
}
}
} else {
nodeStates.add(NodeState.RUNNING);
}
// List all node details with more information.
if (cliParser.hasOption(NODE_SHOW_DETAILS)) {
listDetailedClusterNodes(nodeStates);
} else {
listClusterNodes(nodeStates);
}
} else if (cliParser.hasOption(HELP_CMD)) {
printUsage(opts);
return 0;
} else {
syserr.println("Invalid Command Usage : ");
printUsage(opts);
}
return 0;
}
/**
* It prints the usage of the command
*
* @param opts
*/
private void printUsage(Options opts) {
new HelpFormatter().printHelp("node", opts);
}
/**
* Lists the nodes matching the given node states
*
* @param nodeStates
* @throws YarnException
* @throws IOException
*/
private void listClusterNodes(Set<NodeState> nodeStates)
throws YarnException, IOException {
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(sysout, Charset.forName("UTF-8")));
List<NodeReport> nodesReport = client.getNodeReports(
nodeStates.toArray(new NodeState[0]));
writer.println("Total Nodes:" + nodesReport.size());
writer.printf(NODES_PATTERN, "Node-Id", "Node-State", "Node-Http-Address",
"Number-of-Running-Containers");
for (NodeReport nodeReport : nodesReport) {
writer.printf(NODES_PATTERN, nodeReport.getNodeId(), nodeReport
.getNodeState(), nodeReport.getHttpAddress(), nodeReport
.getNumContainers());
}
writer.flush();
}
/**
* Lists the nodes which are matching the given node states along with
* detailed node informations such as resource usage etc.
*
* @param nodeStates
* @throws YarnException
* @throws IOException
*/
private void listDetailedClusterNodes(Set<NodeState> nodeStates)
throws YarnException, IOException {
PrintWriter writer = new PrintWriter(new OutputStreamWriter(sysout,
Charset.forName("UTF-8")));
List<NodeReport> nodesReport = client.getNodeReports(nodeStates
.toArray(new NodeState[0]));
writer.println("Total Nodes:" + nodesReport.size());
writer.printf(NODES_PATTERN, "Node-Id", "Node-State", "Node-Http-Address",
"Number-of-Running-Containers");
for (NodeReport nodeReport : nodesReport) {
writer.printf(NODES_PATTERN, nodeReport.getNodeId(),
nodeReport.getNodeState(), nodeReport.getHttpAddress(),
nodeReport.getNumContainers());
writer.println("Detailed Node Information :");
writer.print("\tConfigured Resources : ");
writer.println(nodeReport.getCapability());
writer.print("\tAllocated Resources : ");
if (nodeReport.getUsed() != null) {
writer.print(nodeReport.getUsed());
}
writer.println();
writer.print("\tResource Utilization by Node : ");
if (nodeReport.getNodeUtilization() != null) {
writer.print("PMem:"
+ nodeReport.getNodeUtilization().getPhysicalMemory()
+ " MB, VMem:" + nodeReport.getNodeUtilization().getVirtualMemory()
+ " MB, VCores:" + nodeReport.getNodeUtilization().getCPU());
}
writer.println();
writer.print("\tResource Utilization by Containers : ");
if (nodeReport.getAggregatedContainersUtilization() != null) {
writer.print("PMem:"
+ nodeReport.getAggregatedContainersUtilization()
.getPhysicalMemory()
+ " MB, VMem:"
+ nodeReport.getAggregatedContainersUtilization()
.getVirtualMemory() + " MB, VCores:"
+ nodeReport.getAggregatedContainersUtilization().getCPU());
}
writer.println();
writer.print("\tNode-Labels : ");
// Create a List for node labels since we need it get sorted
List<String> nodeLabelsList = new ArrayList<String>(
nodeReport.getNodeLabels());
Collections.sort(nodeLabelsList);
writer.println(StringUtils.join(nodeLabelsList.iterator(), ','));
}
writer.flush();
}
/**
* Prints the node report for node id.
*
* @param nodeIdStr
* @throws YarnException
*/
private void printNodeStatus(String nodeIdStr) throws YarnException,
IOException {
NodeId nodeId = NodeId.fromString(nodeIdStr);
List<NodeReport> nodesReport = client.getNodeReports();
// Use PrintWriter.println, which uses correct platform line ending.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter nodeReportStr = new PrintWriter(
new OutputStreamWriter(baos, Charset.forName("UTF-8")));
NodeReport nodeReport = null;
for (NodeReport report : nodesReport) {
if (!report.getNodeId().equals(nodeId)) {
continue;
}
nodeReport = report;
nodeReportStr.println("Node Report : ");
nodeReportStr.print("\tNode-Id : ");
nodeReportStr.println(nodeReport.getNodeId());
nodeReportStr.print("\tRack : ");
nodeReportStr.println(nodeReport.getRackName());
nodeReportStr.print("\tNode-State : ");
nodeReportStr.println(nodeReport.getNodeState());
nodeReportStr.print("\tNode-Http-Address : ");
nodeReportStr.println(nodeReport.getHttpAddress());
nodeReportStr.print("\tLast-Health-Update : ");
nodeReportStr.println(DateFormatUtils.format(
new Date(nodeReport.getLastHealthReportTime()),
"E dd/MMM/yy hh:mm:ss:SSzz"));
nodeReportStr.print("\tHealth-Report : ");
nodeReportStr
.println(nodeReport.getHealthReport());
nodeReportStr.print("\tContainers : ");
nodeReportStr.println(nodeReport.getNumContainers());
nodeReportStr.print("\tMemory-Used : ");
nodeReportStr.println((nodeReport.getUsed() == null) ? "0MB"
: (nodeReport.getUsed().getMemorySize() + "MB"));
nodeReportStr.print("\tMemory-Capacity : ");
nodeReportStr.println(nodeReport.getCapability().getMemorySize() + "MB");
nodeReportStr.print("\tCPU-Used : ");
nodeReportStr.println((nodeReport.getUsed() == null) ? "0 vcores"
: (nodeReport.getUsed().getVirtualCores() + " vcores"));
nodeReportStr.print("\tCPU-Capacity : ");
nodeReportStr.println(nodeReport.getCapability().getVirtualCores() + " vcores");
nodeReportStr.print("\tNode-Labels : ");
// Create a List for node labels since we need it get sorted
List<String> nodeLabelsList =
new ArrayList<String>(report.getNodeLabels());
Collections.sort(nodeLabelsList);
nodeReportStr.println(StringUtils.join(nodeLabelsList.iterator(), ','));
nodeReportStr.print("\tResource Utilization by Node : ");
if (nodeReport.getNodeUtilization() != null) {
nodeReportStr.print("PMem:"
+ nodeReport.getNodeUtilization().getPhysicalMemory()
+ " MB, VMem:" + nodeReport.getNodeUtilization().getVirtualMemory()
+ " MB, VCores:" + nodeReport.getNodeUtilization().getCPU());
}
nodeReportStr.println();
nodeReportStr.print("\tResource Utilization by Containers : ");
if (nodeReport.getAggregatedContainersUtilization() != null) {
nodeReportStr.print("PMem:"
+ nodeReport.getAggregatedContainersUtilization()
.getPhysicalMemory()
+ " MB, VMem:"
+ nodeReport.getAggregatedContainersUtilization()
.getVirtualMemory() + " MB, VCores:"
+ nodeReport.getAggregatedContainersUtilization().getCPU());
}
nodeReportStr.println();
}
if (nodeReport == null) {
nodeReportStr.print("Could not find the node report for node id : "
+ nodeIdStr);
}
nodeReportStr.close();
sysout.println(baos.toString("UTF-8"));
}
private String getAllValidNodeStates() {
StringBuilder sb = new StringBuilder();
sb.append("The valid node state can be one of the following: ");
for (NodeState state : NodeState.values()) {
sb.append(state).append(",");
}
String output = sb.toString();
return output.substring(0, output.length() - 1) + ".";
}
}