Add RouteTable API. Limitations: Does not contain support for VgwRoutePropagation.
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/b3d21f96 Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/b3d21f96 Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/b3d21f96 Branch: refs/heads/master Commit: b3d21f965288b44cadc750ff1dde2ec7ac45fff6 Parents: a900628 Author: Geoff Macartney <[email protected]> Authored: Fri May 12 16:44:30 2017 +0100 Committer: Ignasi Barrera <[email protected]> Committed: Mon May 29 10:22:46 2017 +0200 ---------------------------------------------------------------------- .../java/org/jclouds/aws/ec2/AWSEC2Api.java | 17 +- .../BindRouteTableIdsToIndexedFormParams.java | 32 ++ .../java/org/jclouds/aws/ec2/domain/Route.java | 107 +++++++ .../org/jclouds/aws/ec2/domain/RouteTable.java | 99 ++++++ .../aws/ec2/domain/RouteTableAssociation.java | 71 +++++ .../jclouds/aws/ec2/features/RouteTableApi.java | 279 +++++++++++++++++ .../aws/ec2/options/InternetGatewayOptions.java | 5 +- .../jclouds/aws/ec2/options/RouteOptions.java | 254 ++++++++++++++++ .../aws/ec2/options/RouteTableOptions.java | 75 +++++ .../xml/AssociateRouteTableResponseHandler.java | 40 +++ .../xml/CreateRouteTableResponseHandler.java | 55 ++++ .../xml/DescribeRouteTablesResponseHandler.java | 100 ++++++ .../org/jclouds/aws/ec2/xml/RouteHandler.java | 48 +++ .../jclouds/aws/ec2/xml/RouteSetHandler.java | 77 +++++ .../xml/RouteTableAssociationSetHandler.java | 79 +++++ .../jclouds/aws/ec2/xml/RouteTableHandler.java | 116 +++++++ .../features/InternetGatewayApiLiveTest.java | 8 +- .../features/InternetGatewayApiMockTest.java | 8 +- .../aws/ec2/features/RouteTableApiLiveTest.java | 293 ++++++++++++++++++ .../aws/ec2/features/RouteTableApiMockTest.java | 301 +++++++++++++++++++ .../aws/ec2/internal/BaseAWSEC2ApiMockTest.java | 17 +- .../test/resources/associate_route_table.xml | 4 + .../create_internet_gateway_dry_run.xml | 11 - .../aws-ec2/src/test/resources/create_route.xml | 4 + .../src/test/resources/create_route_table.xml | 24 ++ .../aws-ec2/src/test/resources/delete_route.xml | 4 + .../src/test/resources/delete_route_table.xml | 4 + .../test/resources/describe_route_tables.xml | 74 +++++ .../resources/describe_route_tables_invalid.xml | 20 ++ .../test/resources/disassociate_route_table.xml | 4 + .../aws-ec2/src/test/resources/dry_run.xml | 11 + .../src/test/resources/replace_route.xml | 4 + 32 files changed, 2225 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/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 a094ce6..d2808af 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 @@ -24,6 +24,7 @@ import org.jclouds.aws.ec2.features.AWSSubnetApi; import org.jclouds.aws.ec2.features.InternetGatewayApi; import org.jclouds.aws.ec2.features.MonitoringApi; import org.jclouds.aws.ec2.features.PlacementGroupApi; +import org.jclouds.aws.ec2.features.RouteTableApi; import org.jclouds.aws.ec2.features.SpotInstanceApi; import org.jclouds.aws.ec2.features.VPCApi; import org.jclouds.ec2.EC2Api; @@ -142,10 +143,24 @@ public interface AWSEC2Api extends EC2Api { Optional<? extends InternetGatewayApi> getInternetGatewayApi(); /** - * Provides synchronous access to InternetGateway services in a given region. + * Provides synchronous access to Internet Gateway services in a given region. */ @Delegate Optional<? extends InternetGatewayApi> getInternetGatewayApiForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region ); + + /** + * Provides synchronous access to Route Table services. + */ + @Delegate + Optional<? extends RouteTableApi> getRouteTableApi(); + + /** + * Provides synchronous access to Route Table services in a given region. + */ + @Delegate + Optional<? extends RouteTableApi> getRouteTableApiForRegion( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region + ); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindRouteTableIdsToIndexedFormParams.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindRouteTableIdsToIndexedFormParams.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindRouteTableIdsToIndexedFormParams.java new file mode 100644 index 0000000..4c2ec42 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/binders/BindRouteTableIdsToIndexedFormParams.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.binders; + +import org.jclouds.aws.util.AWSUtils; +import org.jclouds.http.HttpRequest; +import org.jclouds.rest.Binder; + +/** + * Binds the String [] to form parameters named with RouteTableId.index + */ +public class BindRouteTableIdsToIndexedFormParams implements Binder { + @Override + public <R extends HttpRequest> R bindToRequest(R request, Object input) { + return AWSUtils.indexStringArrayToFormValuesWithPrefix(request, "RouteTableId", input); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Route.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Route.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Route.java new file mode 100644 index 0000000..39d2d92 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Route.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.domain; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +/** + * A route in an Amazon EC2 Route Table. + * + * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Route.html" >doc</a> + */ +@AutoValue +public abstract class Route { + + public enum RouteState { + + /** + * An active route. + */ + ACTIVE, + + /** + * Indicates that the route's target isn't available (for example, the specified gateway isn't attached + * to the VPC, or the specified NAT instance has been terminated). + */ + BLACKHOLE, + + /** + * Value supplied was not valid. + */ + UNRECOGNIZED; + + public String value() { + return name().toLowerCase(); + } + + public static RouteState fromValue(String v) { + if (v == null || v.isEmpty()) { + throw new IllegalArgumentException("Value cannot be null or empty"); + } + try { + return valueOf(v.toUpperCase()); + } catch (IllegalArgumentException e) { + return UNRECOGNIZED; + } + } + } + + + @Nullable + public abstract String destinationCidrBlock(); + + @Nullable + public abstract String gatewayId(); + + @Nullable + public abstract RouteState state(); + + @Nullable + public abstract String origin(); + + @SerializedNames({"destinationCidrBlock", "gatewayId", "state", "origin"}) + public static Route create(String destinationCidrBlock, String gatewayId, RouteState state, String origin) { + return builder() + .destinationCidrBlock(destinationCidrBlock) + .gatewayId(gatewayId) + .state(state) + .origin(origin) + .build(); + } + + Route() {} + + public static Builder builder() { + return new AutoValue_Route.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder destinationCidrBlock(String destinationCidrBlock); + + public abstract Builder gatewayId(String gatewayId); + + public abstract Builder state(RouteState state); + + public abstract Builder origin(String origin); + + public abstract Route build(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTable.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTable.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTable.java new file mode 100644 index 0000000..b4eb182 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTable.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.domain; + +import java.util.List; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * Amazon EC2 Route Table. + * + * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RouteTable.html" >doc</a> + */ +@AutoValue +public abstract class RouteTable { + + @Nullable + public abstract String id(); + + @Nullable + public abstract String vpcId(); + + @Nullable + public abstract List<Route> routeSet(); + + @Nullable + public abstract List<RouteTableAssociation> associationSet(); + + @Nullable + public abstract Map<String, String> tags(); + + @SerializedNames({"routeTableId", "vpcId", "routeSet", "associationSet", "tagSet"}) + public static RouteTable create(String id, + String vpcId, + List<Route> routeSet, + List<RouteTableAssociation> associationSet, + Map<String, String> tags) { + return builder() + .id(id) + .vpcId(vpcId) + .routeSet(routeSet) + .associationSet(associationSet) + .tags(tags) + .build(); + } + + RouteTable() {} + + public static Builder builder() { + return new AutoValue_RouteTable.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder id(String id); + public abstract Builder vpcId(String vpcId); + public abstract Builder routeSet(List<Route> routeSet); + public abstract Builder associationSet(List<RouteTableAssociation> associationSet); + public abstract Builder tags(Map<String, String> tags); + + @Nullable abstract List<Route> routeSet(); + @Nullable abstract List<RouteTableAssociation> associationSet(); + @Nullable abstract Map<String, String> tags(); + + abstract RouteTable autoBuild(); + + public RouteTable build() { + routeSet(routeSet() != null ? ImmutableList.copyOf(routeSet()) : ImmutableList.<Route>of()); + associationSet(associationSet() != null + ? ImmutableList.copyOf(associationSet()) + : ImmutableList.<RouteTableAssociation>of()); + tags(tags() != null ? ImmutableMap.copyOf(tags()) : ImmutableMap.<String, String>of()); + return autoBuild(); + } + + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTableAssociation.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTableAssociation.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTableAssociation.java new file mode 100644 index 0000000..2b25afa --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/RouteTableAssociation.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.domain; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +/** + * An association of a route to a subnet. + * + * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RouteTableAssociation.html">AWS docs</a> + */ +@AutoValue +public abstract class RouteTableAssociation { + + + @Nullable + public abstract String id(); + + @Nullable + public abstract String routeTableId(); + + @Nullable + public abstract String subnetId(); + + @Nullable + public abstract Boolean main(); + + @SerializedNames({"routeTableAssociationId", "routeTableId", "subnetId", "main"}) + public static RouteTableAssociation create(String id, String routeTableId, String subnetId, Boolean main) { + return builder() + .id(id) + .routeTableId(routeTableId) + .subnetId(subnetId) + .main(main) + .build(); + } + + RouteTableAssociation() {} + + public static Builder builder() { + return new AutoValue_RouteTableAssociation.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + public abstract Builder routeTableId(String routeTableId); + public abstract Builder subnetId(String subnetId); + public abstract Builder main(Boolean main); + + public abstract RouteTableAssociation build(); + + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/RouteTableApi.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/RouteTableApi.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/RouteTableApi.java new file mode 100644 index 0000000..3190e60 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/features/RouteTableApi.java @@ -0,0 +1,279 @@ +/* + * 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.binders.BindRouteTableIdsToIndexedFormParams; +import org.jclouds.aws.ec2.domain.RouteTable; +import org.jclouds.aws.ec2.options.RouteOptions; +import org.jclouds.aws.ec2.options.RouteTableOptions; +import org.jclouds.aws.ec2.xml.AssociateRouteTableResponseHandler; +import org.jclouds.aws.ec2.xml.CreateRouteTableResponseHandler; +import org.jclouds.aws.ec2.xml.DescribeRouteTablesResponseHandler; +import org.jclouds.aws.ec2.xml.ReturnValueHandler; +import org.jclouds.aws.filters.FormSigner; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.EndpointParam; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.FormParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.VirtualHost; +import org.jclouds.rest.annotations.XMLResponseParser; + +import com.google.common.collect.FluentIterable; + +/** + * Provides access to AWS Route Table services. + * + * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RouteTable.html">RouteTable docs</a> + */ +@RequestFilters(FormSigner.class) +@VirtualHost +@Path("/") +public interface RouteTableApi { + + /** + * Creates a {@link RouteTable} + * + * @param region The region to create the table in. + * @param vpcId The ID of the VPC + * @return The route table + */ + @Named("CreateRouteTable") + @POST + @FormParams(keys = ACTION, values = "CreateRouteTable") + @XMLResponseParser(CreateRouteTableResponseHandler.class) + RouteTable createRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("VpcId") String vpcId); + + /** + * Creates a {@link RouteTable}, supplying options. + * + * @param region The region to create the table in + * @param vpcId The ID of the VPC + * @param options Options for the request + * @return The route table + */ + @Named("CreateRouteTable") + @POST + @FormParams(keys = ACTION, values = "CreateRouteTable") + @XMLResponseParser(CreateRouteTableResponseHandler.class) + RouteTable createRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("VpcId") String vpcId, + RouteTableOptions options); + + /** + * Deletes a {@link RouteTable} + * + * @param region The region to delete the table from + * @param routeTableId The ID of the table to delete + * @return true if the route table was found and deleted + */ + @Named("DeleteRouteTable") + @POST + @FormParams(keys = ACTION, values = "DeleteRouteTable") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean deleteRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId); + + /** + * Delete a {@link RouteTable}, supplying options. + * + * @param region The region to delete the table from + * @param routeTableId The ID of the table to delete + * @param options Options for the request + * @return true if the route table was found and deleted + */ + @Named("DeleteRouteTable") + @POST + @FormParams(keys = ACTION, values = "DeleteRouteTable") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean deleteRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId, + RouteTableOptions options); + + /** + * Associates a subnet with a route table. The subnet and route table must be in the same VPC. + * This association causes traffic originating from the subnet to be routed according to the routes in the route table. + * The action returns an association ID, which you need in order to disassociate the route table from the subnet later. + * A route table can be associated with multiple subnets. + * + * @param region Region of the VPC for the route table + * @param routeTableId ID of the route table + * @param subnetId ID of the subnet to associate + * + * @return The association ID which you need in order to disassociate the route table from the subnet later. + */ + @Named("AssociateRouteTable") + @POST + @FormParams(keys = ACTION, values = "AssociateRouteTable") + @XMLResponseParser(AssociateRouteTableResponseHandler.class) + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + String associateRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId, + @FormParam("SubnetId") String subnetId); + + /** + * @see #associateRouteTable(java.lang.String, java.lang.String, java.lang.String) + * + * @param region Region of the VPC for the route table + * @param routeTableId ID of the route table + * @param subnetId ID of the subnet to associate + * @param options Options for the request + * + * @return The association ID which you need in order to disassociate the route table from the subnet later. + */ + @Named("AssociateRouteTable") + @POST + @FormParams(keys = ACTION, values = "AssociateRouteTable") + @XMLResponseParser(AssociateRouteTableResponseHandler.class) + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + String associateRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId, + @FormParam("SubnetId") String subnetId, + RouteTableOptions options); + + /** + * Disassociates a subnet from a route table. + * After you perform this action, the subnet no longer uses the routes in the route table. + * Instead, it uses the routes in the VPC's main route table. + * @param region Region of the route table + * @param associationId association id returned by {@link #associateRouteTable(String, String, String)} + * @return true if the subnet was found and disassociated. + */ + @Named("DisassociateRouteTable") + @POST + @FormParams(keys = ACTION, values = "DisassociateRouteTable") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean disassociateRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("AssociationId") String associationId); + + /** + * @see #disassociateRouteTable(String, String) + * @param region Region of the route table + * @param associationId association id returned by {@link #associateRouteTable(String, String, String)} + * @param options Options for the request + * @return true if the subnet was found and disassociated. + */ + @Named("DisassociateRouteTable") + @POST + @FormParams(keys = ACTION, values = "DisassociateRouteTable") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean disassociateRouteTable( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("AssociationId") String associationId, + RouteTableOptions options); + + /** + * Creates a route in a route table within a VPC. + * + * @param region region of the VPC + * @param routeTableId ID of the route table to put the route in + * @param options You must specify one of the following targets: Internet gateway or virtual + * private gateway, NAT instance, NAT gateway, VPC peering connection, + * network interface, or egress-only Internet gateway. + * @return true if the route was created + */ + @Named("CreateRoute") + @POST + @FormParams(keys = ACTION, values = "CreateRoute") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean createRoute( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId, + RouteOptions options); + + /** + * Replaces a route in a route table within a VPC. + * + * @param region region of the VPC + * @param routeTableId ID of the route table containing the route to replace + * @param options You must specify only one of the following targets: Internet gateway or virtual + * private gateway, NAT instance, NAT gateway, VPC peering connection, + * network interface, or egress-only Internet gateway. + * @return true if the route was found and replaced + */ + @Named("ReplaceRoute") + @POST + @FormParams(keys = ACTION, values = "ReplaceRoute") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean replaceRoute( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId, + RouteOptions options); + + /** + * Delete a route from a route table. + * + * @param region region of the VPC + * @param routeTableId ID of the route table owning the route + * @param options This should include the destination CIDR block of the route to delete + * + * @return true if the route was found and deleted + * + * <p> + * <b>Example:</b> + * <pre> + * api.deleteRoute(region, routeTable.id(), destinationCidrBlock("10.20.30.0/24")) + * </pre> + * </p> + */ + @Named("DeleteRoute") + @POST + @FormParams(keys = ACTION, values = "DeleteRoute") + @XMLResponseParser(ReturnValueHandler.class) + @Fallback(Fallbacks.FalseOnNotFoundOr404.class) + boolean deleteRoute( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @FormParam("RouteTableId") String routeTableId, + RouteOptions options); + + /** + * Describes route tables. + * @param region The region to search for route tables. + */ + @Named("DescribeRouteTables") + @POST + @FormParams(keys = ACTION, values = "DescribeRouteTables") + @XMLResponseParser(DescribeRouteTablesResponseHandler.class) + @Fallback(Fallbacks.EmptyFluentIterableOnNotFoundOr404.class) + FluentIterable<RouteTable> describeRouteTables( + @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region, + @BinderParam(BindRouteTableIdsToIndexedFormParams.class) String... routeTableIds); +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/InternetGatewayOptions.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/InternetGatewayOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/InternetGatewayOptions.java index 6449ae4..cff7311 100644 --- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/InternetGatewayOptions.java +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/InternetGatewayOptions.java @@ -28,7 +28,7 @@ import org.jclouds.ec2.options.internal.BaseEC2RequestOptions; * import static org.jclouds.ec2.options.InternetGatewayOptions.Builder.* * <p/> * EC2Api connection = // get connection - * Future<Set<ImageMetadata>> images = + * InternetGateway gw = * connection.getInternetGatewayApi().get().createInternetGateway(region, dryRun()); * <code> * @@ -41,7 +41,8 @@ public class InternetGatewayOptions extends BaseEC2RequestOptions { public static final InternetGatewayOptions NONE = new InternetGatewayOptions(); /** - * Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. + * Checks whether you have the required permissions for the action, without actually making the request, + * and provides an error response. */ public InternetGatewayOptions dryRun() { formParameters.put("DryRun", "true"); http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteOptions.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteOptions.java new file mode 100644 index 0000000..751bb29 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteOptions.java @@ -0,0 +1,254 @@ +/* + * 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 Route operations. <h2> + * Usage</h2> The recommended way to instantiate such an object is to statically import + * RouteOptions.Builder.* and invoke a static creation method followed by an instance mutator + * (if needed): + * <p/> + * <code> + * import static org.jclouds.ec2.options.RouteOptions.Builder.* + * <p/> + * EC2Api connection = // get connection + * Route r = connection.getRouteTableApi().get() + * .createRoute(region, routeTableId, gatewayId("igw-97e68af3").destinationCidrBlock("172.18.19.0/24")); + * <code> + * + * @see <a + * href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateRoute.html" + * /> + */ +public class RouteOptions extends BaseEC2RequestOptions { + + /** + * Checks whether you have the required permissions for the action, without actually making the request, + * and provides an error response. + */ + public RouteOptions dryRun() { + formParameters.put("DryRun", "true"); + return this; + } + + public boolean isDryRun() { + return getFirstFormOrNull("DryRun") != null; + } + + /** + * The IPv4 CIDR address block used for the destination match. + * Routing decisions are based on the most specific match. + */ + public RouteOptions destinationCidrBlock(String destinationCidrBlock) { + formParameters.put("DestinationCidrBlock", checkNotNull(destinationCidrBlock, "destinationCidrBlock")); + return this; + } + + /** + * @see RouteOptions#destinationCidrBlock(java.lang.String) + */ + public String getDestinationCidrBlock() { + return getFirstFormOrNull("DestinationCidrBlock"); + } + + /** + * The IPv6 CIDR block used for the destination match. Routing decisions are based on the most specific match. + */ + public RouteOptions destinationIpv6CidrBlock(String destinationIpv6CidrBlock) { + formParameters.put("DestinationIpv6CidrBlock", checkNotNull(destinationIpv6CidrBlock, "destinationIpv6CidrBlock")); + return this; + } + + /** + * @see RouteOptions#destinationIpv6CidrBlock(java.lang.String) + */ + public String getDestinationIpv6CidrBlock() { + return getFirstFormOrNull("DestinationIpv6CidrBlock"); + } + + /** + * The ID of an Internet gateway or virtual private gateway attached to your VPC. + */ + public RouteOptions gatewayId(String gatewayId) { + formParameters.put("GatewayId", checkNotNull(gatewayId, "gatewayId")); + return this; + } + + /** + * @see RouteOptions#gatewayId(java.lang.String) + */ + public String getGatewayId() { + return getFirstFormOrNull("GatewayId"); + } + + /** + * [IPv6 traffic only] The ID of an egress-only Internet gateway. + */ + public RouteOptions egressOnlyInternetGatewayId(String egressOnlyInternetGatewayId) { + formParameters.put("EgressOnlyInternetGatewayId", + checkNotNull(egressOnlyInternetGatewayId, "egressOnlyInternetGatewayId")); + return this; + } + + /** + * @see RouteOptions#egressOnlyInternetGatewayId(java.lang.String) + */ + public String getEgressOnlyInternetGatewayId() { + return getFirstFormOrNull("EgressOnlyInternetGatewayId"); + } + + /** + * [IPv4 traffic only] The ID of a NAT gateway. + */ + public RouteOptions natGatewayId(String natGatewayId) { + formParameters.put("NatGatewayId", checkNotNull(natGatewayId, "natGatewayId")); + return this; + } + + /** + * @see RouteOptions#natGatewayId(String) + */ + public String getNatGatewayId() { + return getFirstFormOrNull("NatGatewayId"); + } + + /** + * The ID of a network interface. + */ + public RouteOptions networkInterfaceId(String networkInterfaceId) { + formParameters.put("NetworkInterfaceId", checkNotNull(networkInterfaceId, "networkInterfaceId")); + return this; + } + + /** + * @see RouteOptions#networkInterfaceId(String) + */ + public String getNetworkInterfaceId() { + return getFirstFormOrNull("NetworkInterfaceId"); + } + + /** + * The ID of a NAT instance in your VPC. The operation fails if you specify an instance ID unless + * exactly one network interface is attached. + */ + public RouteOptions instanceId(String instanceId) { + formParameters.put("InstanceId", checkNotNull(instanceId, "instanceId")); + return this; + } + + /** + * @see RouteOptions#instanceId(String) + */ + public String getInstanceId() { + return getFirstFormOrNull("InstanceId"); + } + + /** + * The ID of a VPC peering connection. + */ + public RouteOptions vpcPeeringConnectionId(String vpcPeeringConnectionId) { + formParameters.put("VpcPeeringConnectionId", checkNotNull(vpcPeeringConnectionId, "vpcPeeringConnectionId")); + return this; + } + + /** + * @see RouteOptions#vpcPeeringConnectionId(String) + */ + public String getVpcPeeringConnectionId() { + return getFirstFormOrNull("VpcPeeringConnectionId"); + } + + + public static class Builder { + /** + * @see RouteOptions#dryRun() + */ + public static RouteOptions dryRun() { + RouteOptions options = new RouteOptions(); + return options.dryRun(); + } + + /** + * @see RouteOptions#destinationCidrBlock(java.lang.String) + */ + public static RouteOptions destinationCidrBlock(String destinationCidrBlock) { + RouteOptions options = new RouteOptions(); + return options.destinationCidrBlock(destinationCidrBlock); + } + + /** + * @see RouteOptions#destinationIpv6CidrBlock(java.lang.String) + */ + public static RouteOptions destinationIpv6CidrBlock(String destinationIpv6CidrBlock) { + RouteOptions options = new RouteOptions(); + return options.destinationIpv6CidrBlock(destinationIpv6CidrBlock); + } + + /** + * @see RouteOptions#gatewayId(java.lang.String) + */ + public static RouteOptions gatewayId(String gatewayId) { + RouteOptions options = new RouteOptions(); + return options.gatewayId(gatewayId); + } + + /** + * @see RouteOptions#egressOnlyInternetGatewayId(java.lang.String) + */ + public static RouteOptions egressOnlyInternetGatewayId(String egressOnlyInternetGatewayId) { + RouteOptions options = new RouteOptions(); + return options.egressOnlyInternetGatewayId(egressOnlyInternetGatewayId); + } + + /** + * @see RouteOptions#natGatewayId(String) + */ + public static RouteOptions natGatewayId(String natGatewayId) { + RouteOptions options = new RouteOptions(); + return options.natGatewayId(natGatewayId); + } + + /** + * @see RouteOptions#networkInterfaceId(String) + */ + public static RouteOptions networkInterfaceId(String networkInterfaceId) { + RouteOptions options = new RouteOptions(); + return options.networkInterfaceId(networkInterfaceId); + } + + /** + * @see RouteOptions#vpcPeeringConnectionId(String) + */ + public static RouteOptions vpcPeeringConnectionId(String vpcPeeringConnectionId) { + RouteOptions options = new RouteOptions(); + return options.vpcPeeringConnectionId(vpcPeeringConnectionId); + } + + /** + * @see RouteOptions#instanceId(String) + */ + public static RouteOptions instanceId(String instanceId) { + RouteOptions options = new RouteOptions(); + return options.instanceId(instanceId); + } + + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteTableOptions.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteTableOptions.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteTableOptions.java new file mode 100644 index 0000000..4960d4e --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/options/RouteTableOptions.java @@ -0,0 +1,75 @@ +/* + * 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 RouteTable operations. <h2> + * Usage</h2> The recommended way to instantiate such an object is to statically import + * RouteTableOptions.Builder.* and invoke a static creation method followed by an instance mutator + * (if needed): + * <p/> + * <code> + * import static org.jclouds.ec2.options.RouteTableOptions.Builder.* + * <p/> + * EC2Api connection = // get connection + * RouteTable table = connection.getRouteTableApi().get().createRouteTable(vpcId, dryRun()); + * <code> + * + * @see <a + * href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateRouteTable.html" + * /> + */ +public class RouteTableOptions extends BaseEC2RequestOptions { + + /** + * Checks whether you have the required permissions for the action, without actually making the request, + * and provides an error response. + */ + public RouteTableOptions dryRun() { + formParameters.put("DryRun", "true"); + return this; + } + + public boolean isDryRun() { + return getFirstFormOrNull("DryRun") != null; + } + + /** + * The IPv4 CIDR address block used for the destination match. + * Routing decisions are based on the most specific match. + */ + public RouteTableOptions destinationCidrBlock(String destinationCidrBlock) { + formParameters.put("DestinationCidrBlock", checkNotNull(destinationCidrBlock, "destinationCidrBlock")); + return this; + } + + + public static class Builder { + /** + * @see RouteTableOptions#dryRun() + */ + public static RouteTableOptions dryRun() { + RouteTableOptions options = new RouteTableOptions(); + return options.dryRun(); + } + + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/AssociateRouteTableResponseHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/AssociateRouteTableResponseHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/AssociateRouteTableResponseHandler.java new file mode 100644 index 0000000..fa104fb --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/AssociateRouteTableResponseHandler.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import org.jclouds.http.functions.ParseSax; + +public class AssociateRouteTableResponseHandler extends ParseSax.HandlerWithResult<String> { + + private StringBuilder currentText = new StringBuilder(); + private String value; + + public String getResult() { + return value; + } + + public void endElement(String uri, String name, String qName) { + if (qName.equalsIgnoreCase("associationId")) { + this.value = currentText.toString().trim(); + } + currentText.setLength(0); + } + + public void characters(char[] ch, int start, int length) { + currentText.append(ch, start, length); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/CreateRouteTableResponseHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/CreateRouteTableResponseHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/CreateRouteTableResponseHandler.java new file mode 100644 index 0000000..eacb4f2 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/CreateRouteTableResponseHandler.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import javax.inject.Inject; + +import org.jclouds.aws.ec2.domain.RouteTable; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +/** + * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RouteTable.html">RouteTable docs</a> + */ +public class CreateRouteTableResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<RouteTable> { + + private RouteTableHandler routeTableHandler; + + @Inject + CreateRouteTableResponseHandler(RouteTableHandler routeTableHandler) { + this.routeTableHandler = routeTableHandler; + } + + public RouteTable getResult() { + return routeTableHandler.getResult(); + } + + @Override + public void startElement(String uri, String name, String qName, Attributes attrs) { + routeTableHandler.startElement(uri, name, qName, attrs); + } + + @Override + public void endElement(String uri, String name, String qName) { + routeTableHandler.endElement(uri, name, qName); + } + + @Override + public void characters(char[] ch, int start, int length) { + routeTableHandler.characters(ch, start, length); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeRouteTablesResponseHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeRouteTablesResponseHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeRouteTablesResponseHandler.java new file mode 100644 index 0000000..0146f67 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/DescribeRouteTablesResponseHandler.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import java.util.List; + +import javax.inject.Inject; + +import org.jclouds.aws.ec2.domain.RouteTable; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Lists; + +/** + * @see <a href="http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RouteTable.html">RouteTable docs</a> + */ +public class DescribeRouteTablesResponseHandler + extends ParseSax.HandlerForGeneratedRequestWithResult<FluentIterable<RouteTable>> { + + private RouteTableHandler routeTableHandler; + private List<RouteTable> tables = Lists.newArrayList(); + + private boolean inRouteSet; + private boolean inAssociationSet; + private boolean inPropagatingVgwSet; + private boolean inTagSet; + + @Inject + DescribeRouteTablesResponseHandler(RouteTableHandler routeTableHandler) { + this.routeTableHandler = routeTableHandler; + } + + public FluentIterable<RouteTable> getResult() { + try { + return FluentIterable.from(tables); + } finally { + tables = Lists.newArrayList(); + } + } + + @Override + public void startElement(String uri, String name, String qName, Attributes attrs) { + if (equalsOrSuffix(qName, "routeSet")) { + inRouteSet = true; + } else if (equalsOrSuffix(qName, "associationSet")) { + inAssociationSet = true; + } else if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = true; + } else if (equalsOrSuffix(qName, "propagatingVgwSet")) { + inPropagatingVgwSet = true; + } + routeTableHandler.startElement(uri, name, qName, attrs); + } + + private boolean inSubElement() { + return inRouteSet || inTagSet || inAssociationSet || inPropagatingVgwSet; + } + + @Override + public void endElement(String uri, String name, String qName) { + if (equalsOrSuffix(qName, "routeSet")) { + inRouteSet = false; + routeTableHandler.endElement(uri, name, qName); + } else if (equalsOrSuffix(qName, "associationSet")) { + inAssociationSet = false; + routeTableHandler.endElement(uri, name, qName); + } else if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = false; + routeTableHandler.endElement(uri, name, qName); + } else if (equalsOrSuffix(qName, "item") && !inSubElement()) { + final RouteTable table = routeTableHandler.getResult(); + tables.add(table); + } else { + routeTableHandler.endElement(uri, name, qName); + } + } + + @Override + public void characters(char[] ch, int start, int length) { + routeTableHandler.characters(ch, start, length); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteHandler.java new file mode 100644 index 0000000..2956cff --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteHandler.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import org.jclouds.aws.ec2.domain.Route; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +public class RouteHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Route> { + + private StringBuilder currentText = new StringBuilder(); + + Route.Builder builder = Route.builder(); + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) { + + } + + @Override + public void endElement(String uri, String localName, String qName) { + + } + + @Override + public void characters(char[] ch, int start, int length) { + currentText.append(ch, start, length); + } + + @Override + public Route getResult() { + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteSetHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteSetHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteSetHandler.java new file mode 100644 index 0000000..d5326c4 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteSetHandler.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import java.util.List; + +import org.jclouds.aws.ec2.domain.Route; +import org.jclouds.aws.ec2.domain.Route.RouteState; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +import com.google.common.collect.Lists; + +public class RouteSetHandler extends ParseSax.HandlerForGeneratedRequestWithResult<List<Route>> { + + private StringBuilder currentText = new StringBuilder(); + List<Route> results = Lists.newArrayList(); + + Route.Builder builder; + + @Override + public List<Route> getResult() { + try { + return results; + } finally { + results = Lists.newArrayList(); + } + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) { + currentText.setLength(0); + if (qName.equalsIgnoreCase("item")) { + builder = Route.builder(); + } + } + + @Override + public void endElement(String uri, String name, String qName) { + if (builder == null) { + return; + } + if (equalsOrSuffix(qName, "item")) { + results.add(builder.build()); + builder = null; + } else if (equalsOrSuffix(qName, "destinationCidrBlock")) { + builder.destinationCidrBlock(currentText.toString()); + } else if (equalsOrSuffix(qName, "gatewayId")) { + builder.gatewayId(currentText.toString()); + } else if (equalsOrSuffix(qName, "state")) { + builder.state(RouteState.fromValue(currentText.toString())); + } else if (equalsOrSuffix(qName, "origin")) { + builder.origin(currentText.toString()); + } + } + + @Override + public void characters(char[] ch, int start, int length) { + currentText.append(ch, start, length); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableAssociationSetHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableAssociationSetHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableAssociationSetHandler.java new file mode 100644 index 0000000..4a355d7 --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableAssociationSetHandler.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import java.util.List; + +import org.jclouds.aws.ec2.domain.RouteTableAssociation; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +import com.google.common.collect.Lists; + +public class RouteTableAssociationSetHandler extends + ParseSax.HandlerForGeneratedRequestWithResult<List<RouteTableAssociation>> { + + private StringBuilder currentText = new StringBuilder(); + RouteTableAssociation.Builder builder; + + List<RouteTableAssociation> results = Lists.newArrayList(); + + @Override + public List<RouteTableAssociation> getResult() { + try { + return results; + } finally { + results = Lists.newArrayList(); + } + } + + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) { + currentText.setLength(0); + if (qName.equalsIgnoreCase("item")) { + builder = RouteTableAssociation.builder(); + } + } + + @Override + public void endElement(String uri, String name, String qName) { + if (builder == null) { + return; + } + if (equalsOrSuffix(qName, "item")) { + results.add(builder.build()); + builder = null; + } else if (equalsOrSuffix(qName, "routeTableAssociationId")) { + builder.id(currentText.toString()); + } else if (equalsOrSuffix(qName, "routeTableId")) { + builder.routeTableId(currentText.toString()); + } else if (equalsOrSuffix(qName, "subnetId")) { + builder.subnetId(currentText.toString()); + } else if (equalsOrSuffix(qName, "main")) { + builder.main(Boolean.valueOf(currentText.toString())); + } + } + + @Override + public void characters (char[] ch, int start, int length) { + currentText.append(ch, start, length); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableHandler.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableHandler.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableHandler.java new file mode 100644 index 0000000..733815d --- /dev/null +++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/xml/RouteTableHandler.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.aws.ec2.xml; + +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import javax.inject.Inject; + +import org.jclouds.aws.ec2.domain.RouteTable; +import org.jclouds.ec2.xml.TagSetHandler; +import org.jclouds.http.functions.ParseSax; +import org.xml.sax.Attributes; + +public class RouteTableHandler extends ParseSax.HandlerWithResult<RouteTable> { + + RouteTable.Builder builder = RouteTable.builder(); + private StringBuilder currentText = new StringBuilder(); + private RouteSetHandler routeSetHandler; + private RouteTableAssociationSetHandler routeTableAssociationSetHandler; + private TagSetHandler tagSetHandler; + boolean inRouteSet; + boolean inRouteTableAssociationSet; + boolean inTagSet; + // TODO propagatingVgwSetHandler + + + @Inject + RouteTableHandler(TagSetHandler tagSetHandler, RouteSetHandler routeSetHandler, + RouteTableAssociationSetHandler routeTableAssociationSetHandler) { + this.tagSetHandler = tagSetHandler; + this.routeSetHandler = routeSetHandler; + this.routeTableAssociationSetHandler = routeTableAssociationSetHandler; + } + + @Override + public RouteTable getResult() { + try { + return builder.build(); + } finally { + builder = RouteTable.builder(); + } + } + + + @Override + public void startElement(String uri, String name, String qName, Attributes attrs) { + currentText.setLength(0); + if (equalsOrSuffix(qName, "routeSet")) { + inRouteSet = true; + } else if (equalsOrSuffix(qName, "associationSet")) { + inRouteTableAssociationSet = true; + } else if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = true; + } + + if (inTagSet) { + tagSetHandler.startElement(uri, name, qName, attrs); + } else if (inRouteTableAssociationSet) { + routeTableAssociationSetHandler.startElement(uri, name, qName, attrs); + } else if (inRouteSet) { + routeSetHandler.startElement(uri, name, qName, attrs); + } + } + + @Override + public void endElement(String uri, String name, String qName) { + if (equalsOrSuffix(qName, "tagSet")) { + inTagSet = false; + builder.tags(tagSetHandler.getResult()); + } else if (equalsOrSuffix(qName, "routeSet")) { + inRouteSet = false; + builder.routeSet(routeSetHandler.getResult()); + } else if (equalsOrSuffix(qName, "associationSet")) { + inRouteTableAssociationSet = false; + builder.associationSet(routeTableAssociationSetHandler.getResult()); + } else if (inRouteSet) { + routeSetHandler.endElement(uri, name, qName); + } else if (inRouteTableAssociationSet) { + routeTableAssociationSetHandler.endElement(uri, name, qName); + } else if (inTagSet) { + tagSetHandler.endElement(uri, name, qName); + } else if (equalsOrSuffix(qName, "vpcId")) { + builder.vpcId(currentText.toString()); + } else if (equalsOrSuffix(qName, "routeTableId")) { + builder.id(currentText.toString()); + } + currentText.setLength(0); + } + + @Override + public void characters(char[] ch, int start, int length) { + if (inRouteSet) { + routeSetHandler.characters(ch, start, length); + } else if (inRouteTableAssociationSet) { + routeTableAssociationSetHandler.characters(ch, start, length); + } else if (inTagSet) { + tagSetHandler.characters(ch, start, length); + } else { + currentText.append(ch, start, length); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiLiveTest.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiLiveTest.java index c44acf4..e2b2d5f 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiLiveTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiLiveTest.java @@ -36,6 +36,7 @@ import org.jclouds.aws.ec2.domain.VPC; import org.jclouds.aws.ec2.options.CreateVpcOptions; import org.jclouds.aws.ec2.options.InternetGatewayOptions; import org.jclouds.ec2.features.TagApi; +import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -49,7 +50,9 @@ import com.google.common.collect.ImmutableMap; @Test(groups = "live") public class InternetGatewayApiLiveTest extends BaseApiLiveTest<AWSEC2Api> { - private static final String TEST_REGION = "eu-west-1"; + // Define -Djclouds.test.region=whatever to test in your preferred region; + // defaults to null, jclouds will pick the provider's default region + private static final String TEST_REGION = System.getProperty("jclouds.test.region"); public InternetGatewayApiLiveTest() { provider = "aws-ec2"; @@ -60,8 +63,8 @@ public class InternetGatewayApiLiveTest extends BaseApiLiveTest<AWSEC2Api> { private VPCApi vpcClient; private VPC vpc; - private InternetGateway gateway; + private String simpleName = InternetGatewayApiLiveTest.class.getSimpleName() + new Random().nextInt(10000); @BeforeClass(groups = {"integration", "live"}) @@ -149,6 +152,7 @@ public class InternetGatewayApiLiveTest extends BaseApiLiveTest<AWSEC2Api> { try { gwClient.createInternetGateway(TEST_REGION, dryRun()); + Assert.fail("Operation completed when exception was expected"); } catch (AWSResponseException e) { assertEquals(e.getError().getCode(), "DryRunOperation", "Expected DryRunOperation but got " + e.getError()); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiMockTest.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiMockTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiMockTest.java index 8c65702..ef39e93 100644 --- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiMockTest.java +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/InternetGatewayApiMockTest.java @@ -16,6 +16,7 @@ */ package org.jclouds.aws.ec2.features; +import static javax.ws.rs.core.Response.Status.PRECONDITION_FAILED; import static org.jclouds.aws.ec2.options.InternetGatewayOptions.Builder.dryRun; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; @@ -29,6 +30,7 @@ import org.jclouds.aws.ec2.domain.InternetGateway; import org.jclouds.aws.ec2.domain.InternetGatewayAttachment; import org.jclouds.aws.ec2.internal.BaseAWSEC2ApiMockTest; import org.jclouds.aws.ec2.options.InternetGatewayOptions; +import org.testng.Assert; import org.testng.annotations.Test; import com.google.common.collect.FluentIterable; @@ -164,7 +166,6 @@ public class InternetGatewayApiMockTest extends BaseAWSEC2ApiMockTest { assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); assertPosted(DEFAULT_REGION, "Action=DescribeInternetGateways"); - } public void deleteInternetGateway() throws Exception { @@ -193,18 +194,19 @@ public class InternetGatewayApiMockTest extends BaseAWSEC2ApiMockTest { public void testWithOptions() throws Exception { enqueueRegions(DEFAULT_REGION); - enqueueXml(DEFAULT_REGION, "/create_internet_gateway_dry_run.xml"); + enqueueXml(PRECONDITION_FAILED, DEFAULT_REGION, "/dry_run.xml"); try { gatewayApi().createInternetGateway(DEFAULT_REGION, dryRun()); + Assert.fail("Expected 'DryRunOperation' exception was not thrown"); } catch (AWSResponseException e) { assertEquals(e.getError().getCode(), "DryRunOperation", "Expected DryRunOperation but got " + e.getError()); } assertPosted(DEFAULT_REGION, "Action=DescribeRegions"); assertPosted(DEFAULT_REGION, "Action=CreateInternetGateway&DryRun=true"); - } + private InternetGatewayApi gatewayApi() { return api().getInternetGatewayApi().get(); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/b3d21f96/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/RouteTableApiLiveTest.java ---------------------------------------------------------------------- diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/RouteTableApiLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/RouteTableApiLiveTest.java new file mode 100644 index 0000000..3c57984 --- /dev/null +++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/features/RouteTableApiLiveTest.java @@ -0,0 +1,293 @@ +/* + * 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 java.util.logging.Logger.getAnonymousLogger; +import static org.jclouds.aws.ec2.options.RouteOptions.Builder.destinationCidrBlock; +import static org.jclouds.aws.ec2.options.RouteOptions.Builder.gatewayId; +import static org.jclouds.aws.ec2.options.RouteTableOptions.Builder.dryRun; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.List; +import java.util.Random; + +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.aws.AWSResponseException; +import org.jclouds.aws.ec2.AWSEC2Api; +import org.jclouds.aws.ec2.domain.InternetGateway; +import org.jclouds.aws.ec2.domain.Route; +import org.jclouds.aws.ec2.domain.RouteTable; +import org.jclouds.aws.ec2.domain.VPC; +import org.jclouds.aws.ec2.options.InternetGatewayOptions; +import org.jclouds.ec2.domain.Subnet; +import org.jclouds.ec2.features.TagApi; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +/** + * Tests behavior of {@link RouteTableApi} + */ +@Test(groups = "live") +public class RouteTableApiLiveTest extends BaseApiLiveTest<AWSEC2Api> { + + // Define -Djclouds.test.region=whatever to test in your preferred region; + // defaults to null, jclouds will pick the provider's default region + public static final String TEST_REGION = System.getProperty("jclouds.test.region"); + public static final String TEST_DESTINATION_CIDR = "172.18.19.0/24"; + public static final String VPC_CIDR = "10.20.30.0/24"; + public static final String VPC_SUBNET = "10.20.30.0/28"; + + public RouteTableApiLiveTest() { + provider = "aws-ec2"; + } + + private RouteTableApi routeTableApi; + private InternetGatewayApi gwApi; + private TagApi tagger; + private VPCApi vpcClient; + private AWSSubnetApi subnetApi; + + private VPC vpc; + private InternetGateway gateway; + + private RouteTable routeTable; + private String associationId; + private Subnet subnet; + + private String simpleName = RouteTableApiLiveTest.class.getSimpleName() + new Random().nextInt(10000); + + @BeforeClass(groups = {"integration", "live"}) + public void setupContext() { + routeTableApi = api.getRouteTableApiForRegion(TEST_REGION).get(); + vpcClient = api.getVPCApi().get(); + tagger = api.getTagApiForRegion(TEST_REGION).get(); + gwApi = api.getInternetGatewayApiForRegion(TEST_REGION).get(); + subnetApi = api.getAWSSubnetApi().get(); + } + + @Test + public void testDescribe() { + vpc = vpcClient.createVpc(TEST_REGION, VPC_CIDR); + assertNotNull(vpc, "Failed to create VPC to test attachments"); + tagger.applyToResources(ImmutableMap.of("Name", simpleName), ImmutableList.of(vpc.id())); + + // When you create a VPC it automatically gets a route table whose single route has the CIDR of the VPC + // and whose "target" is "local". + final FluentIterable<RouteTable> routeTables = routeTableApi.describeRouteTables(TEST_REGION); + assertNotNull(routeTables, "Failed to return list of RouteTables"); + Optional<RouteTable> vpcRT = Iterables.tryFind(routeTables, new Predicate<RouteTable>() { + @Override public boolean apply(RouteTable input) { + return vpc.id().equals(input.vpcId()); + } + }); + assertTrue(vpcRT.isPresent(), "Could not find VPC " + vpc.id() + " in described route tables"); + RouteTable rt = vpcRT.get(); + assertEquals(rt.associationSet().size(), 1, + "Route for test VPC has wrong number of associations, should be 1: " + rt.associationSet()); + assertTrue(rt.associationSet().get(0).main(), "Association for route " + rt.id() + "should be 'main'"); + assertEquals(rt.routeSet().size(), 1, + "Wrong number of routes in default route table for VPC " + vpc.id()); + final String defaultCidr = rt.routeSet().get(0).destinationCidrBlock(); + assertEquals(defaultCidr, vpc.cidrBlock(), + "Route in default route table does not match CIDR of VPC, " + defaultCidr + " should be " + vpc.cidrBlock()); + + } + + @Test(dependsOnMethods = "testDescribe") + public void testCreate() { + + // When you create a new route table for the VPC it automatically gets a route to match the VPC CIDR + routeTable = routeTableApi.createRouteTable(TEST_REGION, vpc.id()); + assertNotNull(routeTable, "Gateway was not successfully created"); + + assertEquals(routeTable.vpcId(), vpc.id(), + "RouteTable VPC ID " + routeTable.vpcId() + " does not match VPC's ID " + vpc.id()); + final List<Route> routes = routeTable.routeSet(); + assertEquals(routes.size(), 1, "Unexpected number of routes in new table: " + routes.size()); + assertEquals(routes.get(0).destinationCidrBlock(), vpc.cidrBlock(), + "CIDR for route table " + routes.get(0).destinationCidrBlock() + + " does not match VPC CIDR" + vpc.cidrBlock()); + assertEquals(routes.get(0).state(), Route.RouteState.ACTIVE, "Route should be active"); + assertEquals(routeTable.tags().size(), 0, "Freshly created routeTable has tags"); + + tagger.applyToResources(ImmutableMap.of("Name", simpleName), ImmutableList.of(routeTable.id())); + getAnonymousLogger().info("Created routeTable " + simpleName + " with id " + routeTable.id()); + } + + @Test(dependsOnMethods = "testDescribe") + public void testCreateWithOptions() { + + try { + routeTableApi.createRouteTable(TEST_REGION, vpc.id(), dryRun()); + Assert.fail("Expected 'DryRunOperation' exception was not thrown"); + } catch (AWSResponseException e) { + assertDryRun(e); + } + } + + @Test(dependsOnMethods = "testCreate") + public void testAssociateWithOptions() { + subnet = subnetApi.createSubnetInRegion(TEST_REGION, vpc.id(), VPC_SUBNET); + assertNotNull(subnet, "Failed to create subnet in " + vpc.id()); + + try { + routeTableApi.associateRouteTable(TEST_REGION, routeTable.id(), subnet.getSubnetId(), dryRun()); + Assert.fail("Expected 'DryRunOperation' exception was not thrown"); + } catch (AWSResponseException e) { + assertDryRun(e); + } + } + + @Test(dependsOnMethods = "testAssociateWithOptions") + public void testAssociate() { + associationId = routeTableApi.associateRouteTable(TEST_REGION, routeTable.id(), subnet.getSubnetId()); + assertNotNull(associationId, + "Failed to obtain association id for " + routeTable.id() + " and " + subnet.getSubnetId()); + + routeTable = routeTableApi.describeRouteTables(TEST_REGION, routeTable.id()).toList().get(0); + assertEquals(routeTable.associationSet().size(), 1, + "Could not find expected association in routeTable " + routeTable.id()); + } + + @Test(dependsOnMethods = "testAssociate") + public void testDisassociateWithOptions() { + try { + routeTableApi.disassociateRouteTable(TEST_REGION, associationId, dryRun()); + Assert.fail("Expected 'DryRunOperation' exception was not thrown"); + } catch (AWSResponseException e) { + assertDryRun(e); + } + } + + @Test(dependsOnMethods = "testDisassociateWithOptions") + public void testDisassociate() { + final boolean result = routeTableApi.disassociateRouteTable(TEST_REGION, associationId); + assertTrue(result, "Failed to disassociate " + associationId + " from " + routeTable.id()); + + routeTable = routeTableApi.describeRouteTables(TEST_REGION, routeTable.id()).toList().get(0); + assertEquals(routeTable.associationSet().size(), 0, + "Found associations where none should exist in " + routeTable.id() + ": " + routeTable.associationSet()); + + subnetApi.deleteSubnetInRegion(TEST_REGION, subnet.getSubnetId()); + } + + @Test(dependsOnMethods = "testCreate") + public void testCreateRoute() { + + // If you attach an Internet Gateway, Network Interface, or Virtual Private Gateway to the VPC + // you can then add a route through it to the route table. Issue a CreateRoute request specifying + // the gateway (or network interface id etc.) to route through, and supplying the CIDR range that should + // be routed through it. This can be any CIDR. + + gateway = gwApi.createInternetGateway(TEST_REGION, InternetGatewayOptions.NONE); + assertNotNull(gateway, "Gateway was not successfully created"); + + final Boolean attached = gwApi.attachInternetGateway(TEST_REGION, gateway.id(), vpc.id()); + assertTrue(attached, "Gateway " + gateway.id() + " failed to attach to VPC " + vpc.id()); + + final boolean created = routeTableApi.createRoute(TEST_REGION, routeTable.id(), + gatewayId(gateway.id()) + .destinationCidrBlock(TEST_DESTINATION_CIDR)); + assertTrue(created, "Failed to add route to table " + routeTable.id()); + + final ImmutableList<RouteTable> routeTables = + routeTableApi.describeRouteTables(TEST_REGION, routeTable.id()).toList(); + assertEquals(routeTables.size(), 1, "Could not find existing route table " + routeTable.id()); + Optional<Route> optRoute = Iterables.tryFind(routeTables.get(0).routeSet(), new Predicate<Route>() { + @Override + public boolean apply(Route route) { + return route.gatewayId().equals(gateway.id()); + } + }); + assertTrue(optRoute.isPresent(), "Could not find route added to gateway " + gateway.id()); + Route route = optRoute.get(); + assertEquals(route.destinationCidrBlock(), TEST_DESTINATION_CIDR, + "CIDR routed through " + gateway.id() + " does not match specification " + TEST_DESTINATION_CIDR); + } + + @Test(dependsOnMethods = "testCreateRoute") + public void testDeleteRoute() { + final boolean deleted = + routeTableApi.deleteRoute(TEST_REGION, routeTable.id(), destinationCidrBlock(TEST_DESTINATION_CIDR)); + assertTrue(deleted, "Failed to delete " + TEST_DESTINATION_CIDR + " route from route table " + routeTable.id()); + + // clean up the test gateway + final Boolean cleaned = gwApi.detachInternetGateway(TEST_REGION, gateway.id(), vpc.id()); + assertTrue(cleaned, "Failed to delete gateway " + gateway.id()); + + final boolean gatewayDeleted = gwApi.deleteInternetGateway(TEST_REGION, gateway.id()); + assertTrue(gatewayDeleted, "Failed to delete test gateway " + gateway.id()); + } + + @Test(enabled = false /* dependsOnMethods = "testCreateRoute" */) + public void testReplaceRoute() { + // TODO: + // At present there is support for creating internet gateways and attaching them to VPCs. + // However, you can't attach two internet gateways to the same VPC, so the replaceRoute test must replace + // the internet gateway target with one of an virtual private gateway, NAT instance, + // NAT gateway, VPC peering connection, network interface, or egress-only Internet gateway. + // Add this test when e.g. NATGatewayApi is added. + } + + @Test(dependsOnMethods = "testDeleteRoute") + public void testDeleteRouteTableWithOptions() { + try { + routeTableApi.deleteRouteTable(TEST_REGION, routeTable.id(), dryRun()); + Assert.fail("Expected 'DryRunOperation' exception was not thrown"); + } catch (AWSResponseException e) { + assertDryRun(e); + } + } + + @Test(dependsOnMethods = "testDeleteRouteTableWithOptions") + public void testDeleteRouteTable() { + + final ImmutableList<RouteTable> before = + routeTableApi.describeRouteTables(TEST_REGION, routeTable.id()).toList(); + assertEquals(before.size(), 1, "Unexpected response to describe of " + routeTable.id() + ": " + before); + assertEquals(before.get(0).id(), routeTable.id(), "Wrong table returned for " + routeTable.id() + ": " + before); + + final boolean deleted = routeTableApi.deleteRouteTable(TEST_REGION, routeTable.id()); + assertTrue(deleted, "Failed to delete route table " + routeTable.id()); + + final ImmutableList<RouteTable> after = routeTableApi.describeRouteTables(TEST_REGION, routeTable.id()).toList(); + assertEquals(after.size(), 0, "Unexpected response to describe after deleting " + routeTable.id() + ": " + after); + } + + @AfterClass(alwaysRun = true) + public void cleanup() { + if (vpc != null) { + assertTrue(vpcClient.deleteVpc(TEST_REGION, vpc.id())); + } + } + + private void assertDryRun(AWSResponseException e) { + assertEquals(e.getError().getCode(), "DryRunOperation", "Expected DryRunOperation but got " + e.getError()); + } + +}
