blob: 7139b86db488cca055ce8fc32d0b27d25e578f4b [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;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070021import org.apache.karaf.shell.api.action.Argument;
22import org.apache.karaf.shell.api.action.Command;
23import org.apache.karaf.shell.api.action.lifecycle.Service;
24import org.apache.karaf.shell.api.action.Option;
Madan Jampani30a57f82015-03-02 12:19:41 -080025import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.cli.AbstractShellCommand;
27import org.onosproject.cluster.Leadership;
Ray Milkey3bceb012018-09-07 13:42:46 -070028import org.onosproject.cluster.LeadershipAdminService;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070029import org.onosproject.cluster.NodeId;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080030
Ray Milkey3bceb012018-09-07 13:42:46 -070031import java.util.Comparator;
32import java.util.List;
33import java.util.Map;
34import java.util.regex.Pattern;
Ray Milkey1c198d62015-03-04 14:03:52 -080035
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080036/**
37 * Prints the leader for every topic.
38 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070039@Service
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080040@Command(scope = "onos", name = "leaders",
41 description = "Finds the leader for particular topic.")
42public class LeaderCommand extends AbstractShellCommand {
43
Madan Jampani620f70d2016-01-30 22:22:47 -080044 private static final String FMT = "%-30s | %-15s | %-5s | %-10s |";
Madan Jampani08727672016-02-01 11:57:14 -080045 private static final String FMT_C = "%-30s | %-15s | %-5s | %-10s | %-19s |";
Ayaka Koshibe941f8602015-04-15 14:17:08 -070046 private boolean allTopics;
47 private Pattern pattern;
48
49 @Argument(index = 0, name = "topic", description = "A leadership topic. Can be a regex",
50 required = false, multiValued = false)
51 String topicPattern = null;
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070052
53 @Option(name = "-c", aliases = "--candidates",
54 description = "List candidate Nodes for each topic's leadership race",
55 required = false, multiValued = false)
56 private boolean showCandidates = false;
Brian O'Connora0d31002014-12-01 13:43:18 -080057
Ray Milkey1c198d62015-03-04 14:03:52 -080058 /**
59 * Compares leaders, sorting by toString() output.
60 */
Madan Jampani620f70d2016-01-30 22:22:47 -080061 private Comparator<Leadership> leadershipComparator = (l1, l2) ->
62 String.valueOf(l1.leaderNodeId()).compareTo(String.valueOf(l2.leaderNodeId()));
Ray Milkey1c198d62015-03-04 14:03:52 -080063
64 /**
65 * Displays text representing the leaders.
66 *
67 * @param leaderBoard map of leaders
68 */
69 private void displayLeaders(Map<String, Leadership> leaderBoard) {
Madan Jampani5756c352015-04-29 00:23:58 -070070 print("------------------------------------------------------------------------");
Madan Jampani620f70d2016-01-30 22:22:47 -080071 print(FMT, "Topic", "Leader", "Term", "Elected");
Madan Jampani5756c352015-04-29 00:23:58 -070072 print("------------------------------------------------------------------------");
Madan Jampani30a57f82015-03-02 12:19:41 -080073
Jonathan Hartf2fda812015-02-17 15:21:03 -080074 leaderBoard.values()
75 .stream()
Ayaka Koshibe941f8602015-04-15 14:17:08 -070076 .filter(l -> allTopics || pattern.matcher(l.topic()).matches())
Madan Jampani620f70d2016-01-30 22:22:47 -080077 .filter(l -> l.leader() != null)
Jonathan Hartf2fda812015-02-17 15:21:03 -080078 .sorted(leadershipComparator)
Madan Jampani30a57f82015-03-02 12:19:41 -080079 .forEach(l -> print(FMT,
80 l.topic(),
Madan Jampani620f70d2016-01-30 22:22:47 -080081 l.leaderNodeId(),
82 l.leader().term(),
83 Tools.timeAgo(l.leader().termStartTime())));
Madan Jampani5756c352015-04-29 00:23:58 -070084 print("------------------------------------------------------------------------");
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080085 }
Ray Milkey1c198d62015-03-04 14:03:52 -080086
Madan Jampani08727672016-02-01 11:57:14 -080087 private void displayCandidates(Map<String, Leadership> leaderBoard) {
88 print("--------------------------------------------------------------------------------------------");
89 print(FMT_C, "Topic", "Leader", "Term", "Elected", "Candidates");
90 print("--------------------------------------------------------------------------------------------");
91 leaderBoard.entrySet()
Ayaka Koshibec19b8b82015-04-08 15:18:24 -070092 .stream()
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070093 .filter(es -> allTopics || pattern.matcher(es.getKey()).matches())
Madan Jampani08727672016-02-01 11:57:14 -080094 .sorted((a, b) -> leadershipComparator.compare(a.getValue(), b.getValue()))
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070095 .forEach(es -> {
Madan Jampani08727672016-02-01 11:57:14 -080096 Leadership l = es.getValue();
97 List<NodeId> candidateList = l.candidates();
98 if (candidateList == null || candidateList.isEmpty()) {
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -070099 return;
100 }
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()),
Madan Jampani08727672016-02-01 11:57:14 -0800104 l.leader().term(),
105 Tools.timeAgo(l.leader().termStartTime()),
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700106 // formatting hacks to get it into a table
Madan Jampani08727672016-02-01 11:57:14 -0800107 candidateList.get(0).toString());
108 candidateList.subList(1, candidateList.size())
109 .forEach(n -> print(FMT_C, " ", " ", " ", " ", n));
110 print(FMT_C, " ", " ", " ", " ", " ");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700111 });
Madan Jampani08727672016-02-01 11:57:14 -0800112 print("--------------------------------------------------------------------------------------------");
Ayaka Koshibec19b8b82015-04-08 15:18:24 -0700113 }
114
Ray Milkey1c198d62015-03-04 14:03:52 -0800115 /**
Madan Jampani08727672016-02-01 11:57:14 -0800116 * Returns JSON node representing the leaders and candidates.
Ray Milkey1c198d62015-03-04 14:03:52 -0800117 *
118 * @param leaderBoard map of leaders
119 */
120 private JsonNode json(Map<String, Leadership> leaderBoard) {
121 ObjectMapper mapper = new ObjectMapper();
122 ArrayNode result = mapper.createArrayNode();
Madan Jampani08727672016-02-01 11:57:14 -0800123 leaderBoard.forEach((topic, leadership) -> {
124 result.add(
Ray Milkey1c198d62015-03-04 14:03:52 -0800125 mapper.createObjectNode()
Madan Jampani08727672016-02-01 11:57:14 -0800126 .put("topic", topic)
127 .put("leader", leadership.leaderNodeId() == null ?
128 "none" : leadership.leaderNodeId().toString())
129 .put("term", leadership.leader() != null ?
130 leadership.leader().term() : 0)
131 .put("termStartTime", leadership.leader() != null ?
132 leadership.leader().termStartTime() : 0)
133 .put("candidates", leadership.candidates().toString()));
134 });
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700135 return result;
136 }
Ray Milkey1c198d62015-03-04 14:03:52 -0800137
138 @Override
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 protected void doExecute() {
Ray Milkey3bceb012018-09-07 13:42:46 -0700140 LeadershipAdminService leaderService = get(LeadershipAdminService.class);
Ray Milkey1c198d62015-03-04 14:03:52 -0800141 Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard();
Ayaka Koshibe941f8602015-04-15 14:17:08 -0700142 if (topicPattern == null) {
143 allTopics = true;
144 } else {
145 allTopics = false;
146 pattern = Pattern.compile(topicPattern);
147 }
148
Madan Jampani08727672016-02-01 11:57:14 -0800149 if (outputJson()) {
150 print("%s", json(leaderBoard));
151 return;
152 }
153
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700154 if (showCandidates) {
Madan Jampani08727672016-02-01 11:57:14 -0800155 displayCandidates(leaderBoard);
Ayaka Koshibe0d886fc2015-04-23 11:53:41 -0700156 } else {
Madan Jampani08727672016-02-01 11:57:14 -0800157 displayLeaders(leaderBoard);
Ray Milkey1c198d62015-03-04 14:03:52 -0800158 }
159 }
160}