Added option to specify tags or route-table-id, quoted doc strings, added more detail to returned route table object, numerous minor fixes

pull/18777/head
whiter 9 years ago committed by Matt Clay
parent 6cde07994e
commit 3961f30f66

@ -20,50 +20,47 @@ short_description: Manage route tables for AWS virtual private clouds
description: description:
- Manage route tables for AWS virtual private clouds - Manage route tables for AWS virtual private clouds
version_added: "2.0" version_added: "2.0"
author: Robert Estelle (@erydo) author: Robert Estelle (@erydo), Rob White (@wimnat)
options: options:
vpc_id: lookup:
description: description:
- VPC ID of the VPC in which to create the route table. - "Look up route table by either tags or by route table ID. Non-unique tag lookup will fail. If no tags are specifed then no lookup for an existing route table is performed and a new route table will be created. To change tags of a route table, you must look up by id."
required: true required: false
route_table_id: default: tag
choices: [ 'tag', 'id' ]
propagating_vgw_ids:
description: description:
- The ID of the route table to update or delete. - "Enable route propagation from virtual gateways specified by ID."
required: false required: false
default: null route_table_id:
resource_tags:
description: description:
- A dictionary array of resource tags of the form: { tag1: value1, tag2: value2 }. Tags in this list are used to uniquely identify route tables within a VPC when the route_table_id is not supplied. - "The ID of the route table to update or delete."
required: false required: false
default: null default: null
routes: routes:
description: description:
- List of routes in the route table. Routes are specified as dicts containing the keys 'dest' and one of 'gateway_id', 'instance_id', 'interface_id', or 'vpc_peering_connection'. If 'gateway_id' is specified, you can refer to the VPC's IGW by using the value 'igw'. - "List of routes in the route table. Routes are specified as dicts containing the keys 'dest' and one of 'gateway_id', 'instance_id', 'interface_id', or 'vpc_peering_connection'. If 'gateway_id' is specified, you can refer to the VPC's IGW by using the value 'igw'."
required: true required: true
state:
description:
- "Create or destroy the VPC route table"
required: false
default: present
choices: [ 'present', 'absent' ]
subnets: subnets:
description: description:
- An array of subnets to add to this route table. Subnets may be specified by either subnet ID, Name tag, or by a CIDR such as '10.0.0.0/24'. - "An array of subnets to add to this route table. Subnets may be specified by either subnet ID, Name tag, or by a CIDR such as '10.0.0.0/24'."
required: true required: true
propagating_vgw_ids: tags:
description: description:
- Enable route propagation from virtual gateways specified by ID. - "A dictionary array of resource tags of the form: { tag1: value1, tag2: value2 }. Tags in this list are used to uniquely identify route tables within a VPC when the route_table_id is not supplied."
required: false required: false
wait: default: null
description: aliases: [ "resource_tags" ]
- Wait for the VPC to be in state 'available' before returning. vpc_id:
required: false
default: "no"
choices: [ "yes", "no" ]
wait_timeout:
description:
- How long before wait gives up, in seconds.
default: 300
state:
description: description:
- Create or destroy the VPC route table - "VPC ID of the VPC in which to create the route table."
required: false required: true
default: present
choices: [ 'present', 'absent' ]
extends_documentation_fragment: aws extends_documentation_fragment: aws
''' '''
@ -73,36 +70,35 @@ EXAMPLES = '''
# Basic creation example: # Basic creation example:
- name: Set up public subnet route table - name: Set up public subnet route table
local_action: ec2_vpc_route_table:
module: ec2_vpc_route_table
vpc_id: vpc-1245678 vpc_id: vpc-1245678
region: us-west-1 region: us-west-1
resource_tags: tags:
Name: Public Name: Public
subnets: subnets:
- '{{jumpbox_subnet.subnet_id}}' - "{{ jumpbox_subnet.subnet_id }}"
- '{{frontend_subnet.subnet_id}}' - "{{ frontend_subnet.subnet_id }}"
- '{{vpn_subnet.subnet_id}}' - "{{ vpn_subnet.subnet_id }}"
routes: routes:
- dest: 0.0.0.0/0 - dest: 0.0.0.0/0
gateway_id: '{{igw.gateway_id}}' gateway_id: "{{ igw.gateway_id }}"
register: public_route_table register: public_route_table
- name: Set up NAT-protected route table - name: Set up NAT-protected route table
local_action: ec2_vpc_route_table:
module: ec2_vpc_route_table
vpc_id: vpc-1245678 vpc_id: vpc-1245678
region: us-west-1 region: us-west-1
resource_tags: tags:
- Name: Internal - Name: Internal
subnets: subnets:
- '{{application_subnet.subnet_id}}' - "{{ application_subnet.subnet_id }}"
- 'Database Subnet' - 'Database Subnet'
- '10.0.0.0/8' - '10.0.0.0/8'
routes: routes:
- dest: 0.0.0.0/0 - dest: 0.0.0.0/0
instance_id: '{{nat.instance_id}}' instance_id: "{{ nat.instance_id }}"
register: nat_route_table register: nat_route_table
''' '''
@ -210,12 +206,12 @@ def find_igw(vpc_conn, vpc_id):
filters={'attachment.vpc-id': vpc_id}) filters={'attachment.vpc-id': vpc_id})
if not igw: if not igw:
return AnsibleIgwSearchException('No IGW found for VPC "{0}"'. raise AnsibleIgwSearchException('No IGW found for VPC {0}'.
format(vpc_id)) format(vpc_id))
elif len(igw) == 1: elif len(igw) == 1:
return igw[0].id return igw[0].id
else: else:
raise AnsibleIgwSearchException('Multiple IGWs found for VPC "{0}"'. raise AnsibleIgwSearchException('Multiple IGWs found for VPC {0}'.
format(vpc_id)) format(vpc_id))
@ -251,17 +247,29 @@ def ensure_tags(vpc_conn, resource_id, tags, add_only, check_mode):
def get_route_table_by_id(vpc_conn, vpc_id, route_table_id): def get_route_table_by_id(vpc_conn, vpc_id, route_table_id):
route_tables = vpc_conn.get_all_route_tables(
route_table_ids=[route_table_id], filters={'vpc_id': vpc_id})
return route_tables[0] if route_tables else None
route_table = None
route_tables = vpc_conn.get_all_route_tables(route_table_ids=[route_table_id], filters={'vpc_id': vpc_id})
if route_tables:
route_table = route_tables[0]
return route_table
def get_route_table_by_tags(vpc_conn, vpc_id, tags): def get_route_table_by_tags(vpc_conn, vpc_id, tags):
count = 0
route_table = None
route_tables = vpc_conn.get_all_route_tables(filters={'vpc_id': vpc_id}) route_tables = vpc_conn.get_all_route_tables(filters={'vpc_id': vpc_id})
for route_table in route_tables: for table in route_tables:
this_tags = get_resource_tags(vpc_conn, route_table.id) this_tags = get_resource_tags(vpc_conn, table.id)
if tags_match(tags, this_tags): if tags_match(tags, this_tags):
return route_table route_table = table
count +=1
if count > 1:
raise RuntimeError("Tags provided do not identify a unique route table")
else:
return route_table
def route_spec_matches_route(route_spec, route): def route_spec_matches_route(route_spec, route):
@ -391,75 +399,132 @@ def ensure_propagation(vpc_conn, route_table, propagating_vgw_ids,
return {'changed': changed} return {'changed': changed}
def ensure_route_table_absent(vpc_conn, vpc_id, route_table_id, resource_tags, def ensure_route_table_absent(connection, module):
check_mode):
if route_table_id: lookup = module.params.get('lookup')
route_table = get_route_table_by_id(vpc_conn, vpc_id, route_table_id) route_table_id = module.params.get('route_table_id')
elif resource_tags: tags = module.params.get('tags')
route_table = get_route_table_by_tags(vpc_conn, vpc_id, resource_tags) vpc_id = module.params.get('vpc_id')
else: check_mode = module.params.get('check_mode')
raise AnsibleRouteTableException(
'must provide route_table_id or resource_tags') if lookup == 'tag':
if tags is not None:
try:
route_table = get_route_table_by_tags(connection, vpc_id, tags)
except EC2ResponseError as e:
module.fail_json(msg=e.message)
except RuntimeError as e:
module.fail_json(msg=e.args[0])
else:
route_table = None
elif lookup == 'id':
try:
route_table = get_route_table_by_id(connection, vpc_id, route_table_id)
except EC2ResponseError as e:
module.fail_json(msg=e.message)
if route_table is None: if route_table is None:
return {'changed': False} return {'changed': False}
vpc_conn.delete_route_table(route_table.id, dry_run=check_mode) try:
connection.delete_route_table(route_table.id, dry_run=check_mode)
except EC2ResponseError as e:
module.fail_json(msg=e.message)
return {'changed': True} return {'changed': True}
def ensure_route_table_present(vpc_conn, vpc_id, route_table_id, resource_tags, def get_route_table_info(route_table):
routes, subnets, propagating_vgw_ids,
check_mode): # Add any routes to array
routes = []
for route in route_table.routes:
routes.append(route.__dict__)
route_table_info = { 'id': route_table.id,
'routes': routes,
'tags': route_table.tags,
'vpc_id': route_table.vpc_id
}
return route_table_info
def create_route_spec(connection, routes, vpc_id):
for route_spec in routes:
rename_key(route_spec, 'dest', 'destination_cidr_block')
if 'gateway_id' in route_spec and route_spec['gateway_id'] and \
route_spec['gateway_id'].lower() == 'igw':
igw = find_igw(connection, vpc_id)
route_spec['gateway_id'] = igw
return routes
def ensure_route_table_present(connection, module):
lookup = module.params.get('lookup')
propagating_vgw_ids = module.params.get('propagating_vgw_ids', [])
route_table_id = module.params.get('route_table_id')
subnets = module.params.get('subnets')
tags = module.params.get('tags')
vpc_id = module.params.get('vpc_id')
check_mode = module.params.get('check_mode')
try:
routes = create_route_spec(connection, module.params.get('routes'), vpc_id)
except AnsibleIgwSearchException as e:
module.fail_json(msg=e[0])
changed = False changed = False
tags_valid = False tags_valid = False
if route_table_id:
route_table = get_route_table_by_id(vpc_conn, vpc_id, route_table_id)
elif resource_tags:
route_table = get_route_table_by_tags(vpc_conn, vpc_id, resource_tags)
tags_valid = route_table is not None
else:
raise AnsibleRouteTableException(
'must provide route_table_id or resource_tags')
if check_mode and route_table is None:
return {'changed': True}
if lookup == 'tag':
if tags is not None:
try:
route_table = get_route_table_by_tags(connection, vpc_id, tags)
except EC2ResponseError as e:
module.fail_json(msg=e.message)
except RuntimeError as e:
module.fail_json(msg=e.args[0])
else:
route_table = None
elif lookup == 'id':
try:
route_table = get_route_table_by_id(connection, vpc_id, route_table_id)
except EC2ResponseError as e:
module.fail_json(msg=e.message)
# If no route table returned then create new route table
if route_table is None: if route_table is None:
print route_table.keys()
try:
route_table = connection.create_route_table(vpc_id, check_mode)
changed = True
except EC2ResponseError, e:
module.fail_json(msg=e.message)
if routes is not None:
try: try:
route_table = vpc_conn.create_route_table(vpc_id) result = ensure_routes(connection, route_table, routes, propagating_vgw_ids, check_mode)
changed = changed or result['changed']
except EC2ResponseError as e: except EC2ResponseError as e:
raise AnsibleRouteTableException( module.fail_json(msg=e.message)
'Unable to create route table {0}, error: {1}'
.format(route_table_id or resource_tags, e)
)
if propagating_vgw_ids is not None: if propagating_vgw_ids is not None:
result = ensure_propagation(vpc_conn, route_table, result = ensure_propagation(vpc_conn, route_table_id,
propagating_vgw_ids, propagating_vgw_ids,
check_mode=check_mode) check_mode=check_mode)
changed = changed or result['changed'] changed = changed or result['changed']
if not tags_valid and resource_tags is not None: if not tags_valid and tags is not None:
result = ensure_tags(vpc_conn, route_table.id, resource_tags, result = ensure_tags(connection, route_table.id, tags,
add_only=True, check_mode=check_mode) add_only=True, check_mode=check_mode)
changed = changed or result['changed'] changed = changed or result['changed']
if routes is not None:
try:
result = ensure_routes(vpc_conn, route_table, routes,
propagating_vgw_ids, check_mode)
changed = changed or result['changed']
except EC2ResponseError as e:
raise AnsibleRouteTableException(
'Unable to ensure routes for route table {0}, error: {1}'
.format(route_table, e)
)
if subnets: if subnets:
associated_subnets = [] associated_subnets = []
try: try:
associated_subnets = find_subnets(vpc_conn, vpc_id, subnets) associated_subnets = find_subnets(connection, vpc_id, subnets)
except EC2ResponseError as e: except EC2ResponseError as e:
raise AnsibleRouteTableException( raise AnsibleRouteTableException(
'Unable to find subnets for route table {0}, error: {1}' 'Unable to find subnets for route table {0}, error: {1}'
@ -467,8 +532,7 @@ def ensure_route_table_present(vpc_conn, vpc_id, route_table_id, resource_tags,
) )
try: try:
result = ensure_subnet_associations( result = ensure_subnet_associations(connection, vpc_id, route_table, associated_subnets, check_mode)
vpc_conn, vpc_id, route_table, associated_subnets, check_mode)
changed = changed or result['changed'] changed = changed or result['changed']
except EC2ResponseError as e: except EC2ResponseError as e:
raise AnsibleRouteTableException( raise AnsibleRouteTableException(
@ -476,23 +540,21 @@ def ensure_route_table_present(vpc_conn, vpc_id, route_table_id, resource_tags,
.format(route_table, e) .format(route_table, e)
) )
return { module.exit_json(changed=changed, route_table=get_route_table_info(route_table))
'changed': changed,
'route_table_id': route_table.id,
}
def main(): def main():
argument_spec = ec2_argument_spec() argument_spec = ec2_argument_spec()
argument_spec.update( argument_spec.update(
dict( dict(
vpc_id = dict(default=None, required=True), lookup = dict(default='tag', required=False, choices=['tag', 'id']),
route_table_id = dict(default=None, required=False),
propagating_vgw_ids = dict(default=None, required=False, type='list'), propagating_vgw_ids = dict(default=None, required=False, type='list'),
resource_tags = dict(default=None, required=False, type='dict'), route_table_id = dict(default=None, required=False),
routes = dict(default=None, required=False, type='list'), routes = dict(default=None, required=False, type='list'),
state = dict(default='present', choices=['present', 'absent']),
subnets = dict(default=None, required=False, type='list'), subnets = dict(default=None, required=False, type='list'),
state = dict(default='present', choices=['present', 'absent']) tags = dict(default=None, required=False, type='dict', aliases=['resource_tags']),
vpc_id = dict(default=None, required=True)
) )
) )
@ -511,34 +573,18 @@ def main():
else: else:
module.fail_json(msg="region must be specified") module.fail_json(msg="region must be specified")
vpc_id = module.params.get('vpc_id') lookup = module.params.get('lookup')
route_table_id = module.params.get('route_table_id') route_table_id = module.params.get('route_table_id')
resource_tags = module.params.get('resource_tags')
propagating_vgw_ids = module.params.get('propagating_vgw_ids', [])
routes = module.params.get('routes')
for route_spec in routes:
rename_key(route_spec, 'dest', 'destination_cidr_block')
if 'gateway_id' in route_spec and route_spec['gateway_id'] and \
route_spec['gateway_id'].lower() == 'igw':
igw = find_igw(connection, vpc_id)
route_spec['gateway_id'] = igw
subnets = module.params.get('subnets')
state = module.params.get('state', 'present') state = module.params.get('state', 'present')
if lookup == 'id' and route_table_id is None:
module.fail_json("You must specify route_table_id if lookup is set to id")
try: try:
if state == 'present': if state == 'present':
result = ensure_route_table_present( result = ensure_route_table_present(connection, module)
connection, vpc_id, route_table_id, resource_tags,
routes, subnets, propagating_vgw_ids, module.check_mode
)
elif state == 'absent': elif state == 'absent':
result = ensure_route_table_absent( result = ensure_route_table_absent(connection, module)
connection, vpc_id, route_table_id, resource_tags,
module.check_mode
)
except AnsibleRouteTableException as e: except AnsibleRouteTableException as e:
module.fail_json(msg=str(e)) module.fail_json(msg=str(e))
@ -549,4 +595,4 @@ from ansible.module_utils.ec2 import * # noqa
if __name__ == '__main__': if __name__ == '__main__':
main() main()

Loading…
Cancel
Save