/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.communication.management.internal; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import de.rcenvironment.core.command.common.CommandException; import de.rcenvironment.core.command.spi.CommandContext; import de.rcenvironment.core.command.spi.CommandDescription; import de.rcenvironment.core.command.spi.CommandPlugin; import de.rcenvironment.core.communication.api.CommunicationService; import de.rcenvironment.core.communication.channel.MessageChannelService; import de.rcenvironment.core.communication.common.InstanceNodeSessionId; import de.rcenvironment.core.communication.management.BenchmarkService; import de.rcenvironment.core.communication.management.BenchmarkSetup; import de.rcenvironment.core.communication.nodeproperties.NodePropertiesService; import de.rcenvironment.core.configuration.ConfigurationService; import de.rcenvironment.core.configuration.ConfigurationService.ConfigurablePathId; import de.rcenvironment.core.utils.common.StringUtils; import de.rcenvironment.core.utils.incubator.GraphvizUtils; /** * A {@link CommandPlugin} providing "net [...]" commands for querying the network and topology state, as well as performing benchmark * operations. * * @author Robert Mischke * @author Jan Flink ("net components") */ public class NetCommandPlugin implements CommandPlugin { private static final String CMD_NET = "net"; private CommunicationService communicationService; private BenchmarkService benchmarkService; private NodePropertiesService nodePropertiesService; private MessageChannelService messageChannelService; private final Log log = LogFactory.getLog(getClass()); private File outputDir; @Override public Collection<CommandDescription> getCommandDescriptions() { final Collection<CommandDescription> contributions = new ArrayList<CommandDescription>(); contributions.add(new CommandDescription(CMD_NET, "", false, "short version of \"net info\"")); contributions.add(new CommandDescription("net info", "", false, "show a list of reachable RCE nodes")); contributions.add(new CommandDescription("net graph", "[<base name>]", true, "generates a Graphviz file of the current network topology")); contributions.add(new CommandDescription("net filter", "", false, "show IP filter status")); contributions.add(new CommandDescription("net filter reload", "", false, "reloads the IP filter configuration")); // developer commands contributions.add(new CommandDescription("net graph -a", "[<base name>]", true, "like \"net graph\", but include unreachable nodes")); contributions.add(new CommandDescription("net bench", "<taskdef>[;<taskDef>]*", true, "run communication benchmark", "<taskDef> = <targetNode|*>([<numMessages>],[<requestSize>],[<responseSize>],", " [<responseDelay(msec)>],[<threadsPerTarget>])")); contributions.add(new CommandDescription("net np", "", true, "show known RCE node properties")); return contributions; } @Override public void execute(CommandContext context) throws CommandException { context.consumeExpectedToken(CMD_NET); String subCmd = context.consumeNextToken(); if (subCmd == null) { // "net" -> "net info" performNetInfo(context); } else { if ("add".equals(subCmd)) { // "net add <...>" context.println("Obsolete command; use \"cn add\" instead"); return; } else if ("bench".equals(subCmd)) { // "net bench <...>" performNetBench(context); } else if ("filter".equals(subCmd)) { performNetFilter(context); } else if ("graph".equals(subCmd)) { performNetGraph(context); } else if ("info".equals(subCmd)) { // TODO review: add "extended" info output? (e.g. "-a" flag) performNetInfo(context); } else if ("np".equals(subCmd)) { performNetNp(context); } else { throw CommandException.unknownCommand(context); } } } /** * OSGi-DS bind method. * * @param newInstance the new service instance */ public void bindCommunicationService(CommunicationService newInstance) { this.communicationService = newInstance; } /** * OSGi-DS bind method. * * @param newInstance the new service instance */ public void bindBenchmarkService(BenchmarkService newInstance) { this.benchmarkService = newInstance; } /** * OSGi-DS bind method. * * @param newInstance the new service instance */ public void bindNodePropertiesService(NodePropertiesService newInstance) { this.nodePropertiesService = newInstance; } /** * OSGi-DS bind method. * * @param newInstance the new service instance */ public void bindConfigurationService(ConfigurationService newInstance) { this.outputDir = newInstance.getConfigurablePath(ConfigurablePathId.PROFILE_OUTPUT); } /** * OSGi-DS bind method. * * @param newInstance the new service instance */ public void bindMessageChannelService(MessageChannelService newInstance) { messageChannelService = newInstance; } private void performNetGraph(CommandContext context) throws CommandException { // sanity check if (outputDir == null || !outputDir.isDirectory()) { throw new IllegalStateException("Invalid output dir: " + outputDir); } String formatName = "graphviz"; if (context.consumeNextTokenIfEquals("-a")) { formatName = "graphviz-all"; context.setDeveloperCommandSetEnabled(true); } List<String> parameters = context.consumeRemainingTokens(); if (parameters.size() > 1) { throw CommandException.wrongNumberOfParameters(context); } String baseName = "rce_network"; // default if (parameters.size() == 1) { baseName = parameters.get(0); } String graphvizData = communicationService.getFormattedNetworkInformation(formatName); File gvFile = new File(outputDir, baseName + ".gv"); File pngFile = new File(outputDir, baseName + ".png"); try { FileUtils.writeStringToFile(gvFile, graphvizData); context.println("Graphviz file written to " + gvFile.getAbsolutePath()); } catch (IOException e) { log.error("Error writing script file " + gvFile.getAbsolutePath(), e); return; } if (GraphvizUtils.renderDotFileToPng(gvFile, pngFile, context.getOutputReceiver())) { context.println("PNG file written to " + pngFile.getAbsolutePath()); } else { context.println("Error running graphviz - PNG file " + pngFile.getAbsolutePath() + " was probably not generated"); } } private void performNetInfo(CommandContext context) { context.println(communicationService.getFormattedNetworkInformation("info")); } private void performNetBench(CommandContext context) throws CommandException { context.setDeveloperCommandSetEnabled(true); List<String> parameters = context.consumeRemainingTokens(); if (parameters.size() != 1) { throw CommandException.wrongNumberOfParameters(context); } BenchmarkSetup setup; try { String benchmarkDescription = parameters.get(0); setup = benchmarkService.parseBenchmarkDescription(benchmarkDescription); } catch (IllegalArgumentException e) { throw CommandException.syntaxError("Error parsing benchmark setup: " + e.toString(), context); } context.println("Benchmark starting"); benchmarkService.executeBenchmark(setup, context.getOutputReceiver()); context.println("Benchmark complete"); } private void performNetFilter(CommandContext context) throws CommandException { String nextToken = context.consumeNextToken(); if (nextToken == null) { // show status messageChannelService.printIPFilterInformation(context.getOutputReceiver()); } else if ("reload".equals(nextToken)) { messageChannelService.loadAndApplyIPFilterConfiguration(); messageChannelService.printIPFilterInformation(context.getOutputReceiver()); } else { throw CommandException.unknownCommand(context); } } private void performNetNp(CommandContext context) { Set<InstanceNodeSessionId> nodes = communicationService.getReachableInstanceNodes(); Map<InstanceNodeSessionId, Map<String, String>> allMetadata = nodePropertiesService.getAllNodeProperties(nodes); context.println("Known node properties:"); for (Map.Entry<InstanceNodeSessionId, Map<String, String>> entry1 : allMetadata.entrySet()) { InstanceNodeSessionId nodeId = entry1.getKey(); context.println(nodeId.toString()); Map<String, String> map = entry1.getValue(); for (Map.Entry<String, String> entry2 : map.entrySet()) { context.println(StringUtils.format(" %s = %s", entry2.getKey(), entry2.getValue())); } } } }