blob: a4b0d3ac3eebdf6db8a9d2d3b60f32b16ba8e314 [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;
19import java.util.Map;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070020import java.util.List;
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 Jampani30a57f82015-03-02 12:19:41 -080043 private static final String FMT = "%-20s | %-15s | %-6s | %-10s |";
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070044 private static final String FMT_C = "%-20s | %-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 Jampani30a57f82015-03-02 12:19:41 -080080 print("--------------------------------------------------------------");
81 print(FMT, "Topic", "Leader", "Epoch", "Elected");
82 print("--------------------------------------------------------------");
83
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())));
93 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,
Ayaka Koshibefd26a302015-04-13 13:59:54 -070097 Map<String, Leadership> candidates) {
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070098 print("--------------------------------------------------------------");
99 print(FMT_C, "Topic", "Leader", "Candidates");
100 print("--------------------------------------------------------------");
101 leaderBoard
102 .values()
103 .stream()
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700104 .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700105 .sorted(leadershipComparator)
106 .forEach(l -> {
Ayaka Koshibefd26a302015-04-13 13:59:54 -0700107 List<NodeId> list = candidates.get(l.topic()).candidates();
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700108 print(FMT_C,
109 l.topic(),
110 l.leader(),
Ayaka Koshibefd26a302015-04-13 13:59:54 -0700111 list.get(0).toString());
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700112 // formatting hacks to get it into a table
Ayaka Koshibefd26a302015-04-13 13:59:54 -0700113 list.subList(1, list.size()).forEach(n -> print(FMT_C, " ", " ", n));
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700114 print(FMT_C, " ", " ", " ");
115 });
116 print("--------------------------------------------------------------");
117 }
118
Ray Milkey1c198d62015-03-04 14:03:52 -0800119 /**
120 * Returns JSON node representing the leaders.
121 *
122 * @param leaderBoard map of leaders
123 */
124 private JsonNode json(Map<String, Leadership> leaderBoard) {
125 ObjectMapper mapper = new ObjectMapper();
126 ArrayNode result = mapper.createArrayNode();
127 leaderBoard.values()
128 .stream()
129 .sorted(leadershipComparator)
130 .forEach(l ->
131 result.add(
132 mapper.createObjectNode()
133 .put("topic", l.topic())
134 .put("leader", l.leader().toString())
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700135 .put("candidates", l.candidates().toString())
Ray Milkey1c198d62015-03-04 14:03:52 -0800136 .put("epoch", l.epoch())
137 .put("electedTime", Tools.timeAgo(l.electedTime()))));
138
139 return result;
140 }
141
142
143 @Override
144 protected void execute() {
145 LeadershipService leaderService = get(LeadershipService.class);
146 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
147
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700148 if (topicPattern == null) {
149 allTopics = true;
150 } else {
151 allTopics = false;
152 pattern = Pattern.compile(topicPattern);
153 }
154
Ray Milkey1c198d62015-03-04 14:03:52 -0800155 if (outputJson()) {
156 print("%s", json(leaderBoard));
157 } else {
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700158 if (showCandidates) {
Ayaka Koshibefd26a302015-04-13 13:59:54 -0700159 Map<String, Leadership> candidates = leaderService.getCandidates();
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700160 displayCandidates(leaderBoard, candidates);
161 } else {
162 displayLeaders(leaderBoard);
163 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800164 }
165 }
166}