| /* |
| * 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.cassandra.tools.nodetool; |
| |
| import io.airlift.airline.Arguments; |
| import io.airlift.airline.Command; |
| import io.airlift.airline.Option; |
| |
| import java.io.PrintStream; |
| import java.net.UnknownHostException; |
| import java.text.DecimalFormat; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.SortedMap; |
| |
| import org.apache.cassandra.locator.EndpointSnitchInfoMBean; |
| import org.apache.cassandra.tools.NodeProbe; |
| import org.apache.cassandra.tools.NodeTool; |
| import org.apache.cassandra.tools.NodeTool.NodeToolCmd; |
| import org.apache.cassandra.tools.nodetool.formatter.TableBuilder; |
| |
| import com.google.common.collect.ArrayListMultimap; |
| |
| @SuppressWarnings("UseOfSystemOutOrSystemErr") |
| @Command(name = "status", description = "Print cluster information (state, load, IDs, ...)") |
| public class Status extends NodeToolCmd |
| { |
| @Arguments(usage = "[<keyspace>]", description = "The keyspace name") |
| private String keyspace = null; |
| |
| @Option(title = "resolve_ip", name = {"-r", "--resolve-ip"}, description = "Show node domain names instead of IPs") |
| private boolean resolveIp = false; |
| |
| private boolean isTokenPerNode = true; |
| private Collection<String> joiningNodes, leavingNodes, movingNodes, liveNodes, unreachableNodes; |
| private Map<String, String> loadMap, hostIDMap; |
| private EndpointSnitchInfoMBean epSnitchInfo; |
| |
| @Override |
| public void execute(NodeProbe probe) |
| { |
| PrintStream out = probe.output().out; |
| joiningNodes = probe.getJoiningNodes(true); |
| leavingNodes = probe.getLeavingNodes(true); |
| movingNodes = probe.getMovingNodes(true); |
| loadMap = probe.getLoadMap(true); |
| Map<String, String> tokensToEndpoints = probe.getTokenToEndpointMap(true); |
| liveNodes = probe.getLiveNodes(true); |
| unreachableNodes = probe.getUnreachableNodes(true); |
| hostIDMap = probe.getHostIdMap(true); |
| epSnitchInfo = probe.getEndpointSnitchInfoProxy(); |
| |
| StringBuilder errors = new StringBuilder(); |
| TableBuilder.SharedTable sharedTable = new TableBuilder.SharedTable(" "); |
| |
| Map<String, Float> ownerships = null; |
| boolean hasEffectiveOwns = false; |
| try |
| { |
| ownerships = probe.effectiveOwnershipWithPort(keyspace); |
| hasEffectiveOwns = true; |
| } |
| catch (IllegalStateException e) |
| { |
| ownerships = probe.getOwnershipWithPort(); |
| errors.append("Note: ").append(e.getMessage()).append("%n"); |
| } |
| catch (IllegalArgumentException ex) |
| { |
| out.printf("%nError: %s%n", ex.getMessage()); |
| System.exit(1); |
| } |
| |
| SortedMap<String, SetHostStatWithPort> dcs = NodeTool.getOwnershipByDcWithPort(probe, resolveIp, tokensToEndpoints, ownerships); |
| |
| // More tokens than nodes (aka vnodes)? |
| if (dcs.size() < tokensToEndpoints.size()) |
| isTokenPerNode = false; |
| |
| // Datacenters |
| for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet()) |
| { |
| TableBuilder tableBuilder = sharedTable.next(); |
| addNodesHeader(hasEffectiveOwns, tableBuilder); |
| |
| ArrayListMultimap<String, HostStatWithPort> hostToTokens = ArrayListMultimap.create(); |
| for (HostStatWithPort stat : dc.getValue()) |
| hostToTokens.put(stat.endpointWithPort.getHostAddressAndPort(), stat); |
| |
| for (String endpoint : hostToTokens.keySet()) |
| { |
| Float owns = ownerships.get(endpoint); |
| List<HostStatWithPort> tokens = hostToTokens.get(endpoint); |
| addNode(endpoint, owns, tokens.get(0), tokens.size(), hasEffectiveOwns, tableBuilder); |
| } |
| } |
| |
| Iterator<TableBuilder> results = sharedTable.complete().iterator(); |
| boolean first = true; |
| for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet()) |
| { |
| if (!first) { |
| out.println(); |
| } |
| first = false; |
| String dcHeader = String.format("Datacenter: %s%n", dc.getKey()); |
| out.print(dcHeader); |
| for (int i = 0; i < (dcHeader.length() - 1); i++) out.print('='); |
| out.println(); |
| |
| // Legend |
| out.println("Status=Up/Down"); |
| out.println("|/ State=Normal/Leaving/Joining/Moving"); |
| TableBuilder dcTable = results.next(); |
| dcTable.printTo(out); |
| } |
| |
| out.printf("%n" + errors); |
| } |
| |
| private void addNodesHeader(boolean hasEffectiveOwns, TableBuilder tableBuilder) |
| { |
| String owns = hasEffectiveOwns ? "Owns (effective)" : "Owns"; |
| |
| if (isTokenPerNode) |
| tableBuilder.add("--", "Address", "Load", owns, "Host ID", "Token", "Rack"); |
| else |
| tableBuilder.add("--", "Address", "Load", "Tokens", owns, "Host ID", "Rack"); |
| } |
| |
| private void addNode(String endpoint, Float owns, HostStatWithPort hostStat, int size, boolean hasEffectiveOwns, |
| TableBuilder tableBuilder) |
| { |
| String status, state, load, strOwns, hostID, rack, epDns; |
| if (liveNodes.contains(endpoint)) status = "U"; |
| else if (unreachableNodes.contains(endpoint)) status = "D"; |
| else status = "?"; |
| if (joiningNodes.contains(endpoint)) state = "J"; |
| else if (leavingNodes.contains(endpoint)) state = "L"; |
| else if (movingNodes.contains(endpoint)) state = "M"; |
| else state = "N"; |
| |
| String statusAndState = status.concat(state); |
| load = loadMap.getOrDefault(endpoint, "?"); |
| strOwns = owns != null && hasEffectiveOwns ? new DecimalFormat("##0.0%").format(owns) : "?"; |
| hostID = hostIDMap.get(endpoint); |
| |
| try |
| { |
| rack = epSnitchInfo.getRack(endpoint); |
| } |
| catch (UnknownHostException e) |
| { |
| throw new RuntimeException(e); |
| } |
| |
| epDns = hostStat.ipOrDns(printPort); |
| if (isTokenPerNode) |
| { |
| tableBuilder.add(statusAndState, epDns, load, strOwns, hostID, hostStat.token, rack); |
| } |
| else |
| { |
| tableBuilder.add(statusAndState, epDns, load, String.valueOf(size), strOwns, hostID, rack); |
| } |
| } |
| |
| } |