diff --git a/service/service/java/source/src/org/globus/workspace/remoting/admin/VmmNode.java b/service/service/java/source/src/org/globus/workspace/remoting/admin/VmmNode.java index 0f377121..6d15a6fe 100644 --- a/service/service/java/source/src/org/globus/workspace/remoting/admin/VmmNode.java +++ b/service/service/java/source/src/org/globus/workspace/remoting/admin/VmmNode.java @@ -58,4 +58,15 @@ public String getNetworkAssociations() { public boolean isVacant() { return vacant; } + + @Override + public String toString() { + return "VmmNode{" + + "hostname='" + hostname + '\'' + + ", poolName='" + poolName + '\'' + + ", memory=" + memory + + ", networkAssociations='" + networkAssociations + '\'' + + ", vacant=" + vacant + + '}'; + } } diff --git a/service/service/java/source/src/org/globus/workspace/remoting/admin/client/AdminClient.java b/service/service/java/source/src/org/globus/workspace/remoting/admin/client/AdminClient.java index 0f1df62e..6d2bc0fa 100644 --- a/service/service/java/source/src/org/globus/workspace/remoting/admin/client/AdminClient.java +++ b/service/service/java/source/src/org/globus/workspace/remoting/admin/client/AdminClient.java @@ -60,12 +60,16 @@ public class AdminClient { final static String[] NODE_FIELDS = new String[] { - FIELD_HOSTNAME, FIELD_POOL, FIELD_MEMORY, - FIELD_NETWORKS, FIELD_IN_USE - }; + FIELD_HOSTNAME, FIELD_POOL, FIELD_MEMORY, FIELD_NETWORKS, + FIELD_IN_USE }; - final static String[] NODE_REPORT_FIELDS = - new String[] {FIELD_STATUS, FIELD_HOSTNAME}; + + final static String[] NODE_REPORT_FIELDS = new String[] { + FIELD_HOSTNAME, FIELD_STATUS, FIELD_POOL, + FIELD_MEMORY, FIELD_NETWORKS, FIELD_IN_USE }; + + final static String[] NODE_REPORT_FIELDS_SHORT = new String[] { + FIELD_HOSTNAME, FIELD_STATUS }; private final Gson gson = new Gson(); @@ -78,7 +82,6 @@ public class AdminClient { private String configPath; private boolean debug; private File socketDirectory; - private RemotingClient remotingClient; private String nodePoolBindingName; private RemoteNodeManagement remoteNodeManagement; private Reporter reporter; @@ -135,11 +138,11 @@ public static void main(String args[]) { } if (paramError != null) { - System.err.println("Parameter Problem: " + paramError.getMessage()); + System.err.println("Parameter Problem:\n" + paramError.getMessage()); System.err.println("See --help"); } else if (execError != null) { - System.err.println("Execution Problem: " + execError.getMessage()); + System.err.println("Execution Problem:\n" + execError.getMessage()); } else { System.err.println("An unexpected error was encountered. Please report this!"); System.err.println(anyError.getMessage()); @@ -238,28 +241,42 @@ private void run_listNodes() throws ExecutionProblem { } private void run_removeNodes() throws ExecutionProblem { + NodeReport[] reports = null; try { final String[] hostnames = this.hosts.toArray(new String[this.hosts.size()]); - this.remoteNodeManagement.removeNodes(hostnames); + final String reportJson = this.remoteNodeManagement.removeNodes(hostnames); + reports = gson.fromJson(reportJson, NodeReport[].class); } catch (RemoteException e) { handleRemoteException(e); } + + try { + reporter.report(nodeReportsToMaps(reports), System.out); + } catch (IOException e) { + throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); + } } private void run_updateNodes() throws ExecutionProblem { - //TODO - final List nodes = new ArrayList(this.hosts.size()); for (String hostname : this.hosts) { nodes.add(new VmmNode(hostname, this.nodePool, this.nodeMemory, this.nodeNetworks, true)); } + NodeReport[] reports = null; try { - this.remoteNodeManagement.updateNodes(gson.toJson(nodes)); + final String reportJson = this.remoteNodeManagement.updateNodes(gson.toJson(nodes)); + reports = gson.fromJson(reportJson, NodeReport[].class); } catch (RemoteException e) { handleRemoteException(e); } + + try { + reporter.report(nodeReportsToMaps(reports), System.out); + } catch (IOException e) { + throw new ExecutionProblem("Problem writing output: " + e.getMessage(), e); + } } private void setupRemoting() throws ExecutionProblem { @@ -272,8 +289,6 @@ private void setupRemoting() throws ExecutionProblem { handleRemoteException(e); } - this.remotingClient = client; - try { final Remote remote = client.lookup(this.nodePoolBindingName); logger.debug("Found remote object " + remote.toString()); @@ -345,21 +360,25 @@ private void loadConfig(String configPath) } this.nodePoolBindingName = nodePoolBinding; - if (!this.nodeMemoryConfigured) { - final String memString = props.getProperty(PROP_DEFAULT_MEMORY); - if (memString != null) { - this.nodeMemory = parseMemory(memString); - this.nodeMemoryConfigured = true; + + // only need node parameter values if doing add-nodes + if (this.action == AdminAction.AddNodes) { + if (!this.nodeMemoryConfigured) { + final String memString = props.getProperty(PROP_DEFAULT_MEMORY); + if (memString != null) { + this.nodeMemory = parseMemory(memString); + this.nodeMemoryConfigured = true; + } } - } - if (this.nodeNetworks == null) { - this.nodeNetworks = props.getProperty(PROP_DEFAULT_NETWORKS); - } + if (this.nodeNetworks == null) { + this.nodeNetworks = props.getProperty(PROP_DEFAULT_NETWORKS); + } - if (this.nodePool == null) { - // if missing or invalid, error will come later if this value is actually needed - this.nodePool = props.getProperty(PROP_DEFAULT_POOL); + if (this.nodePool == null) { + // if missing or invalid, error will come later if this value is actually needed + this.nodePool = props.getProperty(PROP_DEFAULT_POOL); + } } } @@ -584,20 +603,30 @@ private static Map nodeReportToMap(NodeReport nodeReport) { new HashMap(2); map.put(FIELD_HOSTNAME, nodeReport.getHostname()); map.put(FIELD_STATUS, 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); + } 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())); + } return map; } } enum AdminAction { - AddNodes(Opts.ADD_NODES, AdminClient.NODE_REPORT_FIELDS), ListNodes(Opts.LIST_NODES, AdminClient.NODE_FIELDS), - RemoveNodes(Opts.REMOVE_NODES, AdminClient.NODE_REPORT_FIELDS), + RemoveNodes(Opts.REMOVE_NODES, AdminClient.NODE_REPORT_FIELDS_SHORT), UpdateNodes(Opts.UPDATE_NODES, AdminClient.NODE_REPORT_FIELDS), Help(Opts.HELP, null); - private final String option; private final String[] fields; diff --git a/service/service/java/source/src/org/globus/workspace/remoting/admin/client/Reporter.java b/service/service/java/source/src/org/globus/workspace/remoting/admin/client/Reporter.java index ec8ab300..ed4a0291 100644 --- a/service/service/java/source/src/org/globus/workspace/remoting/admin/client/Reporter.java +++ b/service/service/java/source/src/org/globus/workspace/remoting/admin/client/Reporter.java @@ -25,7 +25,7 @@ class Reporter { - public static final String DEFAULT_DELIMITER = ","; + public static final String DEFAULT_DELIMITER = " "; private final Gson gson; @@ -50,7 +50,8 @@ public Reporter(OutputMode mode, String[] fields, String delimiter) { } if (mode == OutputMode.Json) { - this.gson = new GsonBuilder().setPrettyPrinting().create(); + this.gson = new GsonBuilder().setPrettyPrinting(). + serializeNulls().create(); } else { this.gson = null; } @@ -114,12 +115,18 @@ private void _report(Map entry, OutputStreamWriter writer, int k if (this.mode == OutputMode.Friendly) { final String formatString = "%1$-" + keyLength + "s : "; for (Map.Entry pair : entry.entrySet()) { - final String key = String.format(formatString, pair.getKey()); - writer.append(key).append(pair.getValue()).append("\n"); + // skip output of null value entries + if (pair.getValue() != null) { + final String key = String.format(formatString, pair.getKey()); + writer.append(key).append(pair.getValue()).append("\n"); + } } } else if (this.mode == OutputMode.Batch) { boolean first = true; for (String value : entry.values()) { + if (value == null) { + value = ""; + } if (first) { first = false; } else { @@ -144,10 +151,10 @@ private static LinkedHashMap _filterMap(Map src, throw new IllegalArgumentException("destination map is not empty!"); } for (String field : fields) { - final String value = src.get(field); - if (value == null) { + if (!src.containsKey(field)) { throw new IllegalArgumentException("map is missing '"+field+"' field"); } + final String value = src.get(field); dest.put(field, value); } return dest; diff --git a/service/service/java/source/src/org/globus/workspace/remoting/admin/defaults/DefaultRemoteNodeManagement.java b/service/service/java/source/src/org/globus/workspace/remoting/admin/defaults/DefaultRemoteNodeManagement.java index 9cabeb04..9e1a3af5 100644 --- a/service/service/java/source/src/org/globus/workspace/remoting/admin/defaults/DefaultRemoteNodeManagement.java +++ b/service/service/java/source/src/org/globus/workspace/remoting/admin/defaults/DefaultRemoteNodeManagement.java @@ -17,6 +17,8 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.globus.workspace.remoting.admin.NodeReport; import org.globus.workspace.remoting.admin.RemoteNodeManagement; import org.globus.workspace.remoting.admin.VmmNode; @@ -31,6 +33,10 @@ import java.util.List; public class DefaultRemoteNodeManagement implements RemoteNodeManagement { + + private static final Log logger = + LogFactory.getLog(DefaultRemoteNodeManagement.class.getName()); + private final Gson gson; private final TypeToken> vmmNodeCollectionTypeToken; @@ -48,12 +54,28 @@ public void initialize() throws Exception { } public String addNodes(String nodeJson) throws RemoteException { + + if (nodeJson == null) { + throw new IllegalArgumentException("nodeJson may not be null"); + } + Collection nodes = gson.fromJson(nodeJson, vmmNodeCollectionTypeToken.getType()); + if (nodes == null || nodes.isEmpty()) { + throw new IllegalArgumentException( + "you must specify at least one node to add"); + } + List reports = new ArrayList(nodes.size()); for (VmmNode node : nodes) { - final String hostname = node.getHostname(); + String hostname = node.getHostname(); + + if (hostname == null) { + throw new IllegalArgumentException("hostname may not be null"); + } + + logger.info("Adding VMM node " + hostname); try { final ResourcepoolEntry entry = @@ -67,6 +89,7 @@ public String addNodes(String nodeJson) throws RemoteException { NodeReport.STATE_ADDED, resultNode)); } catch (NodeExistsException e) { + logger.info("VMM node " + hostname + " already existed"); reports.add(new NodeReport(hostname, NodeReport.STATE_NODE_EXISTS, null)); } @@ -76,6 +99,8 @@ public String addNodes(String nodeJson) throws RemoteException { public String listNodes() { + logger.debug("Listing VMM nodes"); + final List entries = nodeManagement.getNodes(); final List nodes = new ArrayList(entries.size()); for (ResourcepoolEntry entry : entries) { @@ -87,22 +112,44 @@ public String listNodes() { public String getNode(String hostname) { + if (hostname == null) { + throw new IllegalArgumentException("hostname may not be null"); + } + + logger.debug("Listing VMM node " + hostname); + + final ResourcepoolEntry entry = nodeManagement.getNode(hostname); return gson.toJson(translateResourcepoolEntry(entry)); } public String updateNodes(String nodeJson) { + if (nodeJson == null) { + throw new IllegalArgumentException("nodeJson may not be null"); + } final Collection nodes = gson.fromJson(nodeJson, this.vmmNodeCollectionTypeToken.getType()); + + if (nodes.isEmpty()) { + throw new IllegalArgumentException( + "You must specify at least one VMM node to update"); + } + List reports = new ArrayList(nodes.size()); for (VmmNode node : nodes) { + if (node == null) { + throw new IllegalArgumentException("update request has null node"); + } final String hostname = node.getHostname(); + logger.info("Updating VMM node: " + node.toString()); + try { nodeManagement.updateNode(translateVmmNode(node)); reports.add(new NodeReport(hostname, NodeReport.STATE_UPDATED, node)); } catch (NodeInUseException e) { + logger.info("VMM node was in use, failed to update: " + hostname); reports.add( new NodeReport(hostname, NodeReport.STATE_NODE_IN_USE, null)); @@ -118,6 +165,14 @@ public String removeNode(String hostname) { } private NodeReport _removeNode(String hostname) { + if (hostname == null) { + throw new IllegalArgumentException("hostname may not be null"); + } + hostname = hostname.trim(); + if (hostname.length() == 0) { + throw new IllegalArgumentException("hostname may not be empty"); + } + logger.info("Removing VMM node: " + hostname); String state; try { @@ -134,6 +189,9 @@ private NodeReport _removeNode(String hostname) { } public String removeNodes(String[] hostnames) { + if (hostnames == null || hostnames.length == 0) { + throw new IllegalArgumentException("hostnames may not be null or empty"); + } List reports = new ArrayList(hostnames.length); for (String hostname : hostnames) { reports.add(this._removeNode(hostname)); diff --git a/service/service/java/source/src/org/globus/workspace/scheduler/defaults/DefaultSlotManagement.java b/service/service/java/source/src/org/globus/workspace/scheduler/defaults/DefaultSlotManagement.java index 8344e6ee..0a429a2a 100644 --- a/service/service/java/source/src/org/globus/workspace/scheduler/defaults/DefaultSlotManagement.java +++ b/service/service/java/source/src/org/globus/workspace/scheduler/defaults/DefaultSlotManagement.java @@ -545,6 +545,14 @@ public synchronized ResourcepoolEntry addNode(String hostname, int memory) throws NodeExistsException { + if (hostname == null) { + throw new IllegalArgumentException("hostname may not be null"); + } + hostname = hostname.trim(); + if (hostname.length() == 0) { + throw new IllegalArgumentException("hostname may not be empty"); + } + try { final ResourcepoolEntry existing = this.db.getResourcepoolEntry(hostname); @@ -603,6 +611,13 @@ public List getNodes() { } public ResourcepoolEntry getNode(String hostname) { + if (hostname == null) { + throw new IllegalArgumentException("hostname may not be null"); + } + hostname = hostname.trim(); + if (hostname.length() == 0) { + throw new IllegalArgumentException("hostname may not be empty"); + } try { return this.db.getResourcepoolEntry(hostname); } catch (WorkspaceDatabaseException e) { @@ -617,6 +632,13 @@ public void updateNode(ResourcepoolEntry node) { public synchronized boolean removeNode(String hostname) throws NodeInUseException { + if (hostname == null) { + throw new IllegalArgumentException("hostname may not be null"); + } + hostname = hostname.trim(); + if (hostname.length() == 0) { + throw new IllegalArgumentException("hostname may not be empty"); + } try { final ResourcepoolEntry entry =