package org.sdnplatform.sync.internal; import java.io.File; import java.util.ArrayList; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.debugcounter.IDebugCounterService; import net.floodlightcontroller.debugcounter.NullDebugCounter; import net.floodlightcontroller.threadpool.IThreadPoolService; import net.floodlightcontroller.threadpool.ThreadPool; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sdnplatform.sync.IStoreClient; import org.sdnplatform.sync.ISyncService.Scope; import org.sdnplatform.sync.internal.config.AuthScheme; import org.sdnplatform.sync.internal.config.Node; import org.sdnplatform.sync.internal.config.SyncStoreCCProvider; import org.sdnplatform.sync.internal.util.CryptoUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.net.HostAndPort; import static org.junit.Assert.*; import static org.sdnplatform.sync.internal.SyncManagerTest.waitForValue; import static org.sdnplatform.sync.internal.SyncManagerTest.waitForFullMesh; public class BootstrapTest { protected static Logger logger = LoggerFactory.getLogger(BootstrapTest.class); @Rule public TemporaryFolder dbFolder = new TemporaryFolder(); @Test public void testBootstrap() throws Exception { ArrayList<SyncManager> syncManagers = new ArrayList<SyncManager>(); ArrayList<IStoreClient<Short,Node>> nodeStores = new ArrayList<IStoreClient<Short,Node>>(); ArrayList<IStoreClient<String,String>> unsyncStores = new ArrayList<IStoreClient<String,String>>(); ArrayList<Short> nodeIds = new ArrayList<Short>(); ArrayList<Node> nodes = new ArrayList<Node>(); FloodlightModuleContext fmc = new FloodlightModuleContext(); ThreadPool tp = new ThreadPool(); int curPort = 6699; String keyStorePath = new File(dbFolder.getRoot(), "keystore.jceks").getAbsolutePath(); String keyStorePassword = "bootstrapping is fun!"; CryptoUtil.writeSharedSecret(keyStorePath, keyStorePassword, CryptoUtil.secureRandom(16)); // autobootstrap a cluster of 4 nodes for (int i = 0; i < 4; i++) { SyncManager syncManager = new SyncManager(); syncManagers.add(syncManager); fmc.addService(IThreadPoolService.class, tp); fmc.addService(IDebugCounterService.class, new NullDebugCounter()); String dbPath = new File(dbFolder.getRoot(), "server" + i).getAbsolutePath(); fmc.addConfigParam(syncManager, "dbPath", dbPath); tp.init(fmc); syncManager.init(fmc); tp.startUp(fmc); syncManager.startUp(fmc); syncManager.registerStore("localTestStore", Scope.LOCAL); syncManager.registerStore("globalTestStore", Scope.GLOBAL); IStoreClient<String, String> unsyncStore = syncManager.getStoreClient(SyncStoreCCProvider. SYSTEM_UNSYNC_STORE, String.class, String.class); IStoreClient<Short, Node> nodeStore = syncManager.getStoreClient(SyncStoreCCProvider. SYSTEM_NODE_STORE, Short.class, Node.class); unsyncStores.add(unsyncStore); nodeStores.add(nodeStore); // Note that it will end up going through a transitional state // where it will listen on 6642 because it will use the fallback // config unsyncStore.put("localNodePort", String.valueOf(curPort)); unsyncStore.put(SyncStoreCCProvider.KEY_STORE_PATH, keyStorePath); unsyncStore.put(SyncStoreCCProvider.KEY_STORE_PASSWORD, keyStorePassword); unsyncStore.put(SyncStoreCCProvider.AUTH_SCHEME, AuthScheme.CHALLENGE_RESPONSE.toString()); String curSeed = ""; if (i > 0) { curSeed = HostAndPort.fromParts(nodes.get(i-1).getHostname(), nodes.get(i-1).getPort()). toString(); } // The only thing really needed for bootstrapping is to put // a value for "seeds" into the unsynchronized store. unsyncStore.put("seeds", curSeed); waitForValue(unsyncStore, "localNodeId", null, 3000, "unsyncStore" + i); short nodeId = Short.parseShort(unsyncStore.getValue("localNodeId")); Node node = nodeStore.getValue(nodeId); nodeIds.add(nodeId); nodes.add(node); while (syncManager.getClusterConfig(). getNode().getNodeId() != nodeId) { Thread.sleep(100); } while (syncManager.getClusterConfig(). getNode().getPort() != curPort) { Thread.sleep(100); } for (int j = 0; j <= i; j++) { for (int k = 0; k <= i; k++) { waitForValue(nodeStores.get(j), nodeIds.get(k), nodes.get(k), 3000, "nodeStore" + j); } } curPort -= 1; } for (SyncManager syncManager : syncManagers) { assertEquals(syncManagers.size(), syncManager.getClusterConfig().getNodes().size()); } SyncManager[] syncManagerArr = syncManagers.toArray(new SyncManager[syncManagers.size()]); waitForFullMesh(syncManagerArr, 5000); logger.info("Cluster successfully built. Attempting reseed"); // Test reseeding nodeStores.get(0).delete(nodeIds.get(0)); for (int j = 0; j < nodeIds.size(); j++) { for (int k = 0; k < nodeIds.size(); k++) { waitForValue(nodeStores.get(j), nodeIds.get(k), nodes.get(k), 3000, "nodeStore" + j); } } } }