From 58891a7c9805ae88a4ffa45320319a7ab4ac567e Mon Sep 17 00:00:00 2001 From: Ryan Morgan Date: Fri, 8 Jan 2010 16:10:30 -0800 Subject: [PATCH 1/2] Backport fix for handling of multiple query parameters of the same name --- src/org/hyperic/hq/hqapi1/HQConnection.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/org/hyperic/hq/hqapi1/HQConnection.java b/src/org/hyperic/hq/hqapi1/HQConnection.java index dae7581a..4f0164c1 100644 --- a/src/org/hyperic/hq/hqapi1/HQConnection.java +++ b/src/org/hyperic/hq/hqapi1/HQConnection.java @@ -118,16 +118,16 @@ T doGet(String path, Map params, Class resultClass) uri.append("?"); } - int idx = 0; - for (Iterator i = params.keySet().iterator(); i.hasNext(); idx++) { - String key = (String)i.next(); - String[] vals = params.get(key); - for (String val : vals) { + boolean append = false; + + for (Map.Entry e : params.entrySet()) { + for (String val : e.getValue()) { if (val != null) { - if (idx > 0) { + if (append) { uri.append("&"); } - uri.append(key).append("=").append(urlEncode(val)); + uri.append(e.getKey()).append("=").append(urlEncode(val)); + append = true; } } } From c9df798c1859236639ae47a954ae38f1ad123685 Mon Sep 17 00:00:00 2001 From: Ryan Morgan Date: Fri, 8 Jan 2010 16:59:37 -0800 Subject: [PATCH 2/2] [HHQ-3658] Add MetricApi.reschedule() API. --- hqu/hqapi1/app/MetricController.groovy | 44 +++++++++++++ hqu/hqapi1/plugin.properties | 4 +- src/org/hyperic/hq/hqapi1/MetricApi.java | 40 ++++++++++++ .../hq/hqapi1/test/MetricReschedule_test.java | 62 +++++++++++++++++++ .../hq/hqapi1/tools/MetricCommand.java | 40 +++++++++++- xsd/Metric.xsd | 9 +++ 6 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 src/org/hyperic/hq/hqapi1/test/MetricReschedule_test.java diff --git a/hqu/hqapi1/app/MetricController.groovy b/hqu/hqapi1/app/MetricController.groovy index 4d910180..7eced292 100644 --- a/hqu/hqapi1/app/MetricController.groovy +++ b/hqu/hqapi1/app/MetricController.groovy @@ -1,6 +1,8 @@ import org.hyperic.hq.hqu.rendit.BaseController import org.hyperic.hq.hqapi1.ErrorCode; +import org.hyperic.hq.zevents.ZeventManager; +import org.hyperic.hq.appdef.server.session.ResourceRefreshZevent; class MetricController extends ApiController { @@ -524,4 +526,46 @@ class MetricController extends ApiController { } } } + + def reschedule(params) { + + def schedRequest = new XmlParser().parseText(getUpload('postdata')) + def xmlResources = schedRequest['Resource'] + + if (!xmlResources) { + renderXml() { + StatusResponse() { + out << getFailureXML(ErrorCode.INVALID_PARAMETERS) + } + } + return + } + + def zevents = [] + for (res in xmlResources) { + def resource = getResource(res.'@id'.toInteger()) + if (!resource) { + renderXml() { + StatusResponse() { + out << getFailureXML(ErrorCode.OBJECT_NOT_FOUND, + "Resource with id " + id + + " not found") + } + } + return + } + + def zevent = new ResourceRefreshZevent(user, + resource.entityId); + zevents.add(zevent); + } + + ZeventManager.getInstance().enqueueEvents(zevents); + + renderXml() { + StatusResponse() { + out << getSuccessXML() + } + } + } } diff --git a/hqu/hqapi1/plugin.properties b/hqu/hqapi1/plugin.properties index c3d46aa4..c9cf4702 100644 --- a/hqu/hqapi1/plugin.properties +++ b/hqu/hqapi1/plugin.properties @@ -1,6 +1,6 @@ plugin.name=hqapi1 plugin.helpTag=hqapi -plugin.version=1.6 +plugin.version=1.7 plugin.apiMajor=1 -plugin.apiMinor=6 +plugin.apiMinor=7 diff --git a/src/org/hyperic/hq/hqapi1/MetricApi.java b/src/org/hyperic/hq/hqapi1/MetricApi.java index 71703bd5..e9804965 100644 --- a/src/org/hyperic/hq/hqapi1/MetricApi.java +++ b/src/org/hyperic/hq/hqapi1/MetricApi.java @@ -13,11 +13,13 @@ import org.hyperic.hq.hqapi1.types.Resource; import org.hyperic.hq.hqapi1.types.ResourcePrototype; import org.hyperic.hq.hqapi1.types.StatusResponse; +import org.hyperic.hq.hqapi1.types.MetricsRescheduleRequest; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.ArrayList; /** * The Hyperic HQ Metric API. @@ -277,4 +279,42 @@ public MetricsDataResponse getMetricData(int[] resourceIds, int templateId, return doGet("metric/getResourceData.hqu", params, MetricsDataResponse.class); } + + // Helper function to unroll a resource and it's children into a single list. + private List getFlattenResources(List resources) { + List result = new ArrayList(); + + for (Resource r : resources) { + result.add(r); + if (r.getResource().size() > 0) { + result.addAll(getFlattenResources(r.getResource())); + } + } + return result; + } + + /** + * Reschedule metrics for the given list of {@link org.hyperic.hq.hqapi1.types.Resource}s. + * If the passed in List has child resources, those Resources will also be + * rescheduled. + * + * @param resources A List of {@link org.hyperic.hq.hqapi1.types.Resource}'s + * to reschedule. + * + * @return {@link org.hyperic.hq.hqapi1.types.ResponseStatus#SUCCESS} if the + * metrics were successfully retrieved. + * + * @throws IOException If a network error occurs while making the request. + */ + public StatusResponse reschedule(List resources) + throws IOException { + + List flattened = getFlattenResources(resources); + + MetricsRescheduleRequest request = new MetricsRescheduleRequest(); + request.getResource().addAll(flattened); + + return doPost("metric/reschedule.hqu", request, + StatusResponse.class); + } } diff --git a/src/org/hyperic/hq/hqapi1/test/MetricReschedule_test.java b/src/org/hyperic/hq/hqapi1/test/MetricReschedule_test.java new file mode 100644 index 00000000..b2479364 --- /dev/null +++ b/src/org/hyperic/hq/hqapi1/test/MetricReschedule_test.java @@ -0,0 +1,62 @@ +package org.hyperic.hq.hqapi1.test; + +import org.hyperic.hq.hqapi1.MetricApi; +import org.hyperic.hq.hqapi1.types.StatusResponse; +import org.hyperic.hq.hqapi1.types.Resource; + +import java.util.List; +import java.util.ArrayList; + +public class MetricReschedule_test extends MetricTestBase { + + public MetricReschedule_test(String name) { + super(name); + } + + public void testRescheduleSingle() throws Exception { + MetricApi api = getApi().getMetricApi(); + + Resource platform = getLocalPlatformResource(false, false); + List resources = new ArrayList(); + resources.add(platform); + + StatusResponse response = api.reschedule(resources); + hqAssertSuccess(response); + } + + public void testRescheduleMulti() throws Exception { + MetricApi api = getApi().getMetricApi(); + + // Recurse flag will cause all resources on this platform to be + // resheduled. + Resource platform = getLocalPlatformResource(false, true); + List resources = new ArrayList(); + resources.add(platform); + + StatusResponse response = api.reschedule(resources); + hqAssertSuccess(response); + } + + public void testRescheduleInvalidResource() throws Exception { + MetricApi api = getApi().getMetricApi(); + + List resources = new ArrayList(); + + Resource r = new Resource(); + r.setId(Integer.MAX_VALUE); + resources.add(r); + + StatusResponse response = api.reschedule(resources); + hqAssertFailureObjectNotFound(response); + } + + public void testRescheduleNoResources() throws Exception { + + MetricApi api = getApi().getMetricApi(); + + List resources = new ArrayList(); + + StatusResponse response = api.reschedule(resources); + hqAssertFailureInvalidParameters(response); + } +} diff --git a/src/org/hyperic/hq/hqapi1/tools/MetricCommand.java b/src/org/hyperic/hq/hqapi1/tools/MetricCommand.java index fbab5267..b9498b48 100644 --- a/src/org/hyperic/hq/hqapi1/tools/MetricCommand.java +++ b/src/org/hyperic/hq/hqapi1/tools/MetricCommand.java @@ -10,17 +10,21 @@ import org.hyperic.hq.hqapi1.types.MetricsResponse; import org.hyperic.hq.hqapi1.types.ResourceResponse; import org.hyperic.hq.hqapi1.types.StatusResponse; +import org.hyperic.hq.hqapi1.types.ResourcesResponse; +import org.hyperic.hq.hqapi1.types.Resource; import java.io.InputStream; import java.util.Arrays; import java.util.List; +import java.util.ArrayList; public class MetricCommand extends Command { private static String CMD_LIST = "list"; private static String CMD_SYNC = "sync"; + private static String CMD_RESCHEDULE = "reschedule"; - private static String[] COMMANDS = { CMD_LIST, CMD_SYNC }; + private static String[] COMMANDS = { CMD_LIST, CMD_SYNC, CMD_RESCHEDULE }; private static final String OPT_RESOURCE_ID = "id"; private static final String OPT_ENABLED = "enabled"; @@ -39,6 +43,8 @@ protected void handleCommand(String[] args) throws Exception { list(trim(args)); } else if (args[0].equals(CMD_SYNC)) { sync(trim(args)); + } else if (args[0].equals(CMD_RESCHEDULE)) { + reschedule(trim(args)); } else { printUsage(); System.exit(-1); @@ -96,4 +102,36 @@ private void sync(String[] args) throws Exception { System.out.println("Successfully synced " + metrics.size() + " metrics."); } + + private long getResourceCount(List resources) { + long num = 0; + for (Resource r : resources) { + num++; + if (r.getResource().size() > 0) { + num += getResourceCount(r.getResource()); + } + } + return num; + } + + private void reschedule(String args[]) throws Exception { + + OptionParser p = getOptionParser(); + OptionSet options = getOptions(p, args); + + HQApi api = getApi(options); + + MetricApi metricApi = api.getMetricApi(); + + InputStream is = getInputStream(options); + + ResourcesResponse resp = XmlUtil.deserialize(ResourcesResponse.class, is); + checkSuccess(resp); + + StatusResponse response = metricApi.reschedule(resp.getResource()); + checkSuccess(response); + + System.out.println("Successfully rescheduled " + getResourceCount(resp.getResource()) + + " resources"); + } } diff --git a/xsd/Metric.xsd b/xsd/Metric.xsd index 165bf454..c4b7956c 100644 --- a/xsd/Metric.xsd +++ b/xsd/Metric.xsd @@ -97,5 +97,14 @@ + + + + + + + + +