Madan Jampani
Committed by Gerrit Code Review

New partitions cli option for displaying client information

Change-Id: Iba0a9f7ea809368bf0965b44d8ff60e7486ee3d8
...@@ -18,7 +18,13 @@ package org.onosproject.cli.net; ...@@ -18,7 +18,13 @@ package org.onosproject.cli.net;
18 import java.util.List; 18 import java.util.List;
19 19
20 import org.apache.karaf.shell.commands.Command; 20 import org.apache.karaf.shell.commands.Command;
21 +import org.apache.karaf.shell.commands.Option;
21 import org.onosproject.cli.AbstractShellCommand; 22 import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.cluster.ClusterService;
24 +import org.onosproject.cluster.ControllerNode;
25 +import org.onosproject.cluster.NodeId;
26 +import org.onosproject.store.primitives.PartitionAdminService;
27 +import org.onosproject.store.service.PartitionClientInfo;
22 import org.onosproject.store.service.PartitionInfo; 28 import org.onosproject.store.service.PartitionInfo;
23 import org.onosproject.store.service.StorageAdminService; 29 import org.onosproject.store.service.StorageAdminService;
24 30
...@@ -35,7 +41,13 @@ import com.google.common.collect.Ordering; ...@@ -35,7 +41,13 @@ import com.google.common.collect.Ordering;
35 description = "Lists information about partitions in the system") 41 description = "Lists information about partitions in the system")
36 public class PartitionsListCommand extends AbstractShellCommand { 42 public class PartitionsListCommand extends AbstractShellCommand {
37 43
38 - private static final String FMT = "%-20s %8s %25s %s"; 44 + @Option(name = "-c", aliases = "--clients",
45 + description = "Show inforamtion about partition clients",
46 + required = false, multiValued = false)
47 + private boolean reportClientInfo = false;
48 +
49 + private static final String SERVER_FMT = "%-20s %8s %25s %s";
50 + private static final String CLIENT_FMT = "%-20s %8s %10s %25s";
39 51
40 /** 52 /**
41 * Displays partition info as text. 53 * Displays partition info as text.
...@@ -47,18 +59,18 @@ public class PartitionsListCommand extends AbstractShellCommand { ...@@ -47,18 +59,18 @@ public class PartitionsListCommand extends AbstractShellCommand {
47 return; 59 return;
48 } 60 }
49 print("----------------------------------------------------------"); 61 print("----------------------------------------------------------");
50 - print(FMT, "Name", "Term", "Members", ""); 62 + print(SERVER_FMT, "Name", "Term", "Members", "");
51 print("----------------------------------------------------------"); 63 print("----------------------------------------------------------");
52 64
53 for (PartitionInfo info : partitionInfo) { 65 for (PartitionInfo info : partitionInfo) {
54 boolean first = true; 66 boolean first = true;
55 for (String member : Ordering.natural().sortedCopy(info.members())) { 67 for (String member : Ordering.natural().sortedCopy(info.members())) {
56 if (first) { 68 if (first) {
57 - print(FMT, info.name(), info.term(), member, 69 + print(SERVER_FMT, info.name(), info.term(), member,
58 member.equals(info.leader()) ? "*" : ""); 70 member.equals(info.leader()) ? "*" : "");
59 first = false; 71 first = false;
60 } else { 72 } else {
61 - print(FMT, "", "", member, 73 + print(SERVER_FMT, "", "", member,
62 member.equals(info.leader()) ? "*" : ""); 74 member.equals(info.leader()) ? "*" : "");
63 } 75 }
64 } 76 }
...@@ -69,6 +81,39 @@ public class PartitionsListCommand extends AbstractShellCommand { ...@@ -69,6 +81,39 @@ public class PartitionsListCommand extends AbstractShellCommand {
69 } 81 }
70 82
71 /** 83 /**
84 + * Displays partition client info as text.
85 + *
86 + * @param partitionClientInfo partition client information
87 + */
88 + private void displayPartitionClients(List<PartitionClientInfo> partitionClientInfo) {
89 + if (partitionClientInfo.isEmpty()) {
90 + return;
91 + }
92 + ClusterService clusterService = get(ClusterService.class);
93 + print("-------------------------------------------------------------------");
94 + print(CLIENT_FMT, "Name", "SessionId", "Status", "Servers");
95 + print("-------------------------------------------------------------------");
96 +
97 + for (PartitionClientInfo info : partitionClientInfo) {
98 + boolean first = true;
99 + for (NodeId serverId : Ordering.natural().sortedCopy(info.servers())) {
100 + ControllerNode server = clusterService.getNode(serverId);
101 + String serverString = String.format("%s:%d", server.id(), server.tcpPort());
102 + if (first) {
103 + print(CLIENT_FMT, info.partitionId(), info.sessionId(),
104 + info.status(), serverString);
105 + first = false;
106 + } else {
107 + print(CLIENT_FMT, "", "", "", serverString);
108 + }
109 + }
110 + if (!first) {
111 + print("-------------------------------------------------------------------");
112 + }
113 + }
114 + }
115 +
116 + /**
72 * Converts partition info into a JSON object. 117 * Converts partition info into a JSON object.
73 * 118 *
74 * @param partitionInfo partition descriptions 119 * @param partitionInfo partition descriptions
...@@ -99,15 +144,58 @@ public class PartitionsListCommand extends AbstractShellCommand { ...@@ -99,15 +144,58 @@ public class PartitionsListCommand extends AbstractShellCommand {
99 return partitions; 144 return partitions;
100 } 145 }
101 146
147 + /**
148 + * Converts partition client info into a JSON object.
149 + *
150 + * @param partitionClientInfo partition client descriptions
151 + */
152 + private JsonNode jsonForClientInfo(List<PartitionClientInfo> partitionClientInfo) {
153 + ObjectMapper mapper = new ObjectMapper();
154 + ArrayNode partitions = mapper.createArrayNode();
155 + ClusterService clusterService = get(ClusterService.class);
156 +
157 + // Create a JSON node for each partition client
158 + partitionClientInfo.stream()
159 + .forEach(info -> {
160 + ObjectNode partition = mapper.createObjectNode();
161 +
162 + // Add each member to the "servers" array for this partition
163 + ArrayNode servers = partition.putArray("servers");
164 + info.servers()
165 + .stream()
166 + .map(clusterService::getNode)
167 + .map(node -> String.format("%s:%d", node.ip(), node.tcpPort()))
168 + .forEach(servers::add);
169 +
170 + // Complete the partition attributes and add it to the array
171 + partition.put("partitionId", info.partitionId().toString())
172 + .put("sessionId", info.sessionId())
173 + .put("status", info.status().toString());
174 + partitions.add(partition);
175 +
176 + });
177 +
178 + return partitions;
179 + }
180 +
102 @Override 181 @Override
103 protected void execute() { 182 protected void execute() {
104 StorageAdminService storageAdminService = get(StorageAdminService.class); 183 StorageAdminService storageAdminService = get(StorageAdminService.class);
184 + if (reportClientInfo) {
185 + PartitionAdminService partitionAdminService = get(PartitionAdminService.class);
186 + List<PartitionClientInfo> partitionClientInfo = partitionAdminService.partitionClientInfo();
187 + if (outputJson()) {
188 + print("%s", jsonForClientInfo(partitionClientInfo));
189 + } else {
190 + displayPartitionClients(partitionClientInfo);
191 + }
192 + } else {
105 List<PartitionInfo> partitionInfo = storageAdminService.getPartitionInfo(); 193 List<PartitionInfo> partitionInfo = storageAdminService.getPartitionInfo();
106 -
107 if (outputJson()) { 194 if (outputJson()) {
108 print("%s", json(partitionInfo)); 195 print("%s", json(partitionInfo));
109 } else { 196 } else {
110 displayPartitions(partitionInfo); 197 displayPartitions(partitionInfo);
111 } 198 }
112 } 199 }
200 + }
113 } 201 }
......
...@@ -17,6 +17,7 @@ package org.onosproject.store.primitives; ...@@ -17,6 +17,7 @@ package org.onosproject.store.primitives;
17 17
18 import java.util.List; 18 import java.util.List;
19 19
20 +import org.onosproject.store.service.PartitionClientInfo;
20 import org.onosproject.store.service.PartitionInfo; 21 import org.onosproject.store.service.PartitionInfo;
21 22
22 /** 23 /**
...@@ -29,4 +30,10 @@ public interface PartitionAdminService { ...@@ -29,4 +30,10 @@ public interface PartitionAdminService {
29 * @return list of {@code PartitionInfo} 30 * @return list of {@code PartitionInfo}
30 */ 31 */
31 List<PartitionInfo> partitionInfo(); 32 List<PartitionInfo> partitionInfo();
33 +
34 + /**
35 + * Returns the {@link PartitionClientInfo information} for partition clients.
36 + * @return list of {@code PartitionClientInfo}
37 + */
38 + List<PartitionClientInfo> partitionClientInfo();
32 } 39 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +/*
2 + * Copyright 2016-present Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.store.service;
17 +
18 +import java.util.Collection;
19 +
20 +import org.onosproject.cluster.NodeId;
21 +import org.onosproject.cluster.PartitionId;
22 +import org.onosproject.store.service.DistributedPrimitive.Status;
23 +
24 +import com.google.common.collect.ImmutableList;
25 +
26 +import static com.google.common.base.Preconditions.checkNotNull;
27 +
28 +/**
29 + * Contains information about a database partition client.
30 + */
31 +public class PartitionClientInfo {
32 + private final PartitionId partitionId;
33 + private final Status status;
34 + private final Collection<NodeId> servers;
35 + private final long sessionId;
36 +
37 + public PartitionClientInfo(PartitionId partitionId, Collection<NodeId> servers, long sessionId, Status status) {
38 + this.partitionId = checkNotNull(partitionId);
39 + this.servers = ImmutableList.copyOf(checkNotNull(servers));
40 + this.sessionId = sessionId;
41 + this.status = checkNotNull(status);
42 + }
43 +
44 + /**
45 + * Returns the identifier for the partition.
46 + *
47 + * @return partition id
48 + */
49 + public PartitionId partitionId() {
50 + return partitionId;
51 + }
52 +
53 + /**
54 + * Returns the collection of servers that are members of the partition.
55 + *
56 + * @return active members of the partition
57 + */
58 + public Collection<NodeId> servers() {
59 + return servers;
60 + }
61 +
62 + /**
63 + * Return the sessionId for the partition client.
64 + * @return session id
65 + */
66 + public long sessionId() {
67 + return sessionId;
68 + }
69 +
70 + /**
71 + * Returns the current status for the client session.
72 + * @return status
73 + */
74 + public Status status() {
75 + return status;
76 + }
77 +}
...@@ -49,6 +49,7 @@ import org.onosproject.store.primitives.PartitionAdminService; ...@@ -49,6 +49,7 @@ import org.onosproject.store.primitives.PartitionAdminService;
49 import org.onosproject.store.primitives.PartitionEvent; 49 import org.onosproject.store.primitives.PartitionEvent;
50 import org.onosproject.store.primitives.PartitionEventListener; 50 import org.onosproject.store.primitives.PartitionEventListener;
51 import org.onosproject.store.primitives.PartitionService; 51 import org.onosproject.store.primitives.PartitionService;
52 +import org.onosproject.store.service.PartitionClientInfo;
52 import org.onosproject.store.service.PartitionInfo; 53 import org.onosproject.store.service.PartitionInfo;
53 import org.slf4j.Logger; 54 import org.slf4j.Logger;
54 55
...@@ -176,4 +177,13 @@ public class PartitionManager extends AbstractListenerManager<PartitionEvent, Pa ...@@ -176,4 +177,13 @@ public class PartitionManager extends AbstractListenerManager<PartitionEvent, Pa
176 processMetadataUpdate(event.subject()); 177 processMetadataUpdate(event.subject());
177 } 178 }
178 } 179 }
180 +
181 + @Override
182 + public List<PartitionClientInfo> partitionClientInfo() {
183 + return partitions.values()
184 + .stream()
185 + .map(StoragePartition::client)
186 + .map(StoragePartitionClient::clientInfo)
187 + .collect(Collectors.toList());
188 + }
179 } 189 }
......
...@@ -53,6 +53,7 @@ import org.onosproject.store.service.AsyncDistributedSet; ...@@ -53,6 +53,7 @@ import org.onosproject.store.service.AsyncDistributedSet;
53 import org.onosproject.store.service.AsyncLeaderElector; 53 import org.onosproject.store.service.AsyncLeaderElector;
54 import org.onosproject.store.service.DistributedPrimitive.Status; 54 import org.onosproject.store.service.DistributedPrimitive.Status;
55 import org.onosproject.store.service.DistributedQueue; 55 import org.onosproject.store.service.DistributedQueue;
56 +import org.onosproject.store.service.PartitionClientInfo;
56 import org.onosproject.store.service.Serializer; 57 import org.onosproject.store.service.Serializer;
57 import org.slf4j.Logger; 58 import org.slf4j.Logger;
58 59
...@@ -190,6 +191,17 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana ...@@ -190,6 +191,17 @@ public class StoragePartitionClient implements DistributedPrimitiveCreator, Mana
190 return client.isOpen(); 191 return client.isOpen();
191 } 192 }
192 193
194 + /**
195 + * Returns the {@link PartitionClientInfo information} for this client.
196 + * @return partition client information
197 + */
198 + public PartitionClientInfo clientInfo() {
199 + return new PartitionClientInfo(partition.getId(),
200 + partition.getMembers(),
201 + copycatClient.session().id(),
202 + mapper.apply(copycatClient.state()));
203 + }
204 +
193 private CopycatClient newCopycatClient(Collection<Address> members, 205 private CopycatClient newCopycatClient(Collection<Address> members,
194 Transport transport, 206 Transport transport,
195 io.atomix.catalyst.serializer.Serializer serializer, 207 io.atomix.catalyst.serializer.Serializer serializer,
......