[aws-ec2] Add CRUD for VPC
diff --git a/providers/aws-ec2/pom.xml b/providers/aws-ec2/pom.xml
index edd02cb..cbcba0e 100644
--- a/providers/aws-ec2/pom.xml
+++ b/providers/aws-ec2/pom.xml
@@ -63,6 +63,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>ec2</artifactId>
<version>${project.version}</version>
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 b7e3f80..37ca0e9 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.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 @@
@Override
Optional<? extends AWSSecurityGroupApi> getSecurityGroupApiForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
-
+
/**
* {@inheritDoc}
*/
@@ -78,7 +79,7 @@
*/
@Delegate
Optional<? extends PlacementGroupApi> getPlacementGroupApi();
-
+
@Delegate
Optional<? extends PlacementGroupApi> getPlacementGroupApiForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
@@ -88,7 +89,7 @@
*/
@Delegate
Optional<? extends MonitoringApi> getMonitoringApi();
-
+
@Delegate
Optional<? extends MonitoringApi> getMonitoringApiForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
@@ -99,19 +100,25 @@
@Delegate
@Override
Optional<? extends AWSKeyPairApi> getKeyPairApi();
-
+
@Delegate
@Override
Optional<? extends AWSKeyPairApi> getKeyPairApiForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
-
+
/**
* Provides synchronous access to SpotInstance services.
*/
@Delegate
Optional<? extends SpotInstanceApi> getSpotInstanceApi();
-
+
@Delegate
Optional<? extends SpotInstanceApi> getSpotInstanceApiForRegion(
@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+
+ /**
+ * Provides synchronous access to VPC services.
+ */
+ @Delegate
+ Optional<? extends VPCApi> 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 0000000..9c0c5cc
--- /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 extends HttpRequest> 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 0000000..b2e1e0d
--- /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 <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Vpc.html" >doc</a>
+ */
+@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<String, String> 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<String, String> 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<String, String> 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<String, String> tags();
+
+ abstract VPC autoBuild();
+
+ public VPC build() {
+ tags(tags() != null ? ImmutableMap.copyOf(tags()) : ImmutableMap.<String, String>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 694aab4..d69ba25 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 @@
* @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 0000000..1f69b26
--- /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.
+ * <p/>
+ */
+@RequestFilters(FormSigner.class)
+@VirtualHost
+@Path("/")
+public interface VPCApi {
+
+ /**
+ * Describes all of your VPCs
+ *
+ * @return VPCs or empty if there are none
+ * @see <a href=
+ * "http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html"
+ * >docs</href>
+ */
+ @Named("DescribeVpcs")
+ @POST
+ @FormParams(keys = ACTION, values = "DescribeVpcs")
+ @XMLResponseParser(DescribeVPCsResponseHandler.class)
+ @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
+ FluentIterable<VPC> 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 <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpc.html"
+ * />
+ * @see CreateVpcOptions
+ * @see <a href=
+ * "http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpc.html"
+ * />
+ */
+ @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 0000000..4077101
--- /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. <h2>
+ * Usage</h2> 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):
+ * <p/>
+ * <code>
+ * import static org.jclouds.ec2.options.CreateVpcOptions.Builder.*
+ * <p/>
+ * EC2Api connection = // get connection
+ * Future<Set<ImageMetadata>> images = connection.getVpcApi().get().createVpc(withDescription("123125").noReboot());
+ * <code>
+ *
+ * @see <a
+ * href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateVpc.html"
+ * />
+ */
+public class CreateVpcOptions extends BaseEC2RequestOptions {
+
+ public static final CreateVpcOptions NONE = new CreateVpcOptions();
+
+ /**
+ * The instanceTenancy of the VPC that was provided during image creation.
+ * <p/>
+ *
+ * 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 0000000..095f3e0
--- /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 <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html">xml</a>
+ */
+public class DescribeVPCsResponseHandler extends
+ ParseSax.HandlerForGeneratedRequestWithResult<FluentIterable<VPC>> {
+ private final VPCHandler vpcHandler;
+
+ private StringBuilder currentText = new StringBuilder();
+ private boolean inVpcSet;
+ private boolean inTagSet;
+ private Builder<VPC> vpcs = ImmutableSet.builder();
+
+ @Inject
+ public DescribeVPCsResponseHandler(VPCHandler vpcHandler) {
+ this.vpcHandler = vpcHandler;
+ }
+
+ @Override
+ public FluentIterable<VPC> 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 0000000..9fd6ef6
--- /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<Boolean> {
+
+ 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 0000000..2830d37
--- /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 <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Vpc.html" >xml</a>
+ */
+public class VPCHandler extends ParseSax.HandlerForGeneratedRequestWithResult<VPC> {
+ 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 0000000..06c4873
--- /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<VPC> vpcs = client.describeVpcsInRegion(null, vpc.id());
+ assertTrue(vpcs.toList().size() == 1);
+ }
+
+ @Test(dependsOnMethods = "testCreate")
+ public void testList() {
+ FluentIterable<VPC> 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 0000000..c135207
--- /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<VPC> 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 0000000..b0efc6f
--- /dev/null
+++ b/providers/aws-ec2/src/test/resources/create_vpc.xml
@@ -0,0 +1,11 @@
+<CreateVpcResponse xmlns="http://ec2.amazonaws.com/doc/2016-09-15/">
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
+ <vpc>
+ <vpcId>vpc-1a2b3c4d</vpcId>
+ <state>pending</state>
+ <cidrBlock>10.0.0.0/16</cidrBlock>
+ <dhcpOptionsId>dopt-1a2b3c4d2</dhcpOptionsId>
+ <instanceTenancy>default</instanceTenancy>
+ <tagSet/>
+ </vpc>
+</CreateVpcResponse>
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 0000000..216ad51
--- /dev/null
+++ b/providers/aws-ec2/src/test/resources/delete_vpc.xml
@@ -0,0 +1,4 @@
+<DeleteVpcResponse xmlns="http://ec2.amazonaws.com/doc/2016-09-15/">
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
+ <return>true</return>
+</DeleteVpcResponse>
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 0000000..acaa446
--- /dev/null
+++ b/providers/aws-ec2/src/test/resources/describe_vpcs.xml
@@ -0,0 +1,14 @@
+<DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2016-09-15/">
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
+ <vpcSet>
+ <item>
+ <vpcId>vpc-1a2b3c4d</vpcId>
+ <state>available</state>
+ <cidrBlock>10.0.0.0/23</cidrBlock>
+ <dhcpOptionsId>dopt-7a8b9c2d</dhcpOptionsId>
+ <instanceTenancy>default</instanceTenancy>
+ <isDefault>false</isDefault>
+ <tagSet/>
+ </item>
+ </vpcSet>
+</DescribeVpcsResponse>