blob: 51601d26a5d0a4a3a1c94a6724bbd77bc5c28b49 [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
Ray Milkey3bceb012018-09-07 13:42:46 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
Ayaka Koshibe941f8602015-04-15 14:17:08 -070021import org.apache.karaf.shell.commands.Argument;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080022import org.apache.karaf.shell.commands.Command;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070023import org.apache.karaf.shell.commands.Option;
Madan Jampani30a57f82015-03-02 12:19:41 -080024import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.cli.AbstractShellCommand;
26import org.onosproject.cluster.Leadership;
Ray Milkey3bceb012018-09-07 13:42:46 -070027import org.onosproject.cluster.LeadershipAdminService;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070028import org.onosproject.cluster.NodeId;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080029
Ray Milkey3bceb012018-09-07 13:42:46 -070030import java.util.Comparator;
31import java.util.List;
32import java.util.Map;
33import java.util.regex.Pattern;
Ray Milkey1c198d62015-03-04 14:03:52 -080034
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080035/**
36 * Prints the leader for every topic.
37 */
38@Command(scope = "onos", name = "leaders",
39 description = "Finds the leader for particular topic.")
40public class LeaderCommand extends AbstractShellCommand {
41
Madan Jampani620f70d2016-01-30 22:22:47 -080042 private static final String FMT = "%-30s | %-15s | %-5s | %-10s |";
Madan Jampani08727672016-02-01 11:57:14 -080043 private static final String FMT_C = "%-30s | %-15s | %-5s | %-10s | %-19s |";
Ayaka Koshibe941f8602015-04-15 14:17:08 -070044 private boolean allTopics;
45 private Pattern pattern;
46
47 @Argument(index = 0, name = "topic", description = "A leadership topic. Can be a regex",
48 required = false, multiValued = false)
49 String topicPattern = null;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070050
51 @Option(name = "-c", aliases = "--candidates",
52 description = "List candidate Nodes for each topic's leadership race",
53 required = false, multiValued = false)
54 private boolean showCandidates = false;
Brian O'Connora0d31002014-12-01 13:43:18 -080055
Ray Milkey1c198d62015-03-04 14:03:52 -080056 /**
57 * Compares leaders, sorting by toString() output.
58 */
Madan Jampani620f70d2016-01-30 22:22:47 -080059 private Comparator<Leadership> leadershipComparator = (l1, l2) ->
60 String.valueOf(l1.leaderNodeId()).compareTo(String.valueOf(l2.leaderNodeId()));
Ray Milkey1c198d62015-03-04 14:03:52 -080061
62 /**
63 * Displays text representing the leaders.
64 *
65 * @param leaderBoard map of leaders
66 */
67 private void displayLeaders(Map<String, Leadership> leaderBoard) {
Madan Jampani5756c352015-04-29 00:23:58 -070068 print("------------------------------------------------------------------------");
Madan Jampani620f70d2016-01-30 22:22:47 -080069 print(FMT, "Topic", "Leader", "Term", "Elected");
Madan Jampani5756c352015-04-29 00:23:58 -070070 print("------------------------------------------------------------------------");
Madan Jampani30a57f82015-03-02 12:19:41 -080071
Jonathan Hartf2fda812015-02-17 15:21:03 -080072 leaderBoard.values()
73 .stream()
Ayaka Koshibe941f8602015-04-15 14:17:08 -070074 .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
Madan Jampani620f70d2016-01-30 22:22:47 -080075 .filter(l -> l.leader() != null)
Jonathan Hartf2fda812015-02-17 15:21:03 -080076 .sorted(leadershipComparator)
Madan Jampani30a57f82015-03-02 12:19:41 -080077 .forEach(l -> print(FMT,
78 l.topic(),
Madan Jampani620f70d2016-01-30 22:22:47 -080079 l.leaderNodeId(),
80 l.leader().term(),
81 Tools.timeAgo(l.leader().termStartTime())));
Madan Jampani5756c352015-04-29 00:23:58 -070082 print("------------------------------------------------------------------------");
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080083 }
Ray Milkey1c198d62015-03-04 14:03:52 -080084
Madan Jampani08727672016-02-01 11:57:14 -080085 private void displayCandidates(Map<String, Leadership> leaderBoard) {
86 print("--------------------------------------------------------------------------------------------");
87 print(FMT_C, "Topic", "Leader", "Term", "Elected", "Candidates");
88 print("--------------------------------------------------------------------------------------------");
89 leaderBoard.entrySet()
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070090 .stream()
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070091 .filter(es -> allTopics || pattern.matcher(es.getKey()).matches())
Madan Jampani08727672016-02-01 11:57:14 -080092 .sorted((a, b) -> leadershipComparator.compare(a.getValue(), b.getValue()))
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070093 .forEach(es -> {
Madan Jampani08727672016-02-01 11:57:14 -080094 Leadership l = es.getValue();
95 List<NodeId> candidateList = l.candidates();
96 if (candidateList == null || candidateList.isEmpty()) {
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070097 return;
98 }
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070099 print(FMT_C,
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700100 es.getKey(),
Madan Jampani620f70d2016-01-30 22:22:47 -0800101 String.valueOf(l.leaderNodeId()),
Madan Jampani08727672016-02-01 11:57:14 -0800102 l.leader().term(),
103 Tools.timeAgo(l.leader().termStartTime()),
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700104 // formatting hacks to get it into a table
Madan Jampani08727672016-02-01 11:57:14 -0800105 candidateList.get(0).toString());
106 candidateList.subList(1, candidateList.size())
107 .forEach(n -> print(FMT_C, " ", " ", " ", " ", n));
108 print(FMT_C, " ", " ", " ", " ", " ");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700109 });
Madan Jampani08727672016-02-01 11:57:14 -0800110 print("--------------------------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700111 }
112
Ray Milkey1c198d62015-03-04 14:03:52 -0800113 /**
Madan Jampani08727672016-02-01 11:57:14 -0800114 * Returns JSON node representing the leaders and candidates.
Ray Milkey1c198d62015-03-04 14:03:52 -0800115 *
116 * @param leaderBoard map of leaders
117 */
118 private JsonNode json(Map<String, Leadership> leaderBoard) {
119 ObjectMapper mapper = new ObjectMapper();
120 ArrayNode result = mapper.createArrayNode();
Madan Jampani08727672016-02-01 11:57:14 -0800121 leaderBoard.forEach((topic, leadership) -> {
122 result.add(
Ray Milkey1c198d62015-03-04 14:03:52 -0800123 mapper.createObjectNode()
Madan Jampani08727672016-02-01 11:57:14 -0800124 .put("topic", topic)
125 .put("leader", leadership.leaderNodeId() == null ?
126 "none" : leadership.leaderNodeId().toString())
127 .put("term", leadership.leader() != null ?
128 leadership.leader().term() : 0)
129 .put("termStartTime", leadership.leader() != null ?
130 leadership.leader().termStartTime() : 0)
131 .put("candidates", leadership.candidates().toString()));
132 });
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700133 return result;
134 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800135
136 @Override
137 protected void execute() {
Ray Milkey3bceb012018-09-07 13:42:46 -0700138 LeadershipAdminService leaderService = get(LeadershipAdminService.class);
Ray Milkey1c198d62015-03-04 14:03:52 -0800139 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700140 if (topicPattern == null) {
141 allTopics = true;
142 } else {
143 allTopics = false;
144 pattern = Pattern.compile(topicPattern);
145 }
146
Madan Jampani08727672016-02-01 11:57:14 -0800147 if (outputJson()) {
148 print("%s", json(leaderBoard));
149 return;
150 }
151
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700152 if (showCandidates) {
Madan Jampani08727672016-02-01 11:57:14 -0800153 displayCandidates(leaderBoard);
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700154 } else {
Madan Jampani08727672016-02-01 11:57:14 -0800155 displayLeaders(leaderBoard);
Ray Milkey1c198d62015-03-04 14:03:52 -0800156 }
157 }
158}