Showing
5 changed files
with
187 additions
and
25 deletions
... | @@ -55,6 +55,5 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD | ... | @@ -55,6 +55,5 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD |
55 | * @param role new role | 55 | * @param role new role |
56 | * @return a mastership event | 56 | * @return a mastership event |
57 | */ | 57 | */ |
58 | - MastershipEvent setRole(NodeId nodeId, DeviceId deviceId, | 58 | + MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId); |
59 | - MastershipRole role); | ||
60 | } | 59 | } | ... | ... |
... | @@ -64,9 +64,12 @@ public class MastershipManager | ... | @@ -64,9 +64,12 @@ public class MastershipManager |
64 | checkNotNull(nodeId, NODE_ID_NULL); | 64 | checkNotNull(nodeId, NODE_ID_NULL); |
65 | checkNotNull(deviceId, DEVICE_ID_NULL); | 65 | checkNotNull(deviceId, DEVICE_ID_NULL); |
66 | checkNotNull(role, ROLE_NULL); | 66 | checkNotNull(role, ROLE_NULL); |
67 | - MastershipEvent event = store.setRole(nodeId, deviceId, role); | 67 | + //TODO figure out appropriate action for non-MASTER roles, if we even set those |
68 | - if (event != null) { | 68 | + if (role.equals(MastershipRole.MASTER)) { |
69 | - post(event); | 69 | + MastershipEvent event = store.setMaster(nodeId, deviceId); |
70 | + if (event != null) { | ||
71 | + post(event); | ||
72 | + } | ||
70 | } | 73 | } |
71 | } | 74 | } |
72 | 75 | ... | ... |
1 | +package org.onlab.onos.cluster.impl; | ||
2 | + | ||
3 | +import java.util.Set; | ||
4 | + | ||
5 | +import org.junit.After; | ||
6 | +import org.junit.Before; | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.onos.cluster.ClusterEventListener; | ||
9 | +import org.onlab.onos.cluster.ClusterService; | ||
10 | +import org.onlab.onos.cluster.ControllerNode; | ||
11 | +import org.onlab.onos.cluster.ControllerNode.State; | ||
12 | +import org.onlab.onos.cluster.DefaultControllerNode; | ||
13 | +import org.onlab.onos.cluster.MastershipService; | ||
14 | +import org.onlab.onos.cluster.NodeId; | ||
15 | +import org.onlab.onos.event.impl.TestEventDispatcher; | ||
16 | +import org.onlab.onos.net.DeviceId; | ||
17 | +import org.onlab.onos.net.trivial.impl.SimpleMastershipStore; | ||
18 | +import org.onlab.packet.IpPrefix; | ||
19 | + | ||
20 | +import static org.junit.Assert.assertEquals; | ||
21 | +import static org.onlab.onos.net.MastershipRole.*; | ||
22 | + | ||
23 | +/** | ||
24 | + * Test codifying the mastership service contracts. | ||
25 | + */ | ||
26 | +public class MastershipManagerTest { | ||
27 | + | ||
28 | + private static final NodeId NID_LOCAL = new NodeId("local"); | ||
29 | + private static final NodeId NID_OTHER = new NodeId("foo"); | ||
30 | + private static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1"); | ||
31 | + private static final DeviceId DEV_MASTER = DeviceId.deviceId("of:1"); | ||
32 | + private static final DeviceId DEV_OTHER = DeviceId.deviceId("of:2"); | ||
33 | + | ||
34 | + private MastershipManager mgr; | ||
35 | + protected MastershipService service; | ||
36 | + | ||
37 | + @Before | ||
38 | + public void setUp() { | ||
39 | + mgr = new MastershipManager(); | ||
40 | + service = mgr; | ||
41 | + mgr.store = new SimpleMastershipStore(); | ||
42 | + mgr.eventDispatcher = new TestEventDispatcher(); | ||
43 | + mgr.clusterService = new TestClusterService(); | ||
44 | + mgr.activate(); | ||
45 | + } | ||
46 | + | ||
47 | + @After | ||
48 | + public void tearDown() { | ||
49 | + mgr.deactivate(); | ||
50 | + mgr.clusterService = null; | ||
51 | + mgr.eventDispatcher = null; | ||
52 | + mgr.store = null; | ||
53 | + } | ||
54 | + | ||
55 | + @Test | ||
56 | + public void setRole() { | ||
57 | + mgr.setRole(NID_OTHER, DEV_MASTER, MASTER); | ||
58 | + assertEquals("wrong local role:", STANDBY, mgr.getLocalRole(DEV_MASTER)); | ||
59 | + | ||
60 | + //set to master | ||
61 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
62 | + assertEquals("wrong local role:", MASTER, mgr.getLocalRole(DEV_MASTER)); | ||
63 | + } | ||
64 | + | ||
65 | + @Test | ||
66 | + public void relinquishMastership() { | ||
67 | + //TODO | ||
68 | + } | ||
69 | + | ||
70 | + @Test | ||
71 | + public void requestRoleFor() { | ||
72 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
73 | + mgr.setRole(NID_OTHER, DEV_OTHER, MASTER); | ||
74 | + | ||
75 | + //local should be master for one but standby for other | ||
76 | + assertEquals("wrong role:", MASTER, mgr.requestRoleFor(DEV_MASTER)); | ||
77 | + assertEquals("wrong role:", STANDBY, mgr.requestRoleFor(DEV_OTHER)); | ||
78 | + } | ||
79 | + | ||
80 | + @Test | ||
81 | + public void getMasterFor() { | ||
82 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
83 | + mgr.setRole(NID_OTHER, DEV_OTHER, MASTER); | ||
84 | + assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER)); | ||
85 | + assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_OTHER)); | ||
86 | + | ||
87 | + //have NID_OTHER hand over DEV_OTHER to NID_LOCAL | ||
88 | + mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); | ||
89 | + assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_OTHER)); | ||
90 | + } | ||
91 | + | ||
92 | + @Test | ||
93 | + public void getDevicesOf() { | ||
94 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
95 | + mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); | ||
96 | + assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); | ||
97 | + | ||
98 | + //hand both devices to NID_LOCAL | ||
99 | + mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); | ||
100 | + assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | ||
101 | + } | ||
102 | + | ||
103 | + private final class TestClusterService implements ClusterService { | ||
104 | + | ||
105 | + ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST); | ||
106 | + | ||
107 | + @Override | ||
108 | + public ControllerNode getLocalNode() { | ||
109 | + return local; | ||
110 | + } | ||
111 | + | ||
112 | + @Override | ||
113 | + public Set<ControllerNode> getNodes() { | ||
114 | + return null; | ||
115 | + } | ||
116 | + | ||
117 | + @Override | ||
118 | + public ControllerNode getNode(NodeId nodeId) { | ||
119 | + return null; | ||
120 | + } | ||
121 | + | ||
122 | + @Override | ||
123 | + public State getState(NodeId nodeId) { | ||
124 | + return null; | ||
125 | + } | ||
126 | + | ||
127 | + @Override | ||
128 | + public void addListener(ClusterEventListener listener) { | ||
129 | + } | ||
130 | + | ||
131 | + @Override | ||
132 | + public void removeListener(ClusterEventListener listener) { | ||
133 | + } | ||
134 | + | ||
135 | + } | ||
136 | +} |
... | @@ -42,6 +42,7 @@ public class DistributedMastershipStore | ... | @@ -42,6 +42,7 @@ public class DistributedMastershipStore |
42 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 42 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
43 | protected ClusterService clusterService; | 43 | protected ClusterService clusterService; |
44 | 44 | ||
45 | + @Override | ||
45 | @Activate | 46 | @Activate |
46 | public void activate() { | 47 | public void activate() { |
47 | super.activate(); | 48 | super.activate(); |
... | @@ -61,10 +62,10 @@ public class DistributedMastershipStore | ... | @@ -61,10 +62,10 @@ public class DistributedMastershipStore |
61 | } | 62 | } |
62 | 63 | ||
63 | @Override | 64 | @Override |
64 | - public MastershipEvent setRole(NodeId nodeId, DeviceId deviceId, MastershipRole role) { | 65 | + public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { |
65 | synchronized (this) { | 66 | synchronized (this) { |
66 | NodeId currentMaster = getMaster(deviceId); | 67 | NodeId currentMaster = getMaster(deviceId); |
67 | - if (role == MastershipRole.MASTER && Objects.equals(currentMaster, nodeId)) { | 68 | + if (Objects.equals(currentMaster, nodeId)) { |
68 | return null; | 69 | return null; |
69 | } | 70 | } |
70 | 71 | ||
... | @@ -94,7 +95,7 @@ public class DistributedMastershipStore | ... | @@ -94,7 +95,7 @@ public class DistributedMastershipStore |
94 | @Override | 95 | @Override |
95 | public MastershipRole requestRole(DeviceId deviceId) { | 96 | public MastershipRole requestRole(DeviceId deviceId) { |
96 | // FIXME: for now we are 'selecting' as master whoever asks | 97 | // FIXME: for now we are 'selecting' as master whoever asks |
97 | - setRole(clusterService.getLocalNode().id(), deviceId, MastershipRole.MASTER); | 98 | + setMaster(clusterService.getLocalNode().id(), deviceId); |
98 | return MastershipRole.MASTER; | 99 | return MastershipRole.MASTER; |
99 | } | 100 | } |
100 | 101 | ... | ... |
... | @@ -3,6 +3,8 @@ package org.onlab.onos.net.trivial.impl; | ... | @@ -3,6 +3,8 @@ package org.onlab.onos.net.trivial.impl; |
3 | import static org.slf4j.LoggerFactory.getLogger; | 3 | import static org.slf4j.LoggerFactory.getLogger; |
4 | 4 | ||
5 | import java.util.Collections; | 5 | import java.util.Collections; |
6 | +import java.util.HashSet; | ||
7 | +import java.util.Map; | ||
6 | import java.util.Set; | 8 | import java.util.Set; |
7 | import java.util.concurrent.ConcurrentHashMap; | 9 | import java.util.concurrent.ConcurrentHashMap; |
8 | import java.util.concurrent.ConcurrentMap; | 10 | import java.util.concurrent.ConcurrentMap; |
... | @@ -27,7 +29,7 @@ import static org.onlab.onos.cluster.MastershipEvent.Type.*; | ... | @@ -27,7 +29,7 @@ import static org.onlab.onos.cluster.MastershipEvent.Type.*; |
27 | 29 | ||
28 | /** | 30 | /** |
29 | * Manages inventory of controller mastership over devices using | 31 | * Manages inventory of controller mastership over devices using |
30 | - * trivial in-memory structures implementation. | 32 | + * trivial, non-distributed in-memory structures implementation. |
31 | */ | 33 | */ |
32 | @Component(immediate = true) | 34 | @Component(immediate = true) |
33 | @Service | 35 | @Service |
... | @@ -35,18 +37,19 @@ public class SimpleMastershipStore | ... | @@ -35,18 +37,19 @@ public class SimpleMastershipStore |
35 | extends AbstractStore<MastershipEvent, MastershipStoreDelegate> | 37 | extends AbstractStore<MastershipEvent, MastershipStoreDelegate> |
36 | implements MastershipStore { | 38 | implements MastershipStore { |
37 | 39 | ||
38 | - public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1"); | ||
39 | - | ||
40 | private final Logger log = getLogger(getClass()); | 40 | private final Logger log = getLogger(getClass()); |
41 | 41 | ||
42 | - private ControllerNode instance; | 42 | + public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1"); |
43 | + | ||
44 | + private ControllerNode instance = | ||
45 | + new DefaultControllerNode(new NodeId("local"), LOCALHOST); | ||
43 | 46 | ||
44 | - protected final ConcurrentMap<DeviceId, MastershipRole> roleMap = | 47 | + //devices mapped to their masters, to emulate multiple nodes |
48 | + protected final ConcurrentMap<DeviceId, NodeId> masterMap = | ||
45 | new ConcurrentHashMap<>(); | 49 | new ConcurrentHashMap<>(); |
46 | 50 | ||
47 | @Activate | 51 | @Activate |
48 | public void activate() { | 52 | public void activate() { |
49 | - instance = new DefaultControllerNode(new NodeId("local"), LOCALHOST); | ||
50 | log.info("Started"); | 53 | log.info("Started"); |
51 | } | 54 | } |
52 | 55 | ||
... | @@ -56,23 +59,36 @@ public class SimpleMastershipStore | ... | @@ -56,23 +59,36 @@ public class SimpleMastershipStore |
56 | } | 59 | } |
57 | 60 | ||
58 | @Override | 61 | @Override |
59 | - public MastershipEvent setRole(NodeId nodeId, DeviceId deviceId, | 62 | + public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { |
60 | - MastershipRole role) { | 63 | + |
61 | - if (roleMap.get(deviceId) == null) { | 64 | + NodeId node = masterMap.get(deviceId); |
65 | + if (node == null) { | ||
66 | + masterMap.put(deviceId, nodeId); | ||
67 | + return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | ||
68 | + } | ||
69 | + | ||
70 | + if (node.equals(nodeId)) { | ||
62 | return null; | 71 | return null; |
72 | + } else { | ||
73 | + masterMap.put(deviceId, nodeId); | ||
74 | + return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | ||
63 | } | 75 | } |
64 | - roleMap.put(deviceId, role); | ||
65 | - return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | ||
66 | } | 76 | } |
67 | 77 | ||
68 | @Override | 78 | @Override |
69 | public NodeId getMaster(DeviceId deviceId) { | 79 | public NodeId getMaster(DeviceId deviceId) { |
70 | - return instance.id(); | 80 | + return masterMap.get(deviceId); |
71 | } | 81 | } |
72 | 82 | ||
73 | @Override | 83 | @Override |
74 | public Set<DeviceId> getDevices(NodeId nodeId) { | 84 | public Set<DeviceId> getDevices(NodeId nodeId) { |
75 | - return Collections.unmodifiableSet(roleMap.keySet()); | 85 | + Set<DeviceId> ids = new HashSet<>(); |
86 | + for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) { | ||
87 | + if (d.getValue().equals(nodeId)) { | ||
88 | + ids.add(d.getKey()); | ||
89 | + } | ||
90 | + } | ||
91 | + return Collections.unmodifiableSet(ids); | ||
76 | } | 92 | } |
77 | 93 | ||
78 | @Override | 94 | @Override |
... | @@ -82,11 +98,18 @@ public class SimpleMastershipStore | ... | @@ -82,11 +98,18 @@ public class SimpleMastershipStore |
82 | 98 | ||
83 | @Override | 99 | @Override |
84 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 100 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
85 | - MastershipRole role = roleMap.get(deviceId); | 101 | + NodeId node = masterMap.get(deviceId); |
86 | - if (role == null) { | 102 | + MastershipRole role; |
87 | - //say MASTER. If clustered, we'd figure out if anyone's got dibs here. | 103 | + if (node != null) { |
104 | + if (node.equals(nodeId)) { | ||
105 | + role = MastershipRole.MASTER; | ||
106 | + } else { | ||
107 | + role = MastershipRole.STANDBY; | ||
108 | + } | ||
109 | + } else { | ||
110 | + //masterMap doesn't contain it. | ||
88 | role = MastershipRole.MASTER; | 111 | role = MastershipRole.MASTER; |
89 | - roleMap.put(deviceId, role); | 112 | + masterMap.put(deviceId, nodeId); |
90 | } | 113 | } |
91 | return role; | 114 | return role; |
92 | } | 115 | } | ... | ... |
-
Please register or login to post a comment