Java tutorial
/* * Copyright 1999-2010 University of Chicago * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy * of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.globus.workspace.remoting.admin.client; import org.apache.commons.cli.*; import org.globus.workspace.network.AssociationEntry; import org.globus.workspace.remoting.admin.NodeReport; import org.globus.workspace.remoting.admin.VmmNode; import org.nimbustools.api.services.admin.RemoteNodeManagement; import java.io.*; import java.rmi.RemoteException; import java.util.*; public class AdminClient extends RMIConfig { private static final String PROP_RMI_BINDING_NODEMGMT_DIR = "rmi.binding.nodemgmt"; private static final String PROP_DEFAULT_MEMORY = "node.memory.default"; private static final String PROP_DEFAULT_NETWORKS = "node.networks.default"; private static final String PROP_DEFAULT_POOL = "node.pool.default"; private static final String FIELD_HOSTNAME = "hostname"; private static final String FIELD_POOL = "pool"; private static final String FIELD_MEMORY = "memory"; private static final String FIELD_MEM_REMAIN = "memory available"; private static final String FIELD_NETWORKS = "networks"; private static final String FIELD_ACTIVE = "active"; private static final String FIELD_IN_USE = "in_use"; private static final String FIELD_RESULT = "result"; private static final String FIELD_IP = "ip"; private static final String FIELD_MAC = "mac"; private static final String FIELD_BROADCAST = "broadcast"; private static final String FIELD_SUBNET_MASK = "subnet mask"; private static final String FIELD_GATEWAY = "gateway"; private static final String FIELD_EXPLICIT_MAC = "explicit mac"; final static String[] NODE_FIELDS = new String[] { FIELD_HOSTNAME, FIELD_POOL, FIELD_MEMORY, FIELD_MEM_REMAIN, FIELD_NETWORKS, FIELD_IN_USE, FIELD_ACTIVE }; final static String[] NODE_REPORT_FIELDS = new String[] { FIELD_HOSTNAME, FIELD_POOL, FIELD_MEMORY, FIELD_NETWORKS, FIELD_IN_USE, FIELD_ACTIVE, FIELD_RESULT, }; final static String[] NODE_REPORT_FIELDS_SHORT = new String[] { FIELD_HOSTNAME, FIELD_RESULT }; final static String[] NODE_ALLOCATION_FIELDS = new String[] { FIELD_HOSTNAME, FIELD_IP, FIELD_MAC, FIELD_BROADCAST, FIELD_SUBNET_MASK, FIELD_GATEWAY, FIELD_IN_USE, FIELD_EXPLICIT_MAC }; private AdminAction action; private List<String> hosts; // node options for adding/updating private int nodeMemory; private boolean nodeMemoryConfigured; private String nodeNetworks; private String nodePool; private boolean nodeActive = true; private boolean nodeActiveConfigured; private int inUse = 0; private RemoteNodeManagement remoteNodeManagement; public static void main(String args[]) { Throwable anyError = null; ParameterProblem paramError = null; ExecutionProblem execError = null; int ret = EXIT_OK; try { final AdminClient adminClient = new AdminClient(); adminClient.setupDebug(args); adminClient.run(args); } catch (ParameterProblem e) { paramError = e; anyError = e; ret = EXIT_PARAMETER_PROBLEM; } catch (ExecutionProblem e) { execError = e; anyError = e; ret = EXIT_EXECUTION_PROBLEM; } catch (Throwable t) { anyError = t; ret = EXIT_UNKNOWN_PROBLEM; } if (anyError == null) { System.exit(ret); } else { logger.debug("Got error", anyError); } if (paramError != null) { System.err.println("Parameter Problem:\n\n" + paramError.getMessage()); System.err.println("See --help"); } else if (execError != null) { System.err.println(execError.getMessage()); } else { System.err.println("An unexpected error was encountered. Please report this!"); System.err.println(anyError.getMessage()); System.err.println(); System.err.println("Stack trace:"); anyError.printStackTrace(System.err); } System.exit(ret); } public void run(String[] args) throws ExecutionProblem, ParameterProblem { this.loadArgs(args); if (this.action == AdminAction.Help) { InputStream is = AdminClient.class.getResourceAsStream("help.txt"); System.out.println(super.getHelpText(is)); return; } this.loadAdminClientConfig(); this.remoteNodeManagement = (RemoteNodeManagement) super.setupRemoting(); switch (this.action) { case AddNodes: run_addNodes(); break; case ListNodes: run_listNodes(); break; case RemoveNodes: run_removeNodes(); break; case UpdateNodes: run_updateNodes(); break; case PoolAvailability: run_poolAvail(); break; } } private void run_addNodes() throws ParameterProblem, ExecutionProblem { if (!this.nodeMemoryConfigured) { throw new ParameterProblem( "Node max memory must be specified as an argument (" + Opts.MEMORY_LONG + ") or config value"); } if (this.nodeNetworks == null) { throw new ParameterProblem("Node network associations must be specified as an argument (" + Opts.NETWORKS_LONG + ") or config value"); } if (this.nodePool == null) { throw new ParameterProblem( "Node pool name must be specified as an argument (" + Opts.POOL_LONG + ") or config value"); } final List<VmmNode> nodes = new ArrayList<VmmNode>(this.hosts.size()); for (String hostname : this.hosts) { nodes.add(new VmmNode(hostname, this.nodeActive, this.nodePool, this.nodeMemory, this.nodeNetworks, true)); } final String nodesJson = gson.toJson(nodes); NodeReport[] reports = null; try { final String reportJson = this.remoteNodeManagement.addNodes(nodesJson); reports = gson.fromJson(reportJson, NodeReport[].class); } catch (RemoteException e) { handleRemoteException(e); } try { reporter.report(nodeReportsToMaps(reports), this.outStream); } catch (IOException e) { throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); } } private void run_listNodes() throws ExecutionProblem { VmmNode[] nodes = null; try { final String nodesJson = this.remoteNodeManagement.listNodes(); nodes = this.gson.fromJson(nodesJson, VmmNode[].class); } catch (RemoteException e) { handleRemoteException(e); } try { reporter.report(nodesToMaps(nodes), this.outStream); } catch (IOException e) { throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); } } private void run_removeNodes() throws ExecutionProblem { NodeReport[] reports = null; try { final String[] hostnames = this.hosts.toArray(new String[this.hosts.size()]); final String reportJson = this.remoteNodeManagement.removeNodes(hostnames); reports = gson.fromJson(reportJson, NodeReport[].class); } catch (RemoteException e) { handleRemoteException(e); } try { reporter.report(nodeReportsToMaps(reports), this.outStream); } catch (IOException e) { throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); } } private void run_updateNodes() throws ExecutionProblem { final String[] hostnames = this.hosts.toArray(new String[this.hosts.size()]); final Boolean active = this.nodeActiveConfigured ? this.nodeActive : null; final String resourcepool = this.nodePool; final Integer memory = this.nodeMemoryConfigured ? this.nodeMemory : null; final String networks = this.nodeNetworks; NodeReport[] reports = null; try { final String reportJson = this.remoteNodeManagement.updateNodes(hostnames, active, resourcepool, memory, networks); reports = gson.fromJson(reportJson, NodeReport[].class); } catch (RemoteException e) { super.handleRemoteException(e); } try { reporter.report(nodeReportsToMaps(reports), this.outStream); } catch (IOException e) { throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); } } private void run_poolAvail() throws ExecutionProblem { AssociationEntry[] entries = null; try { if (this.nodePool != null) { final String entriesJson = this.remoteNodeManagement.getNetworkPool(this.nodePool, this.inUse); if (entriesJson == null) { System.err.println("No entries with pool name " + nodePool + " found"); return; } entries = gson.fromJson(entriesJson, AssociationEntry[].class); } else { final String entriesJson = this.remoteNodeManagement.getAllNetworkPools(this.inUse); if (entriesJson == null) { System.err.println("No pool entries found"); return; } entries = gson.fromJson(entriesJson, AssociationEntry[].class); } } catch (RemoteException e) { System.err.println(e.getMessage()); } try { reporter.report(nodeAllocationToMaps(entries), this.outStream); } catch (IOException e) { throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); } } private void loadAdminClientConfig() throws ParameterProblem, ExecutionProblem { super.loadConfig(PROP_RMI_BINDING_NODEMGMT_DIR); // only need node parameter values if doing add-nodes if (this.action == AdminAction.AddNodes) { if (!this.nodeMemoryConfigured) { final String memString = properties.getProperty(PROP_DEFAULT_MEMORY); if (memString != null) { this.nodeMemory = parseMemory(memString); this.nodeMemoryConfigured = true; } } if (this.nodeNetworks == null) { this.nodeNetworks = properties.getProperty(PROP_DEFAULT_NETWORKS); } if (this.nodePool == null) { // if missing or invalid, error will come later if this value is actually needed this.nodePool = properties.getProperty(PROP_DEFAULT_POOL); } } } private void loadArgs(String[] args) throws ParameterProblem { logger.debug("Parsing command line arguments"); final CommandLineParser parser = new PosixParser(); final Opts opts = new Opts(); final CommandLine line; try { line = parser.parse(opts.getOptions(), args); } catch (ParseException e) { throw new ParameterProblem(e.getMessage(), e); } // figure action first AdminAction theAction = null; for (AdminAction a : AdminAction.values()) { if (line.hasOption(a.option())) { if (theAction == null) { theAction = a; } else { throw new ParameterProblem("You may only specify a single action"); } } } if (theAction == null) { throw new ParameterProblem("You must specify an action"); } this.action = theAction; logger.debug("Action: " + theAction); // short circuit for --help arg if (theAction == AdminAction.Help) { return; } // then action-specific arguments if (theAction == AdminAction.AddNodes || theAction == AdminAction.UpdateNodes) { this.hosts = parseHosts(line.getOptionValue(theAction.option())); if (line.hasOption(Opts.MEMORY)) { final String memString = line.getOptionValue(Opts.MEMORY); if (memString == null || memString.trim().length() == 0) { throw new ParameterProblem("Node memory value is empty"); } this.nodeMemory = parseMemory(memString); this.nodeMemoryConfigured = true; } if (line.hasOption(Opts.NETWORKS)) { this.nodeNetworks = line.getOptionValue(Opts.NETWORKS); } if (line.hasOption(Opts.POOL)) { String pool = line.getOptionValue(Opts.POOL); if (pool == null || pool.trim().length() == 0) { throw new ParameterProblem("Node pool value is empty"); } this.nodePool = pool.trim(); } final boolean active = line.hasOption(Opts.ACTIVE); final boolean inactive = line.hasOption(Opts.INACTIVE); if (active && inactive) { throw new ParameterProblem( "You cannot specify both " + Opts.ACTIVE_LONG + " and " + Opts.INACTIVE_LONG); } if (active) { this.nodeActiveConfigured = true; } if (inactive) { this.nodeActive = false; this.nodeActiveConfigured = true; } } else if (theAction == AdminAction.RemoveNodes) { this.hosts = parseHosts(line.getOptionValue(theAction.option())); } else if (theAction == AdminAction.ListNodes) { final String hostArg = line.getOptionValue(AdminAction.ListNodes.option()); if (hostArg != null) { this.hosts = parseHosts(hostArg); } } else if (theAction == AdminAction.PoolAvailability) { if (line.hasOption(Opts.POOL)) { final String pool = line.getOptionValue(Opts.POOL); if (pool == null || pool.trim().length() == 0) { throw new ParameterProblem("Pool name value is empty"); } this.nodePool = pool; } if (line.hasOption(Opts.FREE)) { this.inUse = RemoteNodeManagement.FREE_ENTRIES; } if (line.hasOption(Opts.USED)) { this.inUse = RemoteNodeManagement.USED_ENTRIES; } } //finally everything else if (!line.hasOption(Opts.CONFIG)) { throw new ParameterProblem(Opts.CONFIG_LONG + " option is required"); } String config = line.getOptionValue(Opts.CONFIG); if (config == null || config.trim().length() == 0) { throw new ParameterProblem("Config file path is invalid"); } super.configPath = config.trim(); final boolean batchMode = line.hasOption(Opts.BATCH); final boolean json = line.hasOption(Opts.JSON); final Reporter.OutputMode mode; if (batchMode && json) { throw new ParameterProblem("You cannot specify both " + Opts.BATCH_LONG + " and " + Opts.JSON_LONG); } else if (batchMode) { mode = Reporter.OutputMode.Batch; } else if (json) { mode = Reporter.OutputMode.Json; } else { mode = Reporter.OutputMode.Friendly; } final String[] fields; if (line.hasOption(Opts.REPORT)) { fields = parseFields(line.getOptionValue(Opts.REPORT), theAction); } else { fields = theAction.fields(); } String delimiter = null; if (line.hasOption(Opts.DELIMITER)) { delimiter = line.getOptionValue(Opts.DELIMITER); } this.reporter = new Reporter(mode, fields, delimiter); if (line.hasOption(Opts.OUTPUT)) { final String filename = line.getOptionValue(Opts.OUTPUT); final File f = new File(filename); try { this.outStream = new FileOutputStream(f); } catch (FileNotFoundException e) { throw new ParameterProblem( "Specified output file could not be opened for writing: " + f.getAbsolutePath(), e); } } else { this.outStream = System.out; } final List leftovers = line.getArgList(); if (leftovers != null && !leftovers.isEmpty()) { throw new ParameterProblem("There are unrecognized arguments, check -h to make " + "sure you are doing the intended thing: " + leftovers.toString()); } } private int parseMemory(String memoryString) throws ParameterProblem { final int memory; try { memory = Integer.valueOf(memoryString.trim()); } catch (NumberFormatException e) { throw new ParameterProblem("Node memory value must be numeric"); } if (memory < 0) { throw new ParameterProblem("Node memory value must be non-negative"); } return memory; } private static List<String> parseHosts(String hostString) throws ParameterProblem { if (hostString == null) { throw new ParameterProblem("Hosts list is invalid"); } final String[] hostArray = hostString.trim().split("\\s*,\\s*"); if (hostArray.length == 0) { throw new ParameterProblem("Hosts list is empty"); } final List<String> hosts = new ArrayList<String>(hostArray.length); for (final String host : hostArray) { if (!host.matches("^[\\w-\\.]+$")) { throw new ParameterProblem("Invalid node hostname specified: " + host); } hosts.add(host); } return hosts; } private static List<Map<String, String>> nodesToMaps(VmmNode[] nodes) { List<Map<String, String>> maps = new ArrayList<Map<String, String>>(nodes.length); for (VmmNode node : nodes) { maps.add(nodeToMap(node)); } return maps; } private static Map<String, String> nodeToMap(VmmNode node) { final HashMap<String, String> map = new HashMap<String, String>(7); map.put(FIELD_HOSTNAME, node.getHostname()); map.put(FIELD_POOL, node.getPoolName()); map.put(FIELD_MEMORY, String.valueOf(node.getMemory())); map.put(FIELD_MEM_REMAIN, String.valueOf(node.getMemRemain())); map.put(FIELD_NETWORKS, node.getNetworkAssociations()); map.put(FIELD_IN_USE, String.valueOf(!node.isVacant())); map.put(FIELD_ACTIVE, String.valueOf(node.isActive())); return map; } private static List<Map<String, String>> nodeReportsToMaps(NodeReport[] nodeReports) { List<Map<String, String>> maps = new ArrayList<Map<String, String>>(nodeReports.length); for (NodeReport nodeReport : nodeReports) { maps.add(nodeReportToMap(nodeReport)); } return maps; } private static Map<String, String> nodeReportToMap(NodeReport nodeReport) { final HashMap<String, String> map = new HashMap<String, String>(2); map.put(FIELD_HOSTNAME, nodeReport.getHostname()); map.put(FIELD_RESULT, nodeReport.getState()); final VmmNode node = nodeReport.getNode(); if (node == null) { map.put(FIELD_POOL, null); map.put(FIELD_MEMORY, null); map.put(FIELD_NETWORKS, null); map.put(FIELD_IN_USE, null); map.put(FIELD_ACTIVE, null); } else { map.put(FIELD_POOL, node.getPoolName()); map.put(FIELD_MEMORY, String.valueOf(node.getMemory())); map.put(FIELD_NETWORKS, node.getNetworkAssociations()); map.put(FIELD_IN_USE, String.valueOf(!node.isVacant())); map.put(FIELD_ACTIVE, String.valueOf(node.isActive())); } return map; } private static List<Map<String, String>> nodeAllocationToMaps(AssociationEntry[] entries) { List<Map<String, String>> maps = new ArrayList<Map<String, String>>(entries.length); for (AssociationEntry entry : entries) { maps.add(nodeAllocationToMap(entry)); } return maps; } private static Map<String, String> nodeAllocationToMap(AssociationEntry entry) { final HashMap<String, String> map = new HashMap(8); map.put(FIELD_HOSTNAME, entry.getHostname()); map.put(FIELD_IP, entry.getIpAddress()); map.put(FIELD_MAC, entry.getMac()); map.put(FIELD_BROADCAST, entry.getBroadcast()); map.put(FIELD_SUBNET_MASK, entry.getSubnetMask()); map.put(FIELD_GATEWAY, entry.getGateway()); map.put(FIELD_IN_USE, Boolean.toString(entry.isInUse())); map.put(FIELD_EXPLICIT_MAC, Boolean.toString(entry.isExplicitMac())); return map; } } enum AdminAction implements AdminEnum { AddNodes(Opts.ADD_NODES, AdminClient.NODE_REPORT_FIELDS), ListNodes(Opts.LIST_NODES, AdminClient.NODE_FIELDS), RemoveNodes(Opts.REMOVE_NODES, AdminClient.NODE_REPORT_FIELDS_SHORT), UpdateNodes(Opts.UPDATE_NODES, AdminClient.NODE_REPORT_FIELDS), PoolAvailability(Opts.POOL_AVAILABILITY, AdminClient.NODE_ALLOCATION_FIELDS), Help(Opts.HELP, null); private final String option; private final String[] fields; AdminAction(String option, String[] fields) { this.option = option; this.fields = fields; } public String option() { return option; } public String[] fields() { return fields; } }