blob: 6e2901dab247ab291b06ebe5726d9f0f8c34e9e1 [file] [log] [blame]
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -08001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
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 Jampani5756c352015-04-29 00:23:58 -070044 private static final String FMT_C = "%-30s | %-15s | %-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
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070086 private void displayCandidates(Map<String, Leadership> leaderBoard,
Madan Jampanifd45d5e2015-04-20 13:33:21 -070087 Map<String, List<NodeId>> candidates) {
Madan Jampani5756c352015-04-29 00:23:58 -070088 print("------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070089 print(FMT_C, "Topic", "Leader", "Candidates");
Madan Jampani5756c352015-04-29 00:23:58 -070090 print("------------------------------------------------------------------------");
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070091 candidates
92 .entrySet()
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070093 .stream()
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070094 .filter(es -> allTopics || pattern.matcher(es.getKey()).matches())
95 .forEach(es -> {
96 List<NodeId> list = es.getValue();
97 if (list == null || list.isEmpty()) {
98 return;
99 }
100 Leadership l = leaderBoard.get(es.getKey());
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700101 print(FMT_C,
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700102 es.getKey(),
Madan Jampani620f70d2016-01-30 22:22:47 -0800103 String.valueOf(l.leaderNodeId()),
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700104 // formatting hacks to get it into a table
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700105 list.get(0).toString());
Ayaka Koshibefd26a302015-04-13 13:59:54 -0700106 list.subList(1, list.size()).forEach(n -> print(FMT_C, " ", " ", n));
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700107 print(FMT_C, " ", " ", " ");
108 });
Madan Jampani5756c352015-04-29 00:23:58 -0700109 print("------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700110 }
111
Ray Milkey1c198d62015-03-04 14:03:52 -0800112 /**
113 * Returns JSON node representing the leaders.
114 *
115 * @param leaderBoard map of leaders
116 */
117 private JsonNode json(Map<String, Leadership> leaderBoard) {
118 ObjectMapper mapper = new ObjectMapper();
119 ArrayNode result = mapper.createArrayNode();
120 leaderBoard.values()
121 .stream()
122 .sorted(leadershipComparator)
123 .forEach(l ->
124 result.add(
125 mapper.createObjectNode()
126 .put("topic", l.topic())
Madan Jampani620f70d2016-01-30 22:22:47 -0800127 .put("leader", String.valueOf(l.leaderNodeId()))
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700128 .put("candidates", l.candidates().toString())
Madan Jampani620f70d2016-01-30 22:22:47 -0800129 .put("epoch", l.leader().term())
130 .put("epochStartTime", Tools.timeAgo(l.leader().termStartTime()))));
Ray Milkey1c198d62015-03-04 14:03:52 -0800131
132 return result;
133 }
134
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700135 /**
136 * Returns JSON node representing the leaders.
137 *
138 * @param leaderBoard map of leaders
139 */
140 private JsonNode json(Map<String, Leadership> leaderBoard,
141 Map<String, List<NodeId>> candidateBoard) {
142 ObjectMapper mapper = new ObjectMapper();
143 ArrayNode result = mapper.createArrayNode();
144 candidateBoard.entrySet()
145 .stream()
146 .forEach(es -> {
147 Leadership l = leaderBoard.get(es.getKey());
148 result.add(
149 mapper.createObjectNode()
150 .put("topic", es.getKey())
151 .put("leader", l == null ? "none" : l.leader().toString())
152 .put("candidates", es.getValue().toString()));
153 });
154 return result;
155 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800156
157 @Override
158 protected void execute() {
159 LeadershipService leaderService = get(LeadershipService.class);
160 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700161 if (topicPattern == null) {
162 allTopics = true;
163 } else {
164 allTopics = false;
165 pattern = Pattern.compile(topicPattern);
166 }
167
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700168 if (showCandidates) {
169 Map<String, List<NodeId>> candidates = leaderService
170 .getCandidates();
171 if (outputJson()) {
172 print("%s", json(leaderBoard, candidates));
173 } else {
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700174 displayCandidates(leaderBoard, candidates);
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700175 }
176 } else {
177 if (outputJson()) {
178 print("%s", json(leaderBoard));
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700179 } else {
180 displayLeaders(leaderBoard);
181 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800182 }
183 }
184}