mirror of https://github.com/apache/jclouds.git
JCLOUDS-480 support version 4 signatures for aws-ec2.
This commit is contained in:
parent
85eaea5758
commit
243b96798a
|
@ -21,21 +21,20 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.io.BaseEncoding.base64;
|
import static com.google.common.io.BaseEncoding.base64;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import org.jclouds.aws.filters.FormSigner;
|
import org.jclouds.aws.filters.FormSigner.FormSignerV2;
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.rest.Binder;
|
import org.jclouds.rest.Binder;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||||
|
|
||||||
@Singleton
|
// TODO: see if this still exists in V4
|
||||||
public class BindS3UploadPolicyAndSignature implements Binder {
|
public class BindS3UploadPolicyAndSignature implements Binder {
|
||||||
private final FormSigner signer;
|
private final FormSignerV2 signer;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
BindS3UploadPolicyAndSignature(FormSigner signer) {
|
BindS3UploadPolicyAndSignature(FormSignerV2 signer) {
|
||||||
this.signer = signer;
|
this.signer = signer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,5 +48,4 @@ public class BindS3UploadPolicyAndSignature implements Binder {
|
||||||
builder.put("Storage.S3.UploadPolicySignature", signature);
|
builder.put("Storage.S3.UploadPolicySignature", signature);
|
||||||
return (R) request.toBuilder().replaceFormParams(builder.build()).build();
|
return (R) request.toBuilder().replaceFormParams(builder.build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.apis.ApiMetadata;
|
import org.jclouds.apis.ApiMetadata;
|
||||||
import org.jclouds.aws.domain.Region;
|
import org.jclouds.aws.domain.Region;
|
||||||
import org.jclouds.aws.filters.FormSigner;
|
import org.jclouds.aws.filters.FormSigner.FormSignerV2;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
import org.jclouds.date.DateService;
|
import org.jclouds.date.DateService;
|
||||||
import org.jclouds.ec2.EC2ApiMetadata;
|
import org.jclouds.ec2.EC2ApiMetadata;
|
||||||
|
@ -115,19 +115,19 @@ public abstract class BaseEC2ApiTest<T> extends BaseRestAnnotationProcessingTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FormSigner filter;
|
protected FormSignerV2 filter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkFilters(HttpRequest request) {
|
protected void checkFilters(HttpRequest request) {
|
||||||
assertEquals(request.getFilters().size(), 1);
|
assertEquals(request.getFilters().size(), 1);
|
||||||
assertEquals(request.getFilters().get(0).getClass(), FormSigner.class);
|
assertEquals(request.getFilters().get(0).getClass(), FormSignerV2.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
protected void setupFactory() throws IOException {
|
protected void setupFactory() throws IOException {
|
||||||
super.setupFactory();
|
super.setupFactory();
|
||||||
this.filter = injector.getInstance(FormSigner.class);
|
this.filter = injector.getInstance(FormSignerV2.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,6 +23,7 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.aws.filters.FormSigner;
|
import org.jclouds.aws.filters.FormSigner;
|
||||||
import org.jclouds.date.DateService;
|
import org.jclouds.date.DateService;
|
||||||
import org.jclouds.date.TimeStamp;
|
import org.jclouds.date.TimeStamp;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.rest.ConfiguresHttpApi;
|
import org.jclouds.rest.ConfiguresHttpApi;
|
||||||
import org.jclouds.rest.RequestSigner;
|
import org.jclouds.rest.RequestSigner;
|
||||||
|
|
||||||
|
@ -51,7 +52,18 @@ public abstract class FormSigningHttpApiModule<A> extends AWSHttpApiModule<A> {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
RequestSigner provideRequestSigner(FormSigner in) {
|
RequestSigner provideRequestSigner(FormSigner in) {
|
||||||
return in;
|
if (in instanceof RequestSigner) {
|
||||||
|
return (RequestSigner) in;
|
||||||
|
}
|
||||||
|
return new RequestSigner() {
|
||||||
|
@Override public String createStringToSign(HttpRequest input) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String sign(String toSign) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@ import javax.annotation.Resource;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.aws.domain.SessionCredentials;
|
import org.jclouds.aws.domain.SessionCredentials;
|
||||||
|
@ -66,154 +65,145 @@ import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.TreeMultimap;
|
import com.google.common.collect.TreeMultimap;
|
||||||
import com.google.common.io.ByteProcessor;
|
import com.google.common.io.ByteProcessor;
|
||||||
import com.google.common.net.HttpHeaders;
|
import com.google.common.net.HttpHeaders;
|
||||||
|
import com.google.inject.ImplementedBy;
|
||||||
|
|
||||||
/**
|
@ImplementedBy(FormSigner.FormSignerV2.class)
|
||||||
*
|
public interface FormSigner extends HttpRequestFilter {
|
||||||
* @see <a href=
|
|
||||||
* "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/Query-Common-Parameters.html"
|
|
||||||
* />
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class FormSigner implements HttpRequestFilter, RequestSigner {
|
|
||||||
|
|
||||||
public static final Set<String> mandatoryParametersForSignature = ImmutableSet.of(ACTION, SIGNATURE_METHOD,
|
static final class FormSignerV2 implements FormSigner, RequestSigner {
|
||||||
SIGNATURE_VERSION, VERSION);
|
|
||||||
|
|
||||||
private final SignatureWire signatureWire;
|
public static final Set<String> mandatoryParametersForSignature = ImmutableSet
|
||||||
private final String apiVersion;
|
.of(ACTION, SIGNATURE_METHOD, SIGNATURE_VERSION, VERSION);
|
||||||
private final Supplier<Credentials> creds;
|
|
||||||
private final Provider<String> dateService;
|
|
||||||
private final Crypto crypto;
|
|
||||||
private final HttpUtils utils;
|
|
||||||
|
|
||||||
@Resource
|
private final SignatureWire signatureWire;
|
||||||
@Named(Constants.LOGGER_SIGNATURE)
|
private final String apiVersion;
|
||||||
private Logger signatureLog = Logger.NULL;
|
private final Supplier<Credentials> creds;
|
||||||
|
private final Provider<String> dateService;
|
||||||
|
private final Crypto crypto;
|
||||||
|
private final HttpUtils utils;
|
||||||
|
|
||||||
@Inject
|
@Resource @Named(Constants.LOGGER_SIGNATURE)
|
||||||
public FormSigner(SignatureWire signatureWire, @ApiVersion String apiVersion,
|
private Logger signatureLog = Logger.NULL;
|
||||||
@org.jclouds.location.Provider Supplier<Credentials> creds, @TimeStamp Provider<String> dateService,
|
|
||||||
Crypto crypto, HttpUtils utils) {
|
|
||||||
this.signatureWire = signatureWire;
|
|
||||||
this.apiVersion = apiVersion;
|
|
||||||
this.creds = creds;
|
|
||||||
this.dateService = dateService;
|
|
||||||
this.crypto = crypto;
|
|
||||||
this.utils = utils;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpRequest filter(HttpRequest request) throws HttpException {
|
@Inject FormSignerV2(SignatureWire signatureWire, @ApiVersion String apiVersion,
|
||||||
checkNotNull(request.getFirstHeaderOrNull(HttpHeaders.HOST), "request is not ready to sign; host not present");
|
@org.jclouds.location.Provider Supplier<Credentials> creds, @TimeStamp Provider<String> dateService,
|
||||||
Multimap<String, String> decodedParams = queryParser().apply(request.getPayload().getRawContent().toString());
|
Crypto crypto, HttpUtils utils) {
|
||||||
decodedParams.replaceValues(VERSION, ImmutableSet.of(apiVersion));
|
this.signatureWire = signatureWire;
|
||||||
addSigningParams(decodedParams);
|
this.apiVersion = apiVersion;
|
||||||
validateParams(decodedParams);
|
this.creds = creds;
|
||||||
String stringToSign = createStringToSign(request, decodedParams);
|
this.dateService = dateService;
|
||||||
String signature = sign(stringToSign);
|
this.crypto = crypto;
|
||||||
addSignature(decodedParams, signature);
|
this.utils = utils;
|
||||||
request = setPayload(request, decodedParams);
|
|
||||||
utils.logRequest(signatureLog, request, "<<");
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest setPayload(HttpRequest request, Multimap<String, String> decodedParams) {
|
|
||||||
String queryLine = buildQueryLine(decodedParams);
|
|
||||||
request.setPayload(queryLine);
|
|
||||||
request.getPayload().getContentMetadata().setContentType("application/x-www-form-urlencoded");
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Comparator<String> actionFirstAccessKeyLast = new Comparator<String>() {
|
|
||||||
static final int LEFT_IS_GREATER = 1;
|
|
||||||
static final int RIGHT_IS_GREATER = -1;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(String left, String right) {
|
|
||||||
if (left == right) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ("Action".equals(right) || "AWSAccessKeyId".equals(left)) {
|
|
||||||
return LEFT_IS_GREATER;
|
|
||||||
}
|
|
||||||
if ("Action".equals(left) || "AWSAccessKeyId".equals(right)) {
|
|
||||||
return RIGHT_IS_GREATER;
|
|
||||||
}
|
|
||||||
return natural().compare(left, right);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
private static String buildQueryLine(Multimap<String, String> decodedParams) {
|
public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||||
Multimap<String, String> sortedParams = TreeMultimap.create(actionFirstAccessKeyLast, natural());
|
checkNotNull(request.getFirstHeaderOrNull(HttpHeaders.HOST), "request is not ready to sign; host not present");
|
||||||
sortedParams.putAll(decodedParams);
|
Multimap<String, String> decodedParams = queryParser().apply(request.getPayload().getRawContent().toString());
|
||||||
return encodeQueryLine(sortedParams);
|
decodedParams.replaceValues(VERSION, ImmutableSet.of(apiVersion));
|
||||||
}
|
addSigningParams(decodedParams);
|
||||||
|
validateParams(decodedParams);
|
||||||
@VisibleForTesting
|
String stringToSign = createStringToSign(request, decodedParams);
|
||||||
void validateParams(Multimap<String, String> params) {
|
String signature = sign(stringToSign);
|
||||||
for (String parameter : mandatoryParametersForSignature) {
|
addSignature(decodedParams, signature);
|
||||||
checkState(params.containsKey(parameter), "parameter " + parameter + " is required for signature");
|
request = setPayload(request, decodedParams);
|
||||||
|
utils.logRequest(signatureLog, request, "<<");
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
HttpRequest setPayload(HttpRequest request, Multimap<String, String> decodedParams) {
|
||||||
void addSignature(Multimap<String, String> params, String signature) {
|
String queryLine = buildQueryLine(decodedParams);
|
||||||
params.replaceValues(SIGNATURE, ImmutableList.of(signature));
|
request.setPayload(queryLine);
|
||||||
}
|
request.getPayload().getContentMetadata().setContentType("application/x-www-form-urlencoded");
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
private static final Comparator<String> actionFirstAccessKeyLast = new Comparator<String>() {
|
||||||
public String sign(String toSign) {
|
static final int LEFT_IS_GREATER = 1;
|
||||||
String signature;
|
static final int RIGHT_IS_GREATER = -1;
|
||||||
try {
|
|
||||||
ByteProcessor<byte[]> hmacSHA256 = asByteProcessor(crypto.hmacSHA256(creds.get().credential.getBytes(UTF_8)));
|
@Override
|
||||||
signature = base64().encode(readBytes(toInputStream(toSign), hmacSHA256));
|
public int compare(String left, String right) {
|
||||||
|
if (left == right) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ("Action".equals(right) || "AWSAccessKeyId".equals(left)) {
|
||||||
|
return LEFT_IS_GREATER;
|
||||||
|
}
|
||||||
|
if ("Action".equals(left) || "AWSAccessKeyId".equals(right)) {
|
||||||
|
return RIGHT_IS_GREATER;
|
||||||
|
}
|
||||||
|
return natural().compare(left, right);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static String buildQueryLine(Multimap<String, String> decodedParams) {
|
||||||
|
Multimap<String, String> sortedParams = TreeMultimap.create(actionFirstAccessKeyLast, natural());
|
||||||
|
sortedParams.putAll(decodedParams);
|
||||||
|
return encodeQueryLine(sortedParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting void validateParams(Multimap<String, String> params) {
|
||||||
|
for (String parameter : mandatoryParametersForSignature) {
|
||||||
|
checkState(params.containsKey(parameter), "parameter " + parameter + " is required for signature");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting void addSignature(Multimap<String, String> params, String signature) {
|
||||||
|
params.replaceValues(SIGNATURE, ImmutableList.of(signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public String sign(String toSign) {
|
||||||
|
String signature;
|
||||||
|
try {
|
||||||
|
ByteProcessor<byte[]> hmacSHA256 = asByteProcessor(
|
||||||
|
crypto.hmacSHA256(creds.get().credential.getBytes(UTF_8)));
|
||||||
|
signature = base64().encode(readBytes(toInputStream(toSign), hmacSHA256));
|
||||||
|
if (signatureWire.enabled())
|
||||||
|
signatureWire.input(toInputStream(signature));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new HttpException("error signing request", e);
|
||||||
|
}
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public String createStringToSign(HttpRequest request, Multimap<String, String> decodedParams) {
|
||||||
|
utils.logRequest(signatureLog, request, ">>");
|
||||||
|
StringBuilder stringToSign = new StringBuilder();
|
||||||
|
// StringToSign = HTTPVerb + "\n" +
|
||||||
|
stringToSign.append(request.getMethod()).append("\n");
|
||||||
|
// ValueOfHostHeaderInLowercase + "\n" +
|
||||||
|
stringToSign.append(request.getFirstHeaderOrNull(HttpHeaders.HOST).toLowerCase()).append("\n");
|
||||||
|
// HTTPRequestURI + "\n" +
|
||||||
|
stringToSign.append(request.getEndpoint().getPath()).append("\n");
|
||||||
|
// CanonicalizedFormString <from the preceding step>
|
||||||
|
stringToSign.append(buildCanonicalizedString(decodedParams));
|
||||||
if (signatureWire.enabled())
|
if (signatureWire.enabled())
|
||||||
signatureWire.input(toInputStream(signature));
|
signatureWire.output(stringToSign.toString());
|
||||||
} catch (Exception e) {
|
return stringToSign.toString();
|
||||||
throw new HttpException("error signing request", e);
|
|
||||||
}
|
}
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting String buildCanonicalizedString(Multimap<String, String> decodedParams) {
|
||||||
public String createStringToSign(HttpRequest request, Multimap<String, String> decodedParams) {
|
// note that aws wants to percent encode the canonicalized string without skipping '/' and '?'
|
||||||
utils.logRequest(signatureLog, request, ">>");
|
return encodeQueryLine(TreeMultimap.create(decodedParams), ImmutableList.<Character>of());
|
||||||
StringBuilder stringToSign = new StringBuilder();
|
|
||||||
// StringToSign = HTTPVerb + "\n" +
|
|
||||||
stringToSign.append(request.getMethod()).append("\n");
|
|
||||||
// ValueOfHostHeaderInLowercase + "\n" +
|
|
||||||
stringToSign.append(request.getFirstHeaderOrNull(HttpHeaders.HOST).toLowerCase()).append("\n");
|
|
||||||
// HTTPRequestURI + "\n" +
|
|
||||||
stringToSign.append(request.getEndpoint().getPath()).append("\n");
|
|
||||||
// CanonicalizedFormString <from the preceding step>
|
|
||||||
stringToSign.append(buildCanonicalizedString(decodedParams));
|
|
||||||
if (signatureWire.enabled())
|
|
||||||
signatureWire.output(stringToSign.toString());
|
|
||||||
return stringToSign.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
String buildCanonicalizedString(Multimap<String, String> decodedParams) {
|
|
||||||
// note that aws wants to percent encode the canonicalized string without skipping '/' and '?'
|
|
||||||
return encodeQueryLine(TreeMultimap.create(decodedParams), ImmutableList.<Character> of());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void addSigningParams(Multimap<String, String> params) {
|
|
||||||
params.removeAll(SIGNATURE);
|
|
||||||
params.removeAll(SECURITY_TOKEN);
|
|
||||||
Credentials current = creds.get();
|
|
||||||
if (current instanceof SessionCredentials) {
|
|
||||||
params.put(SECURITY_TOKEN, SessionCredentials.class.cast(current).getSessionToken());
|
|
||||||
}
|
}
|
||||||
params.replaceValues(SIGNATURE_METHOD, ImmutableList.of("HmacSHA256"));
|
|
||||||
params.replaceValues(SIGNATURE_VERSION, ImmutableList.of("2"));
|
|
||||||
params.replaceValues(TIMESTAMP, ImmutableList.of(dateService.get()));
|
|
||||||
params.replaceValues(AWS_ACCESS_KEY_ID, ImmutableList.of(creds.get().identity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String createStringToSign(HttpRequest input) {
|
@VisibleForTesting void addSigningParams(Multimap<String, String> params) {
|
||||||
return createStringToSign(input, queryParser().apply(input.getPayload().getRawContent().toString()));
|
params.removeAll(SIGNATURE);
|
||||||
}
|
params.removeAll(SECURITY_TOKEN);
|
||||||
|
Credentials current = creds.get();
|
||||||
|
if (current instanceof SessionCredentials) {
|
||||||
|
params.put(SECURITY_TOKEN, SessionCredentials.class.cast(current).getSessionToken());
|
||||||
|
}
|
||||||
|
params.replaceValues(SIGNATURE_METHOD, ImmutableList.of("HmacSHA256"));
|
||||||
|
params.replaceValues(SIGNATURE_VERSION, ImmutableList.of("2"));
|
||||||
|
params.replaceValues(TIMESTAMP, ImmutableList.of(dateService.get()));
|
||||||
|
params.replaceValues(AWS_ACCESS_KEY_ID, ImmutableList.of(creds.get().identity));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createStringToSign(HttpRequest input) {
|
||||||
|
return createStringToSign(input, queryParser().apply(input.getPayload().getRawContent().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.filters;
|
||||||
|
|
||||||
|
import static com.google.common.base.Charsets.UTF_8;
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.hash.Hashing.sha256;
|
||||||
|
import static com.google.common.io.BaseEncoding.base16;
|
||||||
|
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
|
import static com.google.common.net.HttpHeaders.HOST;
|
||||||
|
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
|
||||||
|
import static org.jclouds.aws.reference.FormParameters.ACTION;
|
||||||
|
import static org.jclouds.aws.reference.FormParameters.VERSION;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.jclouds.aws.domain.SessionCredentials;
|
||||||
|
import org.jclouds.date.TimeStamp;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpException;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.io.Payload;
|
||||||
|
import org.jclouds.io.Payloads;
|
||||||
|
import org.jclouds.location.Provider;
|
||||||
|
import org.jclouds.providers.ProviderMetadata;
|
||||||
|
import org.jclouds.rest.annotations.ApiVersion;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.inject.ImplementedBy;
|
||||||
|
|
||||||
|
public final class FormSignerV4 implements FormSigner {
|
||||||
|
|
||||||
|
// Specifying a default for how to parse the service and region in this way allows
|
||||||
|
// tests or other downstream services to not have to use guice overrides.
|
||||||
|
@ImplementedBy(ServiceAndRegion.AWSServiceAndRegion.class)
|
||||||
|
public interface ServiceAndRegion {
|
||||||
|
String service();
|
||||||
|
String region(String host);
|
||||||
|
|
||||||
|
static final class AWSServiceAndRegion implements ServiceAndRegion {
|
||||||
|
private final String service;
|
||||||
|
|
||||||
|
@Inject AWSServiceAndRegion(ProviderMetadata provider) {
|
||||||
|
this(provider.getEndpoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
AWSServiceAndRegion(String endpoint) {
|
||||||
|
this.service = parseServiceAndRegion(URI.create(checkNotNull(endpoint, "endpoint")).getHost()).get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String service() {
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String region(String host) {
|
||||||
|
return parseServiceAndRegion(host).get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This will only work for amazon deployments, and perhaps not all of them. */
|
||||||
|
private static List<String> parseServiceAndRegion(String host) {
|
||||||
|
checkArgument(host.endsWith(".amazonaws.com"), "Only AWS endpoints currently supported %s", host);
|
||||||
|
return Splitter.on('.').splitToList(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String apiVersion;
|
||||||
|
private final Supplier<Credentials> creds;
|
||||||
|
private final javax.inject.Provider<String> iso8601Timestamp;
|
||||||
|
private final ServiceAndRegion serviceAndRegion;
|
||||||
|
|
||||||
|
@Inject FormSignerV4(@ApiVersion String apiVersion, @Provider Supplier<Credentials> creds,
|
||||||
|
@TimeStamp javax.inject.Provider<String> iso8601Timestamp, ServiceAndRegion serviceAndRegion) {
|
||||||
|
this.apiVersion = apiVersion;
|
||||||
|
this.creds = creds;
|
||||||
|
this.iso8601Timestamp = iso8601Timestamp;
|
||||||
|
this.serviceAndRegion = serviceAndRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||||
|
checkArgument(request.getHeaders().containsKey(HOST), "request is not ready to sign; host not present");
|
||||||
|
String host = request.getFirstHeaderOrNull(HOST);
|
||||||
|
String form = request.getPayload().getRawContent().toString();
|
||||||
|
checkArgument(form.indexOf(ACTION) != -1, "request is not ready to sign; Action not present %s", form);
|
||||||
|
|
||||||
|
String timestamp = iso8601Timestamp.get();
|
||||||
|
String datestamp = timestamp.substring(0, 8);
|
||||||
|
|
||||||
|
String service = serviceAndRegion.service();
|
||||||
|
String region = serviceAndRegion.region(host);
|
||||||
|
String credentialScope = Joiner.on('/').join(datestamp, region, service, "aws4_request");
|
||||||
|
|
||||||
|
// content-type is not a required signing param. However, examples use this, so we include it to ease testing.
|
||||||
|
ImmutableMap.Builder<String, String> signedHeadersBuilder = ImmutableMap.<String, String> builder() //
|
||||||
|
.put("content-type", request.getPayload().getContentMetadata().getContentType()) //
|
||||||
|
.put("host", host) //
|
||||||
|
.put("x-amz-date", timestamp);
|
||||||
|
|
||||||
|
HttpRequest.Builder<?> requestBuilder = request.toBuilder() //
|
||||||
|
.removeHeader(AUTHORIZATION) //
|
||||||
|
.replaceHeader("X-Amz-Date", timestamp);
|
||||||
|
|
||||||
|
if (form.indexOf(VERSION) == -1) {
|
||||||
|
requestBuilder.addFormParam("Version", apiVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
Credentials credentials = creds.get();
|
||||||
|
|
||||||
|
if (credentials instanceof SessionCredentials) {
|
||||||
|
String token = SessionCredentials.class.cast(credentials).getSessionToken();
|
||||||
|
requestBuilder.replaceHeader("X-Amz-Security-Token", token);
|
||||||
|
signedHeadersBuilder.put("x-amz-security-token", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmutableMap<String, String> signedHeaders = signedHeadersBuilder.build();
|
||||||
|
|
||||||
|
String stringToSign = createStringToSign(requestBuilder.build(), signedHeaders, credentialScope);
|
||||||
|
byte[] signatureKey = signatureKey(credentials.credential, datestamp, region, service);
|
||||||
|
String signature = base16().lowerCase().encode(hmacSHA256(stringToSign, signatureKey));
|
||||||
|
|
||||||
|
StringBuilder authorization = new StringBuilder("AWS4-HMAC-SHA256 ");
|
||||||
|
authorization.append("Credential=").append(credentials.identity).append('/').append(credentialScope).append(", ");
|
||||||
|
authorization.append("SignedHeaders=").append(Joiner.on(';').join(signedHeaders.keySet())).append(", ");
|
||||||
|
authorization.append("Signature=").append(signature);
|
||||||
|
|
||||||
|
return requestBuilder.addHeader(AUTHORIZATION, authorization.toString()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: change EC2 apis to add this themselves with @FormParams
|
||||||
|
private Payload addVersionIfNecessary(Payload payload, String form) {
|
||||||
|
if (form.indexOf(VERSION) == -1) {
|
||||||
|
form += "&Version=" + apiVersion;
|
||||||
|
payload = Payloads.newStringPayload(form);
|
||||||
|
payload.getContentMetadata().setContentType(APPLICATION_FORM_URLENCODED);
|
||||||
|
payload.getContentMetadata().setContentLength((long) form.length());
|
||||||
|
}
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] signatureKey(String secretKey, String datestamp, String region, String service) {
|
||||||
|
byte[] kSecret = ("AWS4" + secretKey).getBytes(UTF_8);
|
||||||
|
byte[] kDate = hmacSHA256(datestamp, kSecret);
|
||||||
|
byte[] kRegion = hmacSHA256(region, kDate);
|
||||||
|
byte[] kService = hmacSHA256(service, kRegion);
|
||||||
|
byte[] kSigning = hmacSHA256("aws4_request", kService);
|
||||||
|
return kSigning;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] hmacSHA256(String data, byte[] key) {
|
||||||
|
try {
|
||||||
|
String algorithm = "HmacSHA256";
|
||||||
|
Mac mac = Mac.getInstance(algorithm);
|
||||||
|
mac.init(new SecretKeySpec(key, algorithm));
|
||||||
|
return mac.doFinal(data.getBytes(UTF_8));
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new HttpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String createStringToSign(HttpRequest request, Map<String, String> signedHeaders, String credentialScope) {
|
||||||
|
StringBuilder canonicalRequest = new StringBuilder();
|
||||||
|
// HTTPRequestMethod + '\n' +
|
||||||
|
canonicalRequest.append(request.getMethod()).append("\n");
|
||||||
|
// CanonicalURI + '\n' +
|
||||||
|
canonicalRequest.append(request.getEndpoint().getPath()).append("\n");
|
||||||
|
// CanonicalQueryString + '\n' +
|
||||||
|
checkArgument(request.getEndpoint().getQuery() == null, "Query parameters not yet supported %s", request);
|
||||||
|
canonicalRequest.append("\n");
|
||||||
|
// CanonicalHeaders + '\n' +
|
||||||
|
for (Map.Entry<String, String> entry : signedHeaders.entrySet()) {
|
||||||
|
canonicalRequest.append(entry.getKey()).append(':').append(entry.getValue()).append('\n');
|
||||||
|
}
|
||||||
|
canonicalRequest.append("\n");
|
||||||
|
|
||||||
|
// SignedHeaders + '\n' +
|
||||||
|
canonicalRequest.append(Joiner.on(';').join(signedHeaders.keySet())).append('\n');
|
||||||
|
|
||||||
|
// HexEncode(Hash(Payload))
|
||||||
|
String payload = request.getPayload().getRawContent().toString();
|
||||||
|
canonicalRequest.append(base16().lowerCase().encode(sha256().hashString(payload, UTF_8).asBytes()));
|
||||||
|
|
||||||
|
StringBuilder toSign = new StringBuilder();
|
||||||
|
// Algorithm + '\n' +
|
||||||
|
toSign.append("AWS4-HMAC-SHA256").append('\n');
|
||||||
|
// RequestDate + '\n' +
|
||||||
|
toSign.append(signedHeaders.get("x-amz-date")).append('\n');
|
||||||
|
// CredentialScope + '\n' +
|
||||||
|
toSign.append(credentialScope).append('\n');
|
||||||
|
// HexEncode(Hash(CanonicalRequest))
|
||||||
|
toSign.append(base16().lowerCase().encode(sha256().hashString(canonicalRequest.toString(), UTF_8).asBytes()));
|
||||||
|
|
||||||
|
return toSign.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import static org.jclouds.providers.AnonymousProviderMetadata.forApiOnEndpoint;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
import org.jclouds.ContextBuilder;
|
import org.jclouds.ContextBuilder;
|
||||||
|
import org.jclouds.aws.filters.FormSigner.FormSignerV2;
|
||||||
import org.jclouds.aws.xml.SessionCredentialsHandlerTest;
|
import org.jclouds.aws.xml.SessionCredentialsHandlerTest;
|
||||||
import org.jclouds.date.TimeStamp;
|
import org.jclouds.date.TimeStamp;
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
|
@ -40,13 +41,9 @@ import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
import com.google.inject.name.Names;
|
import com.google.inject.name.Names;
|
||||||
/**
|
|
||||||
* Tests behavior of {@code FormSigner}
|
@Test(groups = "unit", singleThreaded = true, testName = "FormSignerV2Test")
|
||||||
*/
|
public class FormSignerV2Test {
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during
|
|
||||||
// surefire
|
|
||||||
@Test(groups = "unit", singleThreaded = true, testName = "FormSignerTest")
|
|
||||||
public class FormSignerTest {
|
|
||||||
public static Injector injector(Credentials creds) {
|
public static Injector injector(Credentials creds) {
|
||||||
return ContextBuilder
|
return ContextBuilder
|
||||||
.newBuilder(forApiOnEndpoint(IntegrationTestClient.class, "http://localhost"))
|
.newBuilder(forApiOnEndpoint(IntegrationTestClient.class, "http://localhost"))
|
||||||
|
@ -54,7 +51,7 @@ public class FormSignerTest {
|
||||||
.modules(ImmutableList.<Module> of(new MockModule(), new NullLoggingModule(), new AbstractModule() {
|
.modules(ImmutableList.<Module> of(new MockModule(), new NullLoggingModule(), new AbstractModule() {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(RequestSigner.class).to(FormSigner.class);
|
bind(RequestSigner.class).to(FormSignerV2.class);
|
||||||
bind(String.class).annotatedWith(Names.named(PROPERTY_HEADER_TAG)).toInstance("amz");
|
bind(String.class).annotatedWith(Names.named(PROPERTY_HEADER_TAG)).toInstance("amz");
|
||||||
bind(String.class).annotatedWith(TimeStamp.class).toInstance("2009-11-08T15:54:08.897Z");
|
bind(String.class).annotatedWith(TimeStamp.class).toInstance("2009-11-08T15:54:08.897Z");
|
||||||
}
|
}
|
||||||
|
@ -62,11 +59,11 @@ public class FormSignerTest {
|
||||||
})).buildInjector();
|
})).buildInjector();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FormSigner filter(Credentials creds) {
|
public static FormSignerV2 filter(Credentials creds) {
|
||||||
return injector(creds).getInstance(FormSigner.class);
|
return injector(creds).getInstance(FormSignerV2.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FormSigner staticCredentialsFilter = filter(new Credentials("identity", "credential"));
|
public static FormSignerV2 staticCredentialsFilter = filter(new Credentials("identity", "credential"));
|
||||||
|
|
||||||
HttpRequest request = HttpRequest.builder().method(GET)
|
HttpRequest request = HttpRequest.builder().method(GET)
|
||||||
.endpoint("http://localhost")
|
.endpoint("http://localhost")
|
||||||
|
@ -98,5 +95,4 @@ public class FormSignerTest {
|
||||||
.put("Version", "2010-06-15").build()),
|
.put("Version", "2010-06-15").build()),
|
||||||
"AWSAccessKeyId=foo&Action=DescribeImages&Expires=2008-02-10T12%3A00%3A00Z&ImageId.1=ami-2bb65342&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2010-06-15");
|
"AWSAccessKeyId=foo&Action=DescribeImages&Expires=2008-02-10T12%3A00%3A00Z&ImageId.1=ami-2bb65342&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2010-06-15");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.filters;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
|
import static org.jclouds.aws.filters.FormSignerV4.ServiceAndRegion;
|
||||||
|
import static org.jclouds.aws.filters.FormSignerV4.ServiceAndRegion.AWSServiceAndRegion;
|
||||||
|
import static org.jclouds.sts.options.SessionCredentialsOptions.Builder.durationSeconds;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import javax.inject.Provider;
|
||||||
|
|
||||||
|
import org.jclouds.apis.BaseApiLiveTest;
|
||||||
|
import org.jclouds.aws.domain.SessionCredentials;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.jclouds.rest.ApiContext;
|
||||||
|
import org.jclouds.sts.STSApi;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
|
||||||
|
@Test(groups = "live", singleThreaded = true, testName = "FormSignerV4LiveTest")
|
||||||
|
public class FormSignerV4LiveTest extends BaseApiLiveTest<ApiContext<STSApi>> {
|
||||||
|
|
||||||
|
/** Example request, which hopefully the test user's account has access to! */
|
||||||
|
private final HttpRequest sampleRequest = HttpRequest.builder() //
|
||||||
|
.method("POST") //
|
||||||
|
.endpoint("https://ec2.us-east-1.amazonaws.com/") //
|
||||||
|
.addHeader("Host", "ec2.us-east-1.amazonaws.com") //
|
||||||
|
.addFormParam("Action", "DescribeRegions") //
|
||||||
|
.addFormParam("Version", "2010-08-31") //
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/** Provides the expected iso8601 timestamp format for signature v4. */
|
||||||
|
private final Provider<String> timestamp = new Provider<String>() {
|
||||||
|
SimpleDateFormat iso8601 = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
||||||
|
|
||||||
|
@Override public String get() {
|
||||||
|
iso8601.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
return iso8601.format(new Date());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Test how we parse the AWS service and region based on an endpoint. */
|
||||||
|
private final ServiceAndRegion serviceAndRegion = new AWSServiceAndRegion(sampleRequest.getEndpoint().toString());
|
||||||
|
|
||||||
|
public FormSignerV4LiveTest() {
|
||||||
|
provider = "sts";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void signatureV4() {
|
||||||
|
Supplier<Credentials> accessAndSecretKey = Suppliers.ofInstance(new Credentials(identity, credential));
|
||||||
|
|
||||||
|
FormSignerV4 filter = new FormSignerV4(apiVersion, accessAndSecretKey, timestamp, serviceAndRegion);
|
||||||
|
|
||||||
|
HttpRequest request = filter.filter(sampleRequest);
|
||||||
|
|
||||||
|
assertEquals(api.utils().http().invoke(request).getStatusCode(), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void signatureV4_session() {
|
||||||
|
SessionCredentials creds = api.getApi().createTemporaryCredentials(durationSeconds(MINUTES.toSeconds(15)));
|
||||||
|
Supplier<Credentials> sessionToken = Suppliers.<Credentials>ofInstance(creds);
|
||||||
|
|
||||||
|
FormSignerV4 filter = new FormSignerV4(apiVersion, sessionToken, timestamp, serviceAndRegion);
|
||||||
|
|
||||||
|
HttpRequest request = filter.filter(sampleRequest);
|
||||||
|
|
||||||
|
assertEquals(api.utils().http().invoke(request).getStatusCode(), 200);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.filters;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import javax.inject.Provider;
|
||||||
|
|
||||||
|
import org.jclouds.aws.domain.SessionCredentials;
|
||||||
|
import org.jclouds.aws.filters.FormSignerV4.ServiceAndRegion;
|
||||||
|
import org.jclouds.aws.xml.SessionCredentialsHandlerTest;
|
||||||
|
import org.jclouds.domain.Credentials;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using samples from <a href="http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html">Amazon
|
||||||
|
* docs</a>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public class FormSignerV4Test {
|
||||||
|
|
||||||
|
String apiVersion = "2010-05-08";
|
||||||
|
|
||||||
|
Supplier<Credentials> accessAndSecretKey = Suppliers
|
||||||
|
.ofInstance(new Credentials("AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"));
|
||||||
|
|
||||||
|
Provider<String> timestamp = new Provider<String>() {
|
||||||
|
@Override public String get() {
|
||||||
|
return "20110909T233600Z";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ServiceAndRegion serviceAndRegion = new ServiceAndRegion() {
|
||||||
|
@Override public String service() {
|
||||||
|
return "iam";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String region(String host) {
|
||||||
|
return "us-east-1";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void signSampleRequest() {
|
||||||
|
HttpRequest request = HttpRequest.builder() //
|
||||||
|
.method("POST") //
|
||||||
|
.endpoint("https://iam.amazonaws.com/") //
|
||||||
|
.addHeader("Host", "iam.amazonaws.com") //
|
||||||
|
.payload("Action=ListUsers&Version=2010-05-08")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
request.getPayload().getContentMetadata().setContentType("application/x-www-form-urlencoded; charset=utf-8");
|
||||||
|
|
||||||
|
FormSignerV4 filter = new FormSignerV4(apiVersion, accessAndSecretKey, timestamp, serviceAndRegion);
|
||||||
|
|
||||||
|
HttpRequest filtered = filter.filter(request);
|
||||||
|
|
||||||
|
assertEquals(filtered.getFirstHeaderOrNull("X-Amz-Date"), timestamp.get());
|
||||||
|
|
||||||
|
String sampleSignature = "ced6826de92d2bdeed8f846f0bf508e8559e98e4b0199114b84c54174deb456c";
|
||||||
|
|
||||||
|
assertThat(filtered.getFirstHeaderOrNull("Authorization")).endsWith("Signature=" + sampleSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sessionTokenRequest() {
|
||||||
|
HttpRequest request = HttpRequest.builder() //
|
||||||
|
.method("POST") //
|
||||||
|
.endpoint("https://iam.amazonaws.com/") //
|
||||||
|
.addHeader("Host", "iam.amazonaws.com") //
|
||||||
|
.payload("Action=ListUsers&Version=2010-05-08").build();
|
||||||
|
|
||||||
|
request.getPayload().getContentMetadata().setContentType("application/x-www-form-urlencoded; charset=utf-8");
|
||||||
|
|
||||||
|
SessionCredentials sessionCredentials = new SessionCredentialsHandlerTest().expected();
|
||||||
|
|
||||||
|
FormSignerV4 filter = new FormSignerV4(apiVersion, Suppliers.<Credentials>ofInstance(sessionCredentials),
|
||||||
|
timestamp, serviceAndRegion);
|
||||||
|
|
||||||
|
HttpRequest filtered = filter.filter(request);
|
||||||
|
|
||||||
|
assertEquals(filtered.getFirstHeaderOrNull("X-Amz-Date"), timestamp.get());
|
||||||
|
assertEquals(filtered.getFirstHeaderOrNull("X-Amz-Security-Token"), sessionCredentials.getSessionToken());
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.jclouds.aws.domain.AWSError;
|
import org.jclouds.aws.domain.AWSError;
|
||||||
import org.jclouds.aws.filters.FormSignerTest;
|
import org.jclouds.aws.filters.FormSignerV2Test;
|
||||||
import org.jclouds.domain.Credentials;
|
import org.jclouds.domain.Credentials;
|
||||||
import org.jclouds.http.HttpCommand;
|
import org.jclouds.http.HttpCommand;
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
|
@ -47,7 +47,7 @@ public class AWSUtilsTest {
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
protected void setUpInjector() throws IOException {
|
protected void setUpInjector() throws IOException {
|
||||||
|
|
||||||
utils = FormSignerTest.injector(new Credentials("identity", "credential")).getInstance(AWSUtils.class);
|
utils = FormSignerV2Test.injector(new Credentials("identity", "credential")).getInstance(AWSUtils.class);
|
||||||
|
|
||||||
command = createMock(HttpCommand.class);
|
command = createMock(HttpCommand.class);
|
||||||
expect(command.getCurrentRequest()).andReturn(createMock(HttpRequest.class)).atLeastOnce();
|
expect(command.getCurrentRequest()).andReturn(createMock(HttpRequest.class)).atLeastOnce();
|
||||||
|
|
|
@ -51,5 +51,4 @@ public class SessionCredentialsHandlerTest extends BaseHandlerTest {
|
||||||
.sessionToken("AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT")
|
.sessionToken("AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT")
|
||||||
.expiration(new SimpleDateFormatDateService().iso8601DateParse("2011-07-11T19:55:29.611Z")).build();
|
.expiration(new SimpleDateFormatDateService().iso8601DateParse("2011-07-11T19:55:29.611Z")).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@ package org.jclouds.rest;
|
||||||
|
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated This is an internal interface historically used to debug signature logic. It currently is a broken
|
||||||
|
* abstraction as AWS Signature v4 requires multiple parameters to sign a request.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface RequestSigner {
|
public interface RequestSigner {
|
||||||
|
|
||||||
String createStringToSign(HttpRequest input);
|
String createStringToSign(HttpRequest input);
|
||||||
|
|
|
@ -40,16 +40,11 @@ import org.jclouds.rest.internal.TransformerForRequest;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||||
|
|
||||||
public class RestModule extends AbstractModule {
|
public class RestModule extends AbstractModule {
|
||||||
|
|
||||||
public static final TypeLiteral<Supplier<URI>> URI_SUPPLIER_TYPE = new TypeLiteral<Supplier<URI>>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
protected final AtomicReference<AuthorizationException> authException = newReference();
|
protected final AtomicReference<AuthorizationException> authException = newReference();
|
||||||
|
|
||||||
protected void installLocations() {
|
protected void installLocations() {
|
||||||
|
|
|
@ -101,6 +101,18 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp</groupId>
|
||||||
|
<artifactId>mockwebserver</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<!-- Already provided by jclouds-sshj -->
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.ec2.config;
|
package org.jclouds.aws.ec2.config;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
@ -24,12 +27,15 @@ import org.jclouds.aws.ec2.domain.AWSRunningInstance;
|
||||||
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
||||||
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
|
import org.jclouds.aws.ec2.functions.SpotInstanceRequestToAWSRunningInstance;
|
||||||
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
|
import org.jclouds.aws.ec2.options.AWSRunInstancesOptions;
|
||||||
|
import org.jclouds.aws.filters.FormSigner;
|
||||||
|
import org.jclouds.aws.filters.FormSignerV4;
|
||||||
|
import org.jclouds.date.DateService;
|
||||||
import org.jclouds.ec2.EC2Api;
|
import org.jclouds.ec2.EC2Api;
|
||||||
import org.jclouds.ec2.config.BaseEC2HttpApiModule;
|
import org.jclouds.ec2.config.BaseEC2HttpApiModule;
|
||||||
import org.jclouds.ec2.options.RunInstancesOptions;
|
|
||||||
import org.jclouds.ec2.features.AMIApi;
|
import org.jclouds.ec2.features.AMIApi;
|
||||||
import org.jclouds.ec2.features.InstanceApi;
|
import org.jclouds.ec2.features.InstanceApi;
|
||||||
import org.jclouds.ec2.features.SecurityGroupApi;
|
import org.jclouds.ec2.features.SecurityGroupApi;
|
||||||
|
import org.jclouds.ec2.options.RunInstancesOptions;
|
||||||
import org.jclouds.rest.ConfiguresHttpApi;
|
import org.jclouds.rest.ConfiguresHttpApi;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
@ -42,8 +48,11 @@ import com.google.inject.TypeLiteral;
|
||||||
@ConfiguresHttpApi
|
@ConfiguresHttpApi
|
||||||
public class AWSEC2HttpApiModule extends BaseEC2HttpApiModule<AWSEC2Api> {
|
public class AWSEC2HttpApiModule extends BaseEC2HttpApiModule<AWSEC2Api> {
|
||||||
|
|
||||||
|
private final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
||||||
|
|
||||||
public AWSEC2HttpApiModule() {
|
public AWSEC2HttpApiModule() {
|
||||||
super(AWSEC2Api.class);
|
super(AWSEC2Api.class);
|
||||||
|
iso8601.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@ -72,9 +81,15 @@ public class AWSEC2HttpApiModule extends BaseEC2HttpApiModule<AWSEC2Api> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
bind(FormSigner.class).to(FormSignerV4.class);
|
||||||
bind(RunInstancesOptions.class).to(AWSRunInstancesOptions.class);
|
bind(RunInstancesOptions.class).to(AWSRunInstancesOptions.class);
|
||||||
bind(new TypeLiteral<Function<SpotInstanceRequest, AWSRunningInstance>>() {
|
bind(new TypeLiteral<Function<SpotInstanceRequest, AWSRunningInstance>>() {
|
||||||
}).to(SpotInstanceRequestToAWSRunningInstance.class);
|
}).to(SpotInstanceRequestToAWSRunningInstance.class);
|
||||||
super.configure();
|
super.configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override protected String provideTimeStamp(DateService dateService) {
|
||||||
|
// 20120416T155408Z not 2012-04-16T15:54:08Z
|
||||||
|
return iso8601.format(new Date());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.compute;
|
||||||
|
|
||||||
|
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.blockUntilRunning;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
|
||||||
|
import org.jclouds.compute.ComputeService;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.domain.Template;
|
||||||
|
import org.jclouds.compute.predicates.NodePredicates;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockResponse;
|
||||||
|
|
||||||
|
@Test(groups = "unit", testName = "AWSEC2ComputeServiceMockTest", singleThreaded = true)
|
||||||
|
public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||||
|
|
||||||
|
public void launchVPCSpotInstanceSubnetId() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_cc.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/request_spot_instances-ebs.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/request_spot_instances-ebs.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_ebs.xml");
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse()); // create tags
|
||||||
|
|
||||||
|
ComputeService computeService = computeService();
|
||||||
|
|
||||||
|
Template template = computeService.templateBuilder().locationId("us-east-1a").build();
|
||||||
|
|
||||||
|
template.getOptions().as(AWSEC2TemplateOptions.class)
|
||||||
|
.spotPrice(1f).subnetId("subnet-xyz").keyPair("Demo").blockUntilRunning(false);
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test", 1, template));
|
||||||
|
assertEquals(node.getId(), "us-east-1/sir-228e6406");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RequestSpotInstances&SpotPrice=1.0&InstanceCount=1&LaunchSpecification.ImageId=ami-be3adfd7&LaunchSpecification.Placement.AvailabilityZone=us-east-1a&LaunchSpecification.InstanceType=m1.small&LaunchSpecification.SubnetId=subnet-xyz&LaunchSpecification.KeyName=Demo&LaunchSpecification.UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=sir-228e6406");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ImageId.1=ami-595a0a1c");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateTags&Tag.1.Key=Name&Tag.1.Value=test-228e6406&ResourceId.1=sir-228e6406");
|
||||||
|
}
|
||||||
|
|
||||||
|
String iamInstanceProfileArn = "arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver";
|
||||||
|
|
||||||
|
public void launchSpotInstanceIAMInstanceProfileArn() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_cc.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/created_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/request_spot_instances-ebs.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/request_spot_instances-ebs.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_ebs.xml");
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse()); // create tags
|
||||||
|
|
||||||
|
ComputeService computeService = computeService();
|
||||||
|
|
||||||
|
Template template = computeService.templateBuilder().locationId("us-east-1a").build();
|
||||||
|
|
||||||
|
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).iamInstanceProfileArn(iamInstanceProfileArn)
|
||||||
|
.noKeyPair().blockUntilRunning(false);
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test", 1, template));
|
||||||
|
assertEquals(node.getId(), "us-east-1/sir-228e6406");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RequestSpotInstances&SpotPrice=1.0&InstanceCount=1&LaunchSpecification.ImageId=ami-be3adfd7&LaunchSpecification.Placement.AvailabilityZone=us-east-1a&LaunchSpecification.SecurityGroup.1=jclouds%23test&LaunchSpecification.InstanceType=m1.small&LaunchSpecification.UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&LaunchSpecification.IamInstanceProfile.Arn=arn%3Aaws%3Aiam%3A%3A123456789012%3Ainstance-profile/application_abc/component_xyz/Webserver");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=sir-228e6406");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ImageId.1=ami-595a0a1c");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateTags&Tag.1.Key=Name&Tag.1.Value=test-228e6406&ResourceId.1=sir-228e6406");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void launchSpotInstanceIAMInstanceProfileName() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_cc.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/created_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/request_spot_instances-ebs.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/request_spot_instances-ebs.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_ebs.xml");
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse()); // create tags
|
||||||
|
|
||||||
|
ComputeService computeService = computeService();
|
||||||
|
|
||||||
|
Template template = computeService.templateBuilder().locationId("us-east-1a").build();
|
||||||
|
|
||||||
|
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).iamInstanceProfileName("Webserver")
|
||||||
|
.noKeyPair().blockUntilRunning(false);
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test", 1, template));
|
||||||
|
assertEquals(node.getId(), "us-east-1/sir-228e6406");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RequestSpotInstances&SpotPrice=1.0&InstanceCount=1&LaunchSpecification.ImageId=ami-be3adfd7&LaunchSpecification.Placement.AvailabilityZone=us-east-1a&LaunchSpecification.SecurityGroup.1=jclouds%23test&LaunchSpecification.InstanceType=m1.small&LaunchSpecification.UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&LaunchSpecification.IamInstanceProfile.Name=Webserver");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=sir-228e6406");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ImageId.1=ami-595a0a1c");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateTags&Tag.1.Key=Name&Tag.1.Value=test-228e6406&ResourceId.1=sir-228e6406");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createNodeWithIAMInstanceProfileArn() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/amzn_images.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_cc.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/created_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_instance.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_instances_running-1.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images.xml");
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse()); // create tags
|
||||||
|
|
||||||
|
ComputeService computeService = computeService();
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test", 1,
|
||||||
|
blockUntilRunning(false).iamInstanceProfileArn(iamInstanceProfileArn).noKeyPair()));
|
||||||
|
assertEquals(node.getId(), "us-east-1/i-2baa5550");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RunInstances&ImageId=ami-8ce4b5c9&MinCount=1&MaxCount=1&InstanceType=t1.micro&SecurityGroup.1=jclouds%23test&UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&IamInstanceProfile.Arn=arn%3Aaws%3Aiam%3A%3A123456789012%3Ainstance-profile/application_abc/component_xyz/Webserver");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeInstances&InstanceId.1=i-2baa5550");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ImageId.1=ami-aecd60c7");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateTags&Tag.1.Key=Name&Tag.1.Value=test-2baa5550&ResourceId.1=i-2baa5550");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createNodeWithIAMInstanceProfileName() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/amzn_images.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images_cc.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/created_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_securitygroup.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/new_instance.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_instances_running-1.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_images.xml");
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse()); // create tags
|
||||||
|
|
||||||
|
ComputeService computeService = computeService();
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test", 1,
|
||||||
|
blockUntilRunning(false).iamInstanceProfileName("Webserver").noKeyPair()));
|
||||||
|
assertEquals(node.getId(), "us-east-1/i-2baa5550");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RunInstances&ImageId=ami-8ce4b5c9&MinCount=1&MaxCount=1&InstanceType=t1.micro&SecurityGroup.1=jclouds%23test&UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&IamInstanceProfile.Name=Webserver");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeInstances&InstanceId.1=i-2baa5550");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ImageId.1=ami-aecd60c7");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateTags&Tag.1.Key=Name&Tag.1.Value=test-2baa5550&ResourceId.1=i-2baa5550");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void listNodesWhereImageDoesntExist() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_instances_running-1.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setBody("<DescribeImagesResponse><imagesSet></imagesSet></DescribeImagesResponse>"));
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setBody("<DescribeSpotInstanceRequestsResponse><spotInstanceRequestSet></spotInstanceRequestSet></DescribeSpotInstanceRequestsResponse>"));
|
||||||
|
|
||||||
|
ComputeService computeService = computeService();
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.listNodesDetailsMatching(NodePredicates.all()));
|
||||||
|
assertEquals(node.getId(), "us-east-1/i-2baa5550");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeInstances");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ImageId.1=ami-aecd60c7");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,278 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.compute;
|
|
||||||
|
|
||||||
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.blockUntilRunning;
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
|
|
||||||
import org.jclouds.aws.ec2.compute.internal.BaseAWSEC2ComputeServiceExpectTest;
|
|
||||||
import org.jclouds.compute.ComputeService;
|
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
|
||||||
import org.jclouds.compute.domain.Template;
|
|
||||||
import org.jclouds.compute.predicates.NodePredicates;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.HttpResponse;
|
|
||||||
import org.testng.annotations.BeforeClass;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the compute service abstraction of the EC2 api.
|
|
||||||
*/
|
|
||||||
@Test(groups = "unit", testName = "AWSEC2ComputeServiceExpectTest")
|
|
||||||
public class AWSEC2ComputeServiceExpectTest extends BaseAWSEC2ComputeServiceExpectTest {
|
|
||||||
|
|
||||||
private HttpResponse requestSpotInstancesResponse;
|
|
||||||
private HttpRequest describeSpotInstanceRequest;
|
|
||||||
private HttpResponse describeSpotInstanceResponse;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
@Override
|
|
||||||
protected void setupDefaultRequests() {
|
|
||||||
super.setupDefaultRequests();
|
|
||||||
requestSpotInstancesResponse = HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/request_spot_instances-ebs.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
describeSpotInstanceRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSpotInstanceRequests")
|
|
||||||
.addFormParam("SpotInstanceRequestId.1", "sir-228e6406").build());
|
|
||||||
|
|
||||||
describeSpotInstanceResponse = HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/request_spot_instances-ebs.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testLaunchVPCSpotInstanceSubnetId() throws Exception {
|
|
||||||
HttpRequest requestSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "RequestSpotInstances")
|
|
||||||
.addFormParam("InstanceCount", "1")
|
|
||||||
.addFormParam("LaunchSpecification.ImageId", "ami-be3adfd7")
|
|
||||||
.addFormParam("LaunchSpecification.InstanceType", "m1.small")
|
|
||||||
.addFormParam("LaunchSpecification.KeyName", "Demo")
|
|
||||||
.addFormParam("LaunchSpecification.Placement.AvailabilityZone", "us-east-1a")
|
|
||||||
.addFormParam("LaunchSpecification.SubnetId", "subnet-xyz")
|
|
||||||
.addFormParam("LaunchSpecification.UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK")
|
|
||||||
.addFormParam("SpotPrice", "1.0").build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(requestSpotInstancesRequest, requestSpotInstancesResponse);
|
|
||||||
requestResponseMap.put(describeSpotInstanceRequest, describeSpotInstanceResponse);
|
|
||||||
|
|
||||||
ComputeService createsVPCSpotInstance = requestsSendResponses(requestResponseMap.build());
|
|
||||||
|
|
||||||
Template template = createsVPCSpotInstance.templateBuilder().locationId("us-east-1a").build();
|
|
||||||
|
|
||||||
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).subnetId("subnet-xyz").keyPair("Demo").blockUntilRunning(false);
|
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(createsVPCSpotInstance.createNodesInGroup("test", 1, template));
|
|
||||||
assertEquals(node.getId(), "us-east-1/sir-228e6406");
|
|
||||||
}
|
|
||||||
|
|
||||||
String iamInstanceProfileArn = "arn:aws:iam::123456789012:instance-profile/application_abc/component_xyz/Webserver";
|
|
||||||
|
|
||||||
public void testLaunchSpotInstanceIAMInstanceProfileArn() throws Exception {
|
|
||||||
HttpRequest requestSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "RequestSpotInstances")
|
|
||||||
.addFormParam("InstanceCount", "1")
|
|
||||||
.addFormParam("LaunchSpecification.IamInstanceProfile.Arn", iamInstanceProfileArn)
|
|
||||||
.addFormParam("LaunchSpecification.ImageId", "ami-be3adfd7")
|
|
||||||
.addFormParam("LaunchSpecification.InstanceType", "m1.small")
|
|
||||||
.addFormParam("LaunchSpecification.Placement.AvailabilityZone", "us-east-1a")
|
|
||||||
.addFormParam("LaunchSpecification.SecurityGroup.1", "jclouds#test")
|
|
||||||
.addFormParam("LaunchSpecification.UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK")
|
|
||||||
.addFormParam("SpotPrice", "1.0").build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(requestSpotInstancesRequest, requestSpotInstancesResponse);
|
|
||||||
requestResponseMap.put(describeSpotInstanceRequest, describeSpotInstanceResponse);
|
|
||||||
|
|
||||||
ComputeService createsSpotInstance = requestsSendResponses(requestResponseMap.build());
|
|
||||||
|
|
||||||
Template template = createsSpotInstance.templateBuilder().locationId("us-east-1a").build();
|
|
||||||
|
|
||||||
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).iamInstanceProfileArn(iamInstanceProfileArn)
|
|
||||||
.noKeyPair().blockUntilRunning(false);
|
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(createsSpotInstance.createNodesInGroup("test", 1, template));
|
|
||||||
assertEquals(node.getId(), "us-east-1/sir-228e6406");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testLaunchSpotInstanceIAMInstanceProfileName() throws Exception {
|
|
||||||
HttpRequest requestSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "RequestSpotInstances")
|
|
||||||
.addFormParam("InstanceCount", "1")
|
|
||||||
.addFormParam("LaunchSpecification.IamInstanceProfile.Name", "Webserver")
|
|
||||||
.addFormParam("LaunchSpecification.ImageId", "ami-be3adfd7")
|
|
||||||
.addFormParam("LaunchSpecification.InstanceType", "m1.small")
|
|
||||||
.addFormParam("LaunchSpecification.Placement.AvailabilityZone", "us-east-1a")
|
|
||||||
.addFormParam("LaunchSpecification.SecurityGroup.1", "jclouds#test")
|
|
||||||
.addFormParam("LaunchSpecification.UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK")
|
|
||||||
.addFormParam("SpotPrice", "1.0").build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(requestSpotInstancesRequest, requestSpotInstancesResponse);
|
|
||||||
requestResponseMap.put(describeSpotInstanceRequest, describeSpotInstanceResponse);
|
|
||||||
|
|
||||||
ComputeService createsSpotInstance = requestsSendResponses(requestResponseMap.build());
|
|
||||||
|
|
||||||
Template template = createsSpotInstance.templateBuilder().locationId("us-east-1a").build();
|
|
||||||
|
|
||||||
template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(1f).iamInstanceProfileName("Webserver")
|
|
||||||
.noKeyPair().blockUntilRunning(false);
|
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(createsSpotInstance.createNodesInGroup("test", 1, template));
|
|
||||||
assertEquals(node.getId(), "us-east-1/sir-228e6406");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCreateNodeWithIAMInstanceProfileArn() throws Exception {
|
|
||||||
HttpRequest runInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "RunInstances")
|
|
||||||
.addFormParam("IamInstanceProfile.Arn", iamInstanceProfileArn)
|
|
||||||
.addFormParam("ImageId", "ami-be3adfd7")
|
|
||||||
.addFormParam("InstanceType", "m1.small")
|
|
||||||
.addFormParam("MaxCount", "1")
|
|
||||||
.addFormParam("MinCount", "1")
|
|
||||||
.addFormParam("SecurityGroup.1", "jclouds#test")
|
|
||||||
.addFormParam("UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK").build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(runInstancesRequest, runInstancesResponse);
|
|
||||||
requestResponseMap.put(describeInstanceRequest, describeInstanceResponse);
|
|
||||||
requestResponseMap.put(describeImageRequest, describeImagesResponse);
|
|
||||||
|
|
||||||
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
|
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
|
|
||||||
blockUntilRunning(false).iamInstanceProfileArn(iamInstanceProfileArn).noKeyPair()));
|
|
||||||
assertEquals(node.getId(), "us-east-1/i-2baa5550");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCreateNodeWithIAMInstanceProfileName() throws Exception {
|
|
||||||
HttpRequest runInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "RunInstances")
|
|
||||||
.addFormParam("IamInstanceProfile.Name", "Webserver")
|
|
||||||
.addFormParam("ImageId", "ami-be3adfd7")
|
|
||||||
.addFormParam("InstanceType", "m1.small")
|
|
||||||
.addFormParam("MaxCount", "1")
|
|
||||||
.addFormParam("MinCount", "1")
|
|
||||||
.addFormParam("SecurityGroup.1", "jclouds#test")
|
|
||||||
.addFormParam("UserData", "I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK").build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(runInstancesRequest, runInstancesResponse);
|
|
||||||
requestResponseMap.put(describeInstanceRequest, describeInstanceResponse);
|
|
||||||
requestResponseMap.put(describeImageRequest, describeImagesResponse);
|
|
||||||
|
|
||||||
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
|
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
|
|
||||||
blockUntilRunning(false).iamInstanceProfileName("Webserver").noKeyPair()));
|
|
||||||
assertEquals(node.getId(), "us-east-1/i-2baa5550");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testListNodesWhereImageDoesntExist() throws Exception {
|
|
||||||
HttpRequest describeInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeInstances").build());
|
|
||||||
|
|
||||||
HttpRequest describeSpotInstancesRequest = formSigner.filter(HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSpotInstanceRequests").build());
|
|
||||||
|
|
||||||
HttpResponse noSpotInstancesResponse = HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromStringWithContentType(
|
|
||||||
"<DescribeSpotInstanceRequestsResponse><spotInstanceRequestSet></spotInstanceRequestSet></DescribeSpotInstanceRequestsResponse>",
|
|
||||||
MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
HttpResponse noImagesResponse = HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromStringWithContentType(
|
|
||||||
"<DescribeImagesResponse><imagesSet></imagesSet></DescribeImagesResponse>",
|
|
||||||
MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeImagesRequest, noImagesResponse);
|
|
||||||
requestResponseMap.put(describeInstancesRequest, describeInstanceResponse);
|
|
||||||
requestResponseMap.put(describeSpotInstancesRequest, noSpotInstancesResponse);
|
|
||||||
|
|
||||||
ComputeService listsWithoutImages = requestsSendResponses(requestResponseMap.build());
|
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(listsWithoutImages.listNodesDetailsMatching(NodePredicates.all()));
|
|
||||||
assertEquals(node.getId(), "us-east-1/i-2baa5550");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,6 +29,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.jclouds.aws.domain.Region;
|
import org.jclouds.aws.domain.Region;
|
||||||
import org.jclouds.aws.ec2.AWSEC2Api;
|
import org.jclouds.aws.ec2.AWSEC2Api;
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2ProviderMetadata;
|
||||||
import org.jclouds.aws.ec2.reference.AWSEC2Constants;
|
import org.jclouds.aws.ec2.reference.AWSEC2Constants;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
import org.jclouds.compute.domain.OsFamily;
|
import org.jclouds.compute.domain.OsFamily;
|
||||||
|
@ -46,6 +47,7 @@ import org.jclouds.http.HttpCommand;
|
||||||
import org.jclouds.http.internal.TrackingJavaUrlHttpCommandExecutorService;
|
import org.jclouds.http.internal.TrackingJavaUrlHttpCommandExecutorService;
|
||||||
import org.jclouds.location.reference.LocationConstants;
|
import org.jclouds.location.reference.LocationConstants;
|
||||||
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
|
||||||
|
import org.jclouds.providers.ProviderMetadata;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
@ -59,6 +61,10 @@ public class AWSEC2TemplateBuilderLiveTest extends EC2TemplateBuilderLiveTest {
|
||||||
provider = "aws-ec2";
|
provider = "aws-ec2";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public ProviderMetadata createProviderMetadata() {
|
||||||
|
return new AWSEC2ProviderMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTemplateBuilderM1MEDIUMWithNegativeLookaroundDoesntMatchTestImages() {
|
public void testTemplateBuilderM1MEDIUMWithNegativeLookaroundDoesntMatchTestImages() {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.compute.extensions;
|
||||||
|
|
||||||
|
import static org.jclouds.domain.LocationScope.REGION;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
|
||||||
|
import org.jclouds.compute.domain.SecurityGroup;
|
||||||
|
import org.jclouds.compute.domain.SecurityGroupBuilder;
|
||||||
|
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||||
|
import org.jclouds.domain.LocationBuilder;
|
||||||
|
import org.jclouds.net.domain.IpPermission;
|
||||||
|
import org.jclouds.net.domain.IpProtocol;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
@Test(groups = "unit", testName = "AWSEC2SecurityGroupExtensionMockTest", singleThreaded = true)
|
||||||
|
public class AWSEC2SecurityGroupExtensionApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||||
|
|
||||||
|
SecurityGroup group = new SecurityGroupBuilder() //
|
||||||
|
.id(DEFAULT_REGION + "/sg-3c6ef654") //
|
||||||
|
.providerId("sg-3c6ef654") //
|
||||||
|
.name("jclouds#some-group") //
|
||||||
|
.ownerId("993194456877")
|
||||||
|
.location(new LocationBuilder().scope(REGION).id(DEFAULT_REGION).description("").build()).build();
|
||||||
|
|
||||||
|
IpPermission permByCidrBlock = IpPermission.builder() //
|
||||||
|
.ipProtocol(IpProtocol.TCP) //
|
||||||
|
.fromPort(22) //
|
||||||
|
.toPort(40) //
|
||||||
|
.cidrBlock("0.0.0.0/0").build();
|
||||||
|
|
||||||
|
public void addIpPermissionCidrFromIpPermission() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_cidr.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
|
||||||
|
SecurityGroup newGroup = extension().addIpPermission(permByCidrBlock, group);
|
||||||
|
|
||||||
|
assertEquals(1, newGroup.getIpPermissions().size());
|
||||||
|
|
||||||
|
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
||||||
|
assertEquals(newPerm, permByCidrBlock);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION,
|
||||||
|
"Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=40&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addIpPermissionCidrFromParams() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_cidr.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
|
||||||
|
SecurityGroup newGroup = extension()
|
||||||
|
.addIpPermission(permByCidrBlock.getIpProtocol(), permByCidrBlock.getFromPort(),
|
||||||
|
permByCidrBlock.getToPort(), permByCidrBlock.getTenantIdGroupNamePairs(),
|
||||||
|
permByCidrBlock.getCidrBlocks(), permByCidrBlock.getGroupIds(), group);
|
||||||
|
|
||||||
|
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
||||||
|
assertEquals(newPerm, permByCidrBlock);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION,
|
||||||
|
"Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=40&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
}
|
||||||
|
|
||||||
|
IpPermission permByGroup = IpPermission.builder() //
|
||||||
|
.ipProtocol(IpProtocol.TCP) //
|
||||||
|
.fromPort(22) //
|
||||||
|
.toPort(40) //
|
||||||
|
.tenantIdGroupNamePair(group.getOwnerId(), group.getProviderId()).build();
|
||||||
|
|
||||||
|
public void addIpPermissionGroupFromIpPermission() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_group.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
|
||||||
|
SecurityGroup newGroup = extension().addIpPermission(permByGroup, group);
|
||||||
|
|
||||||
|
assertEquals(1, newGroup.getIpPermissions().size());
|
||||||
|
|
||||||
|
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
||||||
|
assertEquals(newPerm, permByGroup);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION,
|
||||||
|
"Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=40&IpPermissions.0.Groups.0.UserId=993194456877&IpPermissions.0.Groups.0.GroupId=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addIpPermissionGroupFromParams() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/authorize_securitygroup_ingress_response.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_group.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
|
||||||
|
SecurityGroup newGroup = extension()
|
||||||
|
.addIpPermission(permByGroup.getIpProtocol(), permByGroup.getFromPort(), permByGroup.getToPort(),
|
||||||
|
permByGroup.getTenantIdGroupNamePairs(), permByGroup.getCidrBlocks(), permByGroup.getGroupIds(),
|
||||||
|
group);
|
||||||
|
|
||||||
|
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
||||||
|
assertEquals(newPerm, permByGroup);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION,
|
||||||
|
"Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=40&IpPermissions.0.Groups.0.UserId=993194456877&IpPermissions.0.Groups.0.GroupId=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createSecurityGroup() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/created_securitygroup.xml");
|
||||||
|
// TODO: ridiculously chatty
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_single.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_single.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_single.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_securitygroups_extension_single.xml");
|
||||||
|
enqueueXml(DEFAULT_REGION, "/availabilityZones.xml");
|
||||||
|
|
||||||
|
SecurityGroup newGroup = extension()
|
||||||
|
.createSecurityGroup(group.getName().replace("jclouds#", ""), group.getLocation());
|
||||||
|
assertEquals(newGroup.getId(), group.getId());
|
||||||
|
assertEquals(newGroup.getProviderId(), group.getProviderId());
|
||||||
|
assertEquals(newGroup.getName(), group.getName());
|
||||||
|
assertEquals(newGroup.getLocation().getId(), group.getLocation().getId()); // One from response has a parent
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION,
|
||||||
|
"Action=CreateSecurityGroup&GroupName=jclouds%23some-group&GroupDescription=jclouds%23some-group");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23some-group");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23some-group");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23some-group");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecurityGroupExtension extension() {
|
||||||
|
return computeService().getSecurityGroupExtension().get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,414 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.compute.extensions;
|
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
import static org.testng.Assert.assertNotNull;
|
|
||||||
import static org.testng.Assert.assertTrue;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.collect.LinkedHashMultimap;
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import org.jclouds.aws.ec2.compute.internal.BaseAWSEC2ComputeServiceExpectTest;
|
|
||||||
import org.jclouds.compute.domain.SecurityGroup;
|
|
||||||
import org.jclouds.compute.domain.SecurityGroupBuilder;
|
|
||||||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
|
||||||
import org.jclouds.domain.LocationBuilder;
|
|
||||||
import org.jclouds.domain.LocationScope;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.HttpResponse;
|
|
||||||
import org.jclouds.net.domain.IpPermission;
|
|
||||||
import org.jclouds.net.domain.IpProtocol;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
@Test(groups = "unit", testName = "AWSEC2SecurityGroupExtensionExpectTest")
|
|
||||||
public class AWSEC2SecurityGroupExtensionExpectTest extends BaseAWSEC2ComputeServiceExpectTest {
|
|
||||||
|
|
||||||
public void testAddIpPermissionCidrFromIpPermission() {
|
|
||||||
HttpRequest describeSecurityGroupsSingleRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupId.1", "sg-3c6ef654").build());
|
|
||||||
|
|
||||||
HttpResponse describeSecurityGroupsSingleResponse =
|
|
||||||
HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/describe_securitygroups_extension_cidr.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
|
|
||||||
HttpRequest authorizeSecurityGroupIngressRequestRange =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "AuthorizeSecurityGroupIngress")
|
|
||||||
.addFormParam("GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.FromPort", "22")
|
|
||||||
.addFormParam("IpPermissions.0.IpProtocol", "tcp")
|
|
||||||
.addFormParam("IpPermissions.0.IpRanges.0.CidrIp", "0.0.0.0/0")
|
|
||||||
.addFormParam("IpPermissions.0.ToPort", "40")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupsSingleRequest, describeSecurityGroupsSingleResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestRange, authorizeSecurityGroupIngressResponse);
|
|
||||||
|
|
||||||
IpPermission.Builder builder = IpPermission.builder();
|
|
||||||
|
|
||||||
builder.ipProtocol(IpProtocol.TCP);
|
|
||||||
builder.fromPort(22);
|
|
||||||
builder.toPort(40);
|
|
||||||
builder.cidrBlock("0.0.0.0/0");
|
|
||||||
|
|
||||||
IpPermission perm = builder.build();
|
|
||||||
|
|
||||||
SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
|
|
||||||
|
|
||||||
SecurityGroupBuilder groupBuilder = new SecurityGroupBuilder();
|
|
||||||
groupBuilder.id("us-east-1/sg-3c6ef654");
|
|
||||||
groupBuilder.providerId("sg-3c6ef654");
|
|
||||||
groupBuilder.name("jclouds#some-group");
|
|
||||||
groupBuilder.location(new LocationBuilder()
|
|
||||||
.scope(LocationScope.REGION)
|
|
||||||
.id(region)
|
|
||||||
.description("region")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
SecurityGroup origGroup = groupBuilder.build();
|
|
||||||
|
|
||||||
SecurityGroup newGroup = extension.addIpPermission(perm, origGroup);
|
|
||||||
|
|
||||||
assertEquals(1, newGroup.getIpPermissions().size());
|
|
||||||
|
|
||||||
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
|
||||||
|
|
||||||
assertNotNull(newPerm);
|
|
||||||
assertEquals(IpProtocol.TCP, newPerm.getIpProtocol());
|
|
||||||
assertEquals(22, newPerm.getFromPort());
|
|
||||||
assertEquals(40, newPerm.getToPort());
|
|
||||||
assertEquals(1, newPerm.getCidrBlocks().size());
|
|
||||||
assertTrue(newPerm.getCidrBlocks().contains("0.0.0.0/0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAddIpPermissionCidrFromParams() {
|
|
||||||
HttpRequest describeSecurityGroupsSingleRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupId.1", "sg-3c6ef654").build());
|
|
||||||
|
|
||||||
HttpResponse describeSecurityGroupsSingleResponse =
|
|
||||||
HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/describe_securitygroups_extension_cidr.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
|
|
||||||
HttpRequest authorizeSecurityGroupIngressRequestRange =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "AuthorizeSecurityGroupIngress")
|
|
||||||
.addFormParam("GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.FromPort", "22")
|
|
||||||
.addFormParam("IpPermissions.0.IpProtocol", "tcp")
|
|
||||||
.addFormParam("IpPermissions.0.IpRanges.0.CidrIp", "0.0.0.0/0")
|
|
||||||
.addFormParam("IpPermissions.0.ToPort", "40")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupsSingleRequest, describeSecurityGroupsSingleResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestRange, authorizeSecurityGroupIngressResponse);
|
|
||||||
|
|
||||||
SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
|
|
||||||
|
|
||||||
SecurityGroupBuilder groupBuilder = new SecurityGroupBuilder();
|
|
||||||
groupBuilder.id("us-east-1/sg-3c6ef654");
|
|
||||||
groupBuilder.providerId("sg-3c6ef654");
|
|
||||||
groupBuilder.name("jclouds#some-group");
|
|
||||||
groupBuilder.location(new LocationBuilder()
|
|
||||||
.scope(LocationScope.REGION)
|
|
||||||
.id(region)
|
|
||||||
.description("region")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
SecurityGroup origGroup = groupBuilder.build();
|
|
||||||
|
|
||||||
SecurityGroup newGroup = extension.addIpPermission(IpProtocol.TCP,
|
|
||||||
22,
|
|
||||||
40,
|
|
||||||
emptyMultimap(),
|
|
||||||
ImmutableSet.of("0.0.0.0/0"),
|
|
||||||
emptyStringSet(),
|
|
||||||
origGroup);
|
|
||||||
|
|
||||||
assertEquals(1, newGroup.getIpPermissions().size());
|
|
||||||
|
|
||||||
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
|
||||||
|
|
||||||
assertNotNull(newPerm);
|
|
||||||
assertEquals(IpProtocol.TCP, newPerm.getIpProtocol());
|
|
||||||
assertEquals(22, newPerm.getFromPort());
|
|
||||||
assertEquals(40, newPerm.getToPort());
|
|
||||||
assertEquals(1, newPerm.getCidrBlocks().size());
|
|
||||||
assertTrue(newPerm.getCidrBlocks().contains("0.0.0.0/0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAddIpPermissionGroupFromIpPermission() {
|
|
||||||
HttpRequest describeSecurityGroupsSingleRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupId.1", "sg-3c6ef654").build());
|
|
||||||
|
|
||||||
HttpResponse describeSecurityGroupsSingleResponse =
|
|
||||||
HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/describe_securitygroups_extension_group.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
|
|
||||||
HttpRequest authorizeSecurityGroupIngressRequestGroupTenant =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "AuthorizeSecurityGroupIngress")
|
|
||||||
.addFormParam("GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.FromPort", "22")
|
|
||||||
.addFormParam("IpPermissions.0.Groups.0.GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.Groups.0.UserId", "993194456877")
|
|
||||||
.addFormParam("IpPermissions.0.IpProtocol", "tcp")
|
|
||||||
.addFormParam("IpPermissions.0.ToPort", "40")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupsSingleRequest, describeSecurityGroupsSingleResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroupTenant, authorizeSecurityGroupIngressResponse);
|
|
||||||
|
|
||||||
IpPermission.Builder builder = IpPermission.builder();
|
|
||||||
|
|
||||||
builder.ipProtocol(IpProtocol.TCP);
|
|
||||||
builder.fromPort(22);
|
|
||||||
builder.toPort(40);
|
|
||||||
builder.tenantIdGroupNamePair("993194456877", "sg-3c6ef654");
|
|
||||||
|
|
||||||
IpPermission perm = builder.build();
|
|
||||||
|
|
||||||
SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
|
|
||||||
|
|
||||||
SecurityGroupBuilder groupBuilder = new SecurityGroupBuilder();
|
|
||||||
groupBuilder.id("us-east-1/sg-3c6ef654");
|
|
||||||
groupBuilder.providerId("sg-3c6ef654");
|
|
||||||
groupBuilder.name("jclouds#some-group");
|
|
||||||
groupBuilder.location(new LocationBuilder()
|
|
||||||
.scope(LocationScope.REGION)
|
|
||||||
.id(region)
|
|
||||||
.description("region")
|
|
||||||
.build());
|
|
||||||
groupBuilder.ownerId("993194456877");
|
|
||||||
|
|
||||||
SecurityGroup origGroup = groupBuilder.build();
|
|
||||||
|
|
||||||
SecurityGroup newGroup = extension.addIpPermission(perm, origGroup);
|
|
||||||
|
|
||||||
assertEquals(1, newGroup.getIpPermissions().size());
|
|
||||||
|
|
||||||
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
|
||||||
|
|
||||||
assertNotNull(newPerm);
|
|
||||||
assertEquals(IpProtocol.TCP, newPerm.getIpProtocol());
|
|
||||||
assertEquals(22, newPerm.getFromPort());
|
|
||||||
assertEquals(40, newPerm.getToPort());
|
|
||||||
assertEquals(0, newPerm.getCidrBlocks().size());
|
|
||||||
assertEquals(1, newPerm.getTenantIdGroupNamePairs().size());
|
|
||||||
assertTrue(newPerm.getTenantIdGroupNamePairs().keySet().contains(origGroup.getOwnerId()));
|
|
||||||
assertTrue(newPerm.getTenantIdGroupNamePairs().values().contains(origGroup.getProviderId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void testAddIpPermissionGroupFromParams() {
|
|
||||||
HttpRequest describeSecurityGroupsSingleRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupId.1", "sg-3c6ef654").build());
|
|
||||||
|
|
||||||
HttpResponse describeSecurityGroupsSingleResponse =
|
|
||||||
HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/describe_securitygroups_extension_group.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
|
|
||||||
HttpRequest authorizeSecurityGroupIngressRequestGroupTenant =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "AuthorizeSecurityGroupIngress")
|
|
||||||
.addFormParam("GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.FromPort", "22")
|
|
||||||
.addFormParam("IpPermissions.0.Groups.0.GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.Groups.0.UserId", "993194456877")
|
|
||||||
.addFormParam("IpPermissions.0.IpProtocol", "tcp")
|
|
||||||
.addFormParam("IpPermissions.0.ToPort", "40")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupsSingleRequest, describeSecurityGroupsSingleResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
|
||||||
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroupTenant, authorizeSecurityGroupIngressResponse);
|
|
||||||
|
|
||||||
SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
|
|
||||||
|
|
||||||
SecurityGroupBuilder groupBuilder = new SecurityGroupBuilder();
|
|
||||||
groupBuilder.id("us-east-1/sg-3c6ef654");
|
|
||||||
groupBuilder.providerId("sg-3c6ef654");
|
|
||||||
groupBuilder.name("jclouds#some-group");
|
|
||||||
groupBuilder.ownerId("993194456877");
|
|
||||||
groupBuilder.location(new LocationBuilder()
|
|
||||||
.scope(LocationScope.REGION)
|
|
||||||
.id(region)
|
|
||||||
.description("region")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
SecurityGroup origGroup = groupBuilder.build();
|
|
||||||
|
|
||||||
ImmutableMultimap.Builder<String, String> permBuilder = ImmutableMultimap.builder();
|
|
||||||
permBuilder.put(origGroup.getOwnerId(), origGroup.getId());
|
|
||||||
|
|
||||||
SecurityGroup newGroup = extension.addIpPermission(IpProtocol.TCP,
|
|
||||||
22,
|
|
||||||
40,
|
|
||||||
permBuilder.build(),
|
|
||||||
emptyStringSet(),
|
|
||||||
emptyStringSet(),
|
|
||||||
origGroup);
|
|
||||||
|
|
||||||
assertEquals(1, newGroup.getIpPermissions().size());
|
|
||||||
|
|
||||||
IpPermission newPerm = Iterables.getOnlyElement(newGroup.getIpPermissions());
|
|
||||||
|
|
||||||
assertNotNull(newPerm);
|
|
||||||
assertEquals(IpProtocol.TCP, newPerm.getIpProtocol());
|
|
||||||
assertEquals(22, newPerm.getFromPort());
|
|
||||||
assertEquals(40, newPerm.getToPort());
|
|
||||||
assertEquals(0, newPerm.getCidrBlocks().size());
|
|
||||||
assertEquals(1, newPerm.getTenantIdGroupNamePairs().size());
|
|
||||||
assertTrue(newPerm.getTenantIdGroupNamePairs().keySet().contains(origGroup.getOwnerId()));
|
|
||||||
assertTrue(newPerm.getTenantIdGroupNamePairs().values().contains(origGroup.getProviderId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCreateSecurityGroup() {
|
|
||||||
HttpRequest createSecurityGroupExtRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "CreateSecurityGroup")
|
|
||||||
.addFormParam("GroupDescription", "jclouds#some-group")
|
|
||||||
.addFormParam("GroupName", "jclouds#some-group").build());
|
|
||||||
|
|
||||||
HttpRequest describeSecurityGroupsSingleRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupName.1", "jclouds#some-group").build());
|
|
||||||
|
|
||||||
HttpRequest describeSecurityGroupsByIdRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupId.1", "sg-3c6ef654").build());
|
|
||||||
|
|
||||||
HttpResponse describeSecurityGroupsSingleResponse =
|
|
||||||
HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType(
|
|
||||||
"/describe_securitygroups_extension_single.xml", MediaType.APPLICATION_XML)).build();
|
|
||||||
|
|
||||||
|
|
||||||
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
|
||||||
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
|
||||||
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupsSingleRequest, describeSecurityGroupsSingleResponse);
|
|
||||||
requestResponseMap.put(describeSecurityGroupsByIdRequest, describeSecurityGroupsSingleResponse);
|
|
||||||
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
|
||||||
requestResponseMap.put(createSecurityGroupExtRequest, createSecurityGroupResponse);
|
|
||||||
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
|
||||||
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
|
||||||
|
|
||||||
|
|
||||||
SecurityGroupExtension extension = requestsSendResponses(requestResponseMap.build()).getSecurityGroupExtension().get();
|
|
||||||
|
|
||||||
SecurityGroup group = extension.createSecurityGroup("some-group", new LocationBuilder()
|
|
||||||
.scope(LocationScope.REGION)
|
|
||||||
.id(region)
|
|
||||||
.description("region")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
assertEquals("sg-3c6ef654", group.getProviderId());
|
|
||||||
assertEquals(region + "/sg-3c6ef654", group.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Multimap<String, String> emptyMultimap() {
|
|
||||||
return LinkedHashMultimap.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> emptyStringSet() {
|
|
||||||
return Sets.newLinkedHashSet();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.compute.internal;
|
|
||||||
|
|
||||||
import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
|
|
||||||
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTANCE_NAMES;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import org.jclouds.aws.ec2.config.AWSEC2HttpApiModule;
|
|
||||||
import org.jclouds.date.DateService;
|
|
||||||
import org.jclouds.ec2.compute.internal.BaseEC2ComputeServiceExpectTest;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.rest.ConfiguresHttpApi;
|
|
||||||
import org.testng.annotations.BeforeClass;
|
|
||||||
|
|
||||||
import com.google.common.base.Supplier;
|
|
||||||
import com.google.inject.Module;
|
|
||||||
import com.google.inject.Provides;
|
|
||||||
import com.google.inject.TypeLiteral;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the compute service abstraction of the EC2 api.
|
|
||||||
*/
|
|
||||||
public abstract class BaseAWSEC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest {
|
|
||||||
|
|
||||||
protected HttpRequest describeSecurityGroupByIdRequest;
|
|
||||||
|
|
||||||
public BaseAWSEC2ComputeServiceExpectTest() {
|
|
||||||
provider = "aws-ec2";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Properties setupProperties() {
|
|
||||||
Properties properties = super.setupProperties();
|
|
||||||
// zero out cluster image query for now
|
|
||||||
properties.setProperty(PROPERTY_EC2_CC_AMI_QUERY, "");
|
|
||||||
properties.setProperty(PROPERTY_EC2_GENERATE_INSTANCE_NAMES, "false");
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
@Override
|
|
||||||
protected void setupDefaultRequests() {
|
|
||||||
super.setupDefaultRequests();
|
|
||||||
|
|
||||||
describeSecurityGroupByIdRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSecurityGroups")
|
|
||||||
.addFormParam("GroupId.1", "sg-3c6ef654").build());
|
|
||||||
|
|
||||||
authorizeSecurityGroupIngressRequestGroup =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "AuthorizeSecurityGroupIngress")
|
|
||||||
.addFormParam("SourceSecurityGroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("SourceSecurityGroupOwnerId", "993194456877")
|
|
||||||
.addFormParam("GroupName", "jclouds#test").build());
|
|
||||||
|
|
||||||
authorizeSecurityGroupIngressRequest22 =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "AuthorizeSecurityGroupIngress")
|
|
||||||
.addFormParam("GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.0.FromPort", "22")
|
|
||||||
.addFormParam("IpPermissions.0.ToPort", "22")
|
|
||||||
.addFormParam("IpPermissions.0.IpRanges.0.CidrIp", "0.0.0.0/0")
|
|
||||||
.addFormParam("IpPermissions.0.IpProtocol", "tcp")
|
|
||||||
.addFormParam("IpPermissions.1.FromPort", "0")
|
|
||||||
.addFormParam("IpPermissions.1.ToPort", "65535")
|
|
||||||
.addFormParam("IpPermissions.1.Groups.0.GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.1.Groups.0.UserId", "993194456877")
|
|
||||||
.addFormParam("IpPermissions.1.IpProtocol", "tcp")
|
|
||||||
.addFormParam("IpPermissions.2.FromPort", "0")
|
|
||||||
.addFormParam("IpPermissions.2.ToPort", "65535")
|
|
||||||
.addFormParam("IpPermissions.2.Groups.0.GroupId", "sg-3c6ef654")
|
|
||||||
.addFormParam("IpPermissions.2.Groups.0.UserId", "993194456877")
|
|
||||||
.addFormParam("IpPermissions.2.IpProtocol", "udp")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
describeImagesRequest =
|
|
||||||
formSigner.filter(HttpRequest.builder()
|
|
||||||
.method("POST")
|
|
||||||
.endpoint("https://ec2." + region + ".amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2." + region + ".amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeImages")
|
|
||||||
.addFormParam("Filter.1.Name", "owner-id")
|
|
||||||
.addFormParam("Filter.1.Value.1", "137112412989")
|
|
||||||
.addFormParam("Filter.1.Value.2", "801119661308")
|
|
||||||
.addFormParam("Filter.1.Value.3", "063491364108")
|
|
||||||
.addFormParam("Filter.1.Value.4", "099720109477")
|
|
||||||
.addFormParam("Filter.1.Value.5", "411009282317")
|
|
||||||
.addFormParam("Filter.2.Name", "state")
|
|
||||||
.addFormParam("Filter.2.Value.1", "available")
|
|
||||||
.addFormParam("Filter.3.Name", "image-type")
|
|
||||||
.addFormParam("Filter.3.Value.1", "machine").build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfiguresHttpApi
|
|
||||||
protected static class TestAWSEC2HttpApiModule extends AWSEC2HttpApiModule {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
super.configure();
|
|
||||||
// predicatable node names
|
|
||||||
final AtomicInteger suffix = new AtomicInteger();
|
|
||||||
bind(new TypeLiteral<Supplier<String>>() {
|
|
||||||
}).toInstance(new Supplier<String>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String get() {
|
|
||||||
return suffix.getAndIncrement() + "";
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Provides
|
|
||||||
protected String provideTimeStamp(DateService dateService) {
|
|
||||||
return CONSTANT_DATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Module createModule() {
|
|
||||||
return new TestAWSEC2HttpApiModule();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.features;
|
||||||
|
|
||||||
|
import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.executableBy;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
|
||||||
|
import org.jclouds.ec2.domain.Image;
|
||||||
|
import org.jclouds.ec2.domain.Permission;
|
||||||
|
import org.jclouds.ec2.options.CreateImageOptions;
|
||||||
|
import org.jclouds.ec2.options.RegisterImageBackedByEbsOptions;
|
||||||
|
import org.jclouds.ec2.options.RegisterImageOptions;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockResponse;
|
||||||
|
|
||||||
|
@Test(groups = "unit", testName = "AWSAMIApiMockTest", singleThreaded = true)
|
||||||
|
public class AWSAMIApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||||
|
|
||||||
|
public void describeImagesInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/amzn_images.xml");
|
||||||
|
|
||||||
|
Set<? extends Image> result = amiApi().describeImagesInRegion(DEFAULT_REGION);
|
||||||
|
|
||||||
|
assertFalse(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describeImagesInRegion_options() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/amzn_images.xml");
|
||||||
|
|
||||||
|
Set<? extends Image> result = amiApi()
|
||||||
|
.describeImagesInRegion(DEFAULT_REGION, executableBy("me").ownedBy("fred", "nancy").imageIds("1", "2"));
|
||||||
|
|
||||||
|
assertFalse(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages&ExecutableBy=me&Owner.1=fred&Owner.2=nancy&ImageId.1=1&ImageId.2=2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describeImagesInRegion_404() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
|
||||||
|
|
||||||
|
Set<? extends Image> result = amiApi().describeImagesInRegion(DEFAULT_REGION);
|
||||||
|
|
||||||
|
assertTrue(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImages");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setBody("<CreateImageResponse><ImageId>ami-246f8d4d</ImageId></CreateImageResponse>"));
|
||||||
|
|
||||||
|
String result = amiApi().createImageInRegion(DEFAULT_REGION, "name", "instanceId");
|
||||||
|
assertEquals(result, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateImage&Name=name&InstanceId=instanceId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createImageInRegion_options() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION,
|
||||||
|
new MockResponse().setBody("<CreateImageResponse><ImageId>ami-246f8d4d</ImageId></CreateImageResponse>"));
|
||||||
|
|
||||||
|
String result = amiApi().createImageInRegion(DEFAULT_REGION, "name", "instanceId",
|
||||||
|
new CreateImageOptions().withDescription("description").noReboot());
|
||||||
|
assertEquals(result, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreateImage&Name=name&InstanceId=instanceId&Description=description&NoReboot=true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerImageFromManifestInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setBody("<RegisterImageResponse><ImageId>ami-246f8d4d</ImageId></RegisterImageResponse>"));
|
||||||
|
|
||||||
|
String result = amiApi().registerImageFromManifestInRegion(DEFAULT_REGION, "name", "pathToManifest");
|
||||||
|
assertEquals(result, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RegisterImage&Name=name&ImageLocation=pathToManifest");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerImageFromManifestInRegion_options() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setBody("<RegisterImageResponse><ImageId>ami-246f8d4d</ImageId></RegisterImageResponse>"));
|
||||||
|
|
||||||
|
String result = amiApi().registerImageFromManifestInRegion(DEFAULT_REGION, "name", "pathToManifest",
|
||||||
|
new RegisterImageOptions().withDescription("description"));
|
||||||
|
assertEquals(result, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RegisterImage&Name=name&ImageLocation=pathToManifest&Description=description");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerUnixImageBackedByEbsInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse()
|
||||||
|
.setBody("<RegisterImageResponse><ImageId>ami-246f8d4d</ImageId></RegisterImageResponse>"));
|
||||||
|
|
||||||
|
String result = amiApi().registerUnixImageBackedByEbsInRegion(DEFAULT_REGION, "imageName", "snapshotId");
|
||||||
|
assertEquals(result, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RegisterImage&RootDeviceName=/dev/sda1&BlockDeviceMapping.0.DeviceName=/dev/sda1&Name=imageName&BlockDeviceMapping.0.Ebs.SnapshotId=snapshotId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerUnixImageBackedByEbsInRegion_options() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setBody("<RegisterImageResponse><ImageId>ami-246f8d4d</ImageId></RegisterImageResponse>"));
|
||||||
|
|
||||||
|
String result = amiApi().registerUnixImageBackedByEbsInRegion(DEFAULT_REGION, "imageName", "snapshotId",
|
||||||
|
new RegisterImageBackedByEbsOptions().withDescription("description")
|
||||||
|
.addBlockDeviceFromSnapshot("/dev/device", null, "snapshot", false, "gp2", null, false)
|
||||||
|
.addNewBlockDevice("/dev/newdevice", "newblock", 100));
|
||||||
|
assertEquals(result, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=RegisterImage&RootDeviceName=/dev/sda1&BlockDeviceMapping.0.DeviceName=/dev/sda1&Name=imageName&BlockDeviceMapping.0.Ebs.SnapshotId=snapshotId&Description=description&BlockDeviceMapping.1.Ebs.DeleteOnTermination=false&BlockDeviceMapping.1.Ebs.VolumeType=gp2&BlockDeviceMapping.1.DeviceName=/dev/device&BlockDeviceMapping.1.Ebs.SnapshotId=snapshot&BlockDeviceMapping.2.Ebs.DeleteOnTermination=false&BlockDeviceMapping.2.DeviceName=/dev/newdevice&BlockDeviceMapping.2.VirtualName=newblock&BlockDeviceMapping.2.Ebs.VolumeSize=100");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deregisterImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
amiApi().deregisterImageInRegion(DEFAULT_REGION, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DeregisterImage&ImageId=ami-246f8d4d");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBlockDeviceMappingsForImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_image_attribute_blockDeviceMapping.xml");
|
||||||
|
|
||||||
|
Map<String, Image.EbsBlockDevice> result = amiApi()
|
||||||
|
.getBlockDeviceMappingsForImageInRegion(DEFAULT_REGION, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertFalse(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImageAttribute&Attribute=blockDeviceMapping&ImageId=ami-246f8d4d");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getLaunchPermissionForImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_image_attribute_launchPermission.xml");
|
||||||
|
|
||||||
|
Permission result = amiApi().getLaunchPermissionForImageInRegion(DEFAULT_REGION, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImageAttribute&Attribute=launchPermission&ImageId=ami-246f8d4d");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLaunchPermissionsToImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
amiApi().addLaunchPermissionsToImageInRegion(DEFAULT_REGION, ImmutableList.of("bob", "sue"),
|
||||||
|
ImmutableList.of("all"), "imageId");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=ModifyImageAttribute&OperationType=add&Attribute=launchPermission&ImageId=imageId&UserId.1=bob&UserId.2=sue&UserGroup.1=all");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeLaunchPermissionsFromImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
amiApi().removeLaunchPermissionsFromImageInRegion(DEFAULT_REGION, ImmutableList.of("bob", "sue"),
|
||||||
|
ImmutableList.of("all"), "imageId");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=ModifyImageAttribute&OperationType=remove&Attribute=launchPermission&ImageId=imageId&UserId.1=bob&UserId.2=sue&UserGroup.1=all");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetLaunchPermissionsOnImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
amiApi().resetLaunchPermissionsOnImageInRegion(DEFAULT_REGION, "imageId");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=ResetImageAttribute&Attribute=launchPermission&ImageId=imageId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getProductCodesForImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_image_attribute_productCodes.xml");
|
||||||
|
|
||||||
|
Set<String> result = amiApi().getProductCodesForImageInRegion(DEFAULT_REGION, "ami-246f8d4d");
|
||||||
|
|
||||||
|
assertFalse(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeImageAttribute&Attribute=productCodes&ImageId=ami-246f8d4d");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addProductCodesToImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
amiApi().addProductCodesToImageInRegion(DEFAULT_REGION, ImmutableList.of("code1", "code2"), "imageId");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=ModifyImageAttribute&OperationType=add&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeProductCodesFromImageInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
amiApi().removeProductCodesFromImageInRegion(DEFAULT_REGION, ImmutableList.of("code1", "code2"), "imageId");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=ModifyImageAttribute&OperationType=remove&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2");
|
||||||
|
}
|
||||||
|
|
||||||
|
private AWSAMIApi amiApi() {
|
||||||
|
return api().getAMIApi().get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,496 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.features;
|
|
||||||
|
|
||||||
import static org.jclouds.ec2.options.DescribeImagesOptions.Builder.executableBy;
|
|
||||||
import static org.jclouds.reflect.Reflection2.method;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
|
|
||||||
import org.jclouds.aws.ec2.xml.ProductCodesHandler;
|
|
||||||
import org.jclouds.ec2.options.CreateImageOptions;
|
|
||||||
import org.jclouds.ec2.options.DescribeImagesOptions;
|
|
||||||
import org.jclouds.ec2.options.RegisterImageBackedByEbsOptions;
|
|
||||||
import org.jclouds.ec2.options.RegisterImageOptions;
|
|
||||||
import org.jclouds.ec2.xml.BlockDeviceMappingHandler;
|
|
||||||
import org.jclouds.ec2.xml.DescribeImagesResponseHandler;
|
|
||||||
import org.jclouds.ec2.xml.ImageIdHandler;
|
|
||||||
import org.jclouds.ec2.xml.PermissionHandler;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.functions.ParseSax;
|
|
||||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
|
||||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.reflect.Invokable;
|
|
||||||
/**
|
|
||||||
* Tests behavior of {@code AWSAMIApi}
|
|
||||||
*/
|
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
|
||||||
@Test(groups = "unit", testName = "AWSAMIApiTest")
|
|
||||||
public class AWSAMIApiTest extends BaseAWSEC2ApiTest<AWSAMIApi> {
|
|
||||||
public AWSAMIApiTest() {
|
|
||||||
provider = "aws-ec2";
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest createImage = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "CreateImage")
|
|
||||||
.addFormParam("InstanceId", "instanceId")
|
|
||||||
.addFormParam("Name", "name").build();
|
|
||||||
|
|
||||||
public void testCreateImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "createImageInRegion", String.class, String.class, String.class,
|
|
||||||
CreateImageOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "instanceId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(createImage).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest createImageOptions = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "CreateImage")
|
|
||||||
.addFormParam("Description", "description")
|
|
||||||
.addFormParam("InstanceId", "instanceId")
|
|
||||||
.addFormParam("Name", "name")
|
|
||||||
.addFormParam("NoReboot", "true").build();
|
|
||||||
|
|
||||||
public void testCreateImageOptions() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "createImageInRegion", String.class, String.class, String.class,
|
|
||||||
CreateImageOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "instanceId", new CreateImageOptions()
|
|
||||||
.withDescription("description").noReboot()));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(createImageOptions).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest describeImages = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeImages").build();
|
|
||||||
|
|
||||||
public void testDescribeImages() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "describeImagesInRegion", String.class,
|
|
||||||
DescribeImagesOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList((String) null));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(describeImages).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, DescribeImagesResponseHandler.class);
|
|
||||||
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest describeImagesOptions = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeImages")
|
|
||||||
.addFormParam("ExecutableBy", "me")
|
|
||||||
.addFormParam("ImageId.1", "1")
|
|
||||||
.addFormParam("ImageId.2", "2")
|
|
||||||
.addFormParam("Owner.1", "fred")
|
|
||||||
.addFormParam("Owner.2", "nancy").build();
|
|
||||||
|
|
||||||
public void testDescribeImagesOptions() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "describeImagesInRegion", String.class,
|
|
||||||
DescribeImagesOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, executableBy("me").ownedBy("fred", "nancy").imageIds(
|
|
||||||
"1", "2")));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(describeImagesOptions).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, DescribeImagesResponseHandler.class);
|
|
||||||
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest deregisterImage = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DeregisterImage")
|
|
||||||
.addFormParam("ImageId", "imageId").build();
|
|
||||||
|
|
||||||
public void testDeregisterImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "deregisterImageInRegion", String.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(deregisterImage).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest registerImageFromManifest = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "RegisterImage")
|
|
||||||
.addFormParam("ImageLocation", "pathToManifest")
|
|
||||||
.addFormParam("Name", "name").build();
|
|
||||||
|
|
||||||
public void testRegisterImageFromManifest() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "registerImageFromManifestInRegion", String.class, String.class,
|
|
||||||
String.class, RegisterImageOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "pathToManifest"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(registerImageFromManifest).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest registerImageFromManifestOptions = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "RegisterImage")
|
|
||||||
.addFormParam("Description", "description")
|
|
||||||
.addFormParam("ImageLocation", "pathToManifest")
|
|
||||||
.addFormParam("Name", "name").build();
|
|
||||||
|
|
||||||
public void testRegisterImageFromManifestOptions() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "registerImageFromManifestInRegion", String.class, String.class,
|
|
||||||
String.class, RegisterImageOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "pathToManifest", new RegisterImageOptions()
|
|
||||||
.withDescription("description")));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(registerImageFromManifestOptions).getPayload().getRawContent()
|
|
||||||
.toString(), "application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest registerImageBackedByEBS = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "RegisterImage")
|
|
||||||
.addFormParam("BlockDeviceMapping.0.DeviceName", "/dev/sda1")
|
|
||||||
.addFormParam("BlockDeviceMapping.0.Ebs.SnapshotId", "snapshotId")
|
|
||||||
.addFormParam("Name", "imageName")
|
|
||||||
.addFormParam("RootDeviceName", "/dev/sda1").build();
|
|
||||||
|
|
||||||
public void testRegisterImageBackedByEBS() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "registerUnixImageBackedByEbsInRegion", String.class,
|
|
||||||
String.class, String.class, RegisterImageBackedByEbsOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageName", "snapshotId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(registerImageBackedByEBS).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest registerImageBackedByEBSOptions = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "RegisterImage")
|
|
||||||
.addFormParam("BlockDeviceMapping.0.DeviceName", "/dev/sda1")
|
|
||||||
.addFormParam("BlockDeviceMapping.0.Ebs.SnapshotId", "snapshotId")
|
|
||||||
.addFormParam("BlockDeviceMapping.1.DeviceName", "/dev/device")
|
|
||||||
.addFormParam("BlockDeviceMapping.1.Ebs.DeleteOnTermination", "false")
|
|
||||||
.addFormParam("BlockDeviceMapping.1.Ebs.SnapshotId", "snapshot")
|
|
||||||
.addFormParam("BlockDeviceMapping.1.Ebs.VolumeType", "gp2")
|
|
||||||
.addFormParam("BlockDeviceMapping.2.DeviceName", "/dev/newdevice")
|
|
||||||
.addFormParam("BlockDeviceMapping.2.Ebs.DeleteOnTermination", "false")
|
|
||||||
.addFormParam("BlockDeviceMapping.2.Ebs.VolumeSize", "100")
|
|
||||||
.addFormParam("BlockDeviceMapping.2.VirtualName", "newblock")
|
|
||||||
.addFormParam("Description", "description")
|
|
||||||
.addFormParam("Name", "imageName")
|
|
||||||
.addFormParam("RootDeviceName", "/dev/sda1").build();
|
|
||||||
|
|
||||||
public void testRegisterImageBackedByEBSOptions() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "registerUnixImageBackedByEbsInRegion", String.class,
|
|
||||||
String.class, String.class, RegisterImageBackedByEbsOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageName", "snapshotId",
|
|
||||||
new RegisterImageBackedByEbsOptions().withDescription("description").addBlockDeviceFromSnapshot(
|
|
||||||
"/dev/device", null, "snapshot", false, "gp2", null, false).addNewBlockDevice("/dev/newdevice", "newblock", 100)));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(registerImageBackedByEBSOptions).getPayload().getRawContent()
|
|
||||||
.toString(), "application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ImageIdHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest getBlockDeviceMappingsForImage = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeImageAttribute")
|
|
||||||
.addFormParam("Attribute", "blockDeviceMapping")
|
|
||||||
.addFormParam("ImageId", "imageId").build();
|
|
||||||
|
|
||||||
public void testGetBlockDeviceMappingsForImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "getBlockDeviceMappingsForImageInRegion", String.class,
|
|
||||||
String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(getBlockDeviceMappingsForImage).getPayload().getRawContent()
|
|
||||||
.toString(), "application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, BlockDeviceMappingHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest getLaunchPermissionForImage = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeImageAttribute")
|
|
||||||
.addFormParam("Attribute", "launchPermission")
|
|
||||||
.addFormParam("ImageId", "imageId").build();
|
|
||||||
|
|
||||||
public void testGetLaunchPermissionForImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "getLaunchPermissionForImageInRegion", String.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(getLaunchPermissionForImage).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, PermissionHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest addLaunchPermission = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "ModifyImageAttribute")
|
|
||||||
.addFormParam("Attribute", "launchPermission")
|
|
||||||
.addFormParam("ImageId", "imageId")
|
|
||||||
.addFormParam("OperationType", "add")
|
|
||||||
.addFormParam("UserGroup.1", "all")
|
|
||||||
.addFormParam("UserId.1", "bob")
|
|
||||||
.addFormParam("UserId.2", "sue").build();
|
|
||||||
|
|
||||||
public void testAddLaunchPermissionsToImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "addLaunchPermissionsToImageInRegion", String.class,
|
|
||||||
Iterable.class, Iterable.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("bob", "sue"), ImmutableList
|
|
||||||
.of("all"), "imageId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(addLaunchPermission).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest removeLaunchPermission = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "ModifyImageAttribute")
|
|
||||||
.addFormParam("Attribute", "launchPermission")
|
|
||||||
.addFormParam("ImageId", "imageId")
|
|
||||||
.addFormParam("OperationType", "remove")
|
|
||||||
.addFormParam("UserGroup.1", "all")
|
|
||||||
.addFormParam("UserId.1", "bob")
|
|
||||||
.addFormParam("UserId.2", "sue").build();
|
|
||||||
|
|
||||||
public void testRemoveLaunchPermissionsFromImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "removeLaunchPermissionsFromImageInRegion", String.class,
|
|
||||||
Iterable.class, Iterable.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("bob", "sue"), ImmutableList
|
|
||||||
.of("all"), "imageId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(removeLaunchPermission).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest resetLaunchPermissionsOnImage = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "ResetImageAttribute")
|
|
||||||
.addFormParam("Attribute", "launchPermission")
|
|
||||||
.addFormParam("ImageId", "imageId").build();
|
|
||||||
|
|
||||||
public void testResetLaunchPermissionsOnImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "resetLaunchPermissionsOnImageInRegion", String.class,
|
|
||||||
String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request,
|
|
||||||
filter.filter(resetLaunchPermissionsOnImage).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetProductCodesForImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "getProductCodesForImageInRegion", String.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "imageId"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request,
|
|
||||||
"Action=DescribeImageAttribute&Attribute=productCodes&ImageId=imageId",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, ProductCodesHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAddProductCodesToImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "addProductCodesToImageInRegion", String.class, Iterable.class,
|
|
||||||
String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("code1", "code2"), "imageId"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(
|
|
||||||
request,
|
|
||||||
"Action=ModifyImageAttribute&OperationType=add&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRemoveProductCodesFromImage() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(AWSAMIApi.class, "removeProductCodesFromImageInRegion", String.class,
|
|
||||||
Iterable.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, ImmutableList.of("code1", "code2"), "imageId"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(
|
|
||||||
request,
|
|
||||||
"Action=ModifyImageAttribute&OperationType=remove&Attribute=productCodes&ImageId=imageId&ProductCode.1=code1&ProductCode.2=code2",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
|
||||||
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
|
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
|
||||||
import org.jclouds.aws.ec2.xml.AWSEC2DescribeSecurityGroupsResponseHandler;
|
import org.jclouds.aws.ec2.xml.AWSEC2DescribeSecurityGroupsResponseHandler;
|
||||||
import org.jclouds.ec2.util.IpPermissions;
|
import org.jclouds.ec2.util.IpPermissions;
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.functions.ParseSax;
|
import org.jclouds.http.functions.ParseSax;
|
||||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
||||||
import org.jclouds.net.domain.IpPermission;
|
import org.jclouds.net.domain.IpPermission;
|
||||||
|
@ -97,13 +96,6 @@ public class AWSSecurityGroupApiTest extends BaseAWSEC2ApiTest<AWSSecurityGroupA
|
||||||
checkFilters(request);
|
checkFilters(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequest createSecurityGroup = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "CreateSecurityGroup")
|
|
||||||
.addFormParam("GroupDescription", "description")
|
|
||||||
.addFormParam("GroupName", "name").build();
|
|
||||||
|
|
||||||
public void testCreateSecurityGroup() throws SecurityException, NoSuchMethodException, IOException {
|
public void testCreateSecurityGroup() throws SecurityException, NoSuchMethodException, IOException {
|
||||||
Invokable<?, ?> method = method(AWSSecurityGroupApi.class, "createSecurityGroupInRegion", String.class,
|
Invokable<?, ?> method = method(AWSSecurityGroupApi.class, "createSecurityGroupInRegion", String.class,
|
||||||
String.class, String.class);
|
String.class, String.class);
|
||||||
|
@ -113,7 +105,7 @@ public class AWSSecurityGroupApiTest extends BaseAWSEC2ApiTest<AWSSecurityGroupA
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
||||||
assertPayloadEquals(request, filter.filter(createSecurityGroup).getPayload().getRawContent().toString(),
|
assertPayloadEquals(request, "Action=CreateSecurityGroup&GroupName=name&GroupDescription=description&Version=2012-06-01",
|
||||||
"application/x-www-form-urlencoded", false);
|
"application/x-www-form-urlencoded", false);
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
package org.jclouds.aws.ec2.features;
|
package org.jclouds.aws.ec2.features;
|
||||||
|
|
||||||
import static com.google.common.collect.Maps.transformValues;
|
import static com.google.common.collect.Maps.transformValues;
|
||||||
|
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -29,7 +32,8 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.aws.domain.Region;
|
import org.jclouds.aws.domain.Region;
|
||||||
import org.jclouds.aws.ec2.AWSEC2ProviderMetadata;
|
import org.jclouds.aws.ec2.AWSEC2ProviderMetadata;
|
||||||
import org.jclouds.aws.ec2.config.AWSEC2HttpApiModule;
|
import org.jclouds.aws.ec2.config.AWSEC2HttpApiModule;
|
||||||
import org.jclouds.aws.filters.FormSigner;
|
import org.jclouds.aws.filters.FormSignerV4;
|
||||||
|
import org.jclouds.aws.filters.FormSignerV4.ServiceAndRegion;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
import org.jclouds.date.DateService;
|
import org.jclouds.date.DateService;
|
||||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||||
|
@ -49,18 +53,20 @@ import com.google.common.cache.CacheLoader;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.inject.Module;
|
import com.google.inject.Module;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
@Test(groups = "unit")
|
@Test(groups = "unit")
|
||||||
public abstract class BaseAWSEC2ApiTest<T> extends BaseRestAnnotationProcessingTest<T> {
|
public abstract class BaseAWSEC2ApiTest<T> extends BaseRestAnnotationProcessingTest<T> {
|
||||||
|
|
||||||
@ConfiguresHttpApi
|
@ConfiguresHttpApi
|
||||||
protected static class StubAWSEC2HttpApiModule extends AWSEC2HttpApiModule {
|
protected static class StubAWSEC2HttpApiModule extends AWSEC2HttpApiModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String provideTimeStamp(DateService dateService) {
|
protected String provideTimeStamp(DateService dateService) {
|
||||||
return "2009-11-08T15:54:08.897Z";
|
return "20120416T155408Z";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -83,10 +89,10 @@ public abstract class BaseAWSEC2ApiTest<T> extends BaseRestAnnotationProcessingT
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Supplier<URI>> get() {
|
public Map<String, Supplier<URI>> get() {
|
||||||
return transformValues(ImmutableMap.<String, URI> of(Region.EU_WEST_1, URI
|
return transformValues(ImmutableMap
|
||||||
.create("https://ec2.eu-west-1.amazonaws.com"), Region.US_EAST_1, URI
|
.<String, URI>of(Region.EU_WEST_1, URI.create("https://ec2.eu-west-1.amazonaws.com"),
|
||||||
.create("https://ec2.us-east-1.amazonaws.com"), Region.US_WEST_1, URI
|
Region.US_EAST_1, URI.create("https://ec2.us-east-1.amazonaws.com"), Region.US_WEST_1,
|
||||||
.create("https://ec2.us-west-1.amazonaws.com")), Suppliers2.<URI> ofInstanceFunction());
|
URI.create("https://ec2.us-west-1.amazonaws.com")), Suppliers2.<URI>ofInstanceFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -100,21 +106,49 @@ public abstract class BaseAWSEC2ApiTest<T> extends BaseRestAnnotationProcessingT
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides ServiceAndRegion ServiceAndRegion(){
|
||||||
|
return new ServiceAndRegion() {
|
||||||
|
@Override public String service() {
|
||||||
|
return "ec2";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String region(String host) {
|
||||||
|
return "us-east-1";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FormSigner filter;
|
@Override protected void assertNonPayloadHeadersEqual(HttpRequest request, String toMatch) {
|
||||||
|
Multimap<String, String> headersToCheck = LinkedHashMultimap.create();
|
||||||
|
for (String key : request.getHeaders().keySet()) {
|
||||||
|
if (key.equals("X-Amz-Date")) {
|
||||||
|
assertEquals(request.getFirstHeaderOrNull(key), "20120416T155408Z");
|
||||||
|
} else if (key.equals("Authorization")) {
|
||||||
|
assertThat(request.getFirstHeaderOrNull(AUTHORIZATION)).startsWith(
|
||||||
|
"AWS4-HMAC-SHA256 Credential=identity/20120416/"
|
||||||
|
+ "us-east-1/ec2/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=");
|
||||||
|
} else {
|
||||||
|
headersToCheck.putAll(key, request.getHeaders().get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(sortAndConcatHeadersIntoString(headersToCheck), toMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FormSignerV4 filter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkFilters(HttpRequest request) {
|
protected void checkFilters(HttpRequest request) {
|
||||||
assertEquals(request.getFilters().size(), 1);
|
assertEquals(request.getFilters().size(), 1);
|
||||||
assertEquals(request.getFilters().get(0).getClass(), FormSigner.class);
|
assertTrue(request.getFilters().get(0) instanceof FormSignerV4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
protected void setupFactory() throws IOException {
|
protected void setupFactory() throws IOException {
|
||||||
super.setupFactory();
|
super.setupFactory();
|
||||||
this.filter = injector.getInstance(FormSigner.class);
|
this.filter = injector.getInstance(FormSignerV4.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.features;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.MonitoringState;
|
||||||
|
import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
@Test(groups = "unit", testName = "MonitoringApiMockTest", singleThreaded = true)
|
||||||
|
public class MonitoringApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||||
|
|
||||||
|
public void monitorInstancesInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/monitoring.xml");
|
||||||
|
|
||||||
|
Map<String, MonitoringState> result = monitoringApi()
|
||||||
|
.monitorInstancesInRegion(DEFAULT_REGION, "i-911444f0", "i-911444f1");
|
||||||
|
|
||||||
|
assertFalse(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=MonitorInstances&InstanceId.0=i-911444f0&InstanceId.1=i-911444f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unmonitorInstancesInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/monitoring.xml");
|
||||||
|
|
||||||
|
Map<String, MonitoringState> result = monitoringApi()
|
||||||
|
.unmonitorInstancesInRegion(DEFAULT_REGION, "i-911444f0", "i-911444f1");
|
||||||
|
|
||||||
|
assertFalse(result.isEmpty());
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=UnmonitorInstances&InstanceId.0=i-911444f0&InstanceId.1=i-911444f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MonitoringApi monitoringApi() {
|
||||||
|
return api().getMonitoringApi().get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,71 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.features;
|
|
||||||
|
|
||||||
import static org.jclouds.reflect.Reflection2.method;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.jclouds.aws.ec2.xml.MonitoringStateHandler;
|
|
||||||
import org.jclouds.http.functions.ParseSax;
|
|
||||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.reflect.Invokable;
|
|
||||||
/**
|
|
||||||
* Tests behavior of {@code MonitoringApi}
|
|
||||||
*/
|
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
|
||||||
@Test(groups = "unit", testName = "MonitoringApiTest")
|
|
||||||
public class MonitoringApiTest extends BaseAWSEC2ApiTest<MonitoringApi> {
|
|
||||||
|
|
||||||
public void testUnmonitorInstances() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(MonitoringApi.class, "unmonitorInstancesInRegion", String.class, String.class,
|
|
||||||
String[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "instance1", "instance2"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
String payload = "Action=UnmonitorInstances&InstanceId.0=instance1&InstanceId.1=instance2";
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, payload, "application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, MonitoringStateHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testMonitorInstances() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(MonitoringApi.class, "monitorInstancesInRegion", String.class, String.class,
|
|
||||||
String[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "instance1", "instance2"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request,
|
|
||||||
"Action=MonitorInstances&InstanceId.0=instance1&InstanceId.1=instance2",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, MonitoringStateHandler.class);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.features;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
|
|
||||||
import org.jclouds.aws.ec2.AWSEC2Api;
|
|
||||||
import org.jclouds.aws.ec2.compute.internal.BaseAWSEC2ComputeServiceExpectTest;
|
|
||||||
import org.jclouds.aws.ec2.domain.PlacementGroup;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.HttpResponse;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
|
|
||||||
@Test(groups = "unit", testName = "PlacementGroupApiExpectTest")
|
|
||||||
public class PlacementGroupApiExpectTest extends BaseAWSEC2ComputeServiceExpectTest {
|
|
||||||
|
|
||||||
HttpRequest filter = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribePlacementGroups")
|
|
||||||
.addFormParam("Filter.1.Name", "strategy")
|
|
||||||
.addFormParam("Filter.1.Value.1", "cluster")
|
|
||||||
.addFormParam("Signature", "SaA7Un1BE3m9jIEKyjXNdQPzFh/QAJSCebvKXiwUEK0%3D")
|
|
||||||
.addFormParam("SignatureMethod", "HmacSHA256")
|
|
||||||
.addFormParam("SignatureVersion", "2")
|
|
||||||
.addFormParam("Timestamp", "2012-04-16T15%3A54%3A08.897Z")
|
|
||||||
.addFormParam("Version", "2012-06-01")
|
|
||||||
.addFormParam("AWSAccessKeyId", "identity").build();
|
|
||||||
|
|
||||||
public void testFilterWhenResponseIs2xx() {
|
|
||||||
HttpResponse filterResponse = HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType("/describe_placement_groups.xml", "text/xml")).build();
|
|
||||||
|
|
||||||
AWSEC2Api apiWhenExist = requestsSendResponses(describeRegionsRequest, describeRegionsResponse, filter, filterResponse)
|
|
||||||
.getContext().unwrapApi(AWSEC2Api.class);
|
|
||||||
|
|
||||||
PlacementGroup group = getOnlyElement(apiWhenExist.getPlacementGroupApi().get().describePlacementGroupsInRegionWithFilter("us-east-1",
|
|
||||||
ImmutableMultimap.<String, String>builder()
|
|
||||||
.put("strategy", "cluster")
|
|
||||||
.build()));
|
|
||||||
|
|
||||||
assertEquals(group.getName(), "XYZ-cluster");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testFilterWhenResponseIs404() {
|
|
||||||
HttpResponse filterResponse = HttpResponse.builder().statusCode(404).build();
|
|
||||||
|
|
||||||
AWSEC2Api apiWhenNotExist = requestsSendResponses(describeRegionsRequest, describeRegionsResponse, filter, filterResponse)
|
|
||||||
.getContext().unwrapApi(AWSEC2Api.class);
|
|
||||||
|
|
||||||
assertEquals(apiWhenNotExist.getPlacementGroupApi().get().describePlacementGroupsInRegionWithFilter("us-east-1",
|
|
||||||
ImmutableMultimap.<String, String>builder()
|
|
||||||
.put("strategy", "cluster")
|
|
||||||
.build()),
|
|
||||||
ImmutableSet.of());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.features;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.PlacementGroup;
|
||||||
|
import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockResponse;
|
||||||
|
|
||||||
|
@Test(groups = "unit", testName = "PlacementGroupApiMockTest", singleThreaded = true)
|
||||||
|
public class PlacementGroupApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||||
|
|
||||||
|
public void describePlacementGroupsInRegionWithFilter() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_placement_groups.xml");
|
||||||
|
|
||||||
|
PlacementGroup result = getOnlyElement(placementApi()
|
||||||
|
.describePlacementGroupsInRegionWithFilter(DEFAULT_REGION, ImmutableMultimap.of("strategy", "cluster")));
|
||||||
|
|
||||||
|
assertEquals(result.getName(), "XYZ-cluster");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribePlacementGroups&Filter.1.Name=strategy&Filter.1.Value.1=cluster");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describePlacementGroupsInRegionWithFilter_404() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
|
||||||
|
|
||||||
|
assertEquals(placementApi().describePlacementGroupsInRegionWithFilter(DEFAULT_REGION,
|
||||||
|
ImmutableMultimap.of("strategy", "cluster")), ImmutableSet.of());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribePlacementGroups&Filter.1.Name=strategy&Filter.1.Value.1=cluster");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deletePlacementGroupInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
placementApi().deletePlacementGroupInRegion(DEFAULT_REGION, "name");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DeletePlacementGroup&GroupName=name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deletePlacementGroupInRegion_404() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
|
||||||
|
|
||||||
|
placementApi().deletePlacementGroupInRegion(DEFAULT_REGION, "name");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DeletePlacementGroup&GroupName=name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createPlacementGroupInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
placementApi().createPlacementGroupInRegion(DEFAULT_REGION, "name");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreatePlacementGroup&Strategy=cluster&GroupName=name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createPlacementGroupInRegion_strategy() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
placementApi().createPlacementGroupInRegion(DEFAULT_REGION, "name", "cluster");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CreatePlacementGroup&GroupName=name&Strategy=cluster");
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlacementGroupApi placementApi() {
|
||||||
|
return api().getPlacementGroupApi().get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,134 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.features;
|
|
||||||
|
|
||||||
import static org.jclouds.reflect.Reflection2.method;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
|
|
||||||
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
|
|
||||||
import org.jclouds.aws.ec2.xml.DescribePlacementGroupsResponseHandler;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.functions.ParseSax;
|
|
||||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
|
||||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.reflect.Invokable;
|
|
||||||
/**
|
|
||||||
* Tests behavior of {@code PlacementGroupApi}
|
|
||||||
*/
|
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
|
||||||
@Test(groups = "unit", testName = "PlacementGroupApiTest")
|
|
||||||
public class PlacementGroupApiTest extends BaseAWSEC2ApiTest<PlacementGroupApi> {
|
|
||||||
|
|
||||||
public void testDeletePlacementGroup() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(PlacementGroupApi.class, "deletePlacementGroupInRegion", String.class,
|
|
||||||
String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, "Action=DeletePlacementGroup&GroupName=name",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, VoidOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpRequest createPlacementGroup = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "CreatePlacementGroup")
|
|
||||||
.addFormParam("GroupName", "name")
|
|
||||||
.addFormParam("Strategy", "cluster").build();
|
|
||||||
|
|
||||||
public void testCreatePlacementGroup() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(PlacementGroupApi.class, "createPlacementGroupInRegion", String.class,
|
|
||||||
String.class, String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name", "cluster"));
|
|
||||||
|
|
||||||
request = (GeneratedHttpRequest) request.getFilters().get(0).filter(request);
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, filter.filter(createPlacementGroup).getPayload().getRawContent().toString(),
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testCreatePlacementGroupDefault() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(PlacementGroupApi.class, "createPlacementGroupInRegion", String.class,
|
|
||||||
String.class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "name"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, "Action=CreatePlacementGroup&Strategy=cluster&GroupName=name",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, null);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDescribePlacementGroups() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(PlacementGroupApi.class, "describePlacementGroupsInRegion", String.class,
|
|
||||||
String[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList((String) null));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, "Action=DescribePlacementGroups",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, DescribePlacementGroupsResponseHandler.class);
|
|
||||||
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDescribePlacementGroupsArgs() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(PlacementGroupApi.class, "describePlacementGroupsInRegion", String.class,
|
|
||||||
String[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "1", "2"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, "Action=DescribePlacementGroups&GroupName.1=1&GroupName.2=2",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, DescribePlacementGroupsResponseHandler.class);
|
|
||||||
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.features;
|
|
||||||
|
|
||||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
|
|
||||||
import org.jclouds.aws.ec2.AWSEC2Api;
|
|
||||||
import org.jclouds.aws.ec2.compute.internal.BaseAWSEC2ComputeServiceExpectTest;
|
|
||||||
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
|
||||||
import org.jclouds.http.HttpRequest;
|
|
||||||
import org.jclouds.http.HttpResponse;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
|
|
||||||
@Test(groups = "unit", testName = "SpotInstanceApiExpectTest")
|
|
||||||
public class SpotInstanceApiExpectTest extends BaseAWSEC2ComputeServiceExpectTest {
|
|
||||||
|
|
||||||
HttpRequest filter = HttpRequest.builder().method("POST")
|
|
||||||
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
|
||||||
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
|
||||||
.addFormParam("Action", "DescribeSpotInstanceRequests")
|
|
||||||
.addFormParam("Filter.1.Name", "instance-id")
|
|
||||||
.addFormParam("Filter.1.Value.1", "i-ef308e8e")
|
|
||||||
.addFormParam("Signature", "wQtGpumMCDEzvlldKepCKeEjD9iE7eAyiRBlQztcJMA%3D")
|
|
||||||
.addFormParam("SignatureMethod", "HmacSHA256")
|
|
||||||
.addFormParam("SignatureVersion", "2")
|
|
||||||
.addFormParam("Timestamp", "2012-04-16T15%3A54%3A08.897Z")
|
|
||||||
.addFormParam("Version", "2012-06-01")
|
|
||||||
.addFormParam("AWSAccessKeyId", "identity").build();
|
|
||||||
|
|
||||||
public void testFilterWhenResponseIs2xx() {
|
|
||||||
HttpResponse filterResponse = HttpResponse.builder().statusCode(200)
|
|
||||||
.payload(payloadFromResourceWithContentType("/describe_spot_instance.xml", "text/xml")).build();
|
|
||||||
|
|
||||||
AWSEC2Api apiWhenExist = requestsSendResponses(describeRegionsRequest, describeRegionsResponse, filter, filterResponse)
|
|
||||||
.getContext().unwrapApi(AWSEC2Api.class);
|
|
||||||
|
|
||||||
SpotInstanceRequest request = getOnlyElement(apiWhenExist.getSpotInstanceApi().get().describeSpotInstanceRequestsInRegionWithFilter("us-east-1",
|
|
||||||
ImmutableMultimap.<String, String>builder()
|
|
||||||
.put("instance-id", "i-ef308e8e")
|
|
||||||
.build()));
|
|
||||||
|
|
||||||
assertEquals(request.getId(), "sir-1ede0012");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testFilterWhenResponseIs404() {
|
|
||||||
HttpResponse filterResponse = HttpResponse.builder().statusCode(404).build();
|
|
||||||
|
|
||||||
AWSEC2Api apiWhenNotExist = requestsSendResponses(describeRegionsRequest, describeRegionsResponse, filter, filterResponse)
|
|
||||||
.getContext().unwrapApi(AWSEC2Api.class);
|
|
||||||
|
|
||||||
assertEquals(apiWhenNotExist.getSpotInstanceApi().get().describeSpotInstanceRequestsInRegionWithFilter("us-east-1",
|
|
||||||
ImmutableMultimap.<String, String>builder()
|
|
||||||
.put("instance-id", "i-ef308e8e")
|
|
||||||
.build()),
|
|
||||||
ImmutableSet.of());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.features;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||||
|
import static org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions.Builder.from;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.aws.ec2.domain.Spot;
|
||||||
|
import org.jclouds.aws.ec2.domain.SpotInstanceRequest;
|
||||||
|
import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockResponse;
|
||||||
|
|
||||||
|
@Test(groups = "unit", testName = "SpotInstanceApiMockTest", singleThreaded = true)
|
||||||
|
public class SpotInstanceApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||||
|
|
||||||
|
public void describeSpotInstanceRequestsInRegionWithFilter() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_spot_instance.xml");
|
||||||
|
|
||||||
|
SpotInstanceRequest result = getOnlyElement(spotApi()
|
||||||
|
.describeSpotInstanceRequestsInRegionWithFilter(DEFAULT_REGION,
|
||||||
|
ImmutableMultimap.of("instance-id", "i-ef308e8e")));
|
||||||
|
|
||||||
|
assertEquals(result.getId(), "sir-1ede0012");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&Filter.1.Name=instance-id&Filter.1.Value.1=i-ef308e8e");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describeSpotInstanceRequestsInRegionWithFilter_404() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
|
||||||
|
|
||||||
|
assertEquals(spotApi().describeSpotInstanceRequestsInRegionWithFilter(DEFAULT_REGION,
|
||||||
|
ImmutableMultimap.of("instance-id", "i-ef308e8e")), ImmutableSet.of());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&Filter.1.Name=instance-id&Filter.1.Value.1=i-ef308e8e");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelSpotInstanceRequestsInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse());
|
||||||
|
|
||||||
|
spotApi().cancelSpotInstanceRequestsInRegion(DEFAULT_REGION, "sir-f4d44212");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CancelSpotInstanceRequests&SpotInstanceRequestId.1=sir-f4d44212");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelSpotInstanceRequestsInRegion_404() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
|
||||||
|
|
||||||
|
spotApi().cancelSpotInstanceRequestsInRegion(DEFAULT_REGION, "sir-f4d44212");
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=CancelSpotInstanceRequests&SpotInstanceRequestId.1=sir-f4d44212");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describeSpotPriceHistoryInRegion() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_spot_price_history.xml");
|
||||||
|
|
||||||
|
Set<Spot> result = spotApi().describeSpotPriceHistoryInRegion(DEFAULT_REGION);
|
||||||
|
|
||||||
|
assertEquals(result.size(), 3);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotPriceHistory");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describeSpotPriceHistoryInRegion_404() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
|
||||||
|
|
||||||
|
Set<Spot> result = spotApi().describeSpotPriceHistoryInRegion(DEFAULT_REGION);
|
||||||
|
|
||||||
|
assertTrue(result.isEmpty());
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotPriceHistory");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void describeSpotPriceHistoryInRegionOptions() throws Exception {
|
||||||
|
enqueueRegions(DEFAULT_REGION);
|
||||||
|
enqueueXml(DEFAULT_REGION, "/describe_spot_price_history.xml");
|
||||||
|
|
||||||
|
Date from = new Date(12345678910l);
|
||||||
|
Date to = new Date(1234567891011l);
|
||||||
|
|
||||||
|
Set<Spot> result = spotApi().describeSpotPriceHistoryInRegion(DEFAULT_REGION,
|
||||||
|
from(from).to(to).productDescription("description").instanceType("m1.small"));
|
||||||
|
|
||||||
|
assertEquals(result.size(), 3);
|
||||||
|
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||||
|
assertPosted(DEFAULT_REGION, "Action=DescribeSpotPriceHistory&StartTime=1970-05-23T21%3A21%3A18.910Z&EndTime=2009-02-13T23%3A31%3A31.011Z&ProductDescription=description&InstanceType.1=m1.small");
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpotInstanceApi spotApi() {
|
||||||
|
return api().getSpotInstanceApi().get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF 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.aws.ec2.features;
|
|
||||||
|
|
||||||
import static org.jclouds.reflect.Reflection2.method;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
|
|
||||||
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
|
|
||||||
import org.jclouds.aws.ec2.options.DescribeSpotPriceHistoryOptions;
|
|
||||||
import org.jclouds.aws.ec2.xml.DescribeSpotPriceHistoryResponseHandler;
|
|
||||||
import org.jclouds.http.functions.ParseSax;
|
|
||||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
|
||||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.reflect.Invokable;
|
|
||||||
/**
|
|
||||||
* Tests behavior of {@code SpotInstanceApi}
|
|
||||||
*/
|
|
||||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
|
||||||
@Test(groups = "unit", testName = "SpotInstanceApiTest")
|
|
||||||
public class SpotInstanceApiTest extends BaseAWSEC2ApiTest<SpotInstanceApi> {
|
|
||||||
|
|
||||||
public void testCancelSpotInstanceRequests() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(SpotInstanceApi.class, "cancelSpotInstanceRequestsInRegion", String.class,
|
|
||||||
String[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, "id"));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, "Action=CancelSpotInstanceRequests&SpotInstanceRequestId.1=id",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, null);
|
|
||||||
assertFallbackClassEquals(method, VoidOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDescribeSpotPriceHistory() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(SpotInstanceApi.class, "describeSpotPriceHistoryInRegion", String.class,
|
|
||||||
DescribeSpotPriceHistoryOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList((String) null));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(request, "Action=DescribeSpotPriceHistory",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, DescribeSpotPriceHistoryResponseHandler.class);
|
|
||||||
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
Date from = new Date(12345678910l);
|
|
||||||
Date to = new Date(1234567891011l);
|
|
||||||
|
|
||||||
public void testDescribeSpotPriceHistoryArgs() throws SecurityException, NoSuchMethodException, IOException {
|
|
||||||
Invokable<?, ?> method = method(SpotInstanceApi.class, "describeSpotPriceHistoryInRegion", String.class,
|
|
||||||
DescribeSpotPriceHistoryOptions[].class);
|
|
||||||
GeneratedHttpRequest request = processor.createRequest(method, Lists.<Object> newArrayList(null, DescribeSpotPriceHistoryOptions.Builder.from(from)
|
|
||||||
.to(to).productDescription("description").instanceType("m1.small")));
|
|
||||||
|
|
||||||
assertRequestLineEquals(request, "POST https://ec2.us-east-1.amazonaws.com/ HTTP/1.1");
|
|
||||||
assertNonPayloadHeadersEqual(request, "Host: ec2.us-east-1.amazonaws.com\n");
|
|
||||||
assertPayloadEquals(
|
|
||||||
request,
|
|
||||||
"Action=DescribeSpotPriceHistory&StartTime=1970-05-23T21%3A21%3A18.910Z&EndTime=2009-02-13T23%3A31%3A31.011Z&ProductDescription=description&InstanceType.1=m1.small",
|
|
||||||
"application/x-www-form-urlencoded", false);
|
|
||||||
|
|
||||||
assertResponseParserClassEquals(method, request, ParseSax.class);
|
|
||||||
assertSaxResponseParserClassEquals(method, DescribeSpotPriceHistoryResponseHandler.class);
|
|
||||||
assertFallbackClassEquals(method, EmptySetOnNotFoundOr404.class);
|
|
||||||
|
|
||||||
checkFilters(request);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF 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.aws.ec2.internal;
|
||||||
|
|
||||||
|
import static com.google.common.base.Throwables.propagate;
|
||||||
|
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
|
||||||
|
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
|
||||||
|
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
|
||||||
|
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.jclouds.aws.filters.FormSignerV4.ServiceAndRegion;
|
||||||
|
import static org.jclouds.util.Strings2.toStringAndClose;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.ContextBuilder;
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2Api;
|
||||||
|
import org.jclouds.aws.ec2.AWSEC2ProviderMetadata;
|
||||||
|
import org.jclouds.aws.ec2.config.AWSEC2HttpApiModule;
|
||||||
|
import org.jclouds.compute.ComputeService;
|
||||||
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
|
import org.jclouds.date.DateService;
|
||||||
|
import org.jclouds.rest.ConfiguresHttpApi;
|
||||||
|
import org.testng.annotations.AfterMethod;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockResponse;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockWebServer;
|
||||||
|
import com.squareup.okhttp.mockwebserver.RecordedRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests need to run {@code singleThreaded = true) as otherwise tests will clash on the regionToServers field.
|
||||||
|
* Sharing the regionToServers field means less code to write.
|
||||||
|
*/
|
||||||
|
public class BaseAWSEC2ApiMockTest {
|
||||||
|
protected static final String DEFAULT_REGION = "us-east-1";
|
||||||
|
|
||||||
|
// Example keys from http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
|
||||||
|
private static final String ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE";
|
||||||
|
private static final String SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
|
||||||
|
|
||||||
|
private Map<String, MockWebServer> regionToServers = Maps.newLinkedHashMap();
|
||||||
|
|
||||||
|
protected AWSEC2Api api() {
|
||||||
|
return builder(new Properties()).buildApi(AWSEC2Api.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ComputeService computeService() {
|
||||||
|
return builder(new Properties()).buildView(ComputeServiceContext.class).getComputeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContextBuilder builder(Properties overrides) {
|
||||||
|
overrides.setProperty(Constants.PROPERTY_MAX_RETRIES, "1");
|
||||||
|
return ContextBuilder.newBuilder(new AWSEC2ProviderMetadata())
|
||||||
|
.credentials(ACCESS_KEY, SECRET_KEY)
|
||||||
|
.endpoint("http://localhost:" + regionToServers.get(DEFAULT_REGION).getPort())
|
||||||
|
.overrides(overrides)
|
||||||
|
.modules(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Set<Module> modules = ImmutableSet
|
||||||
|
.<Module>of(new MockAWSEC2HttpApiModule(), new ExecutorServiceModule(sameThreadExecutor()));
|
||||||
|
|
||||||
|
@ConfiguresHttpApi
|
||||||
|
class MockAWSEC2HttpApiModule extends AWSEC2HttpApiModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String provideTimeStamp(DateService dateService) {
|
||||||
|
return "20120416T155408Z";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides ServiceAndRegion serviceAndRegion(){
|
||||||
|
return new ServiceAndRegion() {
|
||||||
|
@Override public String service() {
|
||||||
|
return "ec2";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String region(String host) {
|
||||||
|
for (Map.Entry<String, MockWebServer> regionToServer : regionToServers.entrySet()) {
|
||||||
|
if (host.equals("localhost:" + regionToServer.getValue().getPort())) {
|
||||||
|
return regionToServer.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(host + " not found");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void start() throws IOException {
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.play();
|
||||||
|
regionToServers.put(DEFAULT_REGION, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterMethod(alwaysRun = true)
|
||||||
|
public void stop() throws IOException {
|
||||||
|
for (MockWebServer server : regionToServers.values()) {
|
||||||
|
server.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void enqueue(String region, MockResponse response) {
|
||||||
|
regionToServers.get(region).enqueue(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void enqueueRegions(String... regions) throws IOException {
|
||||||
|
StringBuilder describeRegionsResponse = new StringBuilder();
|
||||||
|
describeRegionsResponse.append("<DescribeRegionsResponse>");
|
||||||
|
for (String region : regions) {
|
||||||
|
describeRegionsResponse.append("<item>");
|
||||||
|
describeRegionsResponse.append("<regionName>").append(region).append("</regionName>");
|
||||||
|
if (!regionToServers.containsKey(region)) {
|
||||||
|
MockWebServer server = new MockWebServer();
|
||||||
|
server.play();
|
||||||
|
regionToServers.put(region, server);
|
||||||
|
}
|
||||||
|
String regionEndpoint = "http://localhost:" + regionToServers.get(region).getPort();
|
||||||
|
describeRegionsResponse.append("<regionEndpoint>").append(regionEndpoint).append("</regionEndpoint>");
|
||||||
|
describeRegionsResponse.append("</item>");
|
||||||
|
}
|
||||||
|
describeRegionsResponse.append("</DescribeRegionsResponse>");
|
||||||
|
enqueue(DEFAULT_REGION,
|
||||||
|
new MockResponse().addHeader(CONTENT_TYPE, APPLICATION_XML).setBody(describeRegionsResponse.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void enqueueXml(String region, String resource) {
|
||||||
|
enqueue(region,
|
||||||
|
new MockResponse().addHeader(CONTENT_TYPE, APPLICATION_XML).setBody(stringFromResource(resource)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String stringFromResource(String resourceName) {
|
||||||
|
try {
|
||||||
|
return toStringAndClose(getClass().getResourceAsStream(resourceName));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw propagate(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RecordedRequest assertPosted(String region, String postParams) throws InterruptedException {
|
||||||
|
RecordedRequest request = regionToServers.get(region).takeRequest();
|
||||||
|
assertEquals(request.getMethod(), "POST");
|
||||||
|
assertEquals(request.getPath(), "/");
|
||||||
|
assertEquals(request.getHeader("X-Amz-Date"), "20120416T155408Z");
|
||||||
|
assertThat(
|
||||||
|
request.getHeader(AUTHORIZATION)).startsWith("AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20120416/" +
|
||||||
|
region + "/ec2/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=");
|
||||||
|
String body = new String(request.getBody(), Charsets.UTF_8);
|
||||||
|
assertThat(body).contains("&Version=2012-06-01");
|
||||||
|
assertEquals(body.replace("&Version=2012-06-01", ""), postParams);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue