From 7158b94b431354b472dd804149a8b87cb6b3ea65 Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Tue, 11 Oct 2016 22:22:26 +0200 Subject: [PATCH] [aws-ec2] Add CRUD for VPC --- providers/aws-ec2/pom.xml | 5 + .../java/org/jclouds/aws/ec2/AWSEC2Api.java | 19 ++- .../BindVpcIdsToIndexedFormParams.java | 35 +++++ .../java/org/jclouds/aws/ec2/domain/VPC.java | 141 ++++++++++++++++++ .../aws/ec2/features/SpotInstanceApi.java | 2 +- .../org/jclouds/aws/ec2/features/VPCApi.java | 114 ++++++++++++++ .../aws/ec2/options/CreateVpcOptions.java | 91 +++++++++++ .../ec2/xml/DescribeVPCsResponseHandler.java | 88 +++++++++++ .../aws/ec2/xml/ReturnValueHandler.java | 40 +++++ .../org/jclouds/aws/ec2/xml/VPCHandler.java | 93 ++++++++++++ .../aws/ec2/features/VPCApiLiveTest.java | 76 ++++++++++ .../aws/ec2/features/VPCApiMockTest.java | 91 +++++++++++ .../aws-ec2/src/test/resources/create_vpc.xml | 11 ++ .../aws-ec2/src/test/resources/delete_vpc.xml | 4 + .../src/test/resources/describe_vpcs.xml | 14 ++ 15 files changed, 817 insertions(+), 7 deletions(-) create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindVpcIdsToIndexedFormParams.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/VPC.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/VPCApi.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateVpcOptions.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeVPCsResponseHandler.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/ReturnValueHandler.java create mode 100644 providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/VPCHandler.java create mode 100644 providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiLiveTest.java create mode 100644 providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiMockTest.java create mode 100644 providers/aws-ec2/src/test/resources/create_vpc.xml create mode 100644 providers/aws-ec2/src/test/resources/delete_vpc.xml create mode 100644 providers/aws-ec2/src/test/resources/describe_vpcs.xml diff --git a/providers/aws-ec2/pom.xml b/providers/aws-ec2/pom.xml index edd02cbdfa..cbcba0e63e 100644 --- a/providers/aws-ec2/pom.xml +++ b/providers/aws-ec2/pom.xml @@ -62,6 +62,11 @@ ec2 ${project.version} + + com.google.auto.value + auto-value + provided + org.apache.jclouds.api ec2 diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Api.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Api.java index b7e3f80607..37ca0e971b 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Api.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Api.java @@ -23,6 +23,7 @@ import org.jclouds.aws.ec2.features.AWSSecurityGroupApi; import org.jclouds.aws.ec2.features.MonitoringApi; import org.jclouds.aws.ec2.features.PlacementGroupApi; import org.jclouds.aws.ec2.features.SpotInstanceApi; +import org.jclouds.aws.ec2.features.VPCApi; import org.jclouds.ec2.EC2Api; import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; @@ -59,7 +60,7 @@ public interface AWSEC2Api extends EC2Api { @Override Optional getSecurityGroupApiForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); - + /** * {@inheritDoc} */ @@ -78,7 +79,7 @@ public interface AWSEC2Api extends EC2Api { */ @Delegate Optional getPlacementGroupApi(); - + @Delegate Optional getPlacementGroupApiForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); @@ -88,7 +89,7 @@ public interface AWSEC2Api extends EC2Api { */ @Delegate Optional getMonitoringApi(); - + @Delegate Optional getMonitoringApiForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); @@ -99,19 +100,25 @@ public interface AWSEC2Api extends EC2Api { @Delegate @Override Optional getKeyPairApi(); - + @Delegate @Override Optional getKeyPairApiForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); - + /** * Provides synchronous access to SpotInstance services. */ @Delegate Optional getSpotInstanceApi(); - + @Delegate Optional getSpotInstanceApiForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); + + /** + * Provides synchronous access to VPC services. + */ + @Delegate + Optional getVPCApi(); } diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindVpcIdsToIndexedFormParams.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindVpcIdsToIndexedFormParams.java new file mode 100644 index 0000000000..9c0c5cc1ff --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindVpcIdsToIndexedFormParams.java @@ -0,0 +1,35 @@ +/* + * 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.binders; + +import javax.inject.Singleton; + +import org.jclouds.aws.util.AWSUtils; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.Binder; + +/** + * Binds the String [] to form parameters named with InstanceId.index + */ +@Singleton +public class BindVpcIdsToIndexedFormParams implements Binder { + @Override + public R bindToRequest(R request, Object input) { + return AWSUtils.indexStringArrayToFormValuesWithPrefix(request, "VpcId", input); + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/VPC.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/VPC.java new file mode 100644 index 0000000000..b2e1e0d5bc --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/VPC.java @@ -0,0 +1,141 @@ +/* + * 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.domain; + +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +/** + * Amazon EC2 VPC. + * + * @see doc + */ +@AutoValue +public abstract class VPC { + + public enum State { + /** + * The subnet is available for use. + */ + AVAILABLE, + /** + * The subnet is not yet available for use. + */ + PENDING, UNRECOGNIZED; + public String value() { + return name().toLowerCase(); + } + + public static State fromValue(String v) { + try { + return valueOf(v.toUpperCase()); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + } + + public enum InstanceTenancy { + /** + * The valid tenancy of instances launched into the VPC + */ + DEFAULT, + DEDICATED, + HOST, + UNRECOGNIZED; + public String value() { + return name().toLowerCase(); + } + + public static InstanceTenancy fromValue(String v) { + try { + return valueOf(v.toUpperCase()); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + } + + @Nullable + public abstract String id(); + @Nullable + public abstract State state(); + @Nullable + public abstract String cidrBlock(); + @Nullable + public abstract String dhcpOptionsId(); + @Nullable + public abstract InstanceTenancy instanceTenancy(); + @Nullable + public abstract Boolean isDefault(); + @Nullable + public abstract Map tags(); + + + @SerializedNames({ "vpcId", "state", "cidrBlock", "dhcpOptionsId", "instanceTenancy", "isDefault", "tagSet" }) + public static VPC create(String id, State state, String cidrBlock, String dhcpOptionsId, InstanceTenancy instanceTenancy, Boolean isDefault, Map tags) { + return builder() + .id(id) + .state(state) + .isDefault(isDefault) + .cidrBlock(cidrBlock) + .dhcpOptionsId(dhcpOptionsId) + .instanceTenancy(instanceTenancy) + .tags(tags) + .build(); + } + + VPC() {} + + public static Builder builder() { + return new AutoValue_VPC.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder id(String id); + public abstract Builder state(State state); + public abstract Builder cidrBlock(String cidrBlock); + public abstract Builder dhcpOptionsId(String dhcpOptionsId); + public abstract Builder instanceTenancy(InstanceTenancy instanceTenancy); + public abstract Builder isDefault(Boolean isDefault); + public abstract Builder tags(Map tags); + + @Nullable public abstract String id(); + @Nullable public abstract State state(); + @Nullable public abstract String cidrBlock(); + @Nullable public abstract InstanceTenancy instanceTenancy(); + @Nullable public abstract Boolean isDefault(); + @Nullable public abstract Map tags(); + + abstract VPC autoBuild(); + + public VPC build() { + tags(tags() != null ? ImmutableMap.copyOf(tags()) : ImmutableMap.of()); + return autoBuild(); + } + + + } + +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/SpotInstanceApi.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/SpotInstanceApi.java index 694aab4ab7..d69ba25713 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/SpotInstanceApi.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/SpotInstanceApi.java @@ -193,7 +193,7 @@ public interface SpotInstanceApi { * @param region * Region where the spot instance service is running * @param options - * options to control the list + * options to control the describeVpcsInRegion * * @see #describeSpotInstanceRequestsInRegion * @see #requestSpotInstancesInRegion diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/VPCApi.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/VPCApi.java new file mode 100644 index 0000000000..1f69b26d7f --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/VPCApi.java @@ -0,0 +1,114 @@ +/* + * 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.aws.reference.FormParameters.ACTION; + +import javax.inject.Named; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404; +import org.jclouds.Fallbacks.FalseOnNotFoundOr404; +import org.jclouds.aws.ec2.binders.BindVpcIdsToIndexedFormParams; +import org.jclouds.aws.ec2.domain.VPC; +import org.jclouds.aws.ec2.options.CreateVpcOptions; +import org.jclouds.aws.ec2.xml.DescribeVPCsResponseHandler; +import org.jclouds.aws.ec2.xml.ReturnValueHandler; +import org.jclouds.aws.ec2.xml.VPCHandler; +import org.jclouds.aws.filters.FormSigner; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.EndpointParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.FormParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.VirtualHost; +import org.jclouds.rest.annotations.XMLResponseParser; + +import com.google.common.collect.FluentIterable; + +/** + * Provides access to VPC Services. + *

+ */ +@RequestFilters(FormSigner.class) +@VirtualHost +@Path("/") +public interface VPCApi { + + /** + * Describes all of your VPCs + * + * @return VPCs or empty if there are none + * @see docs + */ + @Named("DescribeVpcs") + @POST + @FormParams(keys = ACTION, values = "DescribeVpcs") + @XMLResponseParser(DescribeVPCsResponseHandler.class) + @Fallback(EmptyFluentIterableOnNotFoundOr404.class) + FluentIterable describeVpcsInRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @BinderParam(BindVpcIdsToIndexedFormParams.class) String... vpcIds); + + /** + * Creates a VPC with the specified CIDR block. + * + * @param region + * VPCs are tied to the Region. + * + * @param cidrBlock + * The network range for the VPC, in CIDR notation. For example, 10.0.0.0/16. + * @return vpc + * + * @see + * @see CreateVpcOptions + * @see + */ + @Named("CreateVpc") + @POST + @FormParams(keys = ACTION, values = "CreateVpc") + @XMLResponseParser(VPCHandler.class) + VPC createVpc( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("CidrBlock") String cidrBlock, CreateVpcOptions... options); + /** + * Deletes {@code VPC}. + * + * @param region + * VPCs are tied to the Region where its files are located within Amazon S3. + * @param vpcId + * The VPC ID. + * + */ + @Named("DeleteVpc") + @POST + @FormParams(keys = ACTION, values = "DeleteVpc") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(FalseOnNotFoundOr404.class) + boolean deleteVpc( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("VpcId") String vpcId); +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateVpcOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateVpcOptions.java new file mode 100644 index 0000000000..4077101052 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateVpcOptions.java @@ -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.ec2.options; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.ec2.options.internal.BaseEC2RequestOptions; + +/** + * Contains options supported in the Form API for the CreateVpc operation.

+ * Usage

The recommended way to instantiate a CreateImageOptions object is to statically import + * CreateVpcOptions.Builder.* and invoke a static creation method followed by an instance mutator + * (if needed): + *

+ * + * import static org.jclouds.ec2.options.CreateVpcOptions.Builder.* + *

+ * EC2Api connection = // get connection + * Future> images = connection.getVpcApi().get().createVpc(withDescription("123125").noReboot()); + * + * + * @see + */ +public class CreateVpcOptions extends BaseEC2RequestOptions { + + public static final CreateVpcOptions NONE = new CreateVpcOptions(); + + /** + * The instanceTenancy of the VPC that was provided during image creation. + *

+ * + * Default: default, Valid Values: default | dedicated | host + */ + public CreateVpcOptions withInstanceTenancy(String instanceTenancy) { + formParameters.put("InstanceTenancy", checkNotNull(instanceTenancy, "instanceTenancy")); + return this; + } + + public String getInstanceTenancy() { + return getFirstFormOrNull("InstanceTenancy"); + + } + + /** + * Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. + */ + public CreateVpcOptions dryRun() { + formParameters.put("DryRun", "true"); + return this; + } + + public boolean isDryRun() { + return getFirstFormOrNull("DryRun") != null; + } + + public static class Builder { + + /** + * @see CreateVpcOptions#withInstanceTenancy(String ) + */ + public static CreateVpcOptions withInstanceTenancy(String instanceTenancy) { + CreateVpcOptions options = new CreateVpcOptions(); + return options.withInstanceTenancy(instanceTenancy); + } + + /** + * @see CreateVpcOptions#dryRun() + */ + public static CreateVpcOptions dryRun() { + CreateVpcOptions options = new CreateVpcOptions(); + return options.dryRun(); + } + + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeVPCsResponseHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeVPCsResponseHandler.java new file mode 100644 index 0000000000..095f3e0084 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeVPCsResponseHandler.java @@ -0,0 +1,88 @@ +/* + * 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.xml; + +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import org.jclouds.aws.ec2.domain.VPC; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSet.Builder; +import com.google.inject.Inject; + +/** + * @see xml + */ +public class DescribeVPCsResponseHandler extends + ParseSax.HandlerForGeneratedRequestWithResult> { + private final VPCHandler vpcHandler; + + private StringBuilder currentText = new StringBuilder(); + private boolean inVpcSet; + private boolean inTagSet; + private Builder vpcs = ImmutableSet.builder(); + + @Inject + public DescribeVPCsResponseHandler(VPCHandler vpcHandler) { + this.vpcHandler = vpcHandler; + } + + @Override + public FluentIterable getResult() { + return FluentIterable.from(vpcs.build()); + } + + @Override + public void startElement(String url, String name, String qName, Attributes attributes) { + if (equalsOrSuffix(qName, "vpcSet")) { + inVpcSet = true; + } else if (inVpcSet) { + if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = true; + } + vpcHandler.startElement(url, name, qName, attributes); + } + } + + @Override + public void endElement(String uri, String name, String qName) { + if (equalsOrSuffix(qName, "vpcSet")) { + inVpcSet = false; + } else if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = false; + vpcHandler.endElement(uri, name, qName); + } else if (equalsOrSuffix(qName, "item") && !inTagSet) { + vpcs.add(vpcHandler.getResult()); + } else if (inVpcSet) { + vpcHandler.endElement(uri, name, qName); + } + + currentText.setLength(0); + } + + @Override + public void characters(char ch[], int start, int length) { + if (inVpcSet) { + vpcHandler.characters(ch, start, length); + } else { + currentText.append(ch, start, length); + } + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/ReturnValueHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/ReturnValueHandler.java new file mode 100644 index 0000000000..9fd6ef6f3d --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/ReturnValueHandler.java @@ -0,0 +1,40 @@ +/* + * 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.xml; + +import org.jclouds.http.functions.ParseSax; + +public class ReturnValueHandler extends ParseSax.HandlerWithResult { + + private StringBuilder currentText = new StringBuilder(); + private boolean value; + + public Boolean getResult() { + return value; + } + + public void endElement(String uri, String name, String qName) { + if (qName.equalsIgnoreCase("return")) { + this.value = Boolean.parseBoolean(currentText.toString().trim()); + } + currentText.setLength(0); + } + + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } +} diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/VPCHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/VPCHandler.java new file mode 100644 index 0000000000..2830d373c4 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/VPCHandler.java @@ -0,0 +1,93 @@ +/* + * 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.xml; + +import static org.jclouds.util.SaxUtils.currentOrNull; +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import javax.inject.Inject; + +import org.jclouds.aws.ec2.domain.VPC; +import org.jclouds.ec2.xml.TagSetHandler; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +/** + * @see xml + */ +public class VPCHandler extends ParseSax.HandlerForGeneratedRequestWithResult { + private StringBuilder currentText = new StringBuilder(); + private VPC.Builder builder = VPC.builder(); + private final TagSetHandler tagSetHandler; + private boolean inTagSet; + + @Inject + public VPCHandler(TagSetHandler tagSetHandler) { + this.tagSetHandler = tagSetHandler; + } + + @Override + public VPC getResult() { + try { + return builder.build(); + } finally { + builder = VPC.builder(); + } + } + + @Override + public void startElement(String uri, String name, String qName, Attributes attrs) { + if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = true; + } + if (inTagSet) { + tagSetHandler.startElement(uri, name, qName, attrs); + } + } + + @Override + public void endElement(String uri, String name, String qName) { + if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = false; + builder.tags(tagSetHandler.getResult()); + } else if (inTagSet) { + tagSetHandler.endElement(uri, name, qName); + } else if (equalsOrSuffix(qName, "dhcpOptionsId")) { + builder.dhcpOptionsId(currentOrNull(currentText)); + } else if (equalsOrSuffix(qName, "state")) { + builder.state(VPC.State.fromValue(currentOrNull(currentText))); + } else if (equalsOrSuffix(qName, "vpcId")) { + builder.id(currentOrNull(currentText)); + } else if (equalsOrSuffix(qName, "cidrBlock")) { + builder.cidrBlock(currentOrNull(currentText)); + } else if (equalsOrSuffix(qName, "instanceTenancy")) { + builder.instanceTenancy(VPC.InstanceTenancy.fromValue(currentOrNull(currentText))); + } else if (equalsOrSuffix(qName, "isDefault")) { + builder.isDefault(Boolean.parseBoolean(currentText.toString().trim())); + } + currentText.setLength(0); + } + + @Override + public void characters(char ch[], int start, int length) { + if (inTagSet) { + tagSetHandler.characters(ch, start, length); + } else { + currentText.append(ch, start, length); + } + } +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiLiveTest.java new file mode 100644 index 0000000000..06c48735b1 --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiLiveTest.java @@ -0,0 +1,76 @@ +/* + * 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 static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +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.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.FluentIterable; + +/** + * Tests behavior of {@code VPCApi} + */ +@Test(groups = "live", singleThreaded = true) +public class VPCApiLiveTest extends BaseComputeServiceContextLiveTest { + public VPCApiLiveTest() { + provider = "aws-ec2"; + } + + private VPCApi client; + private VPC vpc; + + @Override + @BeforeClass(groups = { "integration", "live" }) + public void setupContext() { + super.setupContext(); + client = view.unwrapApi(AWSEC2Api.class).getVPCApi().get(); + } + + @Test + public void testCreate() { + vpc = client.createVpc(null, "10.0.0.0/16", CreateVpcOptions.NONE); + assertNotNull(vpc); + } + + @Test(dependsOnMethods = "testCreate") + public void testGet() { + FluentIterable vpcs = client.describeVpcsInRegion(null, vpc.id()); + assertTrue(vpcs.toList().size() == 1); + } + + @Test(dependsOnMethods = "testCreate") + public void testList() { + FluentIterable vpcs = client.describeVpcsInRegion(null); + assertFalse(vpcs.toList().isEmpty()); + } + + @Test(dependsOnMethods = {"testList", "testGet"}, alwaysRun = true) + public void testDelete() { + if (vpc != null) { + assertTrue(client.deleteVpc(null, vpc.id())); + } + } + +} diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiMockTest.java new file mode 100644 index 0000000000..c13520757c --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiMockTest.java @@ -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.ec2.features; + +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 org.jclouds.aws.ec2.domain.VPC; +import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest; +import org.jclouds.aws.ec2.options.CreateVpcOptions; +import org.testng.annotations.Test; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.squareup.okhttp.mockwebserver.MockResponse; + +@Test(groups = "unit", testName = "VPCApiMockTest", singleThreaded = true) +public class VPCApiMockTest extends BaseAWSEC2ApiMockTest { + + public void createVpc() throws Exception { + enqueueRegions(DEFAULT_REGION); + enqueueXml(DEFAULT_REGION, "/create_vpc.xml"); + VPC result = vpcApi().createVpc(DEFAULT_REGION, "10.0.0.0/16", CreateVpcOptions.NONE); + + assertNotNull(result); + assertEquals(result.id(), "vpc-1a2b3c4d"); + + assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); + assertPosted(DEFAULT_REGION, "Action=CreateVpc&CidrBlock=10.0.0.0/16"); + } + + public void describeVpcsInRegion() throws Exception { + enqueueRegions(DEFAULT_REGION); + enqueueXml(DEFAULT_REGION, "/describe_vpcs.xml"); + FluentIterable result = vpcApi().describeVpcsInRegion(DEFAULT_REGION); + + assertFalse(result.isEmpty()); + assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); + assertPosted(DEFAULT_REGION, "Action=DescribeVpcs"); + } + + public void describeVpcsInRegionReturns404() throws Exception { + enqueueRegions(DEFAULT_REGION); + enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404)); + + assertEquals(vpcApi().describeVpcsInRegion(DEFAULT_REGION), FluentIterable.from(ImmutableSet.of())); + + assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); + assertPosted(DEFAULT_REGION, "Action=DescribeVpcs"); + } + + public void deleteVpc() throws Exception { + enqueueRegions(DEFAULT_REGION); + enqueueXml(DEFAULT_REGION, "/delete_vpc.xml"); + + assertTrue(vpcApi().deleteVpc(DEFAULT_REGION, "vpc-id")); + + assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); + assertPosted(DEFAULT_REGION, "Action=DeleteVpc&VpcId=vpc-id"); + } + + public void deleteVpcReturns404() throws Exception { + enqueueRegions(DEFAULT_REGION); + enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404)); + + assertFalse(vpcApi().deleteVpc(DEFAULT_REGION, "vpc-id")); + + assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); + assertPosted(DEFAULT_REGION, "Action=DeleteVpc&VpcId=vpc-id"); + } + + private VPCApi vpcApi() { + return api().getVPCApi().get(); + } +} diff --git a/providers/aws-ec2/src/test/resources/create_vpc.xml b/providers/aws-ec2/src/test/resources/create_vpc.xml new file mode 100644 index 0000000000..b0efc6f806 --- /dev/null +++ b/providers/aws-ec2/src/test/resources/create_vpc.xml @@ -0,0 +1,11 @@ + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + + vpc-1a2b3c4d + pending + 10.0.0.0/16 + dopt-1a2b3c4d2 + default + + + diff --git a/providers/aws-ec2/src/test/resources/delete_vpc.xml b/providers/aws-ec2/src/test/resources/delete_vpc.xml new file mode 100644 index 0000000000..216ad512db --- /dev/null +++ b/providers/aws-ec2/src/test/resources/delete_vpc.xml @@ -0,0 +1,4 @@ + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + true + diff --git a/providers/aws-ec2/src/test/resources/describe_vpcs.xml b/providers/aws-ec2/src/test/resources/describe_vpcs.xml new file mode 100644 index 0000000000..acaa44615b --- /dev/null +++ b/providers/aws-ec2/src/test/resources/describe_vpcs.xml @@ -0,0 +1,14 @@ + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + + + vpc-1a2b3c4d + available + 10.0.0.0/23 + dopt-7a8b9c2d + default + false + + + +