blob: a848519e5024b43f064ccafd29a85e5aa34c444a [file] [log] [blame]
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.cli.net;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080017
Madan Jampania14047d2015-02-25 12:23:02 -080018import java.util.Comparator;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070019import java.util.List;
Madan Jampanifd45d5e2015-04-20 13:33:21 -070020import java.util.Map;
Ayaka Koshibe941f8602015-04-15 14:17:08 -070021import java.util.regex.Pattern;
Madan Jampania14047d2015-02-25 12:23:02 -080022
Ayaka Koshibe941f8602015-04-15 14:17:08 -070023import org.apache.karaf.shell.commands.Argument;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080024import org.apache.karaf.shell.commands.Command;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070025import org.apache.karaf.shell.commands.Option;
Madan Jampani30a57f82015-03-02 12:19:41 -080026import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.cli.AbstractShellCommand;
28import org.onosproject.cluster.Leadership;
29import org.onosproject.cluster.LeadershipService;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070030import org.onosproject.cluster.NodeId;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080031
Ray Milkey1c198d62015-03-04 14:03:52 -080032import com.fasterxml.jackson.databind.JsonNode;
33import com.fasterxml.jackson.databind.ObjectMapper;
34import com.fasterxml.jackson.databind.node.ArrayNode;
35
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080036/**
37 * Prints the leader for every topic.
38 */
39@Command(scope = "onos", name = "leaders",
40 description = "Finds the leader for particular topic.")
41public class LeaderCommand extends AbstractShellCommand {
42
Madan Jampani620f70d2016-01-30 22:22:47 -080043 private static final String FMT = "%-30s | %-15s | %-5s | %-10s |";
Madan Jampani08727672016-02-01 11:57:14 -080044 private static final String FMT_C = "%-30s | %-15s | %-5s | %-10s | %-19s |";
Ayaka Koshibe941f8602015-04-15 14:17:08 -070045 private boolean allTopics;
46 private Pattern pattern;
47
48 @Argument(index = 0, name = "topic", description = "A leadership topic. Can be a regex",
49 required = false, multiValued = false)
50 String topicPattern = null;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070051
52 @Option(name = "-c", aliases = "--candidates",
53 description = "List candidate Nodes for each topic's leadership race",
54 required = false, multiValued = false)
55 private boolean showCandidates = false;
Brian O'Connora0d31002014-12-01 13:43:18 -080056
Ray Milkey1c198d62015-03-04 14:03:52 -080057 /**
58 * Compares leaders, sorting by toString() output.
59 */
Madan Jampani620f70d2016-01-30 22:22:47 -080060 private Comparator<Leadership> leadershipComparator = (l1, l2) ->
61 String.valueOf(l1.leaderNodeId()).compareTo(String.valueOf(l2.leaderNodeId()));
Ray Milkey1c198d62015-03-04 14:03:52 -080062
63 /**
64 * Displays text representing the leaders.
65 *
66 * @param leaderBoard map of leaders
67 */
68 private void displayLeaders(Map<String, Leadership> leaderBoard) {
Madan Jampani5756c352015-04-29 00:23:58 -070069 print("------------------------------------------------------------------------");
Madan Jampani620f70d2016-01-30 22:22:47 -080070 print(FMT, "Topic", "Leader", "Term", "Elected");
Madan Jampani5756c352015-04-29 00:23:58 -070071 print("------------------------------------------------------------------------");
Madan Jampani30a57f82015-03-02 12:19:41 -080072
Jonathan Hartf2fda812015-02-17 15:21:03 -080073 leaderBoard.values()
74 .stream()
Ayaka Koshibe941f8602015-04-15 14:17:08 -070075 .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
Madan Jampani620f70d2016-01-30 22:22:47 -080076 .filter(l -> l.leader() != null)
Jonathan Hartf2fda812015-02-17 15:21:03 -080077 .sorted(leadershipComparator)
Madan Jampani30a57f82015-03-02 12:19:41 -080078 .forEach(l -> print(FMT,
79 l.topic(),
Madan Jampani620f70d2016-01-30 22:22:47 -080080 l.leaderNodeId(),
81 l.leader().term(),
82 Tools.timeAgo(l.leader().termStartTime())));
Madan Jampani5756c352015-04-29 00:23:58 -070083 print("------------------------------------------------------------------------");
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080084 }
Ray Milkey1c198d62015-03-04 14:03:52 -080085
Madan Jampani08727672016-02-01 11:57:14 -080086 private void displayCandidates(Map<String, Leadership> leaderBoard) {
87 print("--------------------------------------------------------------------------------------------");
88 print(FMT_C, "Topic", "Leader", "Term", "Elected", "Candidates");
89 print("--------------------------------------------------------------------------------------------");
90 leaderBoard.entrySet()
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070091 .stream()
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070092 .filter(es -> allTopics || pattern.matcher(es.getKey()).matches())
Madan Jampani08727672016-02-01 11:57:14 -080093 .sorted((a, b) -> leadershipComparator.compare(a.getValue(), b.getValue()))
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070094 .forEach(es -> {
Madan Jampani08727672016-02-01 11:57:14 -080095 Leadership l = es.getValue();
96 List<NodeId> candidateList = l.candidates();
97 if (candidateList == null || candidateList.isEmpty()) {
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070098 return;
99 }
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700100 print(FMT_C,
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700101 es.getKey(),
Madan Jampani620f70d2016-01-30 22:22:47 -0800102 String.valueOf(l.leaderNodeId()),
Madan Jampani08727672016-02-01 11:57:14 -0800103 l.leader().term(),
104 Tools.timeAgo(l.leader().termStartTime()),
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700105 // formatting hacks to get it into a table
Madan Jampani08727672016-02-01 11:57:14 -0800106 candidateList.get(0).toString());
107 candidateList.subList(1, candidateList.size())
108 .forEach(n -> print(FMT_C, " ", " ", " ", " ", n));
109 print(FMT_C, " ", " ", " ", " ", " ");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700110 });
Madan Jampani08727672016-02-01 11:57:14 -0800111 print("--------------------------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700112 }
113
Ray Milkey1c198d62015-03-04 14:03:52 -0800114 /**
Madan Jampani08727672016-02-01 11:57:14 -0800115 * Returns JSON node representing the leaders and candidates.
Ray Milkey1c198d62015-03-04 14:03:52 -0800116 *
117 * @param leaderBoard map of leaders
118 */
119 private JsonNode json(Map<String, Leadership> leaderBoard) {
120 ObjectMapper mapper = new ObjectMapper();
121 ArrayNode result = mapper.createArrayNode();
Madan Jampani08727672016-02-01 11:57:14 -0800122 leaderBoard.forEach((topic, leadership) -> {
123 result.add(
Ray Milkey1c198d62015-03-04 14:03:52 -0800124 mapper.createObjectNode()
Madan Jampani08727672016-02-01 11:57:14 -0800125 .put("topic", topic)
126 .put("leader", leadership.leaderNodeId() == null ?
127 "none" : leadership.leaderNodeId().toString())
128 .put("term", leadership.leader() != null ?
129 leadership.leader().term() : 0)
130 .put("termStartTime", leadership.leader() != null ?
131 leadership.leader().termStartTime() : 0)
132 .put("candidates", leadership.candidates().toString()));
133 });
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700134 return result;
135 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800136
137 @Override
138 protected void execute() {
139 LeadershipService leaderService = get(LeadershipService.class);
140 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700141 if (topicPattern == null) {
142 allTopics = true;
143 } else {
144 allTopics = false;
145 pattern = Pattern.compile(topicPattern);
146 }
147
Madan Jampani08727672016-02-01 11:57:14 -0800148 if (outputJson()) {
149 print("%s", json(leaderBoard));
150 return;
151 }
152
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700153 if (showCandidates) {
Madan Jampani08727672016-02-01 11:57:14 -0800154 displayCandidates(leaderBoard);
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700155 } else {
Madan Jampani08727672016-02-01 11:57:14 -0800156 displayLeaders(leaderBoard);
Ray Milkey1c198d62015-03-04 14:03:52 -0800157 }
158 }
159}