mirror of
https://github.com/apache/jclouds.git
synced 2025-02-10 03:56:27 +00:00
Add ModifySubnetAttribute
This commit is contained in:
parent
f7390443db
commit
c0f3eb6071
@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.Ordering.natural;
|
||||
import static com.google.common.io.BaseEncoding.base64;
|
||||
import static com.google.common.io.ByteStreams.readBytes;
|
||||
import static org.jclouds.aws.filters.FormSignerUtils.getAnnotatedApiVersion;
|
||||
import static org.jclouds.aws.reference.FormParameters.ACTION;
|
||||
import static org.jclouds.aws.reference.FormParameters.AWS_ACCESS_KEY_ID;
|
||||
import static org.jclouds.aws.reference.FormParameters.SECURITY_TOKEN;
|
||||
@ -59,6 +60,7 @@ import org.jclouds.rest.annotations.ApiVersion;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@ -100,7 +102,15 @@ public interface FormSigner extends HttpRequestFilter {
|
||||
public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
checkNotNull(request.getFirstHeaderOrNull(HttpHeaders.HOST), "request is not ready to sign; host not present");
|
||||
Multimap<String, String> decodedParams = queryParser().apply(request.getPayload().getRawContent().toString());
|
||||
decodedParams.replaceValues(VERSION, ImmutableSet.of(apiVersion));
|
||||
Optional<String> optAnnotatedVersion = getAnnotatedApiVersion(request);
|
||||
String version;
|
||||
if (optAnnotatedVersion.isPresent()) {
|
||||
String annotatedVersion = optAnnotatedVersion.get();
|
||||
version = annotatedVersion.compareTo(apiVersion) > 0 ? annotatedVersion : apiVersion;
|
||||
} else {
|
||||
version = apiVersion;
|
||||
}
|
||||
decodedParams.replaceValues(VERSION, ImmutableSet.of(version));
|
||||
addSigningParams(decodedParams);
|
||||
validateParams(decodedParams);
|
||||
String stringToSign = createStringToSign(request, decodedParams);
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.annotations.SinceApiVersion;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.reflect.Invokable;
|
||||
|
||||
/**
|
||||
* Utilities for FormSigner implementations.
|
||||
*/
|
||||
public final class FormSignerUtils {
|
||||
|
||||
private FormSignerUtils() {}
|
||||
|
||||
/**
|
||||
* Get the version from a @SinceApiVersion() annotation on an API method or its owning class.
|
||||
* @param request The API request for the method.
|
||||
* @return An optional of the value of the annotation.
|
||||
*/
|
||||
public static Optional<String> getAnnotatedApiVersion(HttpRequest request) {
|
||||
if (request instanceof GeneratedHttpRequest) {
|
||||
GeneratedHttpRequest generatedRequest = (GeneratedHttpRequest) request;
|
||||
return getAnnotatedApiVersion(generatedRequest.getInvocation());
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> getAnnotatedApiVersion(Invocation invocation) {
|
||||
final Invokable<?, ?> invokable = invocation.getInvokable();
|
||||
if (invokable.isAnnotationPresent(SinceApiVersion.class)) {
|
||||
return Optional.fromNullable(invokable.getAnnotation(SinceApiVersion.class).value());
|
||||
} else {
|
||||
final Class<?> owner = invokable.getOwnerType().getRawType();
|
||||
if (owner.isAnnotationPresent(SinceApiVersion.class)) {
|
||||
return Optional.fromNullable(owner.getAnnotation(SinceApiVersion.class).value());
|
||||
}
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
}
|
@ -23,6 +23,7 @@ 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 org.jclouds.aws.filters.FormSignerUtils.getAnnotatedApiVersion;
|
||||
import static org.jclouds.aws.reference.FormParameters.ACTION;
|
||||
import static org.jclouds.aws.reference.FormParameters.VERSION;
|
||||
import static org.jclouds.http.utils.Queries.queryParser;
|
||||
@ -46,6 +47,7 @@ import org.jclouds.providers.ProviderMetadata;
|
||||
import org.jclouds.rest.annotations.ApiVersion;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@ -101,7 +103,18 @@ public final class FormSignerV4 implements FormSigner {
|
||||
this.serviceAndRegion = serviceAndRegion;
|
||||
}
|
||||
|
||||
@Override public HttpRequest filter(HttpRequest request) throws HttpException {
|
||||
/**
|
||||
* Adds the Authorization header to the request.
|
||||
*
|
||||
* Also if the method for the operation (or its class) is annotated with a version that is higher than the
|
||||
* default (apiVersion), then the Version parameter of the request is set to be the value from the annotation.
|
||||
*
|
||||
* @param request The HTTP request for the API call.
|
||||
* @return The request
|
||||
* @throws HttpException
|
||||
*/
|
||||
@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();
|
||||
@ -126,7 +139,15 @@ public final class FormSignerV4 implements FormSigner {
|
||||
.replaceHeader("X-Amz-Date", timestamp);
|
||||
|
||||
if (!decodedParams.containsKey(VERSION)) {
|
||||
requestBuilder.addFormParam(VERSION, apiVersion);
|
||||
Optional<String> optAnnotatedVersion = getAnnotatedApiVersion(request);
|
||||
if (optAnnotatedVersion.isPresent()) {
|
||||
String annotatedVersion = optAnnotatedVersion.get();
|
||||
// allow an explicit version annotation to _upgrade_ the version past apiVersion (but not downgrade)
|
||||
String greater = annotatedVersion.compareTo(apiVersion) > 0 ? annotatedVersion : apiVersion;
|
||||
requestBuilder.addFormParam(VERSION, greater);
|
||||
} else {
|
||||
requestBuilder.addFormParam(VERSION, apiVersion);
|
||||
}
|
||||
}
|
||||
|
||||
Credentials credentials = creds.get();
|
||||
|
@ -25,6 +25,8 @@ import javax.ws.rs.Path;
|
||||
|
||||
import org.jclouds.Fallbacks;
|
||||
import org.jclouds.aws.ec2.options.CreateSubnetOptions;
|
||||
import org.jclouds.aws.ec2.options.ModifySubnetAttributeOptions;
|
||||
import org.jclouds.aws.ec2.xml.ReturnValueHandler;
|
||||
import org.jclouds.aws.filters.FormSigner;
|
||||
import org.jclouds.ec2.binders.BindFiltersToIndexedFormParams;
|
||||
import org.jclouds.ec2.binders.BindSubnetIdsToIndexedFormParams;
|
||||
@ -130,4 +132,24 @@ public interface AWSSubnetApi extends SubnetApi {
|
||||
FluentIterable<Subnet> describeSubnetsInRegionWithFilter(
|
||||
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
|
||||
@BinderParam(BindFiltersToIndexedFormParams.class) Multimap<String, String> filter);
|
||||
|
||||
/**
|
||||
* Modifies a subnet attribute. You can only modify one attribute at a time.
|
||||
*
|
||||
* @param region The region for the subnet
|
||||
* @param subnetId The ID of the subnet
|
||||
* @param options The options containing the attribute to modify. You can only modify one attribute at a time.
|
||||
* @return true if the modification was successful
|
||||
*/
|
||||
@SinceApiVersion("2014-06-15")
|
||||
@Named("ModifySubnetAttribute")
|
||||
@POST
|
||||
@Path("/")
|
||||
@FormParams(keys = ACTION, values = "ModifySubnetAttribute")
|
||||
@XMLResponseParser(ReturnValueHandler.class)
|
||||
@Fallback(Fallbacks.FalseOnNotFoundOr404.class)
|
||||
boolean modifySubnetAttribute(
|
||||
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
|
||||
@FormParam("SubnetId") String subnetId,
|
||||
ModifySubnetAttributeOptions options);
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.jclouds.ec2.options.internal.BaseEC2RequestOptions;
|
||||
import org.jclouds.rest.annotations.SinceApiVersion;
|
||||
|
||||
/**
|
||||
* Contains options supported in the Form API for the ModifySubnetAttribute
|
||||
* operation. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a ModifySubnetAttributeOptions
|
||||
* object is to statically import ModifySubnetAttributeOptions.Builder.* and
|
||||
* invoke a static creation method followed by an instance mutator (if needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.aws.ec2.options.ModifySubnetAttributeOptions.Builder.*
|
||||
* <p/>
|
||||
* group = connection.getAWSSubnetApi().modifySubnetAttribute(region, subnetId, mapPublicIpOnLaunch(true));
|
||||
* <code>
|
||||
*
|
||||
* @see <a href=
|
||||
* "http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifySubnetAttribute.html"
|
||||
* />
|
||||
*/
|
||||
@SinceApiVersion("2014-06-15")
|
||||
public class ModifySubnetAttributeOptions extends BaseEC2RequestOptions {
|
||||
|
||||
/**
|
||||
* The Availability Zone for the subnet.
|
||||
*/
|
||||
public ModifySubnetAttributeOptions assignIpv6AddressOnCreation(Boolean assignIpv6AddressOnCreation) {
|
||||
formParameters.put("AssignIpv6AddressOnCreation.Value",
|
||||
checkNotNull(assignIpv6AddressOnCreation, "assignIpv6AddressOnCreation").toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean isAssignIpv6AddressOnCreation() {
|
||||
return Boolean.parseBoolean("AssignIpv6AddressOnCreation.Value");
|
||||
}
|
||||
|
||||
public ModifySubnetAttributeOptions mapPublicIpOnLaunch(Boolean mapPublicIpOnLaunch) {
|
||||
formParameters.put("MapPublicIpOnLaunch.Value",
|
||||
checkNotNull(mapPublicIpOnLaunch, "mapPublicIpOnLaunch").toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Boolean isMapPublicIpOnLaunch() {
|
||||
return Boolean.parseBoolean(getFirstFormOrNull("MapPublicIpOnLaunch.Value"));
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see ModifySubnetAttributeOptions#assignIpv6AddressOnCreation(Boolean )
|
||||
*/
|
||||
public static ModifySubnetAttributeOptions assignIpv6AddressOnCreation(Boolean assignIpv6AddressOnCreation) {
|
||||
ModifySubnetAttributeOptions options = new ModifySubnetAttributeOptions();
|
||||
return options.assignIpv6AddressOnCreation(assignIpv6AddressOnCreation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ModifySubnetAttributeOptions#mapPublicIpOnLaunch(Boolean)
|
||||
*/
|
||||
public static ModifySubnetAttributeOptions mapPublicIpOnLaunch(Boolean mapPublicIpOnLaunch) {
|
||||
ModifySubnetAttributeOptions options = new ModifySubnetAttributeOptions();
|
||||
return options.mapPublicIpOnLaunch(mapPublicIpOnLaunch);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -16,15 +16,19 @@
|
||||
*/
|
||||
package org.jclouds.aws.ec2.features;
|
||||
|
||||
import static org.jclouds.aws.ec2.options.ModifySubnetAttributeOptions.Builder.mapPublicIpOnLaunch;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.jclouds.aws.ec2.AWSEC2Api;
|
||||
import org.jclouds.aws.ec2.domain.VPC;
|
||||
import org.jclouds.aws.ec2.options.CreateVpcOptions;
|
||||
import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
|
||||
import org.jclouds.ec2.domain.Subnet;
|
||||
import org.jclouds.ec2.features.TagApi;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
@ -33,6 +37,7 @@ import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
@ -47,13 +52,15 @@ public class AWSSubnetApiLiveTest extends BaseComputeServiceContextLiveTest {
|
||||
private AWSEC2Api api;
|
||||
private AWSSubnetApi subnetClient;
|
||||
private VPCApi vpcClient;
|
||||
private TagApi tagApi;
|
||||
private String simpleName = getClass().getSimpleName() + new Random().nextInt(10000);
|
||||
|
||||
private Subnet subnet;
|
||||
private VPC vpc;
|
||||
|
||||
public AWSSubnetApiLiveTest() {
|
||||
provider = "aws-ec2";
|
||||
region = "us-west-2";
|
||||
region = "eu-west-1";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,6 +70,7 @@ public class AWSSubnetApiLiveTest extends BaseComputeServiceContextLiveTest {
|
||||
api = view.unwrapApi(AWSEC2Api.class);
|
||||
subnetClient = api.getAWSSubnetApi().get();
|
||||
vpcClient = view.unwrapApi(AWSEC2Api.class).getVPCApi().get();
|
||||
tagApi = api.getTagApiForRegion(region).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -85,10 +93,12 @@ public class AWSSubnetApiLiveTest extends BaseComputeServiceContextLiveTest {
|
||||
|
||||
@Test
|
||||
public void testCreateSubnetInRegion() {
|
||||
vpc = vpcClient.createVpc(region, "10.0.0.0/16", CreateVpcOptions.NONE);
|
||||
subnet = subnetClient.createSubnetInRegion(region, vpc.id(), "10.0.0.0/20");
|
||||
vpc = vpcClient.createVpc(region, "10.21.0.0/16", CreateVpcOptions.NONE);
|
||||
// tag the VPC for ease of identification in console if things go wrong
|
||||
tagApi.applyToResources(ImmutableMap.of("Name", simpleName), ImmutableList.of(vpc.id()));
|
||||
subnet = subnetClient.createSubnetInRegion(region, vpc.id(), "10.21.0.0/20");
|
||||
assertNotNull(subnet);
|
||||
assertEquals(subnet.getCidrBlock(), "10.0.0.0/20");
|
||||
assertEquals(subnet.getCidrBlock(), "10.21.0.0/20");
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateSubnetInRegion")
|
||||
@ -106,6 +116,12 @@ public class AWSSubnetApiLiveTest extends BaseComputeServiceContextLiveTest {
|
||||
assertEquals(subnetFound.getSubnetId(), subnet.getSubnetId());
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateSubnetInRegion")
|
||||
public void testModifySubnetAttribute() {
|
||||
final boolean result = subnetClient.modifySubnetAttribute(region, subnet.getSubnetId(), mapPublicIpOnLaunch(true));
|
||||
assertTrue(result, "Failed to modify subnet attribute");
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateSubnetInRegion")
|
||||
public void testList() {
|
||||
FluentIterable<Subnet> subnets = subnetClient.describeSubnetsInRegionWithFilter(region,
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.jclouds.aws.ec2.features;
|
||||
|
||||
import static org.jclouds.aws.ec2.options.ModifySubnetAttributeOptions.Builder.mapPublicIpOnLaunch;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
@ -203,6 +204,25 @@ public class AWSSubnetApiMockTest extends BaseAWSEC2ApiMockTest {
|
||||
assertPosted(region, "Action=DescribeSubnets");
|
||||
}
|
||||
|
||||
public void modifySubnetAttribute() throws Exception {
|
||||
String region = "us-west-2";
|
||||
enqueueRegions(DEFAULT_REGION);
|
||||
enqueue(DEFAULT_REGION,
|
||||
new MockResponse().setBody("<ModifySubnetAttributeResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-09-15/\">\n" +
|
||||
" <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>\n" +
|
||||
" <return>true</return>\n" +
|
||||
"</ModifySubnetAttributeResponse>"));
|
||||
|
||||
final boolean result =
|
||||
subnetApiForRegion(DEFAULT_REGION).modifySubnetAttribute(DEFAULT_REGION, "subnet-9d4a7b6c", mapPublicIpOnLaunch(true));
|
||||
assertTrue(result, "Failed to match expected test result of 'true'");
|
||||
assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
|
||||
assertPosted(DEFAULT_REGION,
|
||||
"Action=ModifySubnetAttribute&SubnetId=subnet-9d4a7b6c&MapPublicIpOnLaunch.Value=true",
|
||||
"2014-06-15");
|
||||
|
||||
}
|
||||
|
||||
private AWSSubnetApi subnetApi() {
|
||||
return api().getAWSSubnetApi().get();
|
||||
}
|
||||
|
@ -183,7 +183,12 @@ public class BaseAWSEC2ApiMockTest {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected RecordedRequest assertPosted(String region, String postParams) throws InterruptedException {
|
||||
return assertPosted(region, postParams, "2012-06-01");
|
||||
}
|
||||
|
||||
protected RecordedRequest assertPosted(String region, String postParams, String apiVersion) throws InterruptedException {
|
||||
RecordedRequest request = regionToServers.get(region).takeRequest();
|
||||
assertEquals(request.getMethod(), "POST");
|
||||
assertEquals(request.getPath(), "/");
|
||||
@ -192,8 +197,8 @@ public class BaseAWSEC2ApiMockTest {
|
||||
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);
|
||||
assertThat(body).contains("&Version=" + apiVersion);
|
||||
assertEquals(body.replace("&Version=" + apiVersion, ""), postParams);
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user