blob: da4ab13a018f61efe811bc26e42b60088f7625b1 [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 Jampani5756c352015-04-29 00:23:58 -070043 private static final String FMT = "%-30s | %-15s | %-6s | %-10s |";
44 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 */
60 private Comparator<Leadership> leadershipComparator =
61 (e1, e2) -> {
62 if (e1.leader() == null && e2.leader() == null) {
63 return 0;
64 }
65 if (e1.leader() == null) {
66 return 1;
67 }
68 if (e2.leader() == null) {
69 return -1;
70 }
71 return e1.leader().toString().compareTo(e2.leader().toString());
72 };
73
74 /**
75 * Displays text representing the leaders.
76 *
77 * @param leaderBoard map of leaders
78 */
79 private void displayLeaders(Map<String, Leadership> leaderBoard) {
Madan Jampani5756c352015-04-29 00:23:58 -070080 print("------------------------------------------------------------------------");
Madan Jampani30a57f82015-03-02 12:19:41 -080081 print(FMT, "Topic", "Leader", "Epoch", "Elected");
Madan Jampani5756c352015-04-29 00:23:58 -070082 print("------------------------------------------------------------------------");
Madan Jampani30a57f82015-03-02 12:19:41 -080083
Jonathan Hartf2fda812015-02-17 15:21:03 -080084 leaderBoard.values()
85 .stream()
Ayaka Koshibe941f8602015-04-15 14:17:08 -070086 .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
Jonathan Hartf2fda812015-02-17 15:21:03 -080087 .sorted(leadershipComparator)
Madan Jampani30a57f82015-03-02 12:19:41 -080088 .forEach(l -> print(FMT,
89 l.topic(),
90 l.leader(),
91 l.epoch(),
92 Tools.timeAgo(l.electedTime())));
Madan Jampani5756c352015-04-29 00:23:58 -070093 print("------------------------------------------------------------------------");
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080094 }
Ray Milkey1c198d62015-03-04 14:03:52 -080095
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070096 private void displayCandidates(Map<String, Leadership> leaderBoard,
Madan Jampanifd45d5e2015-04-20 13:33:21 -070097 Map<String, List<NodeId>> candidates) {
Madan Jampani5756c352015-04-29 00:23:58 -070098 print("------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070099 print(FMT_C, "Topic", "Leader", "Candidates");
Madan Jampani5756c352015-04-29 00:23:58 -0700100 print("------------------------------------------------------------------------");
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700101 candidates
102 .entrySet()
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700103 .stream()
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700104 .filter(es -> allTopics || pattern.matcher(es.getKey()).matches())
105 .forEach(es -> {
106 List<NodeId> list = es.getValue();
107 if (list == null || list.isEmpty()) {
108 return;
109 }
110 Leadership l = leaderBoard.get(es.getKey());
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700111 print(FMT_C,
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700112 es.getKey(),
113 l == null ? "null" : l.leader(),
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700114 // formatting hacks to get it into a table
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700115 list.get(0).toString());
Ayaka Koshibefd26a302015-04-13 13:59:54 -0700116 list.subList(1, list.size()).forEach(n -> print(FMT_C, " ", " ", n));
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700117 print(FMT_C, " ", " ", " ");
118 });
Madan Jampani5756c352015-04-29 00:23:58 -0700119 print("------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700120 }
121
Ray Milkey1c198d62015-03-04 14:03:52 -0800122 /**
123 * Returns JSON node representing the leaders.
124 *
125 * @param leaderBoard map of leaders
126 */
127 private JsonNode json(Map<String, Leadership> leaderBoard) {
128 ObjectMapper mapper = new ObjectMapper();
129 ArrayNode result = mapper.createArrayNode();
130 leaderBoard.values()
131 .stream()
132 .sorted(leadershipComparator)
133 .forEach(l ->
134 result.add(
135 mapper.createObjectNode()
136 .put("topic", l.topic())
137 .put("leader", l.leader().toString())
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700138 .put("candidates", l.candidates().toString())
Ray Milkey1c198d62015-03-04 14:03:52 -0800139 .put("epoch", l.epoch())
140 .put("electedTime", Tools.timeAgo(l.electedTime()))));
141
142 return result;
143 }
144
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700145 /**
146 * Returns JSON node representing the leaders.
147 *
148 * @param leaderBoard map of leaders
149 */
150 private JsonNode json(Map<String, Leadership> leaderBoard,
151 Map<String, List<NodeId>> candidateBoard) {
152 ObjectMapper mapper = new ObjectMapper();
153 ArrayNode result = mapper.createArrayNode();
154 candidateBoard.entrySet()
155 .stream()
156 .forEach(es -> {
157 Leadership l = leaderBoard.get(es.getKey());
158 result.add(
159 mapper.createObjectNode()
160 .put("topic", es.getKey())
161 .put("leader", l == null ? "none" : l.leader().toString())
162 .put("candidates", es.getValue().toString()));
163 });
164 return result;
165 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800166
167 @Override
168 protected void execute() {
169 LeadershipService leaderService = get(LeadershipService.class);
170 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700171 if (topicPattern == null) {
172 allTopics = true;
173 } else {
174 allTopics = false;
175 pattern = Pattern.compile(topicPattern);
176 }
177
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700178 if (showCandidates) {
179 Map<String, List<NodeId>> candidates = leaderService
180 .getCandidates();
181 if (outputJson()) {
182 print("%s", json(leaderBoard, candidates));
183 } else {
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700184 displayCandidates(leaderBoard, candidates);
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700185 }
186 } else {
187 if (outputJson()) {
188 print("%s", json(leaderBoard));
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700189 } else {
190 displayLeaders(leaderBoard);
191 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800192 }
193 }
194}