You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by an...@apache.org on 2017/05/04 15:41:11 UTC

[1/2] jclouds git commit: JCLOUDS-1269; JCLOUDS-1120: ec2 subnet/securityGroups fixes

Repository: jclouds
Updated Branches:
  refs/heads/master fe134cf61 -> 1c6c36b81


http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiMockTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiMockTest.java
new file mode 100644
index 0000000..4d6b382
--- /dev/null
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiMockTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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 java.util.Set;
+
+import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
+import org.jclouds.aws.ec2.options.CreateSecurityGroupOptions;
+import org.jclouds.ec2.domain.SecurityGroup;
+import org.jclouds.net.domain.IpPermission;
+import org.jclouds.net.domain.IpProtocol;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+
+@Test(groups = "unit", testName = "AWSSecurityGroupApiMockTest", singleThreaded = true)
+public class AWSSecurityGroupApiMockTest extends BaseAWSEC2ApiMockTest {
+
+   private final String describeSecurityGroupsResponse = Joiner.on("\n").join(
+         "<DescribeSecurityGroupsResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-11-15/\">",
+         "  <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>",
+         "  <securityGroupInfo>",
+         "    <item>",
+         "      <ownerId>123456789012</ownerId>",
+         "      <groupId>sg-1a2b3c4d</groupId>",
+         "      <groupName>WebServers</groupName>",
+         "      <groupDescription>Web Servers</groupDescription>",
+         "      <vpcId>vpc-614cc409</vpcId>",
+         "      <ipPermissions>",
+         "        <item>",
+         "          <ipProtocol>-1</ipProtocol>",
+         "          <groups>",
+         "            <item>",
+         "              <userId>123456789012</userId>",
+         "              <groupId>sg-af8661c0</groupId>",
+         "            </item>",
+         "          </groups>",
+         "          <ipRanges/>",
+         "          <prefixListIds/>",
+         "        </item>",
+         "        <item>",
+         "          <ipProtocol>tcp</ipProtocol>",
+         "          <fromPort>22</fromPort>",
+         "          <toPort>22</toPort>",
+         "          <groups/>",
+         "          <ipRanges>",
+         "            <item>",
+         "              <cidrIp>204.246.162.38/32</cidrIp>",
+         "            </item>",
+         "          </ipRanges>",
+         "          <prefixListIds/>",
+         "        </item>",
+         "      </ipPermissions>",
+         "      <ipPermissionsEgress>",
+         "        <item>",
+         "          <ipProtocol>-1</ipProtocol>",
+         "          <groups/>",
+         "          <ipRanges>",
+         "            <item>",
+         "              <cidrIp>0.0.0.0/0</cidrIp>",
+         "            </item>",
+         "          </ipRanges>",
+         "          <prefixListIds/>",
+         "        </item>",
+         "      </ipPermissionsEgress>",
+         "    </item>",
+         "  </securityGroupInfo>",
+         "</DescribeSecurityGroupsResponse>");
+
+   private final String createSecurityGroupResponse = Joiner.on("\n").join(
+         "<CreateSecurityGroupResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-11-15/\">",
+         "  <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>",
+         "  <return>true</return>",
+         "  <groupId>sg-0a42d66a</groupId>",
+         "</CreateSecurityGroupResponse>");
+
+   private final String authorizeSecurityGroupIngressResponse = Joiner.on("\n").join(
+            "<AuthorizeSecurityGroupIngressResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-11-15/\">",
+            "  <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>",
+            "  <return>true</return>",
+            "</AuthorizeSecurityGroupIngressResponse>");
+
+   private final String revokeSecurityGroupIngressResponse = Joiner.on("\n").join(
+         "<RevokeSecurityGroupIngressResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-11-15/\">",
+         "  <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>",
+         "  <return>true</return>",
+         "</RevokeSecurityGroupIngressResponse>");
+
+   private final String deleteSecurityGroupResponse = Joiner.on("\n").join(
+         "<DeleteSecurityGroupResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-11-15/\">",
+         "  <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>",
+         "  <return>true</return>",
+         "</DeleteSecurityGroupResponse>");
+
+   @SuppressWarnings("deprecation")
+   public void describeSecurityGroups() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(describeSecurityGroupsResponse));
+
+      Set<SecurityGroup> results = securityGroupApi().describeSecurityGroupsInRegion(DEFAULT_REGION);
+      SecurityGroup result = Iterables.getOnlyElement(results);
+      assertEquals(result.getId(), "sg-1a2b3c4d");
+      assertEquals(result.getRegion(), "us-east-1");
+      assertEquals(result.getName(), "WebServers");
+      assertEquals(result.getOwnerId(), "123456789012");
+      assertEquals(result.getDescription(), "Web Servers");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups");
+   }
+
+   public void describeSecurityGroupsGiving404() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setResponseCode(404));
+
+      Set<SecurityGroup> results = securityGroupApi().describeSecurityGroupsInRegion(DEFAULT_REGION);
+      assertEquals(results, ImmutableSet.of());
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups");
+   }
+
+   public void describeSecurityGroupsById() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(describeSecurityGroupsResponse));
+
+      Set<SecurityGroup> results = securityGroupApi().describeSecurityGroupsInRegionById(DEFAULT_REGION, "sg-1a2b3c4d");
+      SecurityGroup result = Iterables.getOnlyElement(results);
+      assertEquals(result.getId(), "sg-1a2b3c4d");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-1a2b3c4d");
+   }
+
+   public void describeSecurityGroupsByName() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(describeSecurityGroupsResponse));
+
+      Set<SecurityGroup> results = securityGroupApi().describeSecurityGroupsInRegion(DEFAULT_REGION, "WebServers");
+      SecurityGroup result = Iterables.getOnlyElement(results);
+      assertEquals(result.getId(), "sg-1a2b3c4d");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=WebServers");
+   }
+
+   public void describeSecurityGroupsFiltered() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(describeSecurityGroupsResponse));
+
+      Set<SecurityGroup> results = securityGroupApi().describeSecurityGroupsInRegionWithFilter(DEFAULT_REGION, 
+            ImmutableMultimap.of("group-name", "WebServers", "vpc-id", "vpc-614cc409"));
+      SecurityGroup result = Iterables.getOnlyElement(results);
+      assertEquals(result.getId(), "sg-1a2b3c4d");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=WebServers&Filter.2.Name=vpc-id&Filter.2.Value.1=vpc-614cc409");
+   }
+
+   public void describeSecurityGroupsDifferentRegion() throws Exception {
+      String region = "us-west-2";
+      enqueueRegions(DEFAULT_REGION, region);
+      enqueue(region, new MockResponse().setBody(describeSecurityGroupsResponse));
+
+      Set<SecurityGroup> results = securityGroupApi().describeSecurityGroupsInRegion(region);
+      SecurityGroup result = Iterables.getOnlyElement(results);
+      assertEquals(result.getId(), "sg-1a2b3c4d");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(region, "Action=DescribeSecurityGroups");
+   }
+
+   public void createSecurityGroupsInRegionAndReturnId() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(createSecurityGroupResponse));
+
+      String result = securityGroupApi().createSecurityGroupInRegionAndReturnId(DEFAULT_REGION, "WebServers", "Web Servers", CreateSecurityGroupOptions.Builder.vpcId("vpc-614cc409"));
+      assertEquals(result, "sg-0a42d66a");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=WebServers&GroupDescription=Web%20Servers&VpcId=vpc-614cc409");
+   }
+
+   public void authorizeSecurityGroupIngress() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(authorizeSecurityGroupIngressResponse));
+
+      IpPermission perm = IpPermission.builder().ipProtocol(IpProtocol.TCP).cidrBlock("0.0.0.0/0")
+            .fromPort(8080).toPort(8080).build();
+      securityGroupApi().authorizeSecurityGroupIngressInRegion(DEFAULT_REGION, "sg-1a2b3c4d", perm);
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-1a2b3c4d&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=8080&IpPermissions.0.ToPort=8080&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0");
+   }
+
+   public void authorizeSecurityGroupIngressList() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(authorizeSecurityGroupIngressResponse));
+
+      IpPermission perm = IpPermission.builder().ipProtocol(IpProtocol.TCP).cidrBlock("0.0.0.0/0")
+            .fromPort(8080).toPort(8080).build();
+      IpPermission perm2 = IpPermission.builder().ipProtocol(IpProtocol.TCP).cidrBlock("0.0.0.0/0")
+            .fromPort(8443).toPort(8443).build();
+      securityGroupApi().authorizeSecurityGroupIngressInRegion(DEFAULT_REGION, "sg-1a2b3c4d", ImmutableList.of(perm, perm2));
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-1a2b3c4d&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=8080&IpPermissions.0.ToPort=8080&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=8443&IpPermissions.1.ToPort=8443&IpPermissions.1.IpRanges.0.CidrIp=0.0.0.0/0");
+   }
+
+   public void revokeSecurityGroupIngress() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(revokeSecurityGroupIngressResponse));
+
+      IpPermission perm = IpPermission.builder().ipProtocol(IpProtocol.TCP).cidrBlock("0.0.0.0/0")
+            .fromPort(8080).toPort(8080).build();
+      securityGroupApi().revokeSecurityGroupIngressInRegion(DEFAULT_REGION, "sg-1a2b3c4d", perm);
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=RevokeSecurityGroupIngress&GroupId=sg-1a2b3c4d&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=8080&IpPermissions.0.ToPort=8080&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0");
+   }
+
+   public void revokeSecurityGroupIngressList() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(revokeSecurityGroupIngressResponse));
+
+      IpPermission perm = IpPermission.builder().ipProtocol(IpProtocol.TCP).cidrBlock("0.0.0.0/0")
+            .fromPort(8080).toPort(8080).build();
+      IpPermission perm2 = IpPermission.builder().ipProtocol(IpProtocol.TCP).cidrBlock("0.0.0.0/0")
+            .fromPort(8443).toPort(8443).build();
+      securityGroupApi().revokeSecurityGroupIngressInRegion(DEFAULT_REGION, "sg-1a2b3c4d", ImmutableList.of(perm, perm2));
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=RevokeSecurityGroupIngress&GroupId=sg-1a2b3c4d&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=8080&IpPermissions.0.ToPort=8080&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=8443&IpPermissions.1.ToPort=8443&IpPermissions.1.IpRanges.0.CidrIp=0.0.0.0/0");
+   }
+
+   public void deleteSecurityGroups() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody(deleteSecurityGroupResponse));
+
+      securityGroupApi().deleteSecurityGroupInRegionById(DEFAULT_REGION, "sg-1a2b3c4d");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DeleteSecurityGroup&GroupId=sg-1a2b3c4d");
+   }
+
+   private AWSSecurityGroupApi securityGroupApi() {
+      return api().getSecurityGroupApi().get();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiLiveTest.java
index 0dc9b08..b851f3a 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiLiveTest.java
@@ -16,12 +16,115 @@
  */
 package org.jclouds.aws.ec2.features;
 
-import org.jclouds.ec2.features.SubnetApiLiveTest;
+import static org.testng.Assert.assertEquals;
+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.jclouds.ec2.domain.Subnet;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-@Test(groups = "live", testName = "AWSSubnetApiLiveTest")
-public class AWSSubnetApiLiveTest extends SubnetApiLiveTest {
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Iterables;
+
+/**
+ * Tests behavior of {@code VPCApi}
+ */
+@Test(groups = "live", singleThreaded = true)
+public class AWSSubnetApiLiveTest extends BaseComputeServiceContextLiveTest {
+
+   private String region;
+
+   private AWSEC2Api api;
+   private AWSSubnetApi subnetClient;
+   private VPCApi vpcClient;
+
+   private Subnet subnet;
+   private VPC vpc;
+
    public AWSSubnetApiLiveTest() {
       provider = "aws-ec2";
+      region = "us-west-2";
+   }
+
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setupContext() {
+      super.setupContext();
+      api = view.unwrapApi(AWSEC2Api.class);
+      subnetClient = api.getAWSSubnetApi().get();
+      vpcClient = view.unwrapApi(AWSEC2Api.class).getVPCApi().get();
+   }
+
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDownContext() {
+      try {
+         try {
+            if (subnet != null) {
+               subnetClient.deleteSubnetInRegion(region, subnet.getSubnetId());
+            }
+         } finally {
+            if (vpc != null) {
+               vpcClient.deleteVpc(region, vpc.id());
+            }
+         }
+      } finally {
+         super.tearDownContext();
+      }
+   }
+
+   @Test
+   public void testCreateSubnetInRegion() {
+      vpc = vpcClient.createVpc(region, "10.0.0.0/16", CreateVpcOptions.NONE);
+      subnet = subnetClient.createSubnetInRegion(region, vpc.id(), "10.0.0.0/20");
+      assertNotNull(subnet);
+      assertEquals(subnet.getCidrBlock(), "10.0.0.0/20");
+   }
+
+   @Test(dependsOnMethods = "testCreateSubnetInRegion")
+   public void testGet() {
+      FluentIterable<Subnet> subnets = subnetClient.describeSubnetsInRegion(region, subnet.getSubnetId());
+      Subnet subnetFound = Iterables.getOnlyElement(subnets);
+      assertEquals(subnetFound.getSubnetId(), subnet.getSubnetId());
+   }
+
+   @Test(dependsOnMethods = "testCreateSubnetInRegion")
+   public void testFilter() {
+      FluentIterable<Subnet> subnets = subnetClient.describeSubnetsInRegionWithFilter(region, 
+            ImmutableMultimap.of("subnet-id", subnet.getSubnetId()));
+      Subnet subnetFound = Iterables.getOnlyElement(subnets);
+      assertEquals(subnetFound.getSubnetId(), subnet.getSubnetId());
+   }
+
+   @Test(dependsOnMethods = "testCreateSubnetInRegion")
+   public void testList() {
+      FluentIterable<Subnet> subnets = subnetClient.describeSubnetsInRegionWithFilter(region, 
+            ImmutableMultimap.<String, String>of());
+      Optional<Subnet> subnetFound = Iterables.tryFind(subnets, new Predicate<Subnet>() {
+         @Override
+         public boolean apply(Subnet input) {
+            return input != null && input.getSubnetId().equals(subnet.getSubnetId());
+         }
+      });
+      assertTrue(subnetFound.isPresent(), "subnets=" + ImmutableList.copyOf(subnets));
+   }
+
+   @Test(dependsOnMethods = {"testGet", "testFilter", "testList"}, alwaysRun = true)
+   public void testDelete() {
+      if (subnet != null) {
+         String subnetId = subnet.getSubnetId();
+         subnet = null;
+         subnetClient.deleteSubnetInRegion(region, subnetId);
+      }
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiMockTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiMockTest.java
new file mode 100644
index 0000000..b8f81ca
--- /dev/null
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSubnetApiMockTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.assertTrue;
+
+import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest;
+import org.jclouds.aws.ec2.options.CreateSubnetOptions;
+import org.jclouds.ec2.domain.Subnet;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Iterables;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+
+@Test(groups = "unit", testName = "AWSSubnetApiMockTest", singleThreaded = true)
+public class AWSSubnetApiMockTest extends BaseAWSEC2ApiMockTest {
+
+   private final String describeSubnetsResponse = "<DescribeSubnetsResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-11-15/\">\n" +
+         "  <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>\n" +
+         "  <subnetSet>\n" +
+         "    <item>\n" +
+         "      <subnetId>subnet-9d4a7b6c</subnetId>\n" +
+         "      <state>available</state>\n" +
+         "      <vpcId>vpc-1a2b3c4d</vpcId>\n" +
+         "      <cidrBlock>10.0.1.0/24</cidrBlock> \n" +
+         "      <ipv6CidrBlockAssociationSet>\n" +
+         "        <item>\n" +
+         "          <ipv6CidrBlock>2001:db8:1234:1a00::/64</ipv6CidrBlock>\n" +
+         "          <associationId>subnet-cidr-assoc-abababab</associationId>\n" +
+         "          <ipv6CidrBlockState>\n" +
+         "          <state>ASSOCIATED</state>\n" +
+         "          </ipv6CidrBlockState>\n" +
+         "        </item>\n" +
+         "      </ipv6CidrBlockAssociationSet>\n" +
+         "      <availableIpAddressCount>251</availableIpAddressCount>\n" +
+         "      <availabilityZone>us-east-1a</availabilityZone>\n" +
+         "      <defaultForAz>false</defaultForAz>\n" +
+         "      <mapPublicIpOnLaunch>false</mapPublicIpOnLaunch>\n" +
+         "      <tagSet/>\n" +
+         "      <assignIpv6AddressOnCreation>false</assignIpv6AddressOnCreation>\n" +
+         "    </item>\n" +
+         "  </subnetSet>\n" +
+         "</DescribeSubnetsResponse>";
+
+   public void createSubnetInRegion() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION, new MockResponse().setBody("<CreateSubnetResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-09-15/\">\n" +
+              "  <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>\n" +
+              "  <subnet>\n" +
+              "    <subnetId>subnet-9d4a7b6c</subnetId>\n" +
+              "    <state>pending</state>\n" +
+              "    <vpcId>vpc-1a2b3c4d</vpcId>\n" +
+              "    <cidrBlock>10.0.1.0/24</cidrBlock> \n" +
+              "    <availableIpAddressCount>251</availableIpAddressCount>\n" +
+              "    <availabilityZone>us-east-1a</availabilityZone>\n" +
+              "    <tagSet/>\n" +
+              "  </subnet>\n" +
+              "</CreateSubnetResponse>"));
+
+      Subnet result = subnetApi().createSubnetInRegion(DEFAULT_REGION, "vpc-1a2b3c4d", "10.0.1.0/24");
+      assertEquals(result.getVpcId(), "vpc-1a2b3c4d");
+      assertEquals(result.getCidrBlock(), "10.0.1.0/24");
+      assertEquals(result.getAvailabilityZone(), "us-east-1a");
+      assertEquals(result.getSubnetId(), "subnet-9d4a7b6c");
+      assertEquals(result.getSubnetState().value(), "pending");
+
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=CreateSubnet&VpcId=vpc-1a2b3c4d&CidrBlock=10.0.1.0/24");
+   }
+
+   public void createSubnetInRegion_options() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION,
+            new MockResponse().setBody("<CreateSubnetResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-09-15/\">\n" +
+                    "  <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>\n" +
+                    "  <subnet>\n" +
+                    "    <subnetId>subnet-9d4a7b6c</subnetId>\n" +
+                    "    <state>pending</state>\n" +
+                    "    <vpcId>vpc-1a2b3c4d</vpcId>\n" +
+                    "    <cidrBlock>10.0.1.0/24</cidrBlock> \n" +
+                    "    <availableIpAddressCount>251</availableIpAddressCount>\n" +
+                    "    <availabilityZone>us-east-1a</availabilityZone>\n" +
+                    "    <tagSet/>\n" +
+                    "  </subnet>\n" +
+                    "</CreateSubnetResponse>"));
+
+      Subnet result = subnetApi().createSubnetInRegion(DEFAULT_REGION, "vpc-1a2b3c4d", "10.0.1.0/24",
+            new CreateSubnetOptions().dryRun().availabilityZone("us-east-1a"));
+      assertEquals(result.getVpcId(), "vpc-1a2b3c4d");
+      assertEquals(result.getCidrBlock(), "10.0.1.0/24");
+      assertEquals(result.getAvailabilityZone(), "us-east-1a");
+      assertEquals(result.getSubnetId(), "subnet-9d4a7b6c");
+      assertEquals(result.getSubnetState().value(), "pending");
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=CreateSubnet&VpcId=vpc-1a2b3c4d&CidrBlock=10.0.1.0/24&DryRun=true&AvailabilityZone=us-east-1a");
+   }
+
+   public void deleteSubnetInRegion() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION,
+            new MockResponse().setBody("<DeleteSubnetResponse xmlns=\"http://ec2.amazonaws.com/doc/2016-09-15/\">\n" +
+                    "  <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>\n" +
+                    "  <return>true</return>\n" +
+                    "</DeleteSubnetResponse>"));
+
+      subnetApi().deleteSubnetInRegion(DEFAULT_REGION, "subnet-9d4a7b6c");
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DeleteSubnet&SubnetId=subnet-9d4a7b6c");
+   }
+
+   public void describeSubnetInRegion() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION,
+            new MockResponse().setBody(describeSubnetsResponse));
+
+      FluentIterable<Subnet> results = subnetApi().describeSubnetsInRegion(DEFAULT_REGION);
+      Subnet result = Iterables.getOnlyElement(results);
+      assertEquals(result.getSubnetId(), "subnet-9d4a7b6c");
+      assertEquals(result.getSubnetState().value(), "available");
+      assertEquals(result.getVpcId(), "vpc-1a2b3c4d");
+      assertEquals(result.getCidrBlock(), "10.0.1.0/24");
+      assertEquals(result.getAvailabilityZone(), "us-east-1a");
+      assertEquals(result.getAvailableIpAddressCount(), 251);
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSubnets");
+   }
+
+   public void describeSubnetInRegionWithFilter() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION,
+            new MockResponse().setBody(describeSubnetsResponse));
+
+      FluentIterable<Subnet> results = subnetApi().describeSubnetsInRegionWithFilter(DEFAULT_REGION,
+            ImmutableMultimap.of("vpc-id", "vpc-1a2b3c4d", "availabilityZone", "us-east-1a"));
+      Subnet result = Iterables.getOnlyElement(results);
+      assertEquals(result.getSubnetId(), "subnet-9d4a7b6c");
+      assertEquals(result.getSubnetState().value(), "available");
+      assertEquals(result.getVpcId(), "vpc-1a2b3c4d");
+      assertEquals(result.getCidrBlock(), "10.0.1.0/24");
+      assertEquals(result.getAvailabilityZone(), "us-east-1a");
+      assertEquals(result.getAvailableIpAddressCount(), 251);
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSubnets&Filter.1.Name=vpc-id&Filter.1.Value.1=vpc-1a2b3c4d&Filter.2.Name=availabilityZone&Filter.2.Value.1=us-east-1a");
+   }
+
+   public void describeSubnetInRegionWhen404() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION,
+            new MockResponse().setResponseCode(404));
+
+      FluentIterable<Subnet> results = subnetApi().describeSubnetsInRegion(DEFAULT_REGION);
+      assertTrue(Iterables.isEmpty(results));
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSubnets");
+   }
+
+   public void describeSubnetInRegionWithFilterWhen404() throws Exception {
+      enqueueRegions(DEFAULT_REGION);
+      enqueue(DEFAULT_REGION,
+            new MockResponse().setResponseCode(404));
+
+      FluentIterable<Subnet> results = subnetApi().describeSubnetsInRegionWithFilter(DEFAULT_REGION,
+            ImmutableMultimap.of("vpc-id", "vpc-1a2b3c4d"));
+      assertTrue(Iterables.isEmpty(results));
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSubnets&Filter.1.Name=vpc-id&Filter.1.Value.1=vpc-1a2b3c4d");
+   }
+
+   public void describeSubnetInNonDefaultRegionWhen404() throws Exception {
+      String region = "us-west-2";
+      
+      enqueueRegions(DEFAULT_REGION, region);
+      enqueue(region,
+            new MockResponse().setResponseCode(404));
+
+      FluentIterable<Subnet> results = subnetApiForRegion(region).list();
+      assertTrue(Iterables.isEmpty(results));
+      
+      assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
+      assertPosted(region, "Action=DescribeSubnets");
+   }
+
+   private AWSSubnetApi subnetApi() {
+      return api().getAWSSubnetApi().get();
+   }
+   
+   private AWSSubnetApi subnetApiForRegion(String region) {
+      return api().getAWSSubnetApiForRegion(region).get();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/VPCApiLiveTest.java
----------------------------------------------------------------------
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
index 06c4873..7ee0d31 100644
--- 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
@@ -24,6 +24,7 @@ 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.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -48,6 +49,18 @@ public class VPCApiLiveTest extends BaseComputeServiceContextLiveTest {
       client = view.unwrapApi(AWSEC2Api.class).getVPCApi().get();
    }
 
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDownContext() {
+      try {
+         if (vpc != null) {
+            client.deleteVpc(null, vpc.id());
+         }
+      } finally {
+         super.tearDownContext();
+      }
+   }
+
    @Test
    public void testCreate() {
       vpc = client.createVpc(null, "10.0.0.0/16", CreateVpcOptions.NONE);
@@ -69,7 +82,9 @@ public class VPCApiLiveTest extends BaseComputeServiceContextLiveTest {
    @Test(dependsOnMethods = {"testList", "testGet"}, alwaysRun = true)
    public void testDelete() {
       if (vpc != null) {
-         assertTrue(client.deleteVpc(null, vpc.id()));
+         String vpcId = vpc.id();
+         vpc = null;
+         assertTrue(client.deleteVpc(null, vpcId));
       }
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/internal/BaseAWSEC2ApiMockTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/internal/BaseAWSEC2ApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/internal/BaseAWSEC2ApiMockTest.java
index 796cf69..060e577 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/internal/BaseAWSEC2ApiMockTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/internal/BaseAWSEC2ApiMockTest.java
@@ -116,7 +116,7 @@ public class BaseAWSEC2ApiMockTest {
       }
    }
 
-   @BeforeMethod
+   @BeforeMethod(alwaysRun = true)
    public void start() throws IOException {
       MockWebServer server = new MockWebServer();
       server.play();


[2/2] jclouds git commit: JCLOUDS-1269; JCLOUDS-1120: ec2 subnet/securityGroups fixes

Posted by an...@apache.org.
JCLOUDS-1269; JCLOUDS-1120: ec2 subnet/securityGroups fixes


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/1c6c36b8
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/1c6c36b8
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/1c6c36b8

Branch: refs/heads/master
Commit: 1c6c36b81af44b14b534c9dd5be663cbcd16c8b8
Parents: fe134cf
Author: Andrea Turli <an...@gmail.com>
Authored: Sat Oct 29 15:06:51 2016 +0200
Committer: Andrea Turli <an...@gmail.com>
Committed: Thu May 4 17:40:50 2017 +0200

----------------------------------------------------------------------
 .../BindSubnetIdsToIndexedFormParams.java       |  35 +++
 .../jclouds/ec2/compute/EC2ComputeService.java  |  51 ++--
 .../functions/EC2SecurityGroupIdFromName.java   |   5 +-
 .../predicates/SecurityGroupPresent.java        |   7 +-
 .../jclouds/ec2/features/SecurityGroupApi.java  |  34 +++
 .../ec2/xml/DescribeSubnetsResponseHandler.java |   8 +-
 .../java/org/jclouds/ec2/xml/SubnetHandler.java |  10 +
 .../compute/EC2ComputeServiceExpectTest.java    |   5 +
 .../extensions/EC2ImageExtensionExpectTest.java |   5 -
 .../EC2SecurityGroupExtensionExpectTest.java    |  20 ++
 .../BaseEC2ComputeServiceExpectTest.java        |  16 ++
 .../features/SecurityGroupApiExpectTest.java    |  66 +++++
 .../ec2/features/SecurityGroupApiLiveTest.java  |   2 +-
 .../java/org/jclouds/aws/ec2/AWSEC2Api.java     |  25 +-
 .../AWSEC2CreateSecurityGroupIfNeeded.java      |  14 +-
 ...curityGroupsAsNeededAndReturnRunOptions.java |   9 +-
 .../aws/ec2/features/AWSSecurityGroupApi.java   |   9 +
 .../jclouds/aws/ec2/features/AWSSubnetApi.java  | 133 +++++++++
 .../ec2/options/CreateSecurityGroupOptions.java |   2 +-
 .../aws/ec2/options/CreateSubnetOptions.java    |  85 ++++++
 .../AWSEC2ComputeServiceApiMockTest.java        |  34 +--
 ...AWSEC2SecurityGroupExtensionApiMockTest.java |   4 +-
 .../AWSEC2CreateSecurityGroupIfNeededTest.java  |   3 +-
 ...tyGroupsAsNeededAndReturnRunOptionsTest.java |   2 +-
 .../features/AWSSecurityGroupApiLiveTest.java   |  44 +++
 .../features/AWSSecurityGroupApiMockTest.java   | 270 +++++++++++++++++++
 .../aws/ec2/features/AWSSubnetApiLiveTest.java  | 109 +++++++-
 .../aws/ec2/features/AWSSubnetApiMockTest.java  | 213 +++++++++++++++
 .../aws/ec2/features/VPCApiLiveTest.java        |  17 +-
 .../aws/ec2/internal/BaseAWSEC2ApiMockTest.java |   2 +-
 30 files changed, 1166 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/binders/BindSubnetIdsToIndexedFormParams.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/binders/BindSubnetIdsToIndexedFormParams.java b/apis/ec2/src/main/java/org/jclouds/ec2/binders/BindSubnetIdsToIndexedFormParams.java
new file mode 100644
index 0000000..f71d8d0
--- /dev/null
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/binders/BindSubnetIdsToIndexedFormParams.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.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 query parameters named with SubnetId.index
+ */
+@Singleton
+public class BindSubnetIdsToIndexedFormParams implements Binder {
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      return AWSUtils.indexStringArrayToFormValuesWithPrefix(request, "SubnetId", input);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
index e84b65e..37d7553 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java
@@ -32,9 +32,6 @@ import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTA
 import static org.jclouds.ec2.util.Tags.resourceToTagsAsMap;
 import static org.jclouds.util.Predicates2.retry;
 
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -42,21 +39,10 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicReference;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableMultimap.Builder;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
 import org.jclouds.Constants;
 import org.jclouds.aws.util.AWSUtils;
 import org.jclouds.collect.Memoized;
@@ -95,10 +81,27 @@ import org.jclouds.ec2.compute.options.EC2TemplateOptions;
 import org.jclouds.ec2.domain.InstanceState;
 import org.jclouds.ec2.domain.KeyPair;
 import org.jclouds.ec2.domain.RunningInstance;
+import org.jclouds.ec2.domain.SecurityGroup;
 import org.jclouds.ec2.domain.Tag;
 import org.jclouds.ec2.util.TagFilterBuilder;
 import org.jclouds.scriptbuilder.functions.InitAdminAccess;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableMultimap.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+
 @Singleton
 public class EC2ComputeService extends BaseComputeService {
    private final EC2Api client;
@@ -220,10 +223,16 @@ public class EC2ComputeService extends BaseComputeService {
       checkNotNull(emptyToNull(group), "group must be defined");
       String groupName = namingConvention.create().sharedNameForGroup(group);
 
-      if (!client.getSecurityGroupApi().get().describeSecurityGroupsInRegion(region, groupName).isEmpty()) {
+      Multimap<String, String> securityGroupFilterByName = ImmutableMultimap.of("group-name", groupName);
+      Set<SecurityGroup> securityGroupsToDelete = client.getSecurityGroupApi().get()
+              .describeSecurityGroupsInRegionWithFilter(region, securityGroupFilterByName);
+      if (securityGroupsToDelete.size() > 1) {
+         logger.warn("When trying to delete security group %s found more than one matching the name. Will delete all - %s.",
+                 group, securityGroupsToDelete);
+      }
+      for (SecurityGroup securityGroup : securityGroupsToDelete) {
          logger.debug(">> deleting securityGroup(%s)", groupName);
-         client.getSecurityGroupApi().get().deleteSecurityGroupInRegion(region, groupName);
-         // TODO: test this clear happens
+         client.getSecurityGroupApi().get().deleteSecurityGroupInRegionById(region, securityGroup.getId());
          securityGroupMap.invalidate(new RegionNameAndIngressRules(region, groupName, null, false, null));
          logger.debug("<< deleted securityGroup(%s)", groupName);
       }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/EC2SecurityGroupIdFromName.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/EC2SecurityGroupIdFromName.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/EC2SecurityGroupIdFromName.java
index 640a967..56a7f80 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/EC2SecurityGroupIdFromName.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/EC2SecurityGroupIdFromName.java
@@ -17,6 +17,7 @@
 package org.jclouds.ec2.compute.functions;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMultimap.of;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -42,7 +43,7 @@ public class EC2SecurityGroupIdFromName implements Function<String, String> {
       String[] parts = AWSUtils.parseHandle(input);
       String region = parts[0];
       String name = parts[1];
-
-      return  Iterables.getOnlyElement(api.getSecurityGroupApi().get().describeSecurityGroupsInRegion(region, name), null).getId();
+      return Iterables.getOnlyElement(api.getSecurityGroupApi().get()
+               .describeSecurityGroupsInRegionWithFilter(region, of("group-name", name))).getId();
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
index 7899478..788ce01 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/predicates/SecurityGroupPresent.java
@@ -30,6 +30,7 @@ import org.jclouds.logging.Logger;
 import org.jclouds.rest.ResourceNotFoundException;
 
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
@@ -57,8 +58,8 @@ public class SecurityGroupPresent implements Predicate<RegionAndName> {
       }
    }
 
-   protected SecurityGroup refresh(RegionAndName securityGroup) {
-      return Iterables.getOnlyElement(client.getSecurityGroupApi().get().describeSecurityGroupsInRegion(
-            securityGroup.getRegion(), securityGroup.getName()));
+   protected SecurityGroup refresh(final RegionAndName securityGroup) {
+      return Iterables.getOnlyElement(client.getSecurityGroupApi().get().describeSecurityGroupsInRegionWithFilter(securityGroup.getRegion(),
+              ImmutableMultimap.of("group-name", securityGroup.getName())));
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/features/SecurityGroupApi.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/features/SecurityGroupApi.java b/apis/ec2/src/main/java/org/jclouds/ec2/features/SecurityGroupApi.java
index 28fd497..b44290f 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/features/SecurityGroupApi.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/features/SecurityGroupApi.java
@@ -86,6 +86,39 @@ public interface SecurityGroupApi {
             @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
             @FormParam("GroupName") String name, @FormParam("GroupDescription") String description);
 
+
+   // Supported by
+   //  * AWS
+   //  * Openstack - https://github.com/openstack/ec2-api/blob/61daf6a80fd6cc9ab800e6b6a2cd3d1d827e2527/ec2api/api/security_group.py#L130
+   //  * Eucalyptus - https://docs.eucalyptus.com/eucalyptus/4.4.0/#euca2ools-guide/euca-delete-group.html
+   //                 https://github.com/eucalyptus/euca2ools/blob/096d97ef2729da976759657d6d6f645a6e959e05/euca2ools/commands/ec2/deletesecuritygroup.py#L37
+   /**
+    * Deletes a security group by ID.
+    *
+    * @param region
+    *           Security groups are not copied across Regions. Instances within the Region cannot
+    *           communicate with instances outside the Region using group-based firewall rules.
+    *           Traffic from instances in another Region is seen as WAN bandwidth.
+    * @param id
+    *           ID of the security group to delete.
+    *
+    * @see #describeSecurityGroups
+    * @see #authorizeSecurityGroupIngress
+    * @see #revokeSecurityGroupIngress
+    * @see #createSecurityGroup
+    *
+    * @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DeleteSecurityGroup.html"
+    *      />
+    */
+   @Named("DeleteSecurityGroup")
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DeleteSecurityGroup")
+   @Fallback(VoidOnNotFoundOr404.class)
+   void deleteSecurityGroupInRegionById(
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
+           @FormParam("GroupId") String id);
+   
    /**
     * Deletes a security group that you own.
     * 
@@ -114,6 +147,7 @@ public interface SecurityGroupApi {
 
    /**
     * Returns information about security groups that you own.
+    * <p><em>NOTE</em> Works with groups in default VPC only</p>
     *
     * @param region
     *           Security groups are not copied across Regions. Instances within the Region cannot

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSubnetsResponseHandler.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSubnetsResponseHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSubnetsResponseHandler.java
index 1f25d4b..dbcc968 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSubnetsResponseHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSubnetsResponseHandler.java
@@ -37,6 +37,7 @@ public class DescribeSubnetsResponseHandler extends
    private StringBuilder currentText = new StringBuilder();
    private boolean inSubnetSet;
    private boolean inTagSet;
+   private boolean inIpv6CidrBlockAssociationSet;
    private Builder<Subnet> subnets = ImmutableSet.<Subnet> builder();
 
    @Inject
@@ -56,6 +57,8 @@ public class DescribeSubnetsResponseHandler extends
       } else if (inSubnetSet) {
          if (equalsOrSuffix(qName, "tagSet")) {
             inTagSet = true;
+         } else if (equalsOrSuffix(qName, "ipv6CidrBlockAssociationSet")) {
+            inIpv6CidrBlockAssociationSet = true;
          }
          subnetHandler.startElement(url, name, qName, attributes);
       }
@@ -68,7 +71,10 @@ public class DescribeSubnetsResponseHandler extends
       } else if (equalsOrSuffix(qName, "tagSet")) {
          inTagSet = false;
          subnetHandler.endElement(uri, name, qName);
-      } else if (equalsOrSuffix(qName, "item") && !inTagSet) {
+      } else if (equalsOrSuffix(qName, "ipv6CidrBlockAssociationSet")) {
+         inIpv6CidrBlockAssociationSet = false;
+         subnetHandler.endElement(uri, name, qName);
+      } else if (equalsOrSuffix(qName, "item") && !inTagSet && !inIpv6CidrBlockAssociationSet) {
          subnets.add(subnetHandler.getResult());
       } else if (inSubnetSet) {
          subnetHandler.endElement(uri, name, qName);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/main/java/org/jclouds/ec2/xml/SubnetHandler.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/SubnetHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/SubnetHandler.java
index e055425..1dd21e1 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/SubnetHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/SubnetHandler.java
@@ -33,6 +33,7 @@ public class SubnetHandler extends ParseSax.HandlerForGeneratedRequestWithResult
    private Subnet.Builder builder = Subnet.builder();
    private final TagSetHandler tagSetHandler;
    private boolean inTagSet;
+   private boolean inIpv6CidrBlockAssociationSet;
 
    @Inject
    public SubnetHandler(TagSetHandler tagSetHandler) {
@@ -52,6 +53,8 @@ public class SubnetHandler extends ParseSax.HandlerForGeneratedRequestWithResult
    public void startElement(String uri, String name, String qName, Attributes attrs) {
       if (equalsOrSuffix(qName, "tagSet")) {
          inTagSet = true;
+      } else if (equalsOrSuffix(qName, "ipv6CidrBlockAssociationSet")) {
+         inIpv6CidrBlockAssociationSet = true;
       }
       if (inTagSet) {
          tagSetHandler.startElement(uri, name, qName, attrs);
@@ -60,6 +63,13 @@ public class SubnetHandler extends ParseSax.HandlerForGeneratedRequestWithResult
 
    @Override
    public void endElement(String uri, String name, String qName) {
+      if (equalsOrSuffix(qName, "ipv6CidrBlockAssociationSet")) {
+         inIpv6CidrBlockAssociationSet = false;
+      }
+      if (inIpv6CidrBlockAssociationSet) {
+         return; // ignore contents (otherwise "item" and "state" will confuse us!
+      }
+      
       if (equalsOrSuffix(qName, "tagSet")) {
          inTagSet = false;
          builder.tags(tagSetHandler.getResult());

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceExpectTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceExpectTest.java
index 4ffad1f..6de7d27 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceExpectTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceExpectTest.java
@@ -118,6 +118,7 @@ public class EC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest
       requestResponseMap.put(describeImagesRequest, describeImagesResponse);
       requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
       requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
+      requestResponseMap.put(describeSecurityGroupFilteredRequest, describeSecurityGroupFilteredResponse);
       requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
@@ -144,6 +145,7 @@ public class EC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest
       requestResponseMap.put(describeImagesRequest, describeImagesResponse);
       requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
       requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
+      requestResponseMap.put(describeSecurityGroupFilteredRequest, describeSecurityGroupFilteredResponse);
       requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
@@ -171,6 +173,7 @@ public class EC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest
       requestResponseMap.put(describeImagesRequest, describeImagesResponse);
       requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
       requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
+      requestResponseMap.put(describeSecurityGroupFilteredRequest, describeSecurityGroupFilteredResponse);
       requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
@@ -263,6 +266,7 @@ public class EC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest
       requestResponseMap.put(describeImagesRequest, describeImagesResponse);
       requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
       requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
+      requestResponseMap.put(describeSecurityGroupFilteredRequest, describeSecurityGroupFilteredResponse);
       requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
@@ -298,6 +302,7 @@ public class EC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest
       requestResponseMap.put(describeImagesRequest, describeImagesResponse);
       requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
       requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
+      requestResponseMap.put(describeSecurityGroupFilteredRequest, describeSecurityGroupFilteredResponse);
       requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
       requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2ImageExtensionExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2ImageExtensionExpectTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2ImageExtensionExpectTest.java
index 4ca6c62..11c968a 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2ImageExtensionExpectTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2ImageExtensionExpectTest.java
@@ -40,11 +40,6 @@ public class EC2ImageExtensionExpectTest extends BaseEC2ComputeServiceExpectTest
       requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
       requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
       requestResponseMap.put(describeImagesRequest, describeImagesResponse);
-      requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
-      requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
-      requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
-      requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
-      requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
       requestResponseMap.put(describeInstanceRequest, describeInstanceResponse);
       
       HttpRequest createImageRequest = formSigner.filter(HttpRequest.builder().method("POST")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2SecurityGroupExtensionExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2SecurityGroupExtensionExpectTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2SecurityGroupExtensionExpectTest.java
index 5bb73bb..733edbf 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2SecurityGroupExtensionExpectTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/extensions/EC2SecurityGroupExtensionExpectTest.java
@@ -49,6 +49,12 @@ import com.google.common.collect.Sets;
 @Test(groups = "unit", testName = "EC2SecurityGroupExtensionExpectTest")
 public class EC2SecurityGroupExtensionExpectTest extends BaseEC2ComputeServiceExpectTest {
    
+   public EC2SecurityGroupExtensionExpectTest() {
+      // Don't use the default (us-east-1) region. Better to ensure we always pass through the
+      // desired region, rather than it falling back to the default!
+      region = "eu-west-1";
+   }
+   
    public void testListSecurityGroups() {
       HttpRequest describeSecurityGroupsAllRequest = 
          formSigner.filter(HttpRequest.builder()
@@ -209,10 +215,24 @@ public class EC2SecurityGroupExtensionExpectTest extends BaseEC2ComputeServiceEx
          .payload(payloadFromResourceWithContentType(
                                                      "/describe_securitygroups_extension_single.xml", MediaType.APPLICATION_XML)).build();
       
+      HttpRequest describeSecurityGroupsSingleFilteredRequest = 
+            formSigner.filter(HttpRequest.builder()
+                              .method("POST")
+                              .endpoint("https://ec2." + region + ".amazonaws.com/")
+                              .addHeader("Host", "ec2." + region + ".amazonaws.com")
+                              .addFormParam("Action", "DescribeSecurityGroups")
+                              .addFormParam("Filter.1.Name", "group-name")
+                              .addFormParam("Filter.1.Value.1", "jclouds#some-group").build());
+
+         HttpResponse describeSecurityGroupsSingleFilteredResponse = 
+            HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType(
+                                                        "/describe_securitygroups_extension_single.xml", MediaType.APPLICATION_XML)).build();
 
       Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
       requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
       requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
+      requestResponseMap.put(describeSecurityGroupsSingleFilteredRequest, describeSecurityGroupsSingleFilteredResponse);
       requestResponseMap.put(describeSecurityGroupsSingleRequest, describeSecurityGroupsSingleResponse);
       requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
       requestResponseMap.put(createSecurityGroupExtRequest, createSecurityGroupResponse);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/BaseEC2ComputeServiceExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/BaseEC2ComputeServiceExpectTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/BaseEC2ComputeServiceExpectTest.java
index 4178e74..eb7e397 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/BaseEC2ComputeServiceExpectTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/internal/BaseEC2ComputeServiceExpectTest.java
@@ -46,6 +46,8 @@ public abstract class BaseEC2ComputeServiceExpectTest extends BaseEC2ComputeServ
    protected HttpResponse createKeyPairResponse;
    protected HttpRequest createSecurityGroupRequest;
    protected HttpResponse createSecurityGroupResponse;
+   protected HttpRequest describeSecurityGroupFilteredRequest;
+   protected HttpResponse describeSecurityGroupFilteredResponse;
    protected HttpRequest describeSecurityGroupRequest;
    protected HttpResponse describeSecurityGroupResponse;
    protected HttpRequest authorizeSecurityGroupIngressRequest22;
@@ -124,6 +126,20 @@ public abstract class BaseEC2ComputeServiceExpectTest extends BaseEC2ComputeServ
                            .payload(payloadFromResourceWithContentType(
                                  "/created_securitygroup.xml", MediaType.APPLICATION_XML)).build();
 
+      describeSecurityGroupFilteredRequest = 
+            formSigner.filter(HttpRequest.builder()
+                       .method("POST")
+                       .endpoint("https://ec2." + region + ".amazonaws.com/")
+                       .addHeader("Host", "ec2." + region + ".amazonaws.com")
+                       .addFormParam("Action", "DescribeSecurityGroups")
+                       .addFormParam("Filter.1.Name", "group-name")
+                       .addFormParam("Filter.1.Value.1", "jclouds#test").build());
+   
+      describeSecurityGroupFilteredResponse = 
+            HttpResponse.builder().statusCode(200)
+                        .payload(payloadFromResourceWithContentType(
+                              "/new_securitygroup.xml", MediaType.APPLICATION_XML)).build();
+   
       describeSecurityGroupRequest = 
                formSigner.filter(HttpRequest.builder()
                           .method("POST")

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiExpectTest.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiExpectTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiExpectTest.java
index 811711a..0e5d593 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiExpectTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiExpectTest.java
@@ -45,6 +45,30 @@ public class SecurityGroupApiExpectTest extends BaseEC2ApiExpectTest<EC2Api> {
            .addFormParam("Version", "2010-08-31")
            .addFormParam("AWSAccessKeyId", "identity").build();
 
+   HttpRequest deleteById = HttpRequest.builder().method("POST")
+         .endpoint("https://ec2.us-east-1.amazonaws.com/")
+         .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+         .addFormParam("Action", "DeleteSecurityGroup")
+         .addFormParam("GroupId", "sg-3c6ef654")
+         .addFormParam("Signature", "FhFx9Uv587s+86KuCOngA2x3DiLRuRrkyd0ZTrXAYbc=")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2012-04-16T15:54:08.897Z")
+         .addFormParam("Version", "2010-08-31")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   HttpRequest deleteByName = HttpRequest.builder().method("POST")
+         .endpoint("https://ec2.us-east-1.amazonaws.com/")
+         .addHeader("Host", "ec2.us-east-1.amazonaws.com")
+         .addFormParam("Action", "DeleteSecurityGroup")
+         .addFormParam("GroupName", "jclouds#some-group")
+         .addFormParam("Signature", "Jw9ZpWcnAEPaNtZNZBsMyOUUFP1qGETKUzvHiAOz5C8=")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2012-04-16T15:54:08.897Z")
+         .addFormParam("Version", "2010-08-31")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
    public void testFilterWhenResponseIs2xx() {
       HttpResponse filterResponse = HttpResponse.builder().statusCode(200)
               .payload(payloadFromResourceWithContentType("/describe_securitygroups_extension_single.xml", "text/xml")).build();
@@ -70,4 +94,46 @@ public class SecurityGroupApiExpectTest extends BaseEC2ApiExpectTest<EC2Api> {
                       .build()),
               ImmutableSet.of());
    }
+   
+   public void testDeleteSecurityGroupById() {
+      HttpResponse deleteResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/delete_securitygroup.xml", "text/xml")).build();
+
+      EC2Api apiWhenNotExist = requestsSendResponses(
+            describeRegionsRequest, describeRegionsResponse, 
+            deleteById, deleteResponse);
+
+      apiWhenNotExist.getSecurityGroupApi().get().deleteSecurityGroupInRegionById("us-east-1", "sg-3c6ef654");
+   }
+   
+   public void testDeleteSecurityGroupByIdWhen404() {
+      HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build();
+
+      EC2Api apiWhenNotExist = requestsSendResponses(
+            describeRegionsRequest, describeRegionsResponse, 
+            deleteById, deleteResponse);
+
+      apiWhenNotExist.getSecurityGroupApi().get().deleteSecurityGroupInRegionById("us-east-1", "sg-3c6ef654");
+   }
+   
+   public void testDeleteSecurityGroupByName() {
+      HttpResponse deleteResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/delete_securitygroup.xml", "text/xml")).build();
+
+      EC2Api apiWhenNotExist = requestsSendResponses(
+            describeRegionsRequest, describeRegionsResponse, 
+            deleteByName, deleteResponse);
+
+      apiWhenNotExist.getSecurityGroupApi().get().deleteSecurityGroupInRegion("us-east-1", "jclouds#some-group");
+   }
+   
+   public void testDeleteSecurityGroupByNameWhen404() {
+      HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build();
+
+      EC2Api apiWhenNotExist = requestsSendResponses(
+            describeRegionsRequest, describeRegionsResponse, 
+            deleteByName, deleteResponse);
+
+      apiWhenNotExist.getSecurityGroupApi().get().deleteSecurityGroupInRegion("us-east-1", "jclouds#some-group");
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiLiveTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiLiveTest.java
index d2c1238..c37e7e7 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiLiveTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/features/SecurityGroupApiLiveTest.java
@@ -52,7 +52,7 @@ public class SecurityGroupApiLiveTest extends BaseComputeServiceContextLiveTest
       provider = "ec2";
    }
 
-   private EC2Api ec2Api;
+   protected EC2Api ec2Api;
    protected SecurityGroupApi client;
 
    @Override

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2Api.java
----------------------------------------------------------------------
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 37ca0e9..851597f 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
@@ -20,6 +20,7 @@ import org.jclouds.aws.ec2.features.AWSAMIApi;
 import org.jclouds.aws.ec2.features.AWSInstanceApi;
 import org.jclouds.aws.ec2.features.AWSKeyPairApi;
 import org.jclouds.aws.ec2.features.AWSSecurityGroupApi;
+import org.jclouds.aws.ec2.features.AWSSubnetApi;
 import org.jclouds.aws.ec2.features.MonitoringApi;
 import org.jclouds.aws.ec2.features.PlacementGroupApi;
 import org.jclouds.aws.ec2.features.SpotInstanceApi;
@@ -47,7 +48,7 @@ public interface AWSEC2Api extends EC2Api {
    @Delegate
    @Override
    Optional<? extends AWSInstanceApi> getInstanceApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
    /**
     * {@inheritDoc}
@@ -59,7 +60,7 @@ public interface AWSEC2Api extends EC2Api {
    @Delegate
    @Override
    Optional<? extends AWSSecurityGroupApi> getSecurityGroupApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
    /**
     * {@inheritDoc}
@@ -71,7 +72,7 @@ public interface AWSEC2Api extends EC2Api {
    @Delegate
    @Override
    Optional<? extends AWSAMIApi> getAMIApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
 
    /**
@@ -82,7 +83,7 @@ public interface AWSEC2Api extends EC2Api {
 
    @Delegate
    Optional<? extends PlacementGroupApi> getPlacementGroupApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
    /**
     * Provides synchronous access to Monitoring services.
@@ -92,7 +93,7 @@ public interface AWSEC2Api extends EC2Api {
 
    @Delegate
    Optional<? extends MonitoringApi> getMonitoringApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
    /**
     * {@inheritDoc}
@@ -104,7 +105,7 @@ public interface AWSEC2Api extends EC2Api {
    @Delegate
    @Override
    Optional<? extends AWSKeyPairApi> getKeyPairApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
    /**
     * Provides synchronous access to SpotInstance services.
@@ -114,11 +115,21 @@ public interface AWSEC2Api extends EC2Api {
 
    @Delegate
    Optional<? extends SpotInstanceApi> getSpotInstanceApiForRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 
    /**
     * Provides synchronous access to VPC services.
     */
    @Delegate
    Optional<? extends VPCApi> getVPCApi();
+
+   /**
+    * Provides access to Subnet services.
+    */
+   @Delegate
+   Optional<? extends AWSSubnetApi> getAWSSubnetApi();
+
+   @Delegate
+   Optional<? extends AWSSubnetApi> getAWSSubnetApiForRegion(
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeeded.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeeded.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeeded.java
index 9e17354..1b2b033 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeeded.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeeded.java
@@ -33,6 +33,7 @@ import org.jclouds.aws.ec2.options.CreateSecurityGroupOptions;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.ec2.compute.domain.RegionAndName;
 import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
+import org.jclouds.ec2.domain.SecurityGroup;
 import org.jclouds.logging.Logger;
 import org.jclouds.net.domain.IpPermission;
 import org.jclouds.net.domain.IpProtocol;
@@ -73,7 +74,7 @@ public class AWSEC2CreateSecurityGroupIfNeeded extends CacheLoader<RegionAndName
       return createSecurityGroupInRegion(from.getRegion(), from.getName(), realFrom.getVpcId(), realFrom.getPorts());
    }
 
-   private String createSecurityGroupInRegion(String region, String name, String vpcId, int... ports) {
+   private String createSecurityGroupInRegion(String region, final String name, String vpcId, int... ports) {
       checkNotNull(region, "region");
       checkNotNull(name, "name");
       logger.debug(">> creating securityGroup region(%s) name(%s)", region, name);
@@ -102,7 +103,16 @@ public class AWSEC2CreateSecurityGroupIfNeeded extends CacheLoader<RegionAndName
                                .build());
             }
 
-            String myOwnerId = Iterables.get(securityApi.describeSecurityGroupsInRegion(region, name), 0).getOwnerId();
+            // Use filter (as per `SecurityGroupPresent`, in securityGroupEventualConsistencyDelay)
+            Set<SecurityGroup> securityGroups = securityApi.describeSecurityGroupsInRegionById(region, id);
+            if (securityGroups.isEmpty()) {
+               throw new IllegalStateException(String.format("security group %s/%s not found after creating", region, name));
+            } else if (securityGroups.size() > 1) {
+               throw new IllegalStateException(String.format("multiple security groups matching %s/%s found after creating: %s", 
+                     region, name, securityGroups));
+            }
+            SecurityGroup securityGroup = Iterables.getOnlyElement(securityGroups);
+            String myOwnerId = securityGroup.getOwnerId();
             permissions.add(IpPermission.builder()
                             .fromPort(0)
                             .toPort(65535)

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.java
index 782e376..694e1db 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.java
@@ -43,14 +43,15 @@ import org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAn
 import org.jclouds.ec2.domain.KeyPair;
 import org.jclouds.ec2.domain.Subnet;
 import org.jclouds.ec2.options.RunInstancesOptions;
-import org.jclouds.ec2.util.SubnetFilterBuilder;
 import org.jclouds.logging.Logger;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Iterables;
 
 @Singleton
 public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions extends
@@ -192,7 +193,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
          awsInstanceOptions.withSecurityGroupIds(awsTemplateOptions.getGroupIds());
       String subnetId = awsTemplateOptions.getSubnetId();
       if (subnetId != null) {
-         Set<String> groups = getSecurityGroupsForTagAndOptions(region, group, vpcIdForSubnet(subnetId), template.getOptions());
+         Set<String> groups = getSecurityGroupsForTagAndOptions(region, group, vpcIdForSubnet(region, subnetId), template.getOptions());
          awsInstanceOptions.withSubnetId(subnetId);
          awsInstanceOptions.withSecurityGroupIds(groups);
       } else {
@@ -202,8 +203,8 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions
    }
    
    @VisibleForTesting
-   String vpcIdForSubnet(String subnetId) {
-      Optional<Subnet> subnet = awsEC2Api.getSubnetApi().get().filter(new SubnetFilterBuilder().subnetId(subnetId).build()).first();
+   String vpcIdForSubnet(String region, String subnetId) {
+      Optional<Subnet> subnet = Iterables.tryFind(awsEC2Api.getAWSSubnetApi().get().describeSubnetsInRegion(region, subnetId), Predicates.<Subnet>notNull());
       if (!subnet.isPresent()) {
          throw new IllegalArgumentException("Subnet " + subnetId + " not found");
       }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApi.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApi.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApi.java
index f4e06f6..ef998e8 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApi.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApi.java
@@ -139,6 +139,15 @@ public interface AWSSecurityGroupApi extends SecurityGroupApi {
    @FormParams(keys = ACTION, values = "DescribeSecurityGroups")
    @XMLResponseParser(AWSEC2DescribeSecurityGroupsResponseHandler.class)
    @Fallback(EmptySetOnNotFoundOr404.class)
+   Set<SecurityGroup> describeSecurityGroupsInRegion(
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+   
+   @Named("DescribeSecurityGroups")
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DescribeSecurityGroups")
+   @XMLResponseParser(AWSEC2DescribeSecurityGroupsResponseHandler.class)
+   @Fallback(EmptySetOnNotFoundOr404.class)
    Set<SecurityGroup> describeSecurityGroupsInRegionWithFilter(
            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
            @BinderParam(BindFiltersToIndexedFormParams.class) Multimap<String, String> filter);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSubnetApi.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSubnetApi.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSubnetApi.java
new file mode 100644
index 0000000..ccafebe
--- /dev/null
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/AWSSubnetApi.java
@@ -0,0 +1,133 @@
+/*
+ * 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;
+import org.jclouds.aws.ec2.options.CreateSubnetOptions;
+import org.jclouds.aws.filters.FormSigner;
+import org.jclouds.ec2.binders.BindFiltersToIndexedFormParams;
+import org.jclouds.ec2.binders.BindSubnetIdsToIndexedFormParams;
+import org.jclouds.ec2.domain.Subnet;
+import org.jclouds.ec2.features.SubnetApi;
+import org.jclouds.ec2.xml.DescribeSubnetsResponseHandler;
+import org.jclouds.ec2.xml.SubnetHandler;
+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.SinceApiVersion;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Multimap;
+
+/**
+ * Provides access to Amazon EC2 via the Query API
+ * <p/>
+ *
+ * @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSubnets.html"
+ * >doc</a>
+ */
+@SinceApiVersion("2011-01-01")
+@RequestFilters(FormSigner.class)
+@VirtualHost
+public interface AWSSubnetApi extends SubnetApi {
+
+   /**
+    * Creates a subnet in an existing VPC.
+    *
+    * @param region
+    * @param vpcId     The ID of the VPC.
+    * @param cidrBlock The network range for the subnet, in CIDR notation. For example, 10.0.0.0/24.
+    * @param options
+    * @return AWS Subnet
+    */
+   @Named("CreateSubnet")
+   @POST
+   @Path("/")
+   @XMLResponseParser(SubnetHandler.class)
+   @FormParams(keys = ACTION, values = "CreateSubnet")
+   Subnet createSubnetInRegion(
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
+           @FormParam("VpcId") String vpcId, @FormParam("CidrBlock") String cidrBlock,
+           CreateSubnetOptions... options);
+
+   /**
+    * Deletes a subnet.
+    *
+    * @param region
+    * @param subnetId
+    * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteSubnet.html"
+    * >doc</a>
+    */
+   @Named("DeleteSubnet")
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DeleteSubnet")
+   void deleteSubnetInRegion(
+         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
+           @FormParam("SubnetId") String subnetId);
+
+   /**
+    * Describes one or more of your subnets.
+    *
+    * @param region       Subnet are Region-specific.
+    * @param subnetIds    Subnet to describe.
+    * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html"
+    * >doc</a>
+    */
+   @Named("DescribeSubnets")
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DescribeSubnets")
+   @XMLResponseParser(DescribeSubnetsResponseHandler.class)
+   @Fallback(Fallbacks.EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<Subnet> describeSubnetsInRegion(
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
+           @BinderParam(BindSubnetIdsToIndexedFormParams.class) String... subnetIds);
+
+   /**
+    * Returns information about subnets available to you. If you specify filters,
+    * information about subnets matching those filters is returned. Otherwise, all
+    * subnets you have access to are returned.
+    *
+    * @param region Subnets are Region-specific.
+    * @param filter Multimap of filter key/values.
+    * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html"
+    * >doc</a>
+    */
+   @Named("DescribeSubnets")
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DescribeSubnets")
+   @XMLResponseParser(DescribeSubnetsResponseHandler.class)
+   @Fallback(Fallbacks.EmptyFluentIterableOnNotFoundOr404.class)
+   FluentIterable<Subnet> describeSubnetsInRegionWithFilter(
+           @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
+           @BinderParam(BindFiltersToIndexedFormParams.class) Multimap<String, String> filter);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSecurityGroupOptions.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSecurityGroupOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSecurityGroupOptions.java
index 8e1ec94..604a8c0 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSecurityGroupOptions.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSecurityGroupOptions.java
@@ -31,7 +31,7 @@ import org.jclouds.ec2.options.internal.BaseEC2RequestOptions;
  * import static org.jclouds.aws.ec2.options.CreateSecurityGroupOptions.Builder.*
  * <p/>
  * AWSEC2Api connection = // get connection
- * group = connection.getAMIServices().createSecurityGroup(vpcId("123125").noReboot());
+ * group = connection.getAMIServices().createSecurityGroup(vpcId("123125"));
  * <code>
  * 
  * @see <a href=

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSubnetOptions.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSubnetOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSubnetOptions.java
new file mode 100644
index 0000000..0490a76
--- /dev/null
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/CreateSubnetOptions.java
@@ -0,0 +1,85 @@
+/*
+ * 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 CreateSubnet
+ * operation. <h2>
+ * Usage</h2> The recommended way to instantiate a CreateSubnetOptions
+ * object is to statically import CreateSubnetOptions.Builder.* and
+ * invoke a static creation method followed by an instance mutator (if needed):
+ * <p/>
+ * <code>
+ * import static org.jclouds.aws.ec2.options.CreateSubnetOptions.Builder.*
+ * <p/>
+ * AWSEC2Api connection = // get connection
+ * String vpcId = "vpc-1a2b3c4d";
+ * String cidrBlock = "10.0.1.0/24";
+ * group = connection.getAWSSubnetApi().createSubnetInRegion(vpcId, cirdBlock, availabilityZone("us-east-1a"));
+ * <code>
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/index.html?ApiReference-form-CreateSubnet.html"
+ *      />
+ */
+public class CreateSubnetOptions extends BaseEC2RequestOptions {
+
+   /**
+    * The Availability Zone for the subnet.
+    */
+   public CreateSubnetOptions availabilityZone(String availabilityZone) {
+      formParameters.put("AvailabilityZone", checkNotNull(availabilityZone, "availabilityZone"));
+      return this;
+   }
+
+   public String getAvailabilityZone() {
+      return getFirstFormOrNull("AvailabilityZone");
+   }
+
+   public CreateSubnetOptions dryRun() {
+      formParameters.put("DryRun", "true");
+      return this;
+   }
+
+   public boolean isDryRun() {
+      return Boolean.parseBoolean(getFirstFormOrNull("DryRun"));
+   }
+
+   public static class Builder {
+
+      /**
+       * @see CreateSubnetOptions#availabilityZone(String )
+       */
+      public static CreateSubnetOptions availabilityZone(String availabilityZone) {
+         CreateSubnetOptions options = new CreateSubnetOptions();
+         return options.availabilityZone(availabilityZone);
+      }
+
+      /**
+       * @see CreateSubnetOptions#dryRun()
+       */
+      public static CreateSubnetOptions dryRun() {
+         CreateSubnetOptions options = new CreateSubnetOptions();
+         return options.dryRun();
+      }
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceApiMockTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceApiMockTest.java
index 09f1d10..cc81219 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceApiMockTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/AWSEC2ComputeServiceApiMockTest.java
@@ -76,10 +76,10 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSubnets&Filter.1.Name=subnet-id&Filter.1.Value.1=subnet-9d4a7b6c");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSubnets&SubnetId.1=subnet-9d4a7b6c");
       assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test&VpcId=vpc-1a2b3c4d");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=RequestSpotInstances&SpotPrice=1.0&InstanceCount=1&LaunchSpecification.ImageId=ami-" + getDefaultImageId() + "&LaunchSpecification.Placement.AvailabilityZone=us-east-1a&LaunchSpecification.SecurityGroupId.1=sg-3c6ef654&LaunchSpecification.InstanceType=" + getDefaultSmallestInstanceType() + "&LaunchSpecification.SubnetId=subnet-9d4a7b6c&LaunchSpecification.KeyName=Demo&LaunchSpecification.UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK");
       assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=sir-228e6406");
@@ -118,8 +118,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
       assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=RequestSpotInstances&SpotPrice=1.0&InstanceCount=1&LaunchSpecification.ImageId=ami-" + getDefaultImageId() + "&LaunchSpecification.Placement.AvailabilityZone=us-east-1a&LaunchSpecification.SecurityGroupId.1=sg-3c6ef654&LaunchSpecification.InstanceType=" + getDefaultSmallestInstanceType() + "&LaunchSpecification.UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&LaunchSpecification.IamInstanceProfile.Arn=arn%3Aaws%3Aiam%3A%3A123456789012%3Ainstance-profile/application_abc/component_xyz/Webserver");
       assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=sir-228e6406");
@@ -156,8 +156,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=owner-id&Filter.1.Value.1=137112412989&Filter.1.Value.2=801119661308&Filter.1.Value.3=063491364108&Filter.1.Value.4=099720109477&Filter.1.Value.5=411009282317&Filter.2.Name=state&Filter.2.Value.1=available&Filter.3.Name=image-type&Filter.3.Value.1=machine");
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
       assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=RequestSpotInstances&SpotPrice=1.0&InstanceCount=1&LaunchSpecification.ImageId=ami-" + getDefaultImageId() + "&LaunchSpecification.Placement.AvailabilityZone=us-east-1a&LaunchSpecification.SecurityGroupId.1=sg-3c6ef654&LaunchSpecification.InstanceType=" + getDefaultSmallestInstanceType() + "&LaunchSpecification.UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&LaunchSpecification.IamInstanceProfile.Name=Webserver");
       assertPosted(DEFAULT_REGION, "Action=DescribeSpotInstanceRequests&SpotInstanceRequestId.1=sir-228e6406");
@@ -190,8 +190,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
       assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
       assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=RunInstances&ImageId=ami-8ce4b5c9&MinCount=1&MaxCount=1&InstanceType=" + getDefaultParavirtualInstanceType() + "&SecurityGroupId.1=sg-3c6ef654&UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&IamInstanceProfile.Arn=arn%3Aaws%3Aiam%3A%3A123456789012%3Ainstance-profile/application_abc/component_xyz/Webserver");
       assertPosted(DEFAULT_REGION, "Action=DescribeInstances&InstanceId.1=i-2baa5550");
@@ -224,8 +224,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
       assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
       assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=RunInstances&ImageId=ami-8ce4b5c9&MinCount=1&MaxCount=1&InstanceType=" + getDefaultParavirtualInstanceType() + "&SecurityGroupId.1=sg-3c6ef654&UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&IamInstanceProfile.Name=Webserver");
       assertPosted(DEFAULT_REGION, "Action=DescribeInstances&InstanceId.1=i-2baa5550");
@@ -258,8 +258,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       assertPosted(DEFAULT_REGION, "Action=DescribeImages&Filter.1.Name=virtualization-type&Filter.1.Value.1=hvm&Filter.2.Name=architecture&Filter.2.Value.1=x86_64&Filter.3.Name=owner-id&Filter.3.Value.1=137112412989&Filter.3.Value.2=099720109477&Filter.4.Name=hypervisor&Filter.4.Value.1=xen&Filter.5.Name=state&Filter.5.Value.1=available&Filter.6.Name=image-type&Filter.6.Value.1=machine&Filter.7.Name=root-device-type&Filter.7.Value.1=ebs");
       assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
       assertPosted(DEFAULT_REGION, "Action=CreateSecurityGroup&GroupName=jclouds%23test&GroupDescription=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23test");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=AuthorizeSecurityGroupIngress&GroupId=sg-3c6ef654&IpPermissions.0.IpProtocol=tcp&IpPermissions.0.FromPort=22&IpPermissions.0.ToPort=22&IpPermissions.0.IpRanges.0.CidrIp=0.0.0.0/0&IpPermissions.1.IpProtocol=tcp&IpPermissions.1.FromPort=0&IpPermissions.1.ToPort=65535&IpPermissions.1.Groups.0.UserId=993194456877&IpPermissions.1.Groups.0.GroupId=sg-3c6ef654&IpPermissions.2.IpProtocol=udp&IpPermissions.2.FromPort=0&IpPermissions.2.ToPort=65535&IpPermissions.2.Groups.0.UserId=993194456877&IpPermissions.2.Groups.0.GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=RunInstances&ImageId=ami-8ce4b5c9&MinCount=1&MaxCount=1&InstanceType=" + getDefaultParavirtualInstanceType() + "&SecurityGroupId.1=sg-3c6ef654&UserData=I2Nsb3VkLWNvbmZpZwpyZXBvX3VwZ3JhZGU6IG5vbmUK&Placement.Tenancy=host&Placement.HostId=TestHostId");
       assertPosted(DEFAULT_REGION, "Action=DescribeInstances&InstanceId.1=i-2baa5550");
@@ -302,8 +302,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       computeService.cleanUpIncidentalResources(DEFAULT_REGION, "sg-3c6ef654");
 
       assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23sg-3c6ef654");
-      assertPosted(DEFAULT_REGION, "Action=DeleteSecurityGroup&GroupName=jclouds%23sg-3c6ef654");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23sg-3c6ef654");
+      assertPosted(DEFAULT_REGION, "Action=DeleteSecurityGroup&GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=DescribeKeyPairs&Filter.1.Name=key-name&Filter.1.Value.1=jclouds%23sg-3c6ef654%23%2A");
       assertPosted(DEFAULT_REGION, "Action=DescribeInstances&Filter.1.Name=instance-state-name&Filter.1.Value.1=terminated&Filter.1.Value.2=shutting-down&Filter.2.Name=key-name&Filter.2.Value.1=jclouds%23sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=DeleteKeyPair&KeyName=jclouds%23sg-3c6ef654");
@@ -336,8 +336,8 @@ public class AWSEC2ComputeServiceApiMockTest extends BaseAWSEC2ApiMockTest {
       computeService.cleanUpIncidentalResources(DEFAULT_REGION, "sg-3c6ef654");
 
       assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23sg-3c6ef654");
-      assertPosted(DEFAULT_REGION, "Action=DeleteSecurityGroup&GroupName=jclouds%23sg-3c6ef654");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23sg-3c6ef654");
+      assertPosted(DEFAULT_REGION, "Action=DeleteSecurityGroup&GroupId=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=DescribePlacementGroups&GroupName.1=jclouds%23sg-3c6ef654%23us-east-1");
       assertPosted(DEFAULT_REGION, "Action=DeletePlacementGroup&GroupName=jclouds%23sg-3c6ef654%23us-east-1");
       assertPosted(DEFAULT_REGION, "Action=DescribePlacementGroups&GroupName.1=jclouds%23sg-3c6ef654%23us-east-1");

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2SecurityGroupExtensionApiMockTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2SecurityGroupExtensionApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2SecurityGroupExtensionApiMockTest.java
index 24c91e2..d5f0220 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2SecurityGroupExtensionApiMockTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/extensions/AWSEC2SecurityGroupExtensionApiMockTest.java
@@ -153,8 +153,8 @@ public class AWSEC2SecurityGroupExtensionApiMockTest extends BaseAWSEC2ApiMockTe
       assertPosted(DEFAULT_REGION, "Action=DescribeRegions");
       assertPosted(DEFAULT_REGION,
             "Action=CreateSecurityGroup&GroupName=jclouds%23some-group&GroupDescription=jclouds%23some-group");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23some-group");
-      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupName.1=jclouds%23some-group");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23some-group");
+      assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&Filter.1.Name=group-name&Filter.1.Value.1=jclouds%23some-group");
       assertPosted(DEFAULT_REGION, "Action=DescribeSecurityGroups&GroupId.1=sg-3c6ef654");
       assertPosted(DEFAULT_REGION, "Action=DescribeAvailabilityZones");
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
index bf87309..1880a23 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/loaders/AWSEC2CreateSecurityGroupIfNeededTest.java
@@ -82,7 +82,8 @@ public class AWSEC2CreateSecurityGroupIfNeededTest {
                   new CreateSecurityGroupOptions().vpcId("vpc"))).andReturn("sg-123456");
       expect(group.getOwnerId()).andReturn("ownerId");
       client.authorizeSecurityGroupIngressInRegion("region", "sg-123456", permissions.build());
-      expect(client.describeSecurityGroupsInRegion("region", "group")).andReturn(Set.class.cast(groups));
+      expect(client.describeSecurityGroupsInRegionById("region", "sg-123456"))
+               .andReturn(Set.class.cast(groups));
 
 
       replay(client);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest.java
index f73ebc1..3c738a6 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/strategy/CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsTest.java
@@ -308,7 +308,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
       expect(options.getSubnetId()).andReturn("1");
       expect(options.getUserData()).andReturn(null);
       expect(options.isMonitoringEnabled()).andReturn(false);
-      expect(strategy.vpcIdForSubnet("1")).andReturn("vpc1");
+      expect(strategy.vpcIdForSubnet("", "1")).andReturn("vpc1");
 
       // replay mocks
       replay(options);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/1c6c36b8/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiLiveTest.java
index 9100a5b..dcc2b89 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/AWSSecurityGroupApiLiveTest.java
@@ -19,18 +19,26 @@ package org.jclouds.aws.ec2.features;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
+import java.util.Random;
 import java.util.Set;
 
+import org.jclouds.aws.ec2.AWSEC2Api;
+import org.jclouds.aws.ec2.domain.VPC;
+import org.jclouds.aws.ec2.options.CreateSecurityGroupOptions;
+import org.jclouds.aws.ec2.options.CreateVpcOptions;
+import org.jclouds.ec2.EC2Api;
 import org.jclouds.ec2.domain.SecurityGroup;
 import org.jclouds.ec2.domain.UserIdGroupPair;
 import org.jclouds.ec2.features.SecurityGroupApiLiveTest;
 import org.jclouds.ec2.util.IpPermissions;
 import org.jclouds.net.domain.IpPermission;
 import org.jclouds.net.domain.IpProtocol;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Iterables;
 
 @Test(groups = "live", singleThreaded = true)
 public class AWSSecurityGroupApiLiveTest extends SecurityGroupApiLiveTest {
@@ -116,4 +124,40 @@ public class AWSSecurityGroupApiLiveTest extends SecurityGroupApiLiveTest {
          client.deleteSecurityGroupInRegion(null, group1Name);
       }
    }
+
+   @Override
+   @BeforeClass(groups = { "integration", "live" })
+   public void setupContext() {
+      super.setupContext();
+      ec2Api = view.unwrapApi(EC2Api.class);
+      client = ec2Api.getSecurityGroupApi().get();
+   }
+
+   @Test
+   void testCreateSecurityGroupInVpc() {
+      String region = "us-west-2";
+      String groupName = PREFIX + "1" + new Random().nextInt(10000);
+      String description = "jclouds testCreateSecurityGroupInVpc";
+      
+      VPCApi vpcClient = AWSEC2Api.class.cast(ec2Api).getVPCApi().get();
+      AWSSecurityGroupApi sgClient = AWSSecurityGroupApi.class.cast(client);
+
+      VPC vpc = vpcClient.createVpc(region, "10.0.0.0/16", CreateVpcOptions.NONE);
+      try {
+         String sgId = sgClient.createSecurityGroupInRegionAndReturnId(
+               region, groupName, description, CreateSecurityGroupOptions.Builder.vpcId(vpc.id()));
+
+         try {
+            Set<SecurityGroup> securityGroups = sgClient.describeSecurityGroupsInRegionWithFilter(
+                  region, ImmutableMultimap.of("vpc-id", vpc.id(), "group-id", sgId));
+            SecurityGroup sg = Iterables.getOnlyElement(securityGroups);
+            assertEquals(sg.getId(), sgId);
+            assertEquals(sg.getId(), sgId);
+         } finally {
+            sgClient.deleteSecurityGroupInRegionById(region, sgId);
+         }
+      } finally {
+         vpcClient.deleteVpc(region, vpc.id());
+      }
+   }
 }