Merge pull request #651 from jcscoobyrs/master

Implement PutMetricData for CloudWatch.
This commit is contained in:
Adrian Cole 2012-05-26 08:34:54 -07:00
commit 884e0d867e
18 changed files with 1086 additions and 286 deletions

View File

@ -19,12 +19,15 @@
package org.jclouds.cloudwatch;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Sets;
import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.features.MetricClient;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import java.util.Iterator;
import java.util.Set;
/**
* Utilities for using CloudWatch.
@ -58,10 +61,10 @@ public class CloudWatch {
while (true) {
if (iterator == null) {
lastOptions = ListMetricsOptions.builder()
.dimensions(lastOptions.getDimensions())
.metricName(lastOptions.getMetricName())
.namespace(lastOptions.getNamespace())
.nextToken(response.getNextToken())
.metricName(lastOptions.getMetricName())
.dimensions(lastOptions.getDimensions())
.nextToken(lastOptions.getNextToken())
.build();
response = metricClient.listMetrics(lastOptions);
iterator = response.iterator();
@ -95,4 +98,32 @@ public class CloudWatch {
return listMetrics(cloudWatchClient.getMetricClientForRegion(region), options);
}
/**
* Pushes metrics to CloudWatch.
*
* @param cloudWatchClient the {@link CloudWatchClient} to use for the request
* @param region the region to put the metrics in
* @param metrics the metrics to publish
* @param namespace the namespace to publish the metrics in
*/
public static void putMetricData(CloudWatchClient cloudWatchClient, String region, Iterable<MetricDatum> metrics,
String namespace) {
MetricClient metricClient = cloudWatchClient.getMetricClientForRegion(region);
Iterator<MetricDatum> mIterator = metrics.iterator();
Set<MetricDatum> metricsData = Sets.newLinkedHashSet();
while (mIterator.hasNext()) {
metricsData.add(mIterator.next());
if (metricsData.size() == 10 || !mIterator.hasNext()) {
// Make the call
metricClient.putMetricData(metrics, namespace);
// Reset the list for subsequent call if necessary
if (mIterator.hasNext()) {
metricsData = Sets.newLinkedHashSet();
}
}
}
}
}

View File

@ -18,10 +18,7 @@
*/
package org.jclouds.cloudwatch;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.google.inject.Provides;
import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.features.MetricClient;
@ -33,7 +30,9 @@ import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.inject.Provides;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Provides access to Amazon CloudWatch via the Query API
@ -90,7 +89,7 @@ public interface CloudWatchClient {
* The statistics to be returned for the given metric. ex. Average
* @param options
* more filtering options (e.g. instance ID)
* @see MetricsClient#getMetricStatistics
* @see MetricClient#getMetricStatistics(org.jclouds.cloudwatch.domain.GetMetricStatistics)
*/
@Deprecated
Set<Datapoint> getMetricStatisticsInRegion(@Nullable String region, String metricName, String namespace,

View File

@ -18,8 +18,8 @@
*/
package org.jclouds.cloudwatch.binders;
import javax.inject.Inject;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMultimap;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.GetMetricStatistics;
import org.jclouds.cloudwatch.domain.Statistics;
@ -27,8 +27,9 @@ import org.jclouds.date.DateService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMultimap;
import javax.inject.Inject;
import java.util.HashSet;
import java.util.Set;
/**
* Binds the metrics request to the http request
@ -45,36 +46,49 @@ public class GetMetricStatisticsBinder implements org.jclouds.rest.Binder {
@Inject
protected GetMetricStatisticsBinder(DateService dateService){
this.dateService =dateService;
this.dateService = dateService;
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
GetMetricStatistics getRequest = GetMetricStatistics.class.cast(payload);
Set<Dimension> dimensions = getRequest.getDimensions() != null ?
getRequest.getDimensions() :
new HashSet<Dimension>();
Set<Statistics> statistics = getRequest.getStatistics() != null ?
getRequest.getStatistics() :
new HashSet<Statistics>();
int dimensionIndex = 1;
int statisticIndex = 1;
ImmutableMultimap.Builder<String, String> formParameters = ImmutableMultimap.builder();
ImmutableMultimap.Builder<String, String> formParameters = ImmutableMultimap.<String, String> builder();
for (Dimension dimension : getRequest.getDimensions()) {
for (Dimension dimension : dimensions) {
formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++;
}
formParameters.put("EndTime", dateService.iso8601SecondsDateFormat(getRequest.getEndTime()));
if (getRequest.getEndTime() != null) {
formParameters.put("EndTime", dateService.iso8601SecondsDateFormat(getRequest.getEndTime()));
}
formParameters.put("MetricName", getRequest.getMetricName());
formParameters.put("Namespace", getRequest.getNamespace());
formParameters.put("Period", Integer.toString(getRequest.getPeriod()));
formParameters.put("StartTime", dateService.iso8601SecondsDateFormat(getRequest
.getStartTime()));
if (getRequest.getStartTime() != null) {
formParameters.put("StartTime", dateService.iso8601SecondsDateFormat(getRequest
.getStartTime()));
}
for (Statistics statistic : getRequest.getStatistics()) {
for (Statistics statistic : statistics) {
formParameters.put("Statistics.member." + statisticIndex, statistic.toString());
statisticIndex++;
}
formParameters.put("Unit", getRequest.getUnit().toString());
if (getRequest.getUnit() != null) {
formParameters.put("Unit", getRequest.getUnit().toString());
}
return ModifyRequest.putFormParams(request, formParameters.build());
}
}

View File

@ -0,0 +1,110 @@
/**
* 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.binders;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Inject;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.domain.StatisticSet;
import org.jclouds.date.DateService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.utils.ModifyRequest;
import java.util.HashSet;
import java.util.Set;
/**
* Binds the metrics request to the http request
*
* @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html" />
*
* @author Jeremy Whitlock
*/
@Beta
public class MetricDataBinder implements org.jclouds.rest.Binder {
private final DateService dateService;
@Inject
protected MetricDataBinder(DateService dateService) {
this.dateService = dateService;
}
/**
* {@inheritDoc}
*/
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
Iterable<MetricDatum> metrics = input != null ?
(Iterable<MetricDatum>)input :
new HashSet<MetricDatum>();
ImmutableMultimap.Builder<String, String> formParameters = ImmutableMultimap.builder();
int metricDatumIndex = 1;
for (MetricDatum metricDatum : metrics) {
int dimensionIndex = 1;
StatisticSet statisticSet = metricDatum.getStatisticSet();
Set<Dimension> dimensions = metricDatum.getDimensions() != null ?
metricDatum.getDimensions() :
new HashSet<Dimension>();
for (Dimension dimension : dimensions) {
formParameters.put("MetricData.member." + metricDatumIndex + ".Dimensions.member." + dimensionIndex +
".Name", dimension.getName());
formParameters.put("MetricData.member." + metricDatumIndex + ".Dimensions.member." + dimensionIndex +
".Value", dimension.getValue());
dimensionIndex++;
}
formParameters.put("MetricData.member." + metricDatumIndex + ".MetricName", metricDatum.getMetricName());
if (statisticSet != null) {
formParameters.put("MetricData.member." + metricDatumIndex + ".StatisticValues.Maximum",
String.valueOf(statisticSet.getMaximum()));
formParameters.put("MetricData.member." + metricDatumIndex + ".StatisticValues.Minimum",
String.valueOf(statisticSet.getMinimum()));
formParameters.put("MetricData.member." + metricDatumIndex + ".StatisticValues.SampleCount",
String.valueOf(statisticSet.getSampleCount()));
formParameters.put("MetricData.member." + metricDatumIndex + ".StatisticValues.Sum",
String.valueOf(statisticSet.getSum()));
}
if (metricDatum.getTimestamp() != null) {
formParameters.put("MetricData.member." + metricDatumIndex + ".Timestamp",
dateService.iso8601SecondsDateFormat(metricDatum.getTimestamp()));
}
if (metricDatum.getUnit() != null) {
formParameters.put("MetricData.member." + metricDatumIndex + ".Unit",
String.valueOf(metricDatum.getUnit()));
}
if (metricDatum.getValue() != null) {
formParameters.put("MetricData.member." + metricDatumIndex + ".Value",
String.valueOf(metricDatum.getValue()));
}
metricDatumIndex++;
}
return ModifyRequest.putFormParams(request, formParameters.build());
}
}

View File

@ -18,15 +18,13 @@
*/
package org.jclouds.cloudwatch.domain;
import java.util.Date;
import java.util.Set;
import com.google.common.annotations.Beta;
import com.google.common.collect.Sets;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import java.util.Date;
import java.util.Set;
/**
* Options use to get statistics for the specified metric.
@ -50,9 +48,8 @@ public class GetMetricStatistics {
/**
* Private constructor to enforce using {@link Builder}.
*/
private GetMetricStatistics(@Nullable Set<Dimension> dimensions, Date endTime, String metricName,
String namespace, int period, Date startTime, Set<Statistics> statistics,
Unit unit) {
private GetMetricStatistics(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;
@ -74,6 +71,7 @@ public class GetMetricStatistics {
/**
* return the end time for this request
*/
@Nullable
public Date getEndTime() {
return endTime;
}
@ -81,6 +79,7 @@ public class GetMetricStatistics {
/**
* return the metric name for this request
*/
@Nullable
public String getMetricName() {
return metricName;
}
@ -88,6 +87,7 @@ public class GetMetricStatistics {
/**
* return the namespace for this request
*/
@Nullable
public String getNamespace() {
return namespace;
}
@ -95,6 +95,7 @@ public class GetMetricStatistics {
/**
* return the period for this request
*/
@Nullable
public int getPeriod() {
return period;
}
@ -102,6 +103,7 @@ public class GetMetricStatistics {
/**
* return the start time for this request
*/
@Nullable
public Date getStartTime() {
return startTime;
}
@ -109,6 +111,7 @@ public class GetMetricStatistics {
/**
* return the statistics for this request
*/
@Nullable
public Set<Statistics> getStatistics() {
return statistics;
}
@ -116,6 +119,7 @@ public class GetMetricStatistics {
/**
* return the unit for this request
*/
@Nullable
public Unit getUnit() {
return unit;
}
@ -130,13 +134,13 @@ public class GetMetricStatistics {
public static class Builder {
private Set<Dimension> dimensions = Sets.newLinkedHashSet();
private Set<Dimension> dimensions;
private Date endTime;
private String metricName;
private String namespace;
private int period;
private Date startTime;
private Set<Statistics> statistics = Sets.newLinkedHashSet();
private Set<Statistics> statistics;
private Unit unit;
/**
@ -146,142 +150,102 @@ public class GetMetricStatistics {
public Builder() {}
/**
* A list of dimensions describing qualities of the metric. (Set can be 10 or less items.)
* A list of dimensions describing qualities of the metric.
*
* @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;
}
this.dimensions = dimensions;
return this;
}
/**
* A dimension describing qualities of the metric. (Can be called multiple times up to a maximum of 10 times.)
* A dimension describing qualities of the metric.
*
* @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);
if (dimensions == null) {
dimensions = Sets.newLinkedHashSet();
}
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.)
* results will include datapoints up to the time stamp specified.
*
* @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.)
* The name of the metric.
*
* @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.)
* The namespace of the metric.
*
* @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.)
* The granularity, in seconds, of the returned datapoints.
*
* @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.)
* results include datapoints with the time stamp specified.
*
* @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.)
* The metric statistics to return.
*
* @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;
}
@ -292,28 +256,23 @@ public class GetMetricStatistics {
* @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.");
if (statistics == null) {
statistics = Sets.newLinkedHashSet();
}
this.statistics.add(statistic);
return this;
}
/**
* The unit for the metric. (Should be called once. Subsequent calls will overwrite the previous value.)
* The unit for the metric.
*
* @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;
}
@ -321,22 +280,12 @@ public class GetMetricStatistics {
/**
* 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 GetMetricStatistics 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");
return new GetMetricStatistics(dimensions, endTime, metricName,namespace, period, startTime, statistics, unit);
return new GetMetricStatistics(dimensions, endTime, metricName,namespace, period, startTime, statistics,
unit);
}
}
}

View File

@ -0,0 +1,222 @@
/**
* 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.Date;
import java.util.Set;
/**
* @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html" />
*
* @author Jeremy Whitlock
*/
public class MetricDatum {
private final Set<Dimension> dimensions;
private final String metricName;
private final StatisticSet statisticSet;
private final Date timestamp;
private final Unit unit;
private final Double value;
/**
* Private constructor to enforce using {@link Builder}.
*/
private MetricDatum(Set<Dimension> dimensions, String metricName, StatisticSet statisticSet, Date timestamp,
Unit unit, Double value) {
this.dimensions = dimensions;
this.metricName = metricName;
this.statisticSet = statisticSet;
this.timestamp = timestamp;
this.unit = unit;
this.value = value;
}
/**
* return the list of dimensions describing the the metric.
*/
@Nullable
public Set<Dimension> getDimensions() {
return dimensions;
}
/**
* return the metric name for the metric.
*/
@Nullable
public String getMetricName() {
return metricName;
}
/**
* return the object describing the set of statistical values for the metric
*/
@Nullable
public StatisticSet getStatisticSet() {
return statisticSet;
}
/**
* return the time stamp used for the metric
*/
@Nullable
public Date getTimestamp() {
return timestamp;
}
/**
* return Standard unit used for the metric.
*/
@Nullable
public Unit getUnit() {
return unit;
}
/**
* return the actual value of the metric
*/
@Nullable
public Double getValue() {
return value;
}
/**
* 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;
private String metricName;
private StatisticSet statisticSet;
private Date timestamp;
private Unit unit;
private Double value;
/**
* Creates a new builder. The returned builder is equivalent to the builder
* generated by {@link org.jclouds.cloudwatch.domain.MetricDatum#builder}.
*/
public Builder() {}
/**
* A list of dimensions describing qualities of the metric.
*
* @param dimensions the dimensions describing the qualities of the metric
*
* @return this {@code Builder} object
*/
public Builder dimensions(Set<Dimension> dimensions) {
this.dimensions = dimensions;
return this;
}
/**
* A dimension describing qualities of the metric.
*
* @param dimension the dimension describing the qualities of the metric
*
* @return this {@code Builder} object
*/
public Builder dimension(Dimension dimension) {
if (dimensions == null) {
dimensions = Sets.newLinkedHashSet();
}
this.dimensions.add(dimension);
return this;
}
/**
* The name of the metric.
*
* @param metricName the metric name
*
* @return this {@code Builder} object
*/
public Builder metricName(String metricName) {
this.metricName = metricName;
return this;
}
/**
* The object describing the set of statistical values describing the metric.
*
* @param statisticSet the object describing the set of statistical values for the metric
*
* @return this {@code Builder} object
*/
public Builder statisticSet(StatisticSet statisticSet) {
this.statisticSet = statisticSet;
return this;
}
/**
* The time stamp used for the metric. If not specified, the default value is set to the time the metric data was
* received.
*
* @param timestamp the time stamp used for the metric
*
* @return this {@code Builder} object
*/
public Builder timestamp(Date timestamp) {
this.timestamp = timestamp;
return this;
}
/**
* The unit for the metric.
*
* @param unit the unit for the metric
*
* @return this {@code Builder} object
*/
public Builder unit(Unit unit) {
this.unit = unit;
return this;
}
/**
* The value for the metric.
*
* @param value the value for the metric
*
* @return this {@code Builder} object
*/
public Builder value(Double value) {
this.value = value;
return this;
}
/**
* Returns a newly-created {@code MetricDatum} based on the contents of the {@code Builder}.
*/
public MetricDatum build() {
return new MetricDatum(dimensions, metricName, statisticSet, timestamp, unit, value);
}
}
}

View File

@ -0,0 +1,152 @@
/**
* 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 org.jclouds.javax.annotation.Nullable;
/**
* @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_StatisticSet.html" />
*
* @author Jeremy Whitlock
*/
public class StatisticSet {
private final Double maximum;
private final Double minimum;
private final Double sampleCount;
private final Double sum;
public StatisticSet(Double maximum, Double minimum, Double sampleCount, Double sum) {
this.maximum = maximum;
this.minimum = minimum;
this.sampleCount = sampleCount;
this.sum = sum;
}
/**
* return the maximum value of the sample set
*/
@Nullable
public Double getMaximum() {
return maximum;
}
/**
* return the minimum value of the sample set
*/
@Nullable
public Double getMinimum() {
return minimum;
}
/**
* return the number of samples used for the statistic set
*/
@Nullable
public Double getSampleCount() {
return sampleCount;
}
/**
* return the sum of values for the sample set
*/
@Nullable
public Double getSum() {
return sum;
}
/**
* 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 Double maximum;
private Double minimum;
private Double sampleCount;
private Double sum;
/**
* Creates a new builder. The returned builder is equivalent to the builder
* generated by {@link org.jclouds.cloudwatch.domain.StatisticSet#builder}.
*/
public Builder() {}
/**
* The maximum value of the sample set.
*
* @param maximum the maximum value of the sample set
*
* @return this {@code Builder} object
*/
public Builder maximum(Double maximum) {
this.maximum = maximum;
return this;
}
/**
* The minimum value of the sample set.
*
* @param minimum the minimum value of the sample set
*
* @return this {@code Builder} object
*/
public Builder minimum(Double minimum) {
this.minimum = minimum;
return this;
}
/**
* The the number of samples used for the statistic set.
*
* @param sampleCount the number of samples used for the statistic set
*
* @return this {@code Builder} object
*/
public Builder sampleCount(Double sampleCount) {
this.sampleCount = sampleCount;
return this;
}
/**
* The sum of values for the sample set.
*
* @param sum the sum of values for the sample set
*
* @return this {@code Builder} object
*/
public Builder sum(Double sum) {
this.sum = sum;
return this;
}
/**
* Returns a newly-created {@code StatisticSet} based on the contents of the {@code Builder}.
*/
public StatisticSet build() {
return new StatisticSet(maximum, minimum, sampleCount, sum);
}
}
}

View File

@ -18,14 +18,14 @@
*/
package org.jclouds.cloudwatch.features;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.cloudwatch.binders.GetMetricStatisticsBinder;
import org.jclouds.cloudwatch.binders.MetricDataBinder;
import org.jclouds.cloudwatch.domain.GetMetricStatistics;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.cloudwatch.xml.GetMetricStatisticsResponseHandlerV2;
@ -36,7 +36,9 @@ import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import com.google.common.util.concurrent.ListenableFuture;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
/**
* Provides access to Amazon CloudWatch via the Query API
@ -88,4 +90,13 @@ public interface MetricAsyncClient {
@BinderParam(GetMetricStatisticsBinder.class) GetMetricStatistics statistics,
GetMetricStatisticsOptions options);
/**
* @see MetricClient#putMetricData(Iterable, String)
*/
@POST
@Path("/")
@FormParams(keys = "Action", values = "PutMetricData")
ListenableFuture<Void> putMetricData(@BinderParam(MetricDataBinder.class) Iterable<MetricDatum> metrics,
@FormParam("Namespace") String namespace);
}

View File

@ -18,15 +18,16 @@
*/
package org.jclouds.cloudwatch.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.cloudwatch.domain.GetMetricStatistics;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.concurrent.Timeout;
import java.util.concurrent.TimeUnit;
/**
* Provides access to Amazon CloudWatch via the Query API
* <p/>
@ -45,10 +46,10 @@ public interface MetricClient {
* use returned NextToken (
* {@link org.jclouds.cloudwatch.domain.ListMetricsResponse#getNextToken()}) value with
* subsequent calls .To retrieve all available metrics with one call, use
* {@link #list(MetricsClient, String, org.jclouds.cloudwatch.options.ListMetricsOptions)}.
* {@link org.jclouds.cloudwatch.CloudWatch#listMetrics(MetricClient,
* org.jclouds.cloudwatch.options.ListMetricsOptions)}
*
* @param options
* the options describing the metrics query
* @param options the options describing the metrics query
*
* @return the response object
*/
@ -59,10 +60,8 @@ public interface MetricClient {
/**
* Gets statistics for the specified metric.
*
* @param statistics
* the statistics to gather
* @param options
* the options describing the metric statistics query
* @param statistics the statistics to gather
* @param options the options describing the metric statistics query
*
* @return the response object
*/
@ -70,4 +69,12 @@ public interface MetricClient {
GetMetricStatisticsResponse getMetricStatistics(GetMetricStatistics statistics);
/**
* Publishes metric data points to Amazon CloudWatch.
*
* @param metrics the metrics to publish
* @param namespace the namespace to publish the metrics to
*/
void putMetricData(Iterable<MetricDatum> metrics, String namespace);
}

View File

@ -18,19 +18,16 @@
*/
package org.jclouds.cloudwatch.options;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.http.options.BaseHttpRequestOptions;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Options used to control metric statistics are returned
@ -42,39 +39,32 @@ import com.google.common.collect.Sets;
*/
public class GetMetricStatisticsOptions extends BaseHttpRequestOptions {
private Set<Dimension> dimensions = Sets.newLinkedHashSet();
private Set<Dimension> dimensions;
/**
* A dimension describing qualities of the metric. (Can be called multiple times up to a maximum of 10 times.)
* A dimension describing qualities of the metric.
*
* @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 GetMetricStatisticsOptions dimension(Dimension dimension) {
if (dimension != null) {
Preconditions.checkArgument(dimensions.size() < 10, "dimension member maximum count of 10 exceeded.");
this.dimensions.add(dimension);
if (dimensions == null) {
dimensions = Sets.newLinkedHashSet();
}
this.dimensions.add(dimension);
return this;
}
/**
* A list of dimensions describing qualities of the metric. (Set can be 10 or less items.)
* A list of dimensions describing qualities of the metric.
*
* @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 GetMetricStatisticsOptions dimensions(Set<Dimension> dimensions) {
if (dimensions != null) {
Preconditions.checkArgument(dimensions.size() <= 10, "dimensions can have 10 or fewer members.");
this.dimensions = ImmutableSet.<Dimension>copyOf(dimensions);
}
this.dimensions = dimensions;
return this;
}
@ -137,10 +127,12 @@ public class GetMetricStatisticsOptions extends BaseHttpRequestOptions {
public Multimap<String, String> buildFormParameters() {
Multimap<String, String> formParameters = super.buildFormParameters();
int dimensionIndex = 1;
for (Dimension dimension : dimensions) {
formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++;
if (dimensions != null) {
for (Dimension dimension : dimensions) {
formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++;
}
}
return formParameters;
}

View File

@ -18,7 +18,6 @@
*/
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.http.options.BaseHttpRequestOptions;
@ -105,72 +104,50 @@ public class ListMetricsOptions extends BaseHttpRequestOptions {
public Builder() {}
/**
* The namespace to filter against. (Should be called once. Subsequent calls will overwrite the previous value.
* See {@link org.jclouds.cloudwatch.domain.Namespaces} for the known list of namespaces.)
* The namespace to filter against.
*
* @param namespace the namespace to filter against
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if namespace is empty
*/
public Builder namespace(String namespace) {
if (namespace != null) {
Preconditions.checkArgument(namespace.length() > 1, "namespace must not be empty.");
}
this.namespace = namespace;
return this;
}
/**
* The name of the metric to filter against. (Should be called once. Subsequent calls will overwrite the
* previous value.)
* The name of the metric to filter against.
*
* @param metricName the metric name to filter against
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if metricName is empty
*/
public Builder metricName(String metricName) {
if (metricName != null) {
Preconditions.checkArgument(metricName.length() > 1, "metricName must not be empty.");
}
this.metricName = metricName;
return this;
}
/**
* A list of dimensions to filter against. (Set can be 10 or less items.)
* A list of dimensions to filter against.
*
* @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) {
if (dimensions != null) {
Preconditions.checkArgument(dimensions.size() <= 10, "dimensions can have 10 or fewer members.");
this.dimensions = dimensions;
}
this.dimensions = dimensions;
return this;
}
/**
* A dimension to filter the available metrics by. (Can be called multiple times up to a maximum of 10 times.)
* A dimension to filter the available metrics by.
*
* @param dimension a dimension to filter the returned metrics by
*
* @return this {@code Builder} object
*
* @throws IllegalArgumentException if this is invoked more than 10 times
*/
public Builder dimension(Dimension dimension) {
if (dimension != null) {
Preconditions.checkArgument(dimensions.size() < 10, "dimension member maximum count of 10 exceeded.");
this.dimensions.add(dimension);
}
this.dimensions.add(dimension);
return this;
}
@ -194,20 +171,25 @@ public class ListMetricsOptions extends BaseHttpRequestOptions {
ListMetricsOptions lmo = new ListMetricsOptions(namespace, metricName, dimensions, nextToken);
int dimensionIndex = 1;
// If namespace isn't specified, don't include it
if (namespace != null) {
lmo.formParameters.put("Namespace", namespace);
}
// If metricName isn't specified, don't include it
if (metricName != null) {
lmo.formParameters.put("MetricName", metricName);
}
for (Dimension dimension : dimensions) {
lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++;
// If dimensions isn't specified, don't include it
if (dimensions != null) {
for (Dimension dimension : dimensions) {
lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Name", dimension.getName());
lmo.formParameters.put("Dimensions.member." + dimensionIndex + ".Value", dimension.getValue());
dimensionIndex++;
}
}
// If nextToken isn't specified, don't include it
if (nextToken != null) {
lmo.formParameters.put("NextToken", nextToken);
}

View File

@ -18,15 +18,14 @@
*/
package org.jclouds.cloudwatch.xml;
import java.util.Date;
import javax.inject.Inject;
import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax;
import javax.inject.Inject;
import java.util.Date;
/**
*
* @author Adrian Cole
@ -71,7 +70,7 @@ public class DatapointHandler extends ParseSax.HandlerForGeneratedRequestWithRes
minimum = doubleOrNull();
} else if (qName.equals("Timestamp")) {
timestamp = dateService.iso8601SecondsDateParse(currentText.toString().trim());
} else if (qName.equals("Samples")) {
} else if (qName.equals("SampleCount")) {
samples = doubleOrNull();
} else if (qName.equals("Sum")) {
sum = doubleOrNull();

View File

@ -18,13 +18,25 @@
*/
package org.jclouds.cloudwatch;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.reflect.TypeToken;
import junit.framework.Assert;
import org.jclouds.apis.BaseContextLiveTest;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
/**
@ -58,4 +70,38 @@ public class CloudWatchLiveTest extends BaseContextLiveTest<RestContext<CloudWat
checkArgument(CloudWatch.listMetrics(client, null, ListMetricsOptions.builder().build()).iterator().hasNext());
}
@Test
protected void testCloudWatchPutMetrics() {
String metricName = "TestMetricName" + System.currentTimeMillis();
String namespace = "JCLOUDS/Test";
Date metricTimestamp = new Date();
Set<MetricDatum> metrics = Sets.newLinkedHashSet();
for (int i = 0; i < 11; i++) {
metrics.add(MetricDatum.builder()
.metricName(metricName + "_" + i)
.dimension(new Dimension("BaseMetricName", metricName))
.unit(Unit.COUNT)
.timestamp(metricTimestamp)
.value((double) i)
.build());
}
CloudWatch.putMetricData(client, null, metrics, namespace);
ListMetricsOptions lmo = ListMetricsOptions.builder().namespace(namespace)
.dimension(new Dimension("BaseMetricName", metricName))
.build();
boolean success = new RetryablePredicate<ListMetricsOptions>(new Predicate<ListMetricsOptions>() {
@Override
public boolean apply(ListMetricsOptions options) {
return Iterables.size(CloudWatch.listMetrics(client, null, options)) == 11;
}
}, 20, 1, TimeUnit.MINUTES).apply(lmo);
if (!success) {
Assert.fail("Unable to gather the created CloudWatch data within the time (20m) allotted.");
}
}
}

View File

@ -18,20 +18,24 @@
*/
package org.jclouds.cloudwatch;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import org.easymock.EasyMock;
import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.features.MetricClient;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.util.Set;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
/**
* Tests behavior of {@code CloudWatch}.
@ -97,4 +101,38 @@ public class CloudWatchTest {
Assert.assertEquals(2, Iterables.size(CloudWatch.listMetrics(client, "", options)));
}
/**
* Tests {@link CloudWatch#putMetricData(CloudWatchClient, String, Iterable, String)} where the set of metrics is
* greater than 10.
*
* @throws Exception if anything goes wrong
*/
@Test
public void testPutMetricData() throws Exception {
CloudWatchClient client = createMock(CloudWatchClient.class);
MetricClient metricClient = createMock(MetricClient.class);
Set<MetricDatum> metrics = Sets.newLinkedHashSet();
String namespace = "JCLOUDS/Test";
for (int i = 0; i < 11; i++) {
metrics.add(MetricDatum.builder().build());
}
// Using EasyMock.eq("") because EasyMock makes it impossible to pass null as a String value here
expect(client.getMetricClientForRegion(EasyMock.eq("")))
.andReturn(metricClient)
.atLeastOnce();
metricClient.putMetricData(metrics, namespace);
expectLastCall().times(2);
EasyMock.replay(client, metricClient);
CloudWatch.putMetricData(client, "", metrics, namespace);
EasyMock.verify(metricClient);
}
}

View File

@ -0,0 +1,142 @@
/**
* 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.binders;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
import junit.framework.Assert;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.domain.StatisticSet;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.http.HttpRequest;
import org.testng.annotations.Test;
import java.net.URI;
import java.util.Date;
/**
* Tests behavior of {@link MetricDataBinder}.
*
* @author Jeremy Whitlock
*/
@Test(groups = "unit")
public class MetricDataBinderTest {
Injector injector = Guice.createInjector();
MetricDataBinder binder = injector.getInstance(MetricDataBinder.class);
HttpRequest request = HttpRequest.builder().method("POST").endpoint(URI.create("http://localhost")).build();
public void testMetricWithoutTimestamp() throws Exception {
StatisticSet ss = StatisticSet.builder()
.maximum(4.0)
.minimum(1.0)
.sampleCount(4.0)
.sum(10.0)
.build();
MetricDatum metricDatum = MetricDatum.builder()
.metricName("TestMetricName")
.statisticSet(ss)
.dimension(new Dimension("TestDimension", "FAKE"))
.unit(Unit.COUNT)
.build();
request = binder.bindToRequest(request, ImmutableSet.of(metricDatum));
Assert.assertEquals(request.getPayload().getRawContent(),
"MetricData.member.1.Dimensions.member.1.Name=TestDimension" +
"&MetricData.member.1.Dimensions.member.1.Value=FAKE" +
"&MetricData.member.1.MetricName=TestMetricName" +
"&MetricData.member.1.StatisticValues.Maximum=4.0" +
"&MetricData.member.1.StatisticValues.Minimum=1.0" +
"&MetricData.member.1.StatisticValues.SampleCount=4.0" +
"&MetricData.member.1.StatisticValues.Sum=10.0" +
"&MetricData.member.1.Unit=" + Unit.COUNT.toString());
}
public void testMetricWithMultipleDimensions() throws Exception {
MetricDatum metricDatum = MetricDatum.builder()
.metricName("TestMetricName")
.dimension(new Dimension("TestDimension", "FAKE"))
.dimension(new Dimension("TestDimension2", "FAKE2"))
.unit(Unit.COUNT)
.timestamp(new Date(10000000l))
.value(5.0)
.build();
request = binder.bindToRequest(request, ImmutableSet.of(metricDatum));
Assert.assertEquals(request.getPayload().getRawContent(),
"MetricData.member.1.Dimensions.member.1.Name=TestDimension" +
"&MetricData.member.1.Dimensions.member.1.Value=FAKE" +
"&MetricData.member.1.Dimensions.member.2.Name=TestDimension2" +
"&MetricData.member.1.Dimensions.member.2.Value=FAKE2" +
"&MetricData.member.1.MetricName=TestMetricName" +
"&MetricData.member.1.Timestamp=1970-01-01T02%3A46%3A40Z" +
"&MetricData.member.1.Unit=" + Unit.COUNT.toString() +
"&MetricData.member.1.Value=5.0");
}
public void testMetricWithMultipleDatum() throws Exception {
StatisticSet ss = StatisticSet.builder()
.maximum(4.0)
.minimum(1.0)
.sampleCount(4.0)
.sum(10.0)
.build();
MetricDatum metricDatum = MetricDatum.builder()
.metricName("TestMetricName")
.statisticSet(ss)
.dimension(new Dimension("TestDimension", "FAKE"))
.dimension(new Dimension("TestDimension2", "FAKE2"))
.unit(Unit.COUNT)
.timestamp(new Date(10000000l))
.build();
MetricDatum metricDatum2 = MetricDatum.builder()
.metricName("TestMetricName")
.dimension(new Dimension("TestDimension", "FAKE"))
.unit(Unit.COUNT)
.timestamp(new Date(10000000l))
.value(5.0)
.build();
request = binder.bindToRequest(request, ImmutableSet.of(metricDatum, metricDatum2));
Assert.assertEquals(request.getPayload().getRawContent(),
"MetricData.member.1.Dimensions.member.1.Name=TestDimension" +
"&MetricData.member.1.Dimensions.member.1.Value=FAKE" +
"&MetricData.member.1.Dimensions.member.2.Name=TestDimension2" +
"&MetricData.member.1.Dimensions.member.2.Value=FAKE2" +
"&MetricData.member.1.MetricName=TestMetricName" +
"&MetricData.member.1.StatisticValues.Maximum=4.0" +
"&MetricData.member.1.StatisticValues.Minimum=1.0" +
"&MetricData.member.1.StatisticValues.SampleCount=4.0" +
"&MetricData.member.1.StatisticValues.Sum=10.0" +
"&MetricData.member.1.Timestamp=1970-01-01T02%3A46%3A40Z" +
"&MetricData.member.1.Unit=" + Unit.COUNT.toString() +
"&MetricData.member.2.Dimensions.member.1.Name=TestDimension" +
"&MetricData.member.2.Dimensions.member.1.Value=FAKE" +
"&MetricData.member.2.MetricName=TestMetricName" +
"&MetricData.member.2.Timestamp=1970-01-01T02%3A46%3A40Z" +
"&MetricData.member.2.Unit=" + Unit.COUNT.toString() +
"&MetricData.member.2.Value=5.0");
}
}

View File

@ -18,12 +18,7 @@
*/
package org.jclouds.cloudwatch.features;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Date;
import java.util.TimeZone;
import com.google.common.collect.ImmutableMultimap;
import org.jclouds.cloudwatch.CloudWatchClient;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.EC2Constants;
@ -39,7 +34,11 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.rest.ResourceNotFoundException;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import java.net.URI;
import java.util.Date;
import java.util.TimeZone;
import static org.testng.Assert.assertEquals;
/**
* @author Jeremy Whitlock, Adrian Cole
@ -59,14 +58,14 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
.build())
.payload(
payloadFromStringWithContentType(
new StringBuilder()
.append("Action=ListMetrics").append('&')
.append("Signature=KSh9oQydCR0HMAV6QPYwDzqwQIpxs8I%2Fig7brYgHVZU%3D").append('&')
.append("SignatureMethod=HmacSHA256").append('&')
.append("SignatureVersion=2").append('&')
.append("Timestamp=2009-11-08T15%3A54%3A08.897Z").append('&')
.append("Version=2010-08-01").append('&')
.append("AWSAccessKeyId=identity").toString(), "application/x-www-form-urlencoded"))
"Action=ListMetrics" +
"&Signature=KSh9oQydCR0HMAV6QPYwDzqwQIpxs8I%2Fig7brYgHVZU%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2010-08-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
public void testListMetricsWhenResponseIs2xx() throws Exception {
@ -78,7 +77,8 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
listMetrics, listMetricsResponse);
assertEquals(clientWhenMetricsExist.getMetricClientForRegion(null).listMetrics().toString(),
"ListMetricsResponse{metrics=[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}], nextToken=null}");
"ListMetricsResponse{metrics=[Metric{namespace=AWS/EC2, metricName=CPUUtilization, " +
"dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}], nextToken=null}");
}
// TODO: this should really be an empty set
@ -94,28 +94,28 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
}
public void testListMetricsWithOptionsWhenResponseIs2xx() throws Exception {
HttpRequest listMetricsWithOptions = HttpRequest.builder()
.method("POST")
.endpoint(URI.create("https://monitoring.us-east-1.amazonaws.com/"))
.headers(ImmutableMultimap.<String, String> builder()
.put("Host", "monitoring.us-east-1.amazonaws.com")
.build())
.payload(
payloadFromStringWithContentType(
new StringBuilder()
.append("Action=ListMetrics").append('&')
.append("Dimensions.member.1.Name=InstanceId").append('&')
.append("Dimensions.member.1.Value=SOMEINSTANCEID").append('&')
.append("MetricName=CPUUtilization").append('&')
.append("Namespace=SOMENEXTTOKEN").append('&')
.append("NextToken=AWS%2FEC2").append('&')
.append("Signature=G05HKEx9FJpGZBk02OVYwt3u4g%2FilAY9nU5hJI9LDXA%3D").append('&')
.append("SignatureMethod=HmacSHA256").append('&')
.append("SignatureVersion=2").append('&')
.append("Timestamp=2009-11-08T15%3A54%3A08.897Z").append('&')
.append("Version=2010-08-01").append('&')
.append("AWSAccessKeyId=identity").toString(), "application/x-www-form-urlencoded"))
.build();
HttpRequest listMetricsWithOptions =
HttpRequest.builder()
.method("POST")
.endpoint(URI.create("https://monitoring.us-east-1.amazonaws.com/"))
.headers(ImmutableMultimap.<String, String>builder()
.put("Host", "monitoring.us-east-1.amazonaws.com")
.build())
.payload(payloadFromStringWithContentType(
"Action=ListMetrics" +
"&Dimensions.member.1.Name=InstanceId" +
"&Dimensions.member.1.Value=SOMEINSTANCEID" +
"&MetricName=CPUUtilization" +
"&Namespace=SOMENEXTTOKEN" +
"&NextToken=AWS%2FEC2" +
"&Signature=G05HKEx9FJpGZBk02OVYwt3u4g%2FilAY9nU5hJI9LDXA%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Version=2010-08-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse listMetricsWithOptionsResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/list_metrics.xml", "text/xml")).build();
@ -126,12 +126,14 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
assertEquals(
clientWhenMetricsWithOptionsExist.getMetricClientForRegion(null).listMetrics(
ListMetricsOptions.builder()
.dimension(new Dimension(EC2Constants.Dimension.INSTANCE_ID, "SOMEINSTANCEID"))
.dimension(new Dimension(EC2Constants.Dimension.INSTANCE_ID,
"SOMEINSTANCEID"))
.metricName(EC2Constants.MetricName.CPU_UTILIZATION)
.namespace("SOMENEXTTOKEN")
.nextToken( Namespaces.EC2)
.build()).toString(),
"ListMetricsResponse{metrics=[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}], nextToken=null}");
"ListMetricsResponse{metrics=[Metric{namespace=AWS/EC2, metricName=CPUUtilization, " +
"dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}], nextToken=null}");
}
GetMetricStatistics stats = GetMetricStatistics.builder()
@ -152,21 +154,22 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
.build())
.payload(
payloadFromStringWithContentType(
new StringBuilder()
.append("Action=GetMetricStatistics").append('&')
.append("EndTime=1970-01-01T02%3A46%3A40Z").append('&')
.append("MetricName=CPUUtilization").append('&')
.append("Namespace=AWS%2FEC2").append('&')
.append("Period=60").append('&')
.append("Signature=rmg8%2Ba7w4ycy%2FKfO8rnuj6rDL0jNE96m8GKfjh3SWcw%3D").append('&')
.append("SignatureMethod=HmacSHA256").append('&')
.append("SignatureVersion=2").append('&')
.append("StartTime=1970-01-01T02%3A46%3A40Z").append('&')
.append("Statistics.member.1=Maximum").append('&')
.append("Statistics.member.2=Minimum").append('&')
.append("Timestamp=2009-11-08T15%3A54%3A08.897Z").append('&')
.append("Unit=Percent").append('&').append("Version=2010-08-01").append('&')
.append("AWSAccessKeyId=identity").toString(), "application/x-www-form-urlencoded"))
"Action=GetMetricStatistics" +
"&EndTime=1970-01-01T02%3A46%3A40Z" +
"&MetricName=CPUUtilization" +
"&Namespace=AWS%2FEC2" +
"&Period=60" +
"&Signature=rmg8%2Ba7w4ycy%2FKfO8rnuj6rDL0jNE96m8GKfjh3SWcw%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&StartTime=1970-01-01T02%3A46%3A40Z" +
"&Statistics.member.1=Maximum" +
"&Statistics.member.2=Minimum" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Unit=Percent" +
"&Version=2010-08-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
public void testGetMetricStatisticsWhenResponseIs2xx() throws Exception {
@ -179,7 +182,11 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
assertEquals(
clientWhenMetricsExist.getMetricClientForRegion(null).getMetricStatistics(stats).toString(),
// TODO: make an object for this
"GetMetricStatisticsResponse{label=CPUUtilization, datapoints=[Datapoint{timestamp=Thu Jan 15 16:00:00 PST 2009, customUnit=null, maximum=null, minimum=null, average=0.17777777777777778, sum=null, samples=9.0, unit=Percent}, Datapoint{timestamp=Thu Jan 15 16:01:00 PST 2009, customUnit=null, maximum=null, minimum=null, average=0.1, sum=null, samples=8.0, unit=Percent}]}");
"GetMetricStatisticsResponse{label=CPUUtilization, " +
"datapoints=[Datapoint{timestamp=Thu Jan 15 16:00:00 PST 2009, customUnit=null, maximum=null, " +
"minimum=null, average=0.17777777777777778, sum=null, samples=9.0, unit=Percent}, " +
"Datapoint{timestamp=Thu Jan 15 16:01:00 PST 2009, customUnit=null, maximum=null, minimum=null, " +
"average=0.1, sum=null, samples=8.0, unit=Percent}]}");
}
// TODO: this should really be an empty set
@ -194,35 +201,35 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
}
public void testGetMetricStatisticsWithOptionsWhenResponseIs2xx() throws Exception {
HttpRequest getMetricStatistics = HttpRequest.builder()
.method("POST")
.endpoint(URI.create("https://monitoring.us-east-1.amazonaws.com/"))
.headers(ImmutableMultimap.<String, String> builder()
.put("Host", "monitoring.us-east-1.amazonaws.com")
.build())
.payload(
payloadFromStringWithContentType(
new StringBuilder()
.append("Action=GetMetricStatistics").append('&')
.append("Dimensions.member.1.Name=InstanceId").append('&')
.append("Dimensions.member.1.Value=SOMEINSTANCEID").append('&')
.append("Dimensions.member.2.Name=InstanceType").append('&')
.append("Dimensions.member.2.Value=t1.micro").append('&')
.append("EndTime=1970-01-01T02%3A46%3A40Z").append('&')
.append("MetricName=CPUUtilization").append('&')
.append("Namespace=AWS%2FEC2").append('&')
.append("Period=60").append('&')
.append("Signature=e0WyI%2FNm4hN2%2BMEm1mjRUzsvgvMCdFXbVJWi4ORpwic%3D").append('&')
.append("SignatureMethod=HmacSHA256").append('&')
.append("SignatureVersion=2").append('&')
.append("StartTime=1970-01-01T02%3A46%3A40Z").append('&')
.append("Statistics.member.1=Maximum").append('&')
.append("Statistics.member.2=Minimum").append('&')
.append("Timestamp=2009-11-08T15%3A54%3A08.897Z").append('&')
.append("Unit=Percent").append('&')
.append("Version=2010-08-01").append('&')
.append("AWSAccessKeyId=identity").toString(), "application/x-www-form-urlencoded"))
.build();
HttpRequest getMetricStatistics =
HttpRequest.builder()
.method("POST")
.endpoint(URI.create("https://monitoring.us-east-1.amazonaws.com/"))
.headers(ImmutableMultimap.<String, String> builder()
.put("Host", "monitoring.us-east-1.amazonaws.com")
.build())
.payload(payloadFromStringWithContentType(
"Action=GetMetricStatistics" +
"&Dimensions.member.1.Name=InstanceId" +
"&Dimensions.member.1.Value=SOMEINSTANCEID" +
"&Dimensions.member.2.Name=InstanceType" +
"&Dimensions.member.2.Value=t1.micro" +
"&EndTime=1970-01-01T02%3A46%3A40Z" +
"&MetricName=CPUUtilization" +
"&Namespace=AWS%2FEC2" +
"&Period=60" +
"&Signature=e0WyI%2FNm4hN2%2BMEm1mjRUzsvgvMCdFXbVJWi4ORpwic%3D" +
"&SignatureMethod=HmacSHA256" +
"&SignatureVersion=2" +
"&StartTime=1970-01-01T02%3A46%3A40Z" +
"&Statistics.member.1=Maximum" +
"&Statistics.member.2=Minimum" +
"&Timestamp=2009-11-08T15%3A54%3A08.897Z" +
"&Unit=Percent" +
"&Version=2010-08-01" +
"&AWSAccessKeyId=identity",
"application/x-www-form-urlencoded"))
.build();
HttpResponse getMetricStatisticsResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResourceWithContentType("/get_metric_statistics.xml", "text/xml")).build();
@ -236,7 +243,11 @@ public class MetricClientExpectTest extends BaseCloudWatchClientExpectTest {
clientWhenMetricsExist.getMetricClientForRegion(null).getMetricStatistics(stats,
GetMetricStatisticsOptions.Builder.dimension(dimension1).dimension(dimension2)).toString(),
// TODO: make an object for this
"GetMetricStatisticsResponse{label=CPUUtilization, datapoints=[Datapoint{timestamp=Thu Jan 15 16:00:00 PST 2009, customUnit=null, maximum=null, minimum=null, average=0.17777777777777778, sum=null, samples=9.0, unit=Percent}, Datapoint{timestamp=Thu Jan 15 16:01:00 PST 2009, customUnit=null, maximum=null, minimum=null, average=0.1, sum=null, samples=8.0, unit=Percent}]}");
"GetMetricStatisticsResponse{label=CPUUtilization, " +
"datapoints=[Datapoint{timestamp=Thu Jan 15 16:00:00 PST 2009, customUnit=null, maximum=null, " +
"minimum=null, average=0.17777777777777778, sum=null, samples=9.0, unit=Percent}, " +
"Datapoint{timestamp=Thu Jan 15 16:01:00 PST 2009, customUnit=null, maximum=null, minimum=null, " +
"average=0.1, sum=null, samples=8.0, unit=Percent}]}");
}
}

View File

@ -18,13 +18,10 @@
*/
package org.jclouds.cloudwatch.features;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import junit.framework.Assert;
import org.jclouds.cloudwatch.domain.Datapoint;
import org.jclouds.cloudwatch.domain.Dimension;
import org.jclouds.cloudwatch.domain.EC2Constants;
@ -32,14 +29,23 @@ import org.jclouds.cloudwatch.domain.GetMetricStatistics;
import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
import org.jclouds.cloudwatch.domain.ListMetricsResponse;
import org.jclouds.cloudwatch.domain.Metric;
import org.jclouds.cloudwatch.domain.MetricDatum;
import org.jclouds.cloudwatch.domain.Namespaces;
import org.jclouds.cloudwatch.domain.StatisticSet;
import org.jclouds.cloudwatch.domain.Statistics;
import org.jclouds.cloudwatch.domain.Unit;
import org.jclouds.cloudwatch.internal.BaseCloudWatchClientLiveTest;
import org.jclouds.cloudwatch.options.ListMetricsOptions;
import org.jclouds.predicates.RetryablePredicate;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @author Jeremy Whitlock, Adrian Cole
@ -47,6 +53,95 @@ import com.google.common.collect.ImmutableSet;
@Test(groups = "live", testName = "MetricClientLiveTest")
public class MetricClientLiveTest extends BaseCloudWatchClientLiveTest {
@Test
protected void testPutMetricData() throws Exception {
String metricName = "TestMetricName" + System.currentTimeMillis();
String namespace = "JCLOUDS/Test";
Date metricTimestamp = new Date();
// CloudWatch rounds metric timestamps down to the closest minute
Date metricTimestampInCloudWatch =
new Date(metricTimestamp.getTime() - (metricTimestamp.getTime() % (60 * 1000)));
StatisticSet ss = StatisticSet.builder()
.maximum(4.0)
.minimum(1.0)
.sampleCount(4.0)
.sum(10.0)
.build();
MetricDatum metricDatum = MetricDatum.builder()
.metricName(metricName + "_1")
.statisticSet(ss)
.dimension(new Dimension("BaseMetricName", metricName))
.dimension(new Dimension("TestDimension2", "TEST2"))
.unit(Unit.COUNT)
.timestamp(metricTimestamp)
.build();
MetricDatum metricDatum2 = MetricDatum.builder()
.metricName(metricName + "_2")
.dimension(new Dimension("BaseMetricName", metricName))
.unit(Unit.COUNT)
.timestamp(metricTimestamp)
.value(10.0)
.build();
client().putMetricData(ImmutableSet.of(metricDatum, metricDatum2), namespace);
ListMetricsOptions lmo = ListMetricsOptions.builder().namespace(namespace)
.dimension(new Dimension("BaseMetricName", metricName))
.build();
boolean success = new RetryablePredicate<ListMetricsOptions>(new Predicate<ListMetricsOptions>() {
@Override
public boolean apply(ListMetricsOptions options) {
return Iterables.size(client().listMetrics(options)) == 2;
}
}, 20, 1, TimeUnit.MINUTES).apply(lmo);
if (!success) {
Assert.fail("Unable to gather the created CloudWatch data within the time (20m) allotted.");
}
ListMetricsResponse lmr = client().listMetrics(lmo);
Date endTime = new Date(metricTimestampInCloudWatch.getTime() + (60 * 1000)); // Pad a minute just in case
Date startTime = new Date(metricTimestampInCloudWatch.getTime() - (60 * 1000)); // Pad a minute just in case
for (Metric m : lmr) {
GetMetricStatistics gms = GetMetricStatistics.builder()
.dimensions(m.getDimensions())
.namespace(namespace)
.metricName(m.getMetricName())
.endTime(endTime)
.statistic(Statistics.MAXIMUM)
.statistic(Statistics.MINIMUM)
.statistic(Statistics.SAMPLE_COUNT)
.statistic(Statistics.SUM)
.period(60)
.startTime(startTime)
.unit(Unit.COUNT)
.build();
GetMetricStatisticsResponse gmr = client().getMetricStatistics(gms);
Assert.assertEquals(1, Iterables.size(gmr));
Datapoint datapoint = gmr.iterator().next();
Assert.assertEquals(datapoint.getTimestamp(), metricTimestampInCloudWatch);
Assert.assertNull(datapoint.getCustomUnit());
Assert.assertEquals(Unit.COUNT, datapoint.getUnit());
Assert.assertNull(datapoint.getAverage());
if (m.getDimensions().size() == 1) {
Assert.assertEquals(10.0, datapoint.getMaximum());
Assert.assertEquals(10.0, datapoint.getMinimum());
Assert.assertEquals(10.0, datapoint.getSum());
Assert.assertEquals(1.0, datapoint.getSamples());
} else {
Assert.assertEquals(4.0, datapoint.getMaximum());
Assert.assertEquals(1.0, datapoint.getMinimum());
Assert.assertEquals(10.0, datapoint.getSum());
Assert.assertEquals(4.0, datapoint.getSamples());
}
}
}
// TODO: change this test to retrieve pre-seeded custom metrics
@Test
protected void testGetMetricStatistics() {

View File

@ -4,13 +4,13 @@
<member>
<Timestamp>2009-01-16T00:00:00Z</Timestamp>
<Unit>Percent</Unit>
<Samples>9.0</Samples>
<SampleCount>9.0</SampleCount>
<Average>0.17777777777777778</Average>
</member>
<member>
<Timestamp>2009-01-16T00:01:00Z</Timestamp>
<Unit>Percent</Unit>
<Samples>8.0</Samples>
<SampleCount>8.0</SampleCount>
<Average>0.1</Average>
</member>
</Datapoints>