3

I have a VPC with some routes and subnets. I want to get ansible to work with it but I can't see a way to link the subnet with the route table ID. I've used the ec2_vpc_route_table_facts, ec2_vpc_subnet_facts and ec2_vpc_net_facts modules but unless I'm missing something, none of them provide tell me which subnet is associated with which route table.

TASK [ec2_vpc_route_table_facts] ***********************************************
ok: [localhost]

TASK [display routes] **********************************************************
ok: [localhost] => {
    "msg": {
        "changed": false, 
        "route_tables": [
            {
                "id": "rtb-83fd25e7", 
                "routes": [
                    {
                        "destination_cidr_block": "172.31.0.0/16", 
                        "gateway_id": "local", 
                        "instance_id": null, 
                        "interface_id": null, 
                        "origin": "CreateRouteTable", 
                        "state": "active", 
                        "vpc_peering_connection_id": null
                    }, 
                    {
                        "destination_cidr_block": "0.0.0.0/0", 
                        "gateway_id": "igw-6f792c0a", 
                        "instance_id": null, 
                        "interface_id": null, 
                        "origin": "CreateRoute", 
                        "state": "active", 
                        "vpc_peering_connection_id": null
                    }
                ], 
                "tags": {}, 
                "vpc_id": "vpc-e749a683"
            }, 
            {
                "id": "rtb-abf02bcf", 
                "routes": [
                    {
                        "destination_cidr_block": "172.31.0.0/16", 
                        "gateway_id": "local", 
                        "instance_id": null, 
                        "interface_id": null, 
                        "origin": "CreateRouteTable", 
                        "state": "active", 
                        "vpc_peering_connection_id": null
                    }
                ], 
                "tags": {}, 
                "vpc_id": "vpc-e749a683"
            }
        ]
    }
}

TASK [ec2_vpc_subnet_facts] ****************************************************
ok: [localhost]

TASK [display subnets] *********************************************************
ok: [localhost] => {
    "msg": {
        "changed": false, 
        "subnets": [
            {
                "availability_zone": "eu-west-1b", 
                "available_ip_address_count": 4091, 
                "cidr_block": "172.31.16.0/20", 
                "default_for_az": "true", 
                "id": "subnet-3ac33c4c", 
                "map_public_ip_on_launch": "true", 
                "state": "available", 
                "tags": {}, 
                "vpc_id": "vpc-e749a683"
            }, 
            {
                "availability_zone": "eu-west-1c", 
                "available_ip_address_count": 4091, 
                "cidr_block": "172.31.32.0/20", 
                "default_for_az": "true", 
                "id": "subnet-4efbef17", 
                "map_public_ip_on_launch": "true", 
                "state": "available", 
                "tags": {}, 
                "vpc_id": "vpc-e749a683"
            }, 
            {
                "availability_zone": "eu-west-1a", 
                "available_ip_address_count": 4091, 
                "cidr_block": "172.31.0.0/20", 
                "default_for_az": "true", 
                "id": "subnet-9a3deafe", 
                "map_public_ip_on_launch": "true", 
                "state": "available", 
                "tags": {}, 
                "vpc_id": "vpc-e749a683"
            }
        ]
    }
}

The only way I can see to make this work is to include tags on the route with a sensible value (like the subnet ID). But that would still need someone to manually keep it up to date, there is no way to automate that from Ansible, is there?

Max Allan
  • 303
  • 1
  • 4
  • 11

2 Answers2

1

I think a well placed filter plugin can help you in this situation. For instance if you know the route table id, you can write a simple python function to retrieve a list of subnet_ids associated with the route table id. You will put this filter in the root of your ansible directory.

Example below.... filter_plugins/example.py

def get_all_subnet_ids_in_route_table(route_table_id, region=None):
    """
    Args:
        route_table_id (str): The route table id you are retrieving subnets for.

    Kwargs:
        region (str): The aws region in which the route table exists.

    Basic Usage:
        >>> get_all_subnet_ids_in_route_table("rtb-1234567", "us-west-2")
        ['subnet-1234567', 'subnet-7654321']

    Returns:
        List of subnet ids
    """
    subnet_ids = list()
    client = boto3.client('ec2', region_name=region)
    params = {
        'RouteTableIds': [route_table_id]
    }
    routes = client.describe_route_tables(**params)
    if routes:
        for route in routes['RouteTables']:
            for association in route['Associations']:
                if association.get('SubnetId', None):
                    subnet_ids.append(association['SubnetId'])
        return subnet_ids
    else:
        raise errors.AnsibleFilterError(
            "No subnets were found for {0}".format(route_table_id)
        )


class FilterModule(object):
    ''' Ansible core jinja2 filters '''

    def filters(self):
        return {
            'get_all_subnet_ids_in_route_table': get_all_subnet_ids_in_route_table
        }

If you want to use this filter, it would be as simple as doing the following..

route_table_id: rtb-1234567
aws_region: eu-west-1
subnet_ids_for_example_rt: "{{ route_table_id | get_all_subnet_ids_in_route_table(aws_region) }}"
linuxdynasty
  • 221
  • 1
  • 3
0

It looks like this is fixed as of Ansible 2.3 (https://github.com/ansible/ansible/commit/90002e06ae0ab255d71e6976d7e5d23e93850cd3).

Now when you call ec2_vpc_route_table_facts, in addition to a routes list, each returned route table also has an associations list, which contains any associated subnet_id(s)

{
    "associations": [
        {
            "id": "rtbassoc-02cf4c00",
            "main": false,
            "route_table_id": "rtb-7051d400",
            "subnet_id": "subnet-3099da00"
        }
    ],
    "id": "rtb-7051d400",
    "routes": [
        {
            "destination_cidr_block": "52.123.123.123/32",
            "gateway_id": "igw-96298400",
            "instance_id": null,
            "interface_id": null,
            "state": "active",
            "vpc_peering_connection_id": null
        },
        {
            "destination_cidr_block": "52.123.123.124/32",
            "gateway_id": "igw-96298400",
            "instance_id": null,
            "interface_id": null,
            "state": "active",
            "vpc_peering_connection_id": null
        },
        {
            "destination_cidr_block": "10.69.123.0/24",
            "gateway_id": "local",
            "instance_id": null,
            "interface_id": null,
            "state": "active",
            "vpc_peering_connection_id": null
        }
    ],
    "tags": {
        "Name": "test-gmd-b-routes"
    },
    "vpc_id": "vpc-c5439a00"
}
user187557
  • 111
  • 3