[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>