blob: 0e6ef616a778f29ff37c606f6a114b122619e2b3 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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.cluster.impl;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070017
Claudine Chiudce08152016-03-09 18:19:28 +000018import java.util.List;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070019import java.util.Set;
Claudine Chiudce08152016-03-09 18:19:28 +000020import java.util.function.Consumer;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070021
Claudine Chiudce08152016-03-09 18:19:28 +000022import com.google.common.collect.ImmutableList;
23import com.google.common.collect.ImmutableSet;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070024import org.junit.After;
25import org.junit.Before;
26import org.junit.Test;
Claudine Chiudce08152016-03-09 18:19:28 +000027import org.onlab.junit.TestUtils;
Ray Milkeycc53abd2015-02-19 12:31:33 -080028import org.onlab.packet.IpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.ControllerNode;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.cluster.DefaultControllerNode;
32import org.onosproject.cluster.NodeId;
Thomas Vachuska36002e62015-05-19 16:12:29 -070033import org.onosproject.common.event.impl.TestEventDispatcher;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.mastership.MastershipService;
35import org.onosproject.mastership.MastershipStore;
36import org.onosproject.mastership.MastershipTermService;
37import org.onosproject.net.DeviceId;
Claudine Chiudce08152016-03-09 18:19:28 +000038import org.onosproject.net.region.Region;
39import org.onosproject.net.region.RegionId;
40import org.onosproject.net.region.RegionStore;
41import org.onosproject.net.region.impl.RegionManager;
42import org.onosproject.store.cluster.StaticClusterService;
43import org.onosproject.store.region.impl.DistributedRegionStore;
44import org.onosproject.store.service.TestStorageService;
Thomas Vachuskac97aa612015-06-23 16:00:18 -070045import org.onosproject.store.trivial.SimpleMastershipStore;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070046
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -070047import com.google.common.collect.Sets;
Madan Jampanide003d92015-05-11 17:14:20 -070048import com.google.common.util.concurrent.Futures;
Ayaka Koshibeea5b4ce2014-10-11 14:17:17 -070049
Claudine Chiudce08152016-03-09 18:19:28 +000050import static org.junit.Assert.*;
Ray Milkeycc53abd2015-02-19 12:31:33 -080051import static org.onosproject.net.MastershipRole.MASTER;
52import static org.onosproject.net.MastershipRole.NONE;
53import static org.onosproject.net.MastershipRole.STANDBY;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070054import static org.onosproject.net.NetTestTools.injectEventDispatcher;
Claudine Chiudce08152016-03-09 18:19:28 +000055import static org.onosproject.net.region.Region.Type.METRO;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070056
57/**
58 * Test codifying the mastership service contracts.
59 */
60public class MastershipManagerTest {
61
62 private static final NodeId NID_LOCAL = new NodeId("local");
63 private static final NodeId NID_OTHER = new NodeId("foo");
Pavlin Radoslavov444b5192014-10-28 10:45:19 -070064 private static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
Ayaka Koshibe406d0102014-09-24 16:08:12 -070065 private static final DeviceId DEV_MASTER = DeviceId.deviceId("of:1");
66 private static final DeviceId DEV_OTHER = DeviceId.deviceId("of:2");
67
Claudine Chiudce08152016-03-09 18:19:28 +000068 private static final RegionId RID1 = RegionId.regionId("r1");
69 private static final RegionId RID2 = RegionId.regionId("r2");
70 private static final DeviceId DID1 = DeviceId.deviceId("foo:d1");
71 private static final DeviceId DID2 = DeviceId.deviceId("foo:d2");
72 private static final DeviceId DID3 = DeviceId.deviceId("foo:d3");
73 private static final NodeId NID1 = NodeId.nodeId("n1");
74 private static final NodeId NID2 = NodeId.nodeId("n2");
75 private static final NodeId NID3 = NodeId.nodeId("n3");
76 private static final NodeId NID4 = NodeId.nodeId("n4");
77 private static final ControllerNode CNODE1 =
78 new DefaultControllerNode(NID1, IpAddress.valueOf("127.0.1.1"));
79 private static final ControllerNode CNODE2 =
80 new DefaultControllerNode(NID2, IpAddress.valueOf("127.0.1.2"));
81 private static final ControllerNode CNODE3 =
82 new DefaultControllerNode(NID3, IpAddress.valueOf("127.0.1.3"));
83 private static final ControllerNode CNODE4 =
84 new DefaultControllerNode(NID4, IpAddress.valueOf("127.0.1.4"));
85
86
Ayaka Koshibe406d0102014-09-24 16:08:12 -070087 private MastershipManager mgr;
88 protected MastershipService service;
Claudine Chiudce08152016-03-09 18:19:28 +000089 private TestRegionManager regionManager;
90 private RegionStore regionStore;
91 private TestClusterService testClusterService;
Ayaka Koshibe406d0102014-09-24 16:08:12 -070092
93 @Before
Claudine Chiudce08152016-03-09 18:19:28 +000094 public void setUp() throws Exception {
Ayaka Koshibe406d0102014-09-24 16:08:12 -070095 mgr = new MastershipManager();
96 service = mgr;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070097 injectEventDispatcher(mgr, new TestEventDispatcher());
Claudine Chiudce08152016-03-09 18:19:28 +000098 testClusterService = new TestClusterService();
99 mgr.clusterService = testClusterService;
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800100 mgr.store = new TestSimpleMastershipStore(mgr.clusterService);
Claudine Chiudce08152016-03-09 18:19:28 +0000101 regionStore = new DistributedRegionStore();
102 TestUtils.setField(regionStore, "storageService", new TestStorageService());
103 TestUtils.callMethod(regionStore, "activate",
104 new Class<?>[] {});
105 regionManager = new TestRegionManager();
106 TestUtils.setField(regionManager, "store", regionStore);
107 regionManager.activate();
108 mgr.regionService = regionManager;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700109 mgr.activate();
110 }
111
112 @After
113 public void tearDown() {
114 mgr.deactivate();
115 mgr.clusterService = null;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700116 injectEventDispatcher(mgr, null);
Claudine Chiudce08152016-03-09 18:19:28 +0000117 regionManager.deactivate();
118 mgr.regionService = null;
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700119 mgr.store = null;
120 }
121
122 @Test
123 public void setRole() {
124 mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800125 assertEquals("wrong local role:", NONE, mgr.getLocalRole(DEV_MASTER));
Madan Jampanide003d92015-05-11 17:14:20 -0700126 assertEquals("wrong obtained role:", STANDBY, Futures.getUnchecked(mgr.requestRoleFor(DEV_MASTER)));
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700127
128 //set to master
129 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
130 assertEquals("wrong local role:", MASTER, mgr.getLocalRole(DEV_MASTER));
131 }
132
133 @Test
134 public void relinquishMastership() {
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700135 //no backups - should just turn to NONE for device.
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700136 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
137 assertEquals("wrong role:", MASTER, mgr.getLocalRole(DEV_MASTER));
138 mgr.relinquishMastership(DEV_MASTER);
139 assertNull("wrong master:", mgr.getMasterFor(DEV_OTHER));
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700140 assertEquals("wrong role:", NONE, mgr.getLocalRole(DEV_MASTER));
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700141
142 //not master, nothing should happen
Ayaka Koshibeb62aab52014-10-24 13:15:25 -0700143 mgr.setRole(NID_LOCAL, DEV_OTHER, NONE);
Ayaka Koshibed9f693e2014-09-29 18:04:54 -0700144 mgr.relinquishMastership(DEV_OTHER);
145 assertNull("wrong role:", mgr.getMasterFor(DEV_OTHER));
146
147 //provide NID_OTHER as backup and relinquish
148 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
149 assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER));
150 mgr.setRole(NID_OTHER, DEV_MASTER, STANDBY);
151 mgr.relinquishMastership(DEV_MASTER);
152 assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_MASTER));
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700153 }
154
155 @Test
156 public void requestRoleFor() {
157 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
158 mgr.setRole(NID_OTHER, DEV_OTHER, MASTER);
159
160 //local should be master for one but standby for other
Madan Jampanide003d92015-05-11 17:14:20 -0700161 assertEquals("wrong role:", MASTER, Futures.getUnchecked(mgr.requestRoleFor(DEV_MASTER)));
162 assertEquals("wrong role:", STANDBY, Futures.getUnchecked(mgr.requestRoleFor(DEV_OTHER)));
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700163 }
164
165 @Test
166 public void getMasterFor() {
167 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
168 mgr.setRole(NID_OTHER, DEV_OTHER, MASTER);
169 assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER));
170 assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_OTHER));
171
172 //have NID_OTHER hand over DEV_OTHER to NID_LOCAL
173 mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER);
174 assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_OTHER));
175 }
176
177 @Test
178 public void getDevicesOf() {
179 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
180 mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY);
181 assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size());
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700182 //hand both devices to NID_LOCAL
183 mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER);
184 assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size());
185 }
186
Ayaka Koshibe48239b02014-09-25 17:12:31 -0700187 @Test
188 public void termService() {
Yuta HIGUCHIbcac4992014-11-22 19:27:57 -0800189 MastershipTermService ts = mgr;
Ayaka Koshibe48239b02014-09-25 17:12:31 -0700190
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700191 //term = 1 for both
Ayaka Koshibe48239b02014-09-25 17:12:31 -0700192 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700193 assertEquals("inconsistent term: ", 1, ts.getMastershipTerm(DEV_MASTER).termNumber());
Ayaka Koshibe48239b02014-09-25 17:12:31 -0700194
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700195 //hand devices to NID_LOCAL and back: term = 1 + 2
Ayaka Koshibe48239b02014-09-25 17:12:31 -0700196 mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
197 mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
Yuta HIGUCHIdfe6e3b2014-10-30 11:31:51 -0700198 assertEquals("inconsistent terms: ", 3, ts.getMastershipTerm(DEV_MASTER).termNumber());
Ayaka Koshibe48239b02014-09-25 17:12:31 -0700199 }
200
Claudine Chiudce08152016-03-09 18:19:28 +0000201 @Test
202 public void balanceWithRegion1() {
203 //set up region - 2 sets of masters with 1 node in each
204 Set<NodeId> masterSet1 = ImmutableSet.of(NID1);
205 Set<NodeId> masterSet2 = ImmutableSet.of(NID2);
206 List<Set<NodeId>> masters = ImmutableList.of(masterSet1, masterSet2);
207 Region r = regionManager.createRegion(RID1, "R1", METRO, masters);
208 regionManager.addDevices(RID1, ImmutableSet.of(DID1, DID2));
209 Set<DeviceId> deviceIds = regionManager.getRegionDevices(RID1);
210 assertEquals("incorrect device count", 2, deviceIds.size());
211
212 testClusterService.put(CNODE1, ControllerNode.State.ACTIVE);
213 testClusterService.put(CNODE2, ControllerNode.State.ACTIVE);
214
215 //set master to non region nodes
216 mgr.setRole(NID_LOCAL, DID1, MASTER);
217 mgr.setRole(NID_LOCAL, DID2, MASTER);
218 assertEquals("wrong local role:", MASTER, mgr.getLocalRole(DID1));
219 assertEquals("wrong local role:", MASTER, mgr.getLocalRole(DID2));
220 assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DID1));
221 assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DID2));
222
223 //do region balancing
224 mgr.useRegionForBalanceRoles = true;
225 mgr.balanceRoles();
226 assertEquals("wrong master:", NID1, mgr.getMasterFor(DID1));
227 assertEquals("wrong master:", NID1, mgr.getMasterFor(DID2));
228
229 // make N1 inactive
230 testClusterService.put(CNODE1, ControllerNode.State.INACTIVE);
231 mgr.balanceRoles();
232 assertEquals("wrong master:", NID2, mgr.getMasterFor(DID1));
233 assertEquals("wrong master:", NID2, mgr.getMasterFor(DID2));
234
235 }
236
237 @Test
238 public void balanceWithRegion2() {
239 //set up region - 2 sets of masters with (3 nodes, 1 node)
240 Set<NodeId> masterSet1 = ImmutableSet.of(NID1, NID3, NID4);
241 Set<NodeId> masterSet2 = ImmutableSet.of(NID2);
242 List<Set<NodeId>> masters = ImmutableList.of(masterSet1, masterSet2);
243 Region r = regionManager.createRegion(RID1, "R1", METRO, masters);
244 Set<DeviceId> deviceIdsOrig = ImmutableSet.of(DID1, DID2, DID3, DEV_OTHER);
245 regionManager.addDevices(RID1, deviceIdsOrig);
246 Set<DeviceId> deviceIds = regionManager.getRegionDevices(RID1);
247 assertEquals("incorrect device count", deviceIdsOrig.size(), deviceIds.size());
248 assertEquals("incorrect devices in region", deviceIdsOrig, deviceIds);
249
250 testClusterService.put(CNODE1, ControllerNode.State.ACTIVE);
251 testClusterService.put(CNODE2, ControllerNode.State.ACTIVE);
252 testClusterService.put(CNODE3, ControllerNode.State.ACTIVE);
253 testClusterService.put(CNODE4, ControllerNode.State.ACTIVE);
254
255 //set master to non region nodes
256 deviceIdsOrig.forEach(deviceId1 -> mgr.setRole(NID_LOCAL, deviceId1, MASTER));
257 checkDeviceMasters(deviceIds, Sets.newHashSet(NID_LOCAL), deviceId ->
258 assertEquals("wrong local role:", MASTER, mgr.getLocalRole(deviceId)));
259
260 //do region balancing
261 mgr.useRegionForBalanceRoles = true;
262 mgr.balanceRoles();
263 Set<NodeId> expectedMasters = Sets.newHashSet(NID1, NID3, NID4);
264 checkDeviceMasters(deviceIds, expectedMasters);
265
266 // make N1 inactive
267 testClusterService.put(CNODE1, ControllerNode.State.INACTIVE);
268 expectedMasters.remove(NID1);
269 mgr.balanceRoles();
270 checkDeviceMasters(deviceIds, expectedMasters);
271
272 // make N4 inactive
273 testClusterService.put(CNODE4, ControllerNode.State.INACTIVE);
274 expectedMasters.remove(NID4);
275 mgr.balanceRoles();
276 checkDeviceMasters(deviceIds, expectedMasters);
277
278 // make N3 inactive
279 testClusterService.put(CNODE3, ControllerNode.State.INACTIVE);
280 expectedMasters = Sets.newHashSet(NID2);
281 mgr.balanceRoles();
282 checkDeviceMasters(deviceIds, expectedMasters);
283
284 // make N3 active
285 testClusterService.put(CNODE3, ControllerNode.State.ACTIVE);
286 expectedMasters = Sets.newHashSet(NID3);
287 mgr.balanceRoles();
288 checkDeviceMasters(deviceIds, expectedMasters);
289
290 // make N4 active
291 testClusterService.put(CNODE4, ControllerNode.State.ACTIVE);
292 expectedMasters.add(NID4);
293 mgr.balanceRoles();
294 checkDeviceMasters(deviceIds, expectedMasters);
295
296 // make N1 active
297 testClusterService.put(CNODE1, ControllerNode.State.ACTIVE);
298 expectedMasters.add(NID1);
299 mgr.balanceRoles();
300 checkDeviceMasters(deviceIds, expectedMasters);
301 }
302
303 private void checkDeviceMasters(Set<DeviceId> deviceIds, Set<NodeId> expectedMasters) {
304 checkDeviceMasters(deviceIds, expectedMasters, null);
305 }
306
307 private void checkDeviceMasters(Set<DeviceId> deviceIds, Set<NodeId> expectedMasters,
308 Consumer<DeviceId> checkRole) {
309 // each device's master must be contained in the list of expectedMasters
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700310 deviceIds.forEach(deviceId -> {
Claudine Chiudce08152016-03-09 18:19:28 +0000311 assertTrue("wrong master:", expectedMasters.contains(mgr.getMasterFor(deviceId)));
312 if (checkRole != null) {
313 checkRole.accept(deviceId);
314 }
315 });
316 // each node in expectedMasters must have approximately the same number of devices
317 if (expectedMasters.size() > 1) {
318 int minValue = Integer.MAX_VALUE;
319 int maxDevices = -1;
320 for (NodeId nodeId: expectedMasters) {
321 int numDevicesManagedByNode = mgr.getDevicesOf(nodeId).size();
322 if (numDevicesManagedByNode < minValue) {
323 minValue = numDevicesManagedByNode;
324 }
325 if (numDevicesManagedByNode > maxDevices) {
326 maxDevices = numDevicesManagedByNode;
327 }
328 assertTrue("not balanced:", maxDevices - minValue <= 1);
329 }
330 }
331 }
332
333 private final class TestClusterService extends StaticClusterService {
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700334
335 ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
336
337 @Override
338 public ControllerNode getLocalNode() {
339 return local;
340 }
341
Claudine Chiudce08152016-03-09 18:19:28 +0000342 public void put(ControllerNode cn, ControllerNode.State state) {
343 nodes.put(cn.id(), cn);
344 nodeStates.put(cn.id(), state);
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700345 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700346 }
Yuta HIGUCHI0c6e1842014-11-05 22:34:23 -0800347
348 private final class TestSimpleMastershipStore extends SimpleMastershipStore
349 implements MastershipStore {
350
351 public TestSimpleMastershipStore(ClusterService clusterService) {
352 super.clusterService = clusterService;
353 }
354 }
Claudine Chiudce08152016-03-09 18:19:28 +0000355
356 private class TestRegionManager extends RegionManager {
357 TestRegionManager() {
358 eventDispatcher = new TestEventDispatcher();
359 }
360 }
Ayaka Koshibe406d0102014-09-24 16:08:12 -0700361}