501 lines
19 KiB
Python
501 lines
19 KiB
Python
from __future__ import unicode_literals
|
|
# Ensure 'assert_raises' context manager support for Python 2.6
|
|
import tests.backport_assert_raises
|
|
from nose.tools import assert_raises
|
|
|
|
import boto
|
|
import boto3
|
|
from boto.exception import EC2ResponseError
|
|
import sure # noqa
|
|
|
|
from moto import mock_ec2
|
|
from tests.helpers import requires_boto_gte
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_tables_defaults():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(1)
|
|
|
|
main_route_table = all_route_tables[0]
|
|
main_route_table.vpc_id.should.equal(vpc.id)
|
|
|
|
routes = main_route_table.routes
|
|
routes.should.have.length_of(1)
|
|
|
|
local_route = routes[0]
|
|
local_route.gateway_id.should.equal('local')
|
|
local_route.state.should.equal('active')
|
|
local_route.destination_cidr_block.should.equal(vpc.cidr_block)
|
|
|
|
vpc.delete()
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(0)
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_tables_additional():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
route_table = conn.create_route_table(vpc.id)
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(2)
|
|
all_route_tables[0].vpc_id.should.equal(vpc.id)
|
|
all_route_tables[1].vpc_id.should.equal(vpc.id)
|
|
|
|
all_route_table_ids = [route_table.id for route_table in all_route_tables]
|
|
all_route_table_ids.should.contain(route_table.id)
|
|
|
|
routes = route_table.routes
|
|
routes.should.have.length_of(1)
|
|
|
|
local_route = routes[0]
|
|
local_route.gateway_id.should.equal('local')
|
|
local_route.state.should.equal('active')
|
|
local_route.destination_cidr_block.should.equal(vpc.cidr_block)
|
|
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.delete_vpc(vpc.id)
|
|
cm.exception.code.should.equal('DependencyViolation')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
conn.delete_route_table(route_table.id)
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(1)
|
|
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.delete_route_table("rtb-1234abcd")
|
|
cm.exception.code.should.equal('InvalidRouteTableID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_tables_filters_standard():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
|
|
vpc1 = conn.create_vpc("10.0.0.0/16")
|
|
route_table1 = conn.create_route_table(vpc1.id)
|
|
|
|
vpc2 = conn.create_vpc("10.0.0.0/16")
|
|
route_table2 = conn.create_route_table(vpc2.id)
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(4)
|
|
|
|
# Filter by main route table
|
|
main_route_tables = conn.get_all_route_tables(filters={'association.main':'true'})
|
|
main_route_tables.should.have.length_of(2)
|
|
main_route_table_ids = [route_table.id for route_table in main_route_tables]
|
|
main_route_table_ids.should_not.contain(route_table1.id)
|
|
main_route_table_ids.should_not.contain(route_table2.id)
|
|
|
|
# Filter by VPC
|
|
vpc1_route_tables = conn.get_all_route_tables(filters={'vpc-id':vpc1.id})
|
|
vpc1_route_tables.should.have.length_of(2)
|
|
vpc1_route_table_ids = [route_table.id for route_table in vpc1_route_tables]
|
|
vpc1_route_table_ids.should.contain(route_table1.id)
|
|
vpc1_route_table_ids.should_not.contain(route_table2.id)
|
|
|
|
# Filter by VPC and main route table
|
|
vpc2_main_route_tables = conn.get_all_route_tables(filters={'association.main':'true', 'vpc-id':vpc2.id})
|
|
vpc2_main_route_tables.should.have.length_of(1)
|
|
vpc2_main_route_table_ids = [route_table.id for route_table in vpc2_main_route_tables]
|
|
vpc2_main_route_table_ids.should_not.contain(route_table1.id)
|
|
vpc2_main_route_table_ids.should_not.contain(route_table2.id)
|
|
|
|
# Unsupported filter
|
|
conn.get_all_route_tables.when.called_with(filters={'not-implemented-filter': 'foobar'}).should.throw(NotImplementedError)
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_tables_filters_associations():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
subnet1 = conn.create_subnet(vpc.id, "10.0.0.0/18")
|
|
subnet2 = conn.create_subnet(vpc.id, "10.0.1.0/18")
|
|
subnet3 = conn.create_subnet(vpc.id, "10.0.2.0/18")
|
|
route_table1 = conn.create_route_table(vpc.id)
|
|
route_table2 = conn.create_route_table(vpc.id)
|
|
|
|
association_id1 = conn.associate_route_table(route_table1.id, subnet1.id)
|
|
association_id2 = conn.associate_route_table(route_table1.id, subnet2.id)
|
|
association_id3 = conn.associate_route_table(route_table2.id, subnet3.id)
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(3)
|
|
|
|
# Filter by association ID
|
|
association1_route_tables = conn.get_all_route_tables(filters={'association.route-table-association-id':association_id1})
|
|
association1_route_tables.should.have.length_of(1)
|
|
association1_route_tables[0].id.should.equal(route_table1.id)
|
|
association1_route_tables[0].associations.should.have.length_of(2)
|
|
|
|
# Filter by route table ID
|
|
route_table2_route_tables = conn.get_all_route_tables(filters={'association.route-table-id':route_table2.id})
|
|
route_table2_route_tables.should.have.length_of(1)
|
|
route_table2_route_tables[0].id.should.equal(route_table2.id)
|
|
route_table2_route_tables[0].associations.should.have.length_of(1)
|
|
|
|
# Filter by subnet ID
|
|
subnet_route_tables = conn.get_all_route_tables(filters={'association.subnet-id':subnet1.id})
|
|
subnet_route_tables.should.have.length_of(1)
|
|
subnet_route_tables[0].id.should.equal(route_table1.id)
|
|
association1_route_tables[0].associations.should.have.length_of(2)
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_table_associations():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
subnet = conn.create_subnet(vpc.id, "10.0.0.0/18")
|
|
route_table = conn.create_route_table(vpc.id)
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(2)
|
|
|
|
# Refresh
|
|
route_table = conn.get_all_route_tables(route_table.id)[0]
|
|
route_table.associations.should.have.length_of(0)
|
|
|
|
# Associate
|
|
association_id = conn.associate_route_table(route_table.id, subnet.id)
|
|
|
|
# Refresh
|
|
route_table = conn.get_all_route_tables(route_table.id)[0]
|
|
route_table.associations.should.have.length_of(1)
|
|
|
|
route_table.associations[0].id.should.equal(association_id)
|
|
route_table.associations[0].main.should.equal(False)
|
|
route_table.associations[0].route_table_id.should.equal(route_table.id)
|
|
route_table.associations[0].subnet_id.should.equal(subnet.id)
|
|
|
|
# Associate is idempotent
|
|
association_id_idempotent = conn.associate_route_table(route_table.id, subnet.id)
|
|
association_id_idempotent.should.equal(association_id)
|
|
|
|
# Error: Attempt delete associated route table.
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.delete_route_table(route_table.id)
|
|
cm.exception.code.should.equal('DependencyViolation')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
# Disassociate
|
|
conn.disassociate_route_table(association_id)
|
|
|
|
# Refresh
|
|
route_table = conn.get_all_route_tables(route_table.id)[0]
|
|
route_table.associations.should.have.length_of(0)
|
|
|
|
# Error: Disassociate with invalid association ID
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.disassociate_route_table(association_id)
|
|
cm.exception.code.should.equal('InvalidAssociationID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
# Error: Associate with invalid subnet ID
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.associate_route_table(route_table.id, "subnet-1234abcd")
|
|
cm.exception.code.should.equal('InvalidSubnetID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
# Error: Associate with invalid route table ID
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.associate_route_table("rtb-1234abcd", subnet.id)
|
|
cm.exception.code.should.equal('InvalidRouteTableID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
|
|
@requires_boto_gte("2.16.0")
|
|
@mock_ec2
|
|
def test_route_table_replace_route_table_association():
|
|
"""
|
|
Note: Boto has deprecated replace_route_table_assocation (which returns status)
|
|
and now uses replace_route_table_assocation_with_assoc (which returns association ID).
|
|
"""
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
subnet = conn.create_subnet(vpc.id, "10.0.0.0/18")
|
|
route_table1 = conn.create_route_table(vpc.id)
|
|
route_table2 = conn.create_route_table(vpc.id)
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
all_route_tables.should.have.length_of(3)
|
|
|
|
# Refresh
|
|
route_table1 = conn.get_all_route_tables(route_table1.id)[0]
|
|
route_table1.associations.should.have.length_of(0)
|
|
|
|
# Associate
|
|
association_id1 = conn.associate_route_table(route_table1.id, subnet.id)
|
|
|
|
# Refresh
|
|
route_table1 = conn.get_all_route_tables(route_table1.id)[0]
|
|
route_table2 = conn.get_all_route_tables(route_table2.id)[0]
|
|
|
|
# Validate
|
|
route_table1.associations.should.have.length_of(1)
|
|
route_table2.associations.should.have.length_of(0)
|
|
|
|
route_table1.associations[0].id.should.equal(association_id1)
|
|
route_table1.associations[0].main.should.equal(False)
|
|
route_table1.associations[0].route_table_id.should.equal(route_table1.id)
|
|
route_table1.associations[0].subnet_id.should.equal(subnet.id)
|
|
|
|
# Replace Association
|
|
association_id2 = conn.replace_route_table_association_with_assoc(association_id1, route_table2.id)
|
|
|
|
# Refresh
|
|
route_table1 = conn.get_all_route_tables(route_table1.id)[0]
|
|
route_table2 = conn.get_all_route_tables(route_table2.id)[0]
|
|
|
|
# Validate
|
|
route_table1.associations.should.have.length_of(0)
|
|
route_table2.associations.should.have.length_of(1)
|
|
|
|
route_table2.associations[0].id.should.equal(association_id2)
|
|
route_table2.associations[0].main.should.equal(False)
|
|
route_table2.associations[0].route_table_id.should.equal(route_table2.id)
|
|
route_table2.associations[0].subnet_id.should.equal(subnet.id)
|
|
|
|
# Replace Association is idempotent
|
|
association_id_idempotent = conn.replace_route_table_association_with_assoc(association_id2, route_table2.id)
|
|
association_id_idempotent.should.equal(association_id2)
|
|
|
|
# Error: Replace association with invalid association ID
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.replace_route_table_association_with_assoc("rtbassoc-1234abcd", route_table1.id)
|
|
cm.exception.code.should.equal('InvalidAssociationID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
# Error: Replace association with invalid route table ID
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.replace_route_table_association_with_assoc(association_id2, "rtb-1234abcd")
|
|
cm.exception.code.should.equal('InvalidRouteTableID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_table_get_by_tag():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
|
|
vpc = conn.create_vpc('10.0.0.0/16')
|
|
|
|
route_table = conn.create_route_table(vpc.id)
|
|
route_table.add_tag('Name', 'TestRouteTable')
|
|
|
|
route_tables = conn.get_all_route_tables(filters={'tag:Name': 'TestRouteTable'})
|
|
|
|
route_tables.should.have.length_of(1)
|
|
route_tables[0].vpc_id.should.equal(vpc.id)
|
|
route_tables[0].id.should.equal(route_table.id)
|
|
route_tables[0].tags.should.have.length_of(1)
|
|
route_tables[0].tags['Name'].should.equal('TestRouteTable')
|
|
|
|
|
|
@mock_ec2
|
|
def test_route_table_get_by_tag_boto3():
|
|
ec2 = boto3.resource('ec2', region_name='eu-central-1')
|
|
|
|
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
|
|
|
route_table = ec2.create_route_table(VpcId=vpc.id)
|
|
route_table.create_tags(Tags=[{'Key': 'Name', 'Value': 'TestRouteTable'}])
|
|
|
|
filters = [{'Name': 'tag:Name', 'Values': ['TestRouteTable']}]
|
|
route_tables = list(ec2.route_tables.filter(Filters=filters))
|
|
|
|
route_tables.should.have.length_of(1)
|
|
route_tables[0].vpc_id.should.equal(vpc.id)
|
|
route_tables[0].id.should.equal(route_table.id)
|
|
route_tables[0].tags.should.have.length_of(1)
|
|
route_tables[0].tags[0].should.equal({'Key': 'Name', 'Value': 'TestRouteTable'})
|
|
|
|
|
|
@mock_ec2
|
|
def test_routes_additional():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
main_route_table = conn.get_all_route_tables()[0]
|
|
local_route = main_route_table.routes[0]
|
|
igw = conn.create_internet_gateway()
|
|
ROUTE_CIDR = "10.0.0.4/24"
|
|
|
|
conn.create_route(main_route_table.id, ROUTE_CIDR, gateway_id=igw.id)
|
|
|
|
main_route_table = conn.get_all_route_tables()[0] # Refresh route table
|
|
|
|
main_route_table.routes.should.have.length_of(2)
|
|
new_routes = [route for route in main_route_table.routes if route.destination_cidr_block != vpc.cidr_block]
|
|
new_routes.should.have.length_of(1)
|
|
|
|
new_route = new_routes[0]
|
|
new_route.gateway_id.should.equal(igw.id)
|
|
new_route.instance_id.should.be.none
|
|
new_route.state.should.equal('active')
|
|
new_route.destination_cidr_block.should.equal(ROUTE_CIDR)
|
|
|
|
conn.delete_route(main_route_table.id, ROUTE_CIDR)
|
|
|
|
main_route_table = conn.get_all_route_tables()[0] # Refresh route table
|
|
|
|
main_route_table.routes.should.have.length_of(1)
|
|
new_routes = [route for route in main_route_table.routes if route.destination_cidr_block != vpc.cidr_block]
|
|
new_routes.should.have.length_of(0)
|
|
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.delete_route(main_route_table.id, ROUTE_CIDR)
|
|
cm.exception.code.should.equal('InvalidRoute.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
|
|
@mock_ec2
|
|
def test_routes_replace():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
main_route_table = conn.get_all_route_tables(filters={'association.main':'true','vpc-id':vpc.id})[0]
|
|
local_route = main_route_table.routes[0]
|
|
ROUTE_CIDR = "10.0.0.4/24"
|
|
|
|
# Various route targets
|
|
igw = conn.create_internet_gateway()
|
|
|
|
reservation = conn.run_instances('ami-1234abcd')
|
|
instance = reservation.instances[0]
|
|
|
|
# Create initial route
|
|
conn.create_route(main_route_table.id, ROUTE_CIDR, gateway_id=igw.id)
|
|
|
|
# Replace...
|
|
def get_target_route():
|
|
route_table = conn.get_all_route_tables(main_route_table.id)[0]
|
|
routes = [route for route in route_table.routes if route.destination_cidr_block != vpc.cidr_block]
|
|
routes.should.have.length_of(1)
|
|
return routes[0]
|
|
|
|
conn.replace_route(main_route_table.id, ROUTE_CIDR, instance_id=instance.id)
|
|
|
|
target_route = get_target_route()
|
|
target_route.gateway_id.should.be.none
|
|
target_route.instance_id.should.equal(instance.id)
|
|
target_route.state.should.equal('active')
|
|
target_route.destination_cidr_block.should.equal(ROUTE_CIDR)
|
|
|
|
conn.replace_route(main_route_table.id, ROUTE_CIDR, gateway_id=igw.id)
|
|
|
|
target_route = get_target_route()
|
|
target_route.gateway_id.should.equal(igw.id)
|
|
target_route.instance_id.should.be.none
|
|
target_route.state.should.equal('active')
|
|
target_route.destination_cidr_block.should.equal(ROUTE_CIDR)
|
|
|
|
with assert_raises(EC2ResponseError) as cm:
|
|
conn.replace_route('rtb-1234abcd', ROUTE_CIDR, gateway_id=igw.id)
|
|
cm.exception.code.should.equal('InvalidRouteTableID.NotFound')
|
|
cm.exception.status.should.equal(400)
|
|
cm.exception.request_id.should_not.be.none
|
|
|
|
|
|
@requires_boto_gte("2.19.0")
|
|
@mock_ec2
|
|
def test_routes_not_supported():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
main_route_table = conn.get_all_route_tables()[0]
|
|
local_route = main_route_table.routes[0]
|
|
igw = conn.create_internet_gateway()
|
|
ROUTE_CIDR = "10.0.0.4/24"
|
|
|
|
# Create
|
|
conn.create_route.when.called_with(main_route_table.id, ROUTE_CIDR, interface_id='eni-1234abcd').should.throw(NotImplementedError)
|
|
|
|
# Replace
|
|
igw = conn.create_internet_gateway()
|
|
conn.create_route(main_route_table.id, ROUTE_CIDR, gateway_id=igw.id)
|
|
conn.replace_route.when.called_with(main_route_table.id, ROUTE_CIDR, interface_id='eni-1234abcd').should.throw(NotImplementedError)
|
|
|
|
|
|
@requires_boto_gte("2.34.0")
|
|
@mock_ec2
|
|
def test_routes_vpc_peering_connection():
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
main_route_table = conn.get_all_route_tables(filters={'association.main':'true','vpc-id':vpc.id})[0]
|
|
local_route = main_route_table.routes[0]
|
|
ROUTE_CIDR = "10.0.0.4/24"
|
|
|
|
peer_vpc = conn.create_vpc("11.0.0.0/16")
|
|
vpc_pcx = conn.create_vpc_peering_connection(vpc.id, peer_vpc.id)
|
|
|
|
conn.create_route(main_route_table.id, ROUTE_CIDR, vpc_peering_connection_id=vpc_pcx.id)
|
|
|
|
# Refresh route table
|
|
main_route_table = conn.get_all_route_tables(main_route_table.id)[0]
|
|
new_routes = [route for route in main_route_table.routes if route.destination_cidr_block != vpc.cidr_block]
|
|
new_routes.should.have.length_of(1)
|
|
|
|
new_route = new_routes[0]
|
|
new_route.gateway_id.should.be.none
|
|
new_route.instance_id.should.be.none
|
|
new_route.vpc_peering_connection_id.should.equal(vpc_pcx.id)
|
|
new_route.state.should.equal('blackhole')
|
|
new_route.destination_cidr_block.should.equal(ROUTE_CIDR)
|
|
|
|
|
|
@requires_boto_gte("2.34.0")
|
|
@mock_ec2
|
|
def test_routes_vpn_gateway():
|
|
|
|
conn = boto.connect_vpc('the_key', 'the_secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
main_route_table = conn.get_all_route_tables(filters={'association.main':'true','vpc-id':vpc.id})[0]
|
|
ROUTE_CIDR = "10.0.0.4/24"
|
|
|
|
vpn_gw = conn.create_vpn_gateway(type="ipsec.1")
|
|
|
|
conn.create_route(main_route_table.id, ROUTE_CIDR, gateway_id=vpn_gw.id)
|
|
|
|
main_route_table = conn.get_all_route_tables(main_route_table.id)[0]
|
|
new_routes = [route for route in main_route_table.routes if route.destination_cidr_block != vpc.cidr_block]
|
|
new_routes.should.have.length_of(1)
|
|
|
|
new_route = new_routes[0]
|
|
new_route.gateway_id.should.equal(vpn_gw.id)
|
|
new_route.instance_id.should.be.none
|
|
new_route.vpc_peering_connection_id.should.be.none
|
|
|
|
|
|
@mock_ec2
|
|
def test_network_acl_tagging():
|
|
|
|
conn = boto.connect_vpc('the_key', 'the secret')
|
|
vpc = conn.create_vpc("10.0.0.0/16")
|
|
|
|
route_table = conn.create_route_table(vpc.id)
|
|
route_table.add_tag("a key", "some value")
|
|
|
|
tag = conn.get_all_tags()[0]
|
|
tag.name.should.equal("a key")
|
|
tag.value.should.equal("some value")
|
|
|
|
all_route_tables = conn.get_all_route_tables()
|
|
test_route_table = next(na for na in all_route_tables
|
|
if na.id == route_table.id)
|
|
test_route_table.tags.should.have.length_of(1)
|
|
test_route_table.tags["a key"].should.equal("some value")
|