Madan Jampani
Committed by Gerrit Code Review

ONOS-1326: Added support for observing when node liveness status was last update…

…d. Useful for detecting/debugging stability issues.

Change-Id: I8ffebcf3a09a51c6e3e7526986a0f05530ed757f
...@@ -15,17 +15,19 @@ ...@@ -15,17 +15,19 @@
15 */ 15 */
16 package org.onosproject.cli; 16 package org.onosproject.cli;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode; 18 +import static com.google.common.collect.Lists.newArrayList;
19 -import com.fasterxml.jackson.databind.ObjectMapper;
20 -import com.fasterxml.jackson.databind.node.ArrayNode;
21 -import org.apache.karaf.shell.commands.Command;
22 -import org.onosproject.cluster.ClusterService;
23 -import org.onosproject.cluster.ControllerNode;
24 19
25 import java.util.Collections; 20 import java.util.Collections;
26 import java.util.List; 21 import java.util.List;
27 22
28 -import static com.google.common.collect.Lists.newArrayList; 23 +import org.apache.karaf.shell.commands.Command;
24 +import org.onlab.util.Tools;
25 +import org.onosproject.cluster.ClusterService;
26 +import org.onosproject.cluster.ControllerNode;
27 +
28 +import com.fasterxml.jackson.databind.JsonNode;
29 +import com.fasterxml.jackson.databind.ObjectMapper;
30 +import com.fasterxml.jackson.databind.node.ArrayNode;
29 31
30 /** 32 /**
31 * Lists all controller cluster nodes. 33 * Lists all controller cluster nodes.
...@@ -35,7 +37,7 @@ import static com.google.common.collect.Lists.newArrayList; ...@@ -35,7 +37,7 @@ import static com.google.common.collect.Lists.newArrayList;
35 public class NodesListCommand extends AbstractShellCommand { 37 public class NodesListCommand extends AbstractShellCommand {
36 38
37 private static final String FMT = 39 private static final String FMT =
38 - "id=%s, address=%s:%s, state=%s %s"; 40 + "id=%s, address=%s:%s, state=%s, updated=%s %s";
39 41
40 @Override 42 @Override
41 protected void execute() { 43 protected void execute() {
...@@ -49,6 +51,7 @@ public class NodesListCommand extends AbstractShellCommand { ...@@ -49,6 +51,7 @@ public class NodesListCommand extends AbstractShellCommand {
49 for (ControllerNode node : nodes) { 51 for (ControllerNode node : nodes) {
50 print(FMT, node.id(), node.ip(), node.tcpPort(), 52 print(FMT, node.id(), node.ip(), node.tcpPort(),
51 service.getState(node.id()), 53 service.getState(node.id()),
54 + Tools.timeAgo(service.getLastUpdated(node.id()).getMillis()),
52 node.equals(self) ? "*" : ""); 55 node.equals(self) ? "*" : "");
53 } 56 }
54 } 57 }
......
...@@ -17,6 +17,8 @@ package org.onosproject.cluster; ...@@ -17,6 +17,8 @@ package org.onosproject.cluster;
17 17
18 import java.util.Set; 18 import java.util.Set;
19 19
20 +import org.joda.time.DateTime;
21 +
20 /** 22 /**
21 * Service for obtaining information about the individual nodes within 23 * Service for obtaining information about the individual nodes within
22 * the controller cluster. 24 * the controller cluster.
...@@ -54,6 +56,14 @@ public interface ClusterService { ...@@ -54,6 +56,14 @@ public interface ClusterService {
54 ControllerNode.State getState(NodeId nodeId); 56 ControllerNode.State getState(NodeId nodeId);
55 57
56 /** 58 /**
59 + * Returns the system time when the availability state was last updated.
60 + *
61 + * @param nodeId controller node identifier
62 + * @return system time when the availability state was last updated.
63 + */
64 + DateTime getLastUpdated(NodeId nodeId);
65 +
66 + /**
57 * Adds the specified cluster event listener. 67 * Adds the specified cluster event listener.
58 * 68 *
59 * @param listener the cluster listener 69 * @param listener the cluster listener
......
...@@ -15,11 +15,12 @@ ...@@ -15,11 +15,12 @@
15 */ 15 */
16 package org.onosproject.cluster; 16 package org.onosproject.cluster;
17 17
18 -import org.onosproject.store.Store;
19 -import org.onlab.packet.IpAddress;
20 -
21 import java.util.Set; 18 import java.util.Set;
22 19
20 +import org.joda.time.DateTime;
21 +import org.onlab.packet.IpAddress;
22 +import org.onosproject.store.Store;
23 +
23 /** 24 /**
24 * Manages inventory of controller cluster nodes; not intended for direct use. 25 * Manages inventory of controller cluster nodes; not intended for direct use.
25 */ 26 */
...@@ -56,6 +57,14 @@ public interface ClusterStore extends Store<ClusterEvent, ClusterStoreDelegate> ...@@ -56,6 +57,14 @@ public interface ClusterStore extends Store<ClusterEvent, ClusterStoreDelegate>
56 ControllerNode.State getState(NodeId nodeId); 57 ControllerNode.State getState(NodeId nodeId);
57 58
58 /** 59 /**
60 + * Returns the system when the availability state was last updated.
61 + *
62 + * @param nodeId controller node identifier
63 + * @return system time when the availability state was last updated.
64 + */
65 + DateTime getLastUpdated(NodeId nodeId);
66 +
67 + /**
59 * Adds a new controller node to the cluster. 68 * Adds a new controller node to the cluster.
60 * 69 *
61 * @param nodeId controller node identifier 70 * @param nodeId controller node identifier
......
...@@ -17,6 +17,8 @@ package org.onosproject.cluster; ...@@ -17,6 +17,8 @@ package org.onosproject.cluster;
17 17
18 import java.util.Set; 18 import java.util.Set;
19 19
20 +import org.joda.time.DateTime;
21 +
20 /** 22 /**
21 * Test adapter for the cluster service. 23 * Test adapter for the cluster service.
22 */ 24 */
...@@ -42,6 +44,11 @@ public class ClusterServiceAdapter implements ClusterService { ...@@ -42,6 +44,11 @@ public class ClusterServiceAdapter implements ClusterService {
42 } 44 }
43 45
44 @Override 46 @Override
47 + public DateTime getLastUpdated(NodeId nodeId) {
48 + return null;
49 + }
50 +
51 + @Override
45 public void addListener(ClusterEventListener listener) { 52 public void addListener(ClusterEventListener listener) {
46 } 53 }
47 54
......
...@@ -15,12 +15,20 @@ ...@@ -15,12 +15,20 @@
15 */ 15 */
16 package org.onosproject.cluster.impl; 16 package org.onosproject.cluster.impl;
17 17
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +import static com.google.common.base.Preconditions.checkNotNull;
20 +import static org.slf4j.LoggerFactory.getLogger;
21 +
22 +import java.util.Set;
23 +
18 import org.apache.felix.scr.annotations.Activate; 24 import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component; 25 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate; 26 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference; 27 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality; 28 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service; 29 import org.apache.felix.scr.annotations.Service;
30 +import org.joda.time.DateTime;
31 +import org.onlab.packet.IpAddress;
24 import org.onosproject.cluster.ClusterAdminService; 32 import org.onosproject.cluster.ClusterAdminService;
25 import org.onosproject.cluster.ClusterEvent; 33 import org.onosproject.cluster.ClusterEvent;
26 import org.onosproject.cluster.ClusterEventListener; 34 import org.onosproject.cluster.ClusterEventListener;
...@@ -31,15 +39,8 @@ import org.onosproject.cluster.ControllerNode; ...@@ -31,15 +39,8 @@ import org.onosproject.cluster.ControllerNode;
31 import org.onosproject.cluster.NodeId; 39 import org.onosproject.cluster.NodeId;
32 import org.onosproject.event.AbstractListenerRegistry; 40 import org.onosproject.event.AbstractListenerRegistry;
33 import org.onosproject.event.EventDeliveryService; 41 import org.onosproject.event.EventDeliveryService;
34 -import org.onlab.packet.IpAddress;
35 import org.slf4j.Logger; 42 import org.slf4j.Logger;
36 43
37 -import java.util.Set;
38 -
39 -import static com.google.common.base.Preconditions.checkArgument;
40 -import static com.google.common.base.Preconditions.checkNotNull;
41 -import static org.slf4j.LoggerFactory.getLogger;
42 -
43 /** 44 /**
44 * Implementation of the cluster service. 45 * Implementation of the cluster service.
45 */ 46 */
...@@ -97,6 +98,12 @@ public class ClusterManager implements ClusterService, ClusterAdminService { ...@@ -97,6 +98,12 @@ public class ClusterManager implements ClusterService, ClusterAdminService {
97 return store.getState(nodeId); 98 return store.getState(nodeId);
98 } 99 }
99 100
101 +
102 + @Override
103 + public DateTime getLastUpdated(NodeId nodeId) {
104 + return store.getLastUpdated(nodeId);
105 + }
106 +
100 @Override 107 @Override
101 public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) { 108 public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) {
102 checkNotNull(nodeId, INSTANCE_ID_NULL); 109 checkNotNull(nodeId, INSTANCE_ID_NULL);
......
...@@ -38,6 +38,7 @@ import org.apache.felix.scr.annotations.Activate; ...@@ -38,6 +38,7 @@ import org.apache.felix.scr.annotations.Activate;
38 import org.apache.felix.scr.annotations.Component; 38 import org.apache.felix.scr.annotations.Component;
39 import org.apache.felix.scr.annotations.Deactivate; 39 import org.apache.felix.scr.annotations.Deactivate;
40 import org.apache.felix.scr.annotations.Service; 40 import org.apache.felix.scr.annotations.Service;
41 +import org.joda.time.DateTime;
41 import org.onlab.netty.Endpoint; 42 import org.onlab.netty.Endpoint;
42 import org.onlab.netty.Message; 43 import org.onlab.netty.Message;
43 import org.onlab.netty.MessageHandler; 44 import org.onlab.netty.MessageHandler;
...@@ -99,6 +100,7 @@ public class DistributedClusterStore ...@@ -99,6 +100,7 @@ public class DistributedClusterStore
99 private Set<ControllerNode> seedNodes; 100 private Set<ControllerNode> seedNodes;
100 private final Map<NodeId, ControllerNode> allNodes = Maps.newConcurrentMap(); 101 private final Map<NodeId, ControllerNode> allNodes = Maps.newConcurrentMap();
101 private final Map<NodeId, State> nodeStates = Maps.newConcurrentMap(); 102 private final Map<NodeId, State> nodeStates = Maps.newConcurrentMap();
103 + private final Map<NodeId, DateTime> nodeStateLastUpdatedTimes = Maps.newConcurrentMap();
102 private NettyMessagingService messagingService = new NettyMessagingService(); 104 private NettyMessagingService messagingService = new NettyMessagingService();
103 private ScheduledExecutorService heartBeatSender = Executors.newSingleThreadScheduledExecutor( 105 private ScheduledExecutorService heartBeatSender = Executors.newSingleThreadScheduledExecutor(
104 groupedThreads("onos/cluster/membership", "heartbeat-sender")); 106 groupedThreads("onos/cluster/membership", "heartbeat-sender"));
...@@ -131,7 +133,7 @@ public class DistributedClusterStore ...@@ -131,7 +133,7 @@ public class DistributedClusterStore
131 133
132 seedNodes.forEach(node -> { 134 seedNodes.forEach(node -> {
133 allNodes.put(node.id(), node); 135 allNodes.put(node.id(), node);
134 - nodeStates.put(node.id(), State.INACTIVE); 136 + updateState(node.id(), State.INACTIVE);
135 }); 137 });
136 138
137 establishSelfIdentity(); 139 establishSelfIdentity();
...@@ -216,7 +218,7 @@ public class DistributedClusterStore ...@@ -216,7 +218,7 @@ public class DistributedClusterStore
216 checkArgument(tcpPort > 5000, "Tcp port must be greater than 5000"); 218 checkArgument(tcpPort > 5000, "Tcp port must be greater than 5000");
217 ControllerNode node = new DefaultControllerNode(nodeId, ip, tcpPort); 219 ControllerNode node = new DefaultControllerNode(nodeId, ip, tcpPort);
218 allNodes.put(node.id(), node); 220 allNodes.put(node.id(), node);
219 - nodeStates.put(nodeId, State.INACTIVE); 221 + updateState(nodeId, State.INACTIVE);
220 delegate.notify(new ClusterEvent(ClusterEvent.Type.INSTANCE_ADDED, node)); 222 delegate.notify(new ClusterEvent(ClusterEvent.Type.INSTANCE_ADDED, node));
221 return node; 223 return node;
222 } 224 }
...@@ -231,12 +233,17 @@ public class DistributedClusterStore ...@@ -231,12 +233,17 @@ public class DistributedClusterStore
231 } 233 }
232 } 234 }
233 235
236 + private void updateState(NodeId nodeId, State newState) {
237 + nodeStates.put(nodeId, newState);
238 + nodeStateLastUpdatedTimes.put(nodeId, DateTime.now());
239 + }
240 +
234 private void establishSelfIdentity() { 241 private void establishSelfIdentity() {
235 try { 242 try {
236 IpAddress ip = findLocalIp(); 243 IpAddress ip = findLocalIp();
237 localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip); 244 localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip);
238 allNodes.put(localNode.id(), localNode); 245 allNodes.put(localNode.id(), localNode);
239 - nodeStates.put(localNode.id(), State.ACTIVE); 246 + updateState(localNode.id(), State.ACTIVE);
240 log.info("Local Node: {}", localNode); 247 log.info("Local Node: {}", localNode);
241 } catch (SocketException e) { 248 } catch (SocketException e) {
242 throw new IllegalStateException("Cannot determine local IP", e); 249 throw new IllegalStateException("Cannot determine local IP", e);
...@@ -256,12 +263,12 @@ public class DistributedClusterStore ...@@ -256,12 +263,12 @@ public class DistributedClusterStore
256 double phi = failureDetector.phi(node.id()); 263 double phi = failureDetector.phi(node.id());
257 if (phi >= PHI_FAILURE_THRESHOLD) { 264 if (phi >= PHI_FAILURE_THRESHOLD) {
258 if (currentState == State.ACTIVE) { 265 if (currentState == State.ACTIVE) {
259 - nodeStates.put(node.id(), State.INACTIVE); 266 + updateState(node.id(), State.INACTIVE);
260 notifyStateChange(node.id(), State.ACTIVE, State.INACTIVE); 267 notifyStateChange(node.id(), State.ACTIVE, State.INACTIVE);
261 } 268 }
262 } else { 269 } else {
263 if (currentState == State.INACTIVE) { 270 if (currentState == State.INACTIVE) {
264 - nodeStates.put(node.id(), State.ACTIVE); 271 + updateState(node.id(), State.ACTIVE);
265 notifyStateChange(node.id(), State.INACTIVE, State.ACTIVE); 272 notifyStateChange(node.id(), State.INACTIVE, State.ACTIVE);
266 } 273 }
267 } 274 }
...@@ -334,4 +341,8 @@ public class DistributedClusterStore ...@@ -334,4 +341,8 @@ public class DistributedClusterStore
334 } 341 }
335 } 342 }
336 343
337 -} 344 + @Override
345 + public DateTime getLastUpdated(NodeId nodeId) {
346 + return nodeStateLastUpdatedTimes.get(nodeId);
347 + }
348 +}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -18,6 +18,7 @@ package org.onosproject.store.cluster.impl; ...@@ -18,6 +18,7 @@ package org.onosproject.store.cluster.impl;
18 import com.google.common.base.Optional; 18 import com.google.common.base.Optional;
19 import com.google.common.cache.LoadingCache; 19 import com.google.common.cache.LoadingCache;
20 import com.google.common.collect.ImmutableSet; 20 import com.google.common.collect.ImmutableSet;
21 +import com.google.common.collect.Maps;
21 import com.hazelcast.core.IMap; 22 import com.hazelcast.core.IMap;
22 import com.hazelcast.core.Member; 23 import com.hazelcast.core.Member;
23 import com.hazelcast.core.MemberAttributeEvent; 24 import com.hazelcast.core.MemberAttributeEvent;
...@@ -28,6 +29,7 @@ import org.apache.felix.scr.annotations.Activate; ...@@ -28,6 +29,7 @@ import org.apache.felix.scr.annotations.Activate;
28 import org.apache.felix.scr.annotations.Component; 29 import org.apache.felix.scr.annotations.Component;
29 import org.apache.felix.scr.annotations.Deactivate; 30 import org.apache.felix.scr.annotations.Deactivate;
30 import org.apache.felix.scr.annotations.Service; 31 import org.apache.felix.scr.annotations.Service;
32 +import org.joda.time.DateTime;
31 import org.onosproject.cluster.ClusterEvent; 33 import org.onosproject.cluster.ClusterEvent;
32 import org.onosproject.cluster.ClusterStore; 34 import org.onosproject.cluster.ClusterStore;
33 import org.onosproject.cluster.ClusterStoreDelegate; 35 import org.onosproject.cluster.ClusterStoreDelegate;
...@@ -63,6 +65,7 @@ public class HazelcastClusterStore ...@@ -63,6 +65,7 @@ public class HazelcastClusterStore
63 private String listenerId; 65 private String listenerId;
64 private final MembershipListener listener = new InternalMembershipListener(); 66 private final MembershipListener listener = new InternalMembershipListener();
65 private final Map<NodeId, State> states = new ConcurrentHashMap<>(); 67 private final Map<NodeId, State> states = new ConcurrentHashMap<>();
68 + private final Map<NodeId, DateTime> lastUpdatedTimes = Maps.newConcurrentMap();
66 69
67 private String nodesListenerId; 70 private String nodesListenerId;
68 71
...@@ -123,6 +126,11 @@ public class HazelcastClusterStore ...@@ -123,6 +126,11 @@ public class HazelcastClusterStore
123 } 126 }
124 127
125 @Override 128 @Override
129 + public DateTime getLastUpdated(NodeId nodeId) {
130 + return lastUpdatedTimes.get(nodeId);
131 + }
132 +
133 + @Override
126 public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) { 134 public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) {
127 return addNode(new DefaultControllerNode(nodeId, ip, tcpPort)); 135 return addNode(new DefaultControllerNode(nodeId, ip, tcpPort));
128 } 136 }
...@@ -139,7 +147,7 @@ public class HazelcastClusterStore ...@@ -139,7 +147,7 @@ public class HazelcastClusterStore
139 private synchronized ControllerNode addNode(DefaultControllerNode node) { 147 private synchronized ControllerNode addNode(DefaultControllerNode node) {
140 rawNodes.put(serialize(node.id()), serialize(node)); 148 rawNodes.put(serialize(node.id()), serialize(node));
141 nodes.put(node.id(), Optional.of(node)); 149 nodes.put(node.id(), Optional.of(node));
142 - states.put(node.id(), State.ACTIVE); 150 + updateState(node.id(), State.ACTIVE);
143 return node; 151 return node;
144 } 152 }
145 153
...@@ -153,6 +161,11 @@ public class HazelcastClusterStore ...@@ -153,6 +161,11 @@ public class HazelcastClusterStore
153 return IpAddress.valueOf(member.getSocketAddress().getAddress()); 161 return IpAddress.valueOf(member.getSocketAddress().getAddress());
154 } 162 }
155 163
164 + private void updateState(NodeId nodeId, State newState) {
165 + updateState(nodeId, newState);
166 + lastUpdatedTimes.put(nodeId, DateTime.now());
167 + }
168 +
156 // Interceptor for membership events. 169 // Interceptor for membership events.
157 private class InternalMembershipListener implements MembershipListener { 170 private class InternalMembershipListener implements MembershipListener {
158 @Override 171 @Override
...@@ -166,7 +179,7 @@ public class HazelcastClusterStore ...@@ -166,7 +179,7 @@ public class HazelcastClusterStore
166 public void memberRemoved(MembershipEvent membershipEvent) { 179 public void memberRemoved(MembershipEvent membershipEvent) {
167 log.info("Member {} removed", membershipEvent.getMember()); 180 log.info("Member {} removed", membershipEvent.getMember());
168 NodeId nodeId = new NodeId(memberAddress(membershipEvent.getMember()).toString()); 181 NodeId nodeId = new NodeId(memberAddress(membershipEvent.getMember()).toString());
169 - states.put(nodeId, State.INACTIVE); 182 + updateState(nodeId, State.INACTIVE);
170 notifyDelegate(new ClusterEvent(INSTANCE_DEACTIVATED, getNode(nodeId))); 183 notifyDelegate(new ClusterEvent(INSTANCE_DEACTIVATED, getNode(nodeId)));
171 } 184 }
172 185
...@@ -178,4 +191,4 @@ public class HazelcastClusterStore ...@@ -178,4 +191,4 @@ public class HazelcastClusterStore
178 memberAttributeEvent.getValue()); 191 memberAttributeEvent.getValue());
179 } 192 }
180 } 193 }
181 -} 194 +}
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -15,11 +15,16 @@ ...@@ -15,11 +15,16 @@
15 */ 15 */
16 package org.onosproject.store.trivial.impl; 16 package org.onosproject.store.trivial.impl;
17 17
18 -import com.google.common.collect.ImmutableSet; 18 +import static org.slf4j.LoggerFactory.getLogger;
19 +
20 +import java.util.Set;
21 +
19 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Deactivate; 24 import org.apache.felix.scr.annotations.Deactivate;
22 import org.apache.felix.scr.annotations.Service; 25 import org.apache.felix.scr.annotations.Service;
26 +import org.joda.time.DateTime;
27 +import org.onlab.packet.IpAddress;
23 import org.onosproject.cluster.ClusterEvent; 28 import org.onosproject.cluster.ClusterEvent;
24 import org.onosproject.cluster.ClusterStore; 29 import org.onosproject.cluster.ClusterStore;
25 import org.onosproject.cluster.ClusterStoreDelegate; 30 import org.onosproject.cluster.ClusterStoreDelegate;
...@@ -29,12 +34,9 @@ import org.onosproject.cluster.NodeId; ...@@ -29,12 +34,9 @@ import org.onosproject.cluster.NodeId;
29 import org.onosproject.net.intent.Key; 34 import org.onosproject.net.intent.Key;
30 import org.onosproject.net.intent.PartitionService; 35 import org.onosproject.net.intent.PartitionService;
31 import org.onosproject.store.AbstractStore; 36 import org.onosproject.store.AbstractStore;
32 -import org.onlab.packet.IpAddress;
33 import org.slf4j.Logger; 37 import org.slf4j.Logger;
34 38
35 -import java.util.Set; 39 +import com.google.common.collect.ImmutableSet;
36 -
37 -import static org.slf4j.LoggerFactory.getLogger;
38 40
39 /** 41 /**
40 * Manages inventory of infrastructure devices using trivial in-memory 42 * Manages inventory of infrastructure devices using trivial in-memory
...@@ -52,6 +54,8 @@ public class SimpleClusterStore ...@@ -52,6 +54,8 @@ public class SimpleClusterStore
52 54
53 private ControllerNode instance; 55 private ControllerNode instance;
54 56
57 + private final DateTime creationTime = DateTime.now();
58 +
55 @Activate 59 @Activate
56 public void activate() { 60 public void activate() {
57 instance = new DefaultControllerNode(new NodeId("local"), LOCALHOST); 61 instance = new DefaultControllerNode(new NodeId("local"), LOCALHOST);
...@@ -85,6 +89,11 @@ public class SimpleClusterStore ...@@ -85,6 +89,11 @@ public class SimpleClusterStore
85 } 89 }
86 90
87 @Override 91 @Override
92 + public DateTime getLastUpdated(NodeId nodeId) {
93 + return creationTime;
94 + }
95 +
96 + @Override
88 public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) { 97 public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) {
89 return null; 98 return null;
90 } 99 }
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 */ 15 */
16 package org.onosproject.store.trivial.impl; 16 package org.onosproject.store.trivial.impl;
17 17
18 +import static org.onosproject.mastership.MastershipEvent.Type.BACKUPS_CHANGED;
19 +import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED;
18 import static org.slf4j.LoggerFactory.getLogger; 20 import static org.slf4j.LoggerFactory.getLogger;
19 21
20 import java.util.ArrayList; 22 import java.util.ArrayList;
...@@ -33,6 +35,8 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -33,6 +35,8 @@ import org.apache.felix.scr.annotations.Deactivate;
33 import org.apache.felix.scr.annotations.Reference; 35 import org.apache.felix.scr.annotations.Reference;
34 import org.apache.felix.scr.annotations.ReferenceCardinality; 36 import org.apache.felix.scr.annotations.ReferenceCardinality;
35 import org.apache.felix.scr.annotations.Service; 37 import org.apache.felix.scr.annotations.Service;
38 +import org.joda.time.DateTime;
39 +import org.onlab.packet.IpAddress;
36 import org.onosproject.cluster.ClusterEventListener; 40 import org.onosproject.cluster.ClusterEventListener;
37 import org.onosproject.cluster.ClusterService; 41 import org.onosproject.cluster.ClusterService;
38 import org.onosproject.cluster.ControllerNode; 42 import org.onosproject.cluster.ControllerNode;
...@@ -47,14 +51,11 @@ import org.onosproject.mastership.MastershipTerm; ...@@ -47,14 +51,11 @@ import org.onosproject.mastership.MastershipTerm;
47 import org.onosproject.net.DeviceId; 51 import org.onosproject.net.DeviceId;
48 import org.onosproject.net.MastershipRole; 52 import org.onosproject.net.MastershipRole;
49 import org.onosproject.store.AbstractStore; 53 import org.onosproject.store.AbstractStore;
50 -import org.onlab.packet.IpAddress;
51 import org.slf4j.Logger; 54 import org.slf4j.Logger;
52 55
53 import com.google.common.collect.ImmutableList; 56 import com.google.common.collect.ImmutableList;
54 import com.google.common.collect.ImmutableSet; 57 import com.google.common.collect.ImmutableSet;
55 58
56 -import static org.onosproject.mastership.MastershipEvent.Type.*;
57 -
58 /** 59 /**
59 * Manages inventory of controller mastership over devices using 60 * Manages inventory of controller mastership over devices using
60 * trivial, non-distributed in-memory structures implementation. 61 * trivial, non-distributed in-memory structures implementation.
...@@ -90,6 +91,8 @@ public class SimpleMastershipStore ...@@ -90,6 +91,8 @@ public class SimpleMastershipStore
90 91
91 clusterService = new ClusterService() { 92 clusterService = new ClusterService() {
92 93
94 + private final DateTime creationTime = DateTime.now();
95 +
93 @Override 96 @Override
94 public ControllerNode getLocalNode() { 97 public ControllerNode getLocalNode() {
95 return instance; 98 return instance;
...@@ -118,6 +121,11 @@ public class SimpleMastershipStore ...@@ -118,6 +121,11 @@ public class SimpleMastershipStore
118 } 121 }
119 122
120 @Override 123 @Override
124 + public DateTime getLastUpdated(NodeId nodeId) {
125 + return creationTime;
126 + }
127 +
128 + @Override
121 public void addListener(ClusterEventListener listener) { 129 public void addListener(ClusterEventListener listener) {
122 } 130 }
123 131
......