Extended support to apis/cloudwatch for getting metrics.

* Updated to allow supplying any dimension to describe the metric
* Updated to allow supplying more than one statistic to retrieve
This commit is contained in:
Jeremy Whitlock 2012-04-27 18:43:08 -06:00
parent 588a7c38ad
commit e58d91e78d
10 changed files with 752 additions and 43 deletions

View File

@ -21,12 +21,15 @@ package org.jclouds.cloudwatch;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.aws.filters.FormSigner; import org.jclouds.aws.filters.FormSigner;
import org.jclouds.cloudwatch.domain.Datapoint; import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.ListMetricsResponse; import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.Statistics; import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.functions.ISO8601Format; import org.jclouds.cloudwatch.functions.ISO8601Format;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2;
import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandler; import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandler;
import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandlerV2;
import org.jclouds.cloudwatch.xml.ListMetricsResponseHandler; import org.jclouds.cloudwatch.xml.ListMetricsResponseHandler;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
@ -60,6 +63,7 @@ public interface CloudWatchAsyncClient {
/** /**
* @see CloudWatchClient#getMetricStatisticsInRegion * @see CloudWatchClient#getMetricStatisticsInRegion
*/ */
@Deprecated
@POST @POST
@Path("/") @Path("/")
@XMLResponseParser(GetMetricStatisticsResponseHandler.class) @XMLResponseParser(GetMetricStatisticsResponseHandler.class)
@ -83,4 +87,13 @@ public interface CloudWatchAsyncClient {
@FormParams(keys = "Action", values = "ListMetrics") @FormParams(keys = "Action", values = "ListMetrics")
ListenableFuture<? extends ListMetricsResponse> listMetrics(ListMetricsOptions options); ListenableFuture<? extends ListMetricsResponse> listMetrics(ListMetricsOptions options);
/**
* @see CloudWatchClient#getMetricStatistics(org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2)
*/
@POST
@Path("/")
@XMLResponseParser(GetMetricStatisticsResponseHandlerV2.class)
@FormParams(keys = "Action", values = "GetMetricStatistics")
ListenableFuture<? extends GetMetricStatisticsResponse> getMetricStatistics(GetMetricStatisticsOptionsV2 options);
} }

View File

@ -19,9 +19,11 @@
package org.jclouds.cloudwatch; package org.jclouds.cloudwatch;
import org.jclouds.cloudwatch.domain.Datapoint; import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.ListMetricsResponse; import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.Statistics; import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2;
import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
@ -79,10 +81,10 @@ public interface CloudWatchClient {
* @param options * @param options
* more filtering options (e.g. instance ID) * more filtering options (e.g. instance ID)
*/ */
@Deprecated
Set<Datapoint> getMetricStatisticsInRegion(@Nullable String region, String metricName, String namespace, Set<Datapoint> getMetricStatisticsInRegion(@Nullable String region, String metricName, String namespace,
Date startTime, Date endTime, int period, Statistics statistics, GetMetricStatisticsOptions... options); Date startTime, Date endTime, int period, Statistics statistics, GetMetricStatisticsOptions... options);
/** /**
* Returns a list of valid metrics stored for the AWS account owner. * Returns a list of valid metrics stored for the AWS account owner.
* *
@ -94,8 +96,17 @@ public interface CloudWatchClient {
* *
* @param options the options describing the metrics query * @param options the options describing the metrics query
* *
* @return the list of valid metrics based on the AWS account owner and the options passed in * @return the response object
*/ */
ListMetricsResponse listMetrics(ListMetricsOptions options); ListMetricsResponse listMetrics(ListMetricsOptions options);
/**
* Gets statistics for the specified metric.
*
* @param options the options describing the metric statistics query
*
* @return the response object
*/
GetMetricStatisticsResponse getMetricStatistics(GetMetricStatisticsOptionsV2 options);
} }

View File

@ -0,0 +1,111 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.jclouds.cloudwatch.domain;
import com.google.common.collect.Sets;
import org.jclouds.javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Set;
/**
* @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html" />
*
* @author Jeremy Whitlock
*/
public class GetMetricStatisticsResponse {
private final Set<Datapoint> datapoints;
private final String label;
public GetMetricStatisticsResponse(@Nullable Set<Datapoint> datapoints, String label) {
if (datapoints == null) {
this.datapoints = Sets.newLinkedHashSet();
} else {
this.datapoints = datapoints;
}
this.label = label;
}
/**
* return the list of {@link Datapoint} for the metric
*/
public Set<Datapoint> getDatapoints() {
return datapoints;
}
/**
* return the label describing the specified metric
*/
public String getLabel() {
return label;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GetMetricStatisticsResponse other = (GetMetricStatisticsResponse)obj;
if (datapoints == null) {
if (other.datapoints != null)
return false;
} else if (!datapoints.equals(other.datapoints))
return false;
if (label == null) {
if (other.label != null)
return false;
} else if (!label.equals(other.label))
return false;
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[label=")
.append(label)
.append(", datapoints=[");
Iterator<Datapoint> iterator = datapoints.iterator();
while (iterator.hasNext()) {
builder.append(iterator.next());
if (iterator.hasNext()) {
builder.append(", ");
}
}
builder.append("]]");
return builder.toString();
}
}

View File

@ -34,7 +34,7 @@ public class ListMetricsResponse {
private final Set<Metric> metrics; private final Set<Metric> metrics;
private final String nextToken; private final String nextToken;
public ListMetricsResponse(Set<Metric> metrics, String nextToken) { public ListMetricsResponse(@Nullable Set<Metric> metrics, @Nullable String nextToken) {
// Default to an empty set // Default to an empty set
if (metrics == null) { if (metrics == null) {
this.metrics = Sets.newLinkedHashSet(); this.metrics = Sets.newLinkedHashSet();

View File

@ -18,12 +18,12 @@
*/ */
package org.jclouds.cloudwatch.options; package org.jclouds.cloudwatch.options;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.cloudwatch.domain.Unit; import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.http.options.BaseHttpRequestOptions; import org.jclouds.http.options.BaseHttpRequestOptions;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Options used to control metric statistics are returned * Options used to control metric statistics are returned
* *
@ -32,6 +32,7 @@ import org.jclouds.http.options.BaseHttpRequestOptions;
* /> * />
* @author Andrei Savu * @author Andrei Savu
*/ */
@Deprecated
public class GetMetricStatisticsOptions extends BaseHttpRequestOptions { public class GetMetricStatisticsOptions extends BaseHttpRequestOptions {
public static final GetMetricStatisticsOptions NONE = new GetMetricStatisticsOptions(); public static final GetMetricStatisticsOptions NONE = new GetMetricStatisticsOptions();
@ -73,5 +74,7 @@ public class GetMetricStatisticsOptions extends BaseHttpRequestOptions {
GetMetricStatisticsOptions options = new GetMetricStatisticsOptions(); GetMetricStatisticsOptions options = new GetMetricStatisticsOptions();
return options.unit(unit); return options.unit(unit);
} }
} }
} }

View File

@ -0,0 +1,371 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.jclouds.cloudwatch.options;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.date.DateService;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.javax.annotation.Nullable;
import java.util.Date;
import java.util.Set;
/**
* Options use to get statistics for the specified metric.
*
* @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html" />
*
* @author Jeremy Whitlock
*/
public class GetMetricStatisticsOptionsV2 extends BaseHttpRequestOptions {
private static final DateService dateService = new SimpleDateFormatDateService();
private final Set<Dimension> dimensions;
private final Date endTime;
private final String metricName;
private final String namespace;
private final int period;
private final Date startTime;
private final Set<Statistics> statistics;
private final Unit unit;
/**
* Private constructor to enforce using {@link Builder}.
*/
private GetMetricStatisticsOptionsV2(@Nullable Set<Dimension> dimensions, Date endTime, String metricName,
String namespace, int period, Date startTime, Set<Statistics> statistics,
Unit unit) {
this.dimensions = dimensions;
this.endTime = endTime;
this.metricName = metricName;
this.namespace = namespace;
this.period = period;
this.startTime = startTime;
this.statistics = statistics;
this.unit = unit;
}
/**
* return the set of dimensions for this request
*/
@Nullable
public Set<Dimension> getDimensions() {
return dimensions;
}
/**
* return the end time for this request
*/
public Date getEndTime() {
return endTime;
}
/**
* return the metric name for this request
*/
public String getMetricName() {
return metricName;
}
/**
* return the namespace for this request
*/
public String getNamespace() {
return namespace;
}
/**
* return the period for this request
*/
public int getPeriod() {
return period;
}
/**
* return the start time for this request
*/
public Date getStartTime() {
return startTime;
}
/**
* return the statistics for this request
*/
public Set<Statistics> getStatistics() {
return statistics;
}
/**
* return the unit for this request
*/
public Unit getUnit() {
return unit;
}
/**
* Returns a new builder. The generated builder is equivalent to the builder
* created by the {@link Builder} constructor.
*/
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Set<Dimension> dimensions = Sets.newLinkedHashSet();
private Date endTime;
private String metricName;
private String namespace;
private int period;
private Date startTime;
private Set<Statistics> statistics = Sets.newLinkedHashSet();
private Unit unit;
/**
* Creates a new builder. The returned builder is equivalent to the builder
* generated by {@link ListMetricsOptions#builder}.
*/
public Builder() {}
/**
* A list of dimensions describing qualities of the metric. (Set can be 10 or less items.)
*
* @param dimensions the dimensions describing the qualities of the metric
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if this is invoked more than 10 times
*/
public Builder dimensions(Set<Dimension> dimensions) {
if (dimensions != null) {
Preconditions.checkArgument(dimensions.size() <= 10, "dimensions can have 10 or fewer members.");
this.dimensions = dimensions;
}
return this;
}
/**
* A dimension describing qualities of the metric. (Can be called multiple times up to a maximum of 10 times.)
*
* @param dimension the dimension describing the qualities of the metric
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if the number of dimensions would be greater than 10 after adding
*/
public Builder dimension(Dimension dimension) {
if (dimension != null) {
Preconditions.checkArgument(dimensions.size() < 10, "dimension member maximum count of 10 exceeded.");
this.dimensions.add(dimension);
}
return this;
}
/**
* The time stamp to use for determining the last datapoint to return. The value specified is exclusive so
* results will include datapoints up to the time stamp specified. (Should be called once. Subsequent calls
* will overwrite the previous value.)
*
* @param endTime the timestamp to use for determining the last datapoint to return
*
* @return this {@code Builder} object
*
* @throws NullPointerException if endTime is null
*/
public Builder endTime(Date endTime) {
Preconditions.checkNotNull(endTime, "endTime cannot be null.");
this.endTime = endTime;
return this;
}
/**
* The name of the metric. (Should be called once. Subsequent calls will overwrite the previous value.)
*
* @param metricName the metric name to filter against
*
* @return this {@code Builder} object
*
* @throws NullPointerException if metricName is null
* @throws IllegalArgumentException if metricName is empty
*/
public Builder metricName(String metricName) {
Preconditions.checkNotNull(metricName, "metricName cannot be null.");
Preconditions.checkArgument(metricName.length() > 1, "metricName must not be empty.");
this.metricName = metricName;
return this;
}
/**
* The namespace of the metric. (Should be called once. Subsequent calls will overwrite the previous value.
* See {@link org.jclouds.cloudwatch.domain.Namespaces} for the known list of namespaces.)
*
* @param namespace the namespace to filter against
*
* @return this {@code Builder} object
*
* @throws NullPointerException if namespace is null
* @throws IllegalArgumentException if namespace is empty
*/
public Builder namespace(String namespace) {
Preconditions.checkNotNull(namespace, "namespace cannot be null.");
Preconditions.checkArgument(namespace.length() > 1, "namespace must not be empty.");
this.namespace = namespace;
return this;
}
/**
* The granularity, in seconds, of the returned datapoints. Period must be at least 60 seconds and must be a
* multiple of 60. The default value is 60. (Should be called once. Subsequent calls will overwrite the
* previous value.)
*
* @param period the granularity, in seconds, of the returned datapoints
*
* @return this {@code Builder} object
*
* @throws NullPointerException if period is null
* @throws IllegalArgumentException if period is less than 60 or not a multiple of 60
*/
public Builder period(int period) {
Preconditions.checkNotNull(period, "period cannot be null.");
Preconditions.checkArgument(period >= 60 && period % 60 == 0, "period must be greater than 60 and as a " +
"multiple of 60.");
this.period = period;
return this;
}
/**
* The time stamp to use for determining the first datapoint to return. The value specified is inclusive so
* results include datapoints with the time stamp specified. (Should be called once. Subsequent calls will
* overwrite the previous value.)
*
* @param startTime The time stamp to use for determining the first datapoint to return
*
* @return this {@code Builder} object
*
* @throws NullPointerException if startTime is null
*/
public Builder startTime(Date startTime) {
Preconditions.checkNotNull(startTime, "startTime cannot be null.");
this.startTime = startTime;
return this;
}
/**
* The metric statistics to return. (Should be called once. Subsequent calls will overwrite the previous
* value.)
*
* @param statistics the metric statistics to return.
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if the number of statistics is greater than 5
* @throws NullPointerException if statistics is null
*/
public Builder statistics(Set<Statistics> statistics) {
Preconditions.checkNotNull(statistics, "statistics cannot be null.");
Preconditions.checkArgument(statistics.size() <= 5, "statistics can have 5 or fewer members.");
this.statistics = statistics;
return this;
}
/**
* The metric statistic to return. (Can be called multiple times up to a maximum of 5 times.)
*
* @param statistic the metric statistic to return
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if the number of statistics would be greater than 5 after adding
* @throws NullPointerException if statistic is null
*/
public Builder statistic(Statistics statistic) {
Preconditions.checkNotNull(statistic, "statistic cannot be null.");
Preconditions.checkArgument(statistics.size() < 5, "statistics member maximum count of 5 exceeded.");
this.statistics.add(statistic);
return this;
}
/**
* The unit for the metric. (Should be called once. Subsequent calls will overwrite the previous value.)
*
* @param unit the unit for the metric
*
* @return this {@code Builder} object
*
* @throws NullPointerException if unit is null
*/
public Builder unit(Unit unit) {
Preconditions.checkNotNull(unit, "unit cannot be null.");
this.unit = unit;
return this;
}
/**
* Returns a newly-created {@code GetMetricStatisticsOptionsV2} based on the contents of
* the {@code Builder}.
*
* @throws NullPointerException if any of the required fields are null
* @throws IllegalArgumentException if any of the provided fields don't meet required criteria
*/
public GetMetricStatisticsOptionsV2 build() {
Preconditions.checkNotNull(endTime, "endTime cannot be null.");
Preconditions.checkNotNull(metricName, "metricName cannot be null.");
Preconditions.checkNotNull(namespace, "namespace cannot be null.");
Preconditions.checkNotNull(period, "period cannot be null.");
Preconditions.checkNotNull(startTime, "startTime cannot be null.");
Preconditions.checkNotNull(statistics, "statistics cannot be null.");
Preconditions.checkNotNull(unit, "unit cannot be null.");
Preconditions.checkArgument(statistics.size() >= 1, "statistics must have at least one member");
GetMetricStatisticsOptionsV2 options = new GetMetricStatisticsOptionsV2(dimensions, endTime, metricName,
namespace, period, startTime,
statistics, unit);
int dimensionIndex = 1;
int statisticIndex = 1;
for (Dimension dimension : dimensions) {
options.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
options.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++;
}
options.formParameters.put("EndTime", dateService.iso8601SecondsDateFormat(endTime));
options.formParameters.put("MetricName", metricName);
options.formParameters.put("Namespace", namespace);
options.formParameters.put("Period", Integer.toString(period));
options.formParameters.put("StartTime", dateService.iso8601SecondsDateFormat(startTime));
for (Statistics statistic : statistics) {
options.formParameters.put("Statistics.member." + statisticIndex, statistic.toString());
statisticIndex++;
}
options.formParameters.put("Unit", unit.toString());
return options;
}
}
}

View File

@ -18,11 +18,12 @@
*/ */
package org.jclouds.cloudwatch.options; package org.jclouds.cloudwatch.options;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import org.jclouds.cloudwatch.domain.Dimension; import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.http.options.BaseHttpRequestOptions; import org.jclouds.http.options.BaseHttpRequestOptions;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
/** /**
@ -92,7 +93,7 @@ public class ListMetricsOptions extends BaseHttpRequestOptions {
public static class Builder { public static class Builder {
private Set<Dimension> dimensions = new LinkedHashSet<Dimension>(); private Set<Dimension> dimensions = Sets.newLinkedHashSet();
private String metricName; private String metricName;
private String namespace; private String namespace;
private String nextToken; private String nextToken;
@ -104,58 +105,62 @@ public class ListMetricsOptions extends BaseHttpRequestOptions {
public Builder() {} public Builder() {}
/** /**
* Filter available metrics specific to the namespace provided. To get all metrics regardless of the namespace, * The namespace to filter against. (Should be called once. Subsequent calls will overwrite the previous value.
* do not use this builder option. Only one namespace can be specified at a time so multiple invocations of * See {@link org.jclouds.cloudwatch.domain.Namespaces} for the known list of namespaces.)
* this will just overwrite what was set prior. Available AWS namespaces are listed in the
* {@link org.jclouds.cloudwatch.domain.Namespaces} class. You can also use custom namespaces if you've
* configured CloudWatch for such things.
* *
* @param namespace the namespace to filter the returned metrics by * @param namespace the namespace to filter against
* *
* @return this {@code Builder} object * @return this {@code Builder} object
*
* @throws IllegalArgumentException if namespace is empty
*/ */
public Builder namespace(String namespace) { public Builder namespace(String namespace) {
if (namespace != null) {
Preconditions.checkArgument(namespace.length() > 1, "namespace must not be empty.");
}
this.namespace = namespace; this.namespace = namespace;
return this; return this;
} }
/** /**
* Filter available metrics specific to the provided metric name. To get all metrics regardless of the metric * The name of the metric to filter against. (Should be called once. Subsequent calls will overwrite the
* name, do not use this builder option. Only one namespace can be specified at a time so multiple invocations * previous value.)
* of this will just overwrite what was set prior. Available AWS metric names are listed in the
* org.jclouds.cloudwatch.domain.*Constants classes and are AWS product specific. You can also use custom
* metric names if you've configured CloudWatch for such things.
* *
* @param metricName the metric name to filter the returned metrics by * @param metricName the metric name to filter against
* *
* @return this {@code Builder} object * @return this {@code Builder} object
*
* @throws IllegalArgumentException if metricName is empty
*/ */
public Builder metricName(String metricName) { public Builder metricName(String metricName) {
if (metricName != null) {
Preconditions.checkArgument(metricName.length() > 1, "metricName must not be empty.");
}
this.metricName = metricName; this.metricName = metricName;
return this; return this;
} }
/** /**
* Same as {@link #dimension(org.jclouds.cloudwatch.domain.Dimension)} but replaces the current set of * A list of dimensions to filter against. (Set can be 10 or less items.)
* dimensions with the one passed in.
* *
* @see #dimension(org.jclouds.cloudwatch.domain.Dimension) * @param dimensions the dimensions to filter against
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if the number of dimensions would be greater than 10 after adding
*/ */
public Builder dimensions(Set<Dimension> dimensions) { public Builder dimensions(Set<Dimension> dimensions) {
if (dimensions.size() > 10) { if (dimensions != null) {
throw new IllegalArgumentException("The maximum number of dimensions for ListOptions is 10."); Preconditions.checkArgument(dimensions.size() <= 10, "dimensions can have 10 or fewer members.");
this.dimensions = dimensions;
} }
this.dimensions = dimensions;
return this; return this;
} }
/** /**
* Filter available metrics based on the {@link Dimension} passed in. To get all metrics regardless of the * A dimension to filter the available metrics by. (Can be called multiple times up to a maximum of 10 times.)
* dimension, do not use this builder option. You can specify up to 10 different dimensions per request.
* Available AWS dimensions are listed in the org.jclouds.cloudwatch.domain.*Constants classes and are AWS
* product specific. You can also use custom dimensions if you've configured CloudWatch for such things.
* *
* @param dimension the dimension to filter the returned metrics by * @param dimension a dimension to filter the returned metrics by
* *
* @return this {@code Builder} object * @return this {@code Builder} object
* *
@ -163,19 +168,16 @@ public class ListMetricsOptions extends BaseHttpRequestOptions {
*/ */
public Builder dimension(Dimension dimension) { public Builder dimension(Dimension dimension) {
if (dimension != null) { if (dimension != null) {
if (this.dimensions.size() >= 10) { Preconditions.checkArgument(dimensions.size() < 10, "dimension member maximum count of 10 exceeded.");
throw new IllegalArgumentException("You have exceeded the maximum number of dimensions per " +
"request.");
}
this.dimensions.add(dimension); this.dimensions.add(dimension);
} }
return this; return this;
} }
/** /**
* Specify that this request is a follow-up to retrieve more data from a paginated request. * The token returned by a previous call to indicate that there is more data available.
* *
* @param nextToken the next token * @param nextToken the next token indicating that there is more data available
* *
* @return this {@code Builder} object * @return this {@code Builder} object
*/ */
@ -192,22 +194,22 @@ public class ListMetricsOptions extends BaseHttpRequestOptions {
ListMetricsOptions lmo = new ListMetricsOptions(namespace, metricName, dimensions, nextToken); ListMetricsOptions lmo = new ListMetricsOptions(namespace, metricName, dimensions, nextToken);
int dimensionIndex = 1; int dimensionIndex = 1;
if (this.namespace != null) { if (namespace != null) {
lmo.formParameters.put("Namespace", this.namespace); lmo.formParameters.put("Namespace", namespace);
} }
if (this.metricName != null) { if (metricName != null) {
lmo.formParameters.put("MetricName", this.metricName); lmo.formParameters.put("MetricName", metricName);
} }
for (Dimension dimension : this.dimensions) { for (Dimension dimension : dimensions) {
lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName()); lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue()); lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++; dimensionIndex++;
} }
if (this.nextToken != null) { if (nextToken != null) {
lmo.formParameters.put("NextToken", this.nextToken); lmo.formParameters.put("NextToken", nextToken);
} }
return lmo; return lmo;

View File

@ -0,0 +1,90 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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.jclouds.cloudwatch.xml;
import com.google.common.collect.Sets;
import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import javax.inject.Inject;
import java.util.Set;
/**
* @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html" />
*
* @author Jeremy Whitlock
*/
public class GetMetricStatisticsResponseHandlerV2 extends ParseSax.HandlerWithResult<GetMetricStatisticsResponse> {
private StringBuilder currentText = new StringBuilder();
private Set<Datapoint> datapoints = Sets.newLinkedHashSet();
private String label;
private final DatapointHandler datapointHandler;
private boolean inDatapoints;
@Inject
public GetMetricStatisticsResponseHandlerV2(DatapointHandler DatapointHandler) {
this.datapointHandler = DatapointHandler;
}
public GetMetricStatisticsResponse getResult() {
return new GetMetricStatisticsResponse(datapoints, label);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals("Datapoints")) {
inDatapoints = true;
}
if (inDatapoints) {
datapointHandler.startElement(uri, localName, qName, attributes);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (inDatapoints) {
if (qName.equals("Datapoints")) {
inDatapoints = false;
} else {
datapointHandler.endElement(uri, localName, qName);
if (qName.equals("member")) {
this.datapoints.add(datapointHandler.getResult());
}
}
} else if (qName.equals("Label")) {
label = SaxUtils.currentOrNull(currentText);
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
if (inDatapoints) {
datapointHandler.characters(ch, start, length);
} else {
currentText.append(ch, start, length);
}
}
}

View File

@ -31,7 +31,9 @@ import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.EC2Constants; import org.jclouds.cloudwatch.domain.EC2Constants;
import org.jclouds.cloudwatch.domain.Namespaces; import org.jclouds.cloudwatch.domain.Namespaces;
import org.jclouds.cloudwatch.domain.Statistics; import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2;
import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandler; import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandler;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
@ -66,6 +68,59 @@ import static org.testng.Assert.assertEquals;
@Test(groups = "unit", testName = "CloudWatchAsyncClientTest") @Test(groups = "unit", testName = "CloudWatchAsyncClientTest")
public class CloudWatchAsyncClientTest extends BaseAsyncClientTest<CloudWatchAsyncClient> { public class CloudWatchAsyncClientTest extends BaseAsyncClientTest<CloudWatchAsyncClient> {
/**
* Tests that {@link CloudWatchAsyncClient#getMetricStatistics(org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2)}
* works as expected.
*
* @throws Exception if anything goes wrong
*/
public void testGetMetricStatisticsV2() throws Exception {
Dimension dimension1 = new Dimension(EC2Constants.Dimension.INSTANCE_ID, "SOMEINSTANCEID");
Dimension dimension2 = new Dimension(EC2Constants.Dimension.INSTANCE_TYPE, "t1.micro");
Date endTime = new Date(10000000l);
String metricName = EC2Constants.MetricName.CPU_UTILIZATION;
String namespace = Namespaces.EC2;
int period = 60;
Date startTime = new Date(10000000l);
Statistics statistic1 = Statistics.MAXIMUM;
Statistics statistic2 = Statistics.MINIMUM;
Unit unit = Unit.PERCENT;
GetMetricStatisticsOptionsV2 goodOptions = GetMetricStatisticsOptionsV2.builder()
.dimension(dimension1)
.dimension(dimension2)
.endTime(endTime)
.metricName(metricName)
.namespace(namespace)
.period(period)
.startTime(startTime)
.statistic(statistic1)
.statistic(statistic2)
.unit(unit).build();
Method method = CloudWatchAsyncClient.class.getMethod("getMetricStatistics", GetMetricStatisticsOptionsV2.class);
HttpRequest request = processor.createRequest(method, goodOptions);
assertRequestLineEquals(request, "POST https://monitoring.us-east-1.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: monitoring.us-east-1.amazonaws.com\n");
// Note: Order of request params is alphabetical
assertPayloadEquals(request,
"Action=GetMetricStatistics" +
"&Dimensions.member.1.Name=" + dimension1.getName() +
"&Dimensions.member.1.Value=" + dimension1.getValue() +
"&Dimensions.member.2.Name=" + dimension2.getName() +
"&Dimensions.member.2.Value=" + dimension2.getValue() +
"&EndTime=1970-01-01T02%3A46%3A40Z" +
"&MetricName=" + metricName +
"&Namespace=" + URLEncoder.encode(namespace, "UTF-8") +
"&Period=" + period +
"&StartTime=1970-01-01T02%3A46%3A40Z" +
"&Statistics.member.1=" + statistic1 +
"&Statistics.member.2=" + statistic2 +
"&Unit=" + unit,
"application/x-www-form-urlencoded", false);
}
/** /**
* Tests that {@link CloudWatchAsyncClient#listMetrics(org.jclouds.cloudwatch.options.ListMetricsOptions)} works * Tests that {@link CloudWatchAsyncClient#listMetrics(org.jclouds.cloudwatch.options.ListMetricsOptions)} works
* as expected. * as expected.

View File

@ -18,17 +18,20 @@
*/ */
package org.jclouds.cloudwatch; package org.jclouds.cloudwatch;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import org.jclouds.apis.BaseContextLiveTest; import org.jclouds.apis.BaseContextLiveTest;
import org.jclouds.cloudwatch.domain.Datapoint; import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.Dimension; import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.EC2Constants; import org.jclouds.cloudwatch.domain.EC2Constants;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.ListMetricsResponse; import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.Metric; import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.Namespaces; import org.jclouds.cloudwatch.domain.Namespaces;
import org.jclouds.cloudwatch.domain.Statistics; import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.domain.Unit; import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions; import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptionsV2;
import org.jclouds.cloudwatch.options.ListMetricsOptions; import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
@ -61,6 +64,56 @@ public class CloudWatchClientLiveTest extends BaseContextLiveTest<RestContext<Cl
client = context.getApi(); client = context.getApi();
} }
@Test
protected void testGetMetricStatisticsV2() {
ListMetricsResponse metricsResponse = client.listMetrics(ListMetricsOptions.builder().build());
// Walk through all datapoints in all metrics until we find a metric datapoint that returns statistics
if (metricsResponse.getMetrics().size() > 0) {
for (Metric metric : metricsResponse.getMetrics()) {
Set<Dimension> dimensions = metric.getDimensions();
boolean testRan = false;
for (Dimension dimension : dimensions) {
Date endTime = new Date();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, -60 * 24); // 24 hours
GetMetricStatisticsOptionsV2 options =
GetMetricStatisticsOptionsV2.builder()
.dimension(dimension)
.endTime(endTime)
.metricName(metric.getMetricName())
.namespace(metric.getNamespace())
.period(300)
.startTime(cal.getTime())
.statistics(ImmutableSet.of(Statistics.MAXIMUM,
Statistics.MINIMUM))
.unit(Unit.PERCENT).build();
GetMetricStatisticsResponse response = client.getMetricStatistics(options);
if (response.getDatapoints().size() > 0) {
checkNotNull(response.getLabel());
for (Datapoint datapoint : response.getDatapoints()) {
checkArgument(datapoint.getAverage() == null);
checkNotNull(datapoint.getMaximum());
checkNotNull(datapoint.getMinimum());
}
testRan = true;
break;
}
}
if (testRan) {
break;
}
}
}
}
@Test @Test
protected void testListMetrics() { protected void testListMetrics() {
ListMetricsResponse response; ListMetricsResponse response;