0
votes

Hi I have a requirement to write an Ansible code to launch EC2 instances and assign them to available subnets in round robin fashion. There is only 1 VPC which is created manually, however the number of subnets would change depending on the infrastructure getting launched. My hosts file looks like this

[ABC-database]
ABCDB01

[ABC-application]
ABCFE0[1:2]
ABCBE0[1:2]

[cassandra]
CASS0[1:3]

I have also written code to create a subnet file

subnet1: subnet-7284c12b
subnet2: subnet-fd363e98
subnet3: subnet-c892bfbf

What I have to do is pick up one instance at a time, pick up each instances' configurations from all.yml and keep assigning it to each subnet in a cyclic(round robin) fashion.

Currently I have written a shell script to do this. the script counts the number of subnets in the subnet file and returns a new subnet id every time it is called.

I am stuck after this. How should i call this script while launching ec2 instances? the below code throws an error 'next_subnet' is undefined

- name: Launch instances.
  local_action:
    command: ./get_next_available_subnet.sh
    register: next_subnet
    module: ec2
    region: "{{ region }}"
    keypair: "{{ keypair }}"
    instance_type: "{{item.instance_type}}"
    image: "{{image_id}}"
    vpc_subnet_id: "{{ next_subnet.stdout }}"
    count: 1
    wait: yes
  with_items: "{{component_list}}"

Is there a less messy way to achieve this?

1

1 Answers

2
votes

Your playbook has got two tasks merged into one so the next_subnet variable is not registered when you try to run the ec2 task.

Changing your playbook to this resolves that immediate issue:

- name: Get next subnet
  local_action:
    command: ./get_next_available_subnet.sh
    register: next_subnet

- name: Launch instances
  local_action:
    ec2:
      region: "{{ region }}"
      keypair: "{{ keypair }}"
      instance_type: "{{item.instance_type}}"
      image: "{{image_id}}"
      vpc_subnet_id: "{{ next_subnet.stdout }}"
      count: 1
      wait: yes
  with_items: "{{component_list}}"

However, that then only makes the playbook run rather than being what you want. If you up the count amount each instance still be put in the same subnet as the next_subnet variable is registered just once and then you use it in a loop.

Assuming you can keep calling your script over and over and it will rotate through the available subnet ids then you simply need to iterate the first task to get a list of results which you can use with the second task like this:

- name: Get next subnet
  local_action:
    command: ./get_next_available_subnet.sh
    register: next_subnet
  with_items: component_list

- name: Launch instances
  local_action:
    ec2:
      region: "{{ region }}"
      keypair: "{{ keypair }}"
      instance_type: "{{item.1.instance_type}}"
      image: "{{image_id}}"
      vpc_subnet_id: "{{ item.0.stdout }}"
      count: 1
      wait: yes
  with_together: 
    - next_subnet
    - component_list

Presuming your shell script outputs something like this:

$ ./get_next_available_subnet.sh
subnet-7284c12b
$ ./get_next_available_subnet.sh
subnet-fd363e98
$ ./get_next_available_subnet.sh
subnet-c892bfbf
$ ./get_next_available_subnet.sh
subnet-7284c12b

Then the first task will register the variable of next_subnet with a list of task results which will have a key of stdout and the value of a subnet id. The second task then uses a with_together loop to loop through that list of subnet ids along with the list of instances.