/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package staticContent.evaluation.testbed.core; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.util.Map; import java.util.Set; import staticContent.evaluation.testbed.deploy.coordinator.Coordinator.DiscoveryMode; import staticContent.evaluation.testbed.deploy.registry.DiscoveryRegistry; import staticContent.evaluation.testbed.deploy.testnode.ITestNode; import staticContent.evaluation.testbed.deploy.utility.SimpleSSHClient; import staticContent.evaluation.testbed.deploy.utility.SimpleSftpClient; import staticContent.evaluation.testbed.plan.XMLConfigReader; import staticContent.evaluation.testbed.plan.node.NodeExecutionPlanException; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.SftpException; public class ModelnetExperiment extends SingleExperiment { boolean isModelFileGenerated = false; boolean isRouteFileGenerated = false; @Override protected boolean setupEnvironment() throws InterruptedException, FileNotFoundException, NotBoundException, IOException, JSchException, SftpException { logger.debug("Setup Modelnet started."); Set<String> expectedNodeNames = plan.getPlannedNodeNames(); Set<String> expectedNodeAddresses = plan.getNodeAddresses(); // start RMI registry DiscoveryRegistry.startRegistryServer(); // trigger node registrations logger.debug("Trigger physical node registrations."); coordinator.triggerNodesToRegister(expectedNodeAddresses); // wait for physical node registrations coordinator.waitForNodeRegistrations(expectedNodeNames, expectedNodeAddresses); // distribute code Set<ITestNode> setOfTestnodes = coordinator.getAvailableTestnodes(DiscoveryMode.REGISTRY); ITestNode firstTestnode = setOfTestnodes.iterator().next(); plan.setTestnodes(setOfTestnodes); // copy Modelnet real and virtual topology to lastTestnode to generate model and route file coordinator.InstallOnTestNode(firstTestnode, plan.getRealTopologyFile(), "real_topology.xml"); coordinator.InstallOnTestNode(firstTestnode, plan.getVirtualTopologyFile(), "virtual_topology.xml"); // generate modelnet route file File modelnetRouteFile = generateModelnetRouteFile(firstTestnode); // generate modelnet model file File modelnetModelFile = generateModelnetModelFile(firstTestnode); // extract virtual IP settings from model file Map<String, Set<String>> map = XMLConfigReader.createNodeVirtualIpAssignment(modelnetModelFile); try { plan.configureVirtualIps(map); } catch (NodeExecutionPlanException e) { logger.error("Configuration of virtual IPs failed.", e); } for(ITestNode testnode: setOfTestnodes) { String testnodeName = testnode.getName(); logger.debug("Setup node on: " + testnode.getHostName() + " node name: " + testnodeName); // install modelnet files coordinator.InstallOnTestNode(testnodeName, modelnetModelFile); coordinator.InstallOnTestNode(testnodeName, modelnetRouteFile); // deploy modelnet configuration on testnode deployModelnet(testnode); logger.debug("Finished setup for node on: " + testnode.getHostName()); } // send Modelnet model and route file also to emulators sendModelnetConfigurationToEmulators(); // deploy on emulators deployModelnetConfigurationOnEmulators(); logger.debug("Finished setup."); return true; } @Override public void cleanup() throws RemoteException, FileNotFoundException, JSchException, SftpException { logger.debug("Cleanup testnodes."); Set<ITestNode> setOfTestnodes = coordinator.getAvailableTestnodes(DiscoveryMode.REGISTRY); // TODO parallelize this for(ITestNode testnode: setOfTestnodes) { // delete all created modelnet virtual network interfaces and routes on testnode testnode.executeCommand(new String[] {"/bin/bash", "-c", "<testbedRoot>/scripts/cleanUpModelnetHost"}, false); // clear installDir testnode.executeCommand(new String[] {"/bin/bash", "-c", "/bin/rm -r <testbedRoot>/install/*"}, false); } removeModelnetConfigurationOnEmulators(); logger.debug("Finished cleanup of testnodes."); } /** * Deploys the Modelnet configuration of the experiment on the given testnode. * * @param ITestNode testnode * @throws RemoteException */ protected void deployModelnet(ITestNode testnode) throws RemoteException { logger.debug("Deploy Modelnet setup on the cluster node: " + testnode.getName()); // deploy Modelnet on the cluster String[] modelnetCommand = {"/usr/local/bin/deployhost", "<testbedRoot>/install/virtual_model.xml", "<testbedRoot>/install/virtual_route.xml"}; testnode.executeCommand(modelnetCommand, true); if (!isModelnetDeployed(testnode)) { logger.error("Modelnet deployment failed. Try again ..."); try { Thread.sleep(1000); } catch (InterruptedException e) { } deployModelnet(testnode); } logger.debug("Modelnet deployment finished."); } /** * Returns true if the Modelnet configuration of the experiment is successfully deployed on the given testnode. * * @param ITestNode testnode * @return boolean * @throws RemoteException */ protected boolean isModelnetDeployed(ITestNode testnode) throws RemoteException { Set<String> assignedIps = testnode.getAssignedVirtualAddresses(); Set<String> plannedIps = plan.getVirtualIpsPerNode(testnode); return assignedIps.containsAll(plannedIps); } protected void sendModelnetConfigurationToEmulators() throws JSchException, FileNotFoundException, SftpException { logger.debug("Send Modelnet configuration to emulator nodes."); String tmpDir = System.getProperty("user.dir") +"/inputOutput/testbed/tmp"; String hostProjectRootDir = config.getString("hostProjectRoot"); // TODO parallelize this for (String emulatorName: plan.getModelnetEmulatorNames()) { logger.debug("Send Modelnet configuration to emulator node "+emulatorName+"."); String username = config.getString(emulatorName+"SSHUser"); String password = config.getString(emulatorName+"SSHPassword"); SimpleSftpClient client = new SimpleSftpClient(username, password, emulatorName, 22); client.putFile(tmpDir + "/virtual_model.xml", hostProjectRootDir +"/inputOutput/testbed/install"); client.putFile(tmpDir + "/virtual_route.xml", hostProjectRootDir +"/inputOutput/testbed/install"); client.disconnect(); } } protected void removeModelnetConfigurationOnEmulators() throws JSchException, FileNotFoundException, SftpException { logger.debug("Remove Modelnet configuration from emulator nodes."); String hostProjectRootDir = config.getString("hostProjectRoot"); // TODO parallelize this for (String emulatorName: plan.getModelnetEmulatorNames()) { logger.debug("Remove Modelnet configuration from emulator node "+emulatorName+"."); String username = config.getString(emulatorName+"SSHUser"); String password = config.getString(emulatorName+"SSHPassword"); SimpleSftpClient client = new SimpleSftpClient(username, password, emulatorName, 22); client.removeFile(hostProjectRootDir+"/inputOutput/testbed/install", "virtual_model.xml"); client.removeFile(hostProjectRootDir+"/inputOutput/testbed/install", "virtual_route.xml"); client.disconnect(); } } public void generateModelnetRealTopologyFile() { Set<String> emulatorNodes = plan.getModelnetEmulatorNames(); Set<String> testnodes = plan.getTestnodeNames(); String topologyFileName = System.getProperty("user.dir") +"/inputOutput/testbed/tmp/real_topology.xml"; Writer writer = null; try { writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(topologyFileName), "utf-8")); writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); writer.write("<hardware>\n"); for (String emulatorNodeName: emulatorNodes) { writer.write("<emul hostname=\""+emulatorNodeName+"\" />\n"); } for (String testnodeName: testnodes) { writer.write("<host hostname=\""+testnodeName+"\" />\n"); } writer.write("</hardware>\n"); } catch (IOException ex) { // report } finally { try {writer.close();} catch (Exception ex) {} } plan.setRealTopologyFile(new File(topologyFileName)); } protected void deployModelnetConfigurationOnEmulators() throws JSchException { logger.debug("Deploy Modelnet configuration on emulator nodes."); String hostProjectRootDir = config.getString("hostProjectRoot"); // TODO parallelize this for (String emulatorName: plan.getModelnetEmulatorNames()) { logger.debug("Deploy Modelnet configuration on emulator node "+emulatorName+"."); String username = config.getString(emulatorName+"SSHUser"); String password = config.getString(emulatorName+"SSHPassword"); if (username == null || password == null) { } SimpleSSHClient client = new SimpleSSHClient(username, password, emulatorName, 22); client.executeCommand("/usr/local/bin/deployhost "+hostProjectRootDir+"/inputOutput/testbed/install/virtual_model.xml "+hostProjectRootDir+"/inputOutput/testbed/install/virtual_route.xml >> /var/log/gmixTest.log"); client.disconnect(); } } protected File generateModelnetModelFile(ITestNode testnode) throws RemoteException { logger.debug("Generate Modelnet model file on cluster node: " + testnode.getName()); // deploy Modelnet on the cluster String[] modelnetCommand = {"/bin/bash", "-c", "/usr/local/bin/mkmodel <testbedRoot>/install/virtual_topology.xml <testbedRoot>/install/real_topology.xml > <testbedRoot>/install/virtual_model.xml"}; testnode.executeCommand(modelnetCommand, true); File result = coordinator.copyFileFromTestnode(testnode, "<testbedRoot>/install/virtual_model.xml", "virtual_model.xml"); if (result != null) { isModelFileGenerated = true; } if (!isModelFileGenerated) { logger.error("Generation of Modelnet model file failed. Try again ..."); try { Thread.sleep(1000); } catch (InterruptedException e) { } result = generateModelnetModelFile(testnode); } logger.debug("Generation of Modelnet model file finished."); return result; } protected File generateModelnetRouteFile(ITestNode testnode) throws RemoteException { logger.debug("Generate Modelnet route file on cluster node: " + testnode.getName()); // deploy Modelnet on the cluster String[] modelnetCommand = {"/bin/bash", "-c", "/usr/local/bin/allpairs <testbedRoot>/install/virtual_topology.xml > <testbedRoot>/install/virtual_route.xml"}; testnode.executeCommand(modelnetCommand, true); File result = coordinator.copyFileFromTestnode(testnode, "<testbedRoot>/install/virtual_route.xml", "virtual_route.xml"); if (result != null) { isRouteFileGenerated = true; } if (!isRouteFileGenerated) { logger.error("Generation of Modelnet route file failed. Try again ..."); try { Thread.sleep(1000); } catch (InterruptedException e) { } result = generateModelnetRouteFile(testnode); } logger.debug("Generation of Modelnet route file finished."); return result; } }