Using registered variables and ec2 with_items

I have a role that launches ec2 instances, registers them in a group and waits for the ssh port to respond before continuing on in provisioning. The play works as expected, however for reliability reasons we have to launch instances in more than one availability zone. This requires executing the ec2 module multiple times with different definitions. We can’t use count to launch multiple instances. The standard task for the role is listed below (this only launches one instance definition at a time):

`

  • name: Launch image(s)
    local_action:
    module: ec2
    region: “{{item.ec2_region}}”
    zone: “{{item.ec2_zone}}”
    instance_type: “{{item.ec2_instance_type}}”
    image: “{{item.ec2_image}}”
    key_name: “{{item.ec2_keypair}}”
    exact_count: “{{item.ec2_exact_count}}”
    group: “{{item.ec2_security_groups}}”
    instance_tags: “{{item.ec2_tags}}”
    count_tag: “{{item.ec2_tags}}”
    vpc_subnet_id: “{{item.ec2_vpc_subnet_id}}”
    instance_profile_name: “{{item.ec2_instance_profile_name}}”
    wait: true
    register: ec2

  • name: Add new servers to group for configuration
    local_action: add_host hostname={{item.public_dns_name}} groupname={{ec2_groupname}}
    with_items: ec2.instances
    when: ec2.changed

  • name: Wait for the instances to boot by checking the ssh port
    local_action: wait_for host={{item.public_dns_name}} port=22 delay=60 timeout=320 state=started
    with_items: ec2.instances
    when: ec2.changed

`

To simplify the calling playbook I decided to pass in a list of ec2 definitions and use with_items to launch them. The launching of the instances works fine, but I can’t seem to find the right way to use the registered result. The playbook and a slightly edited version of the registered result is listed below. I need to be able to loop through the instances in the results list, but it doesn’t seem like the looping constructs work in this situation. Anybody run into this kind of pattern and solve it in a different way? I feel like maybe I’m just coming at it from the wrong direction.

`

  • name: Launch image(s)
    local_action:
    module: ec2
    region: “{{item.ec2_region}}”
    zone: “{{item.ec2_zone}}”
    instance_type: “{{item.ec2_instance_type}}”
    image: “{{item.ec2_image}}”
    key_name: “{{item.ec2_keypair}}”
    exact_count: “{{item.ec2_exact_count}}”
    group: “{{item.ec2_security_groups}}”
    instance_tags: “{{item.ec2_tags}}”
    count_tag: “{{item.ec2_tags}}”
    vpc_subnet_id: “{{item.ec2_vpc_subnet_id}}”
    instance_profile_name: “{{item.ec2_instance_profile_name}}”
    wait: true
    register: ec2
    with_items: ec2_defs

`

The registered result looks like this:

`
ok: [localhost] => {
“ec2”: {
“changed”: true,
“msg”: “All items completed”,
“results”: [
{
“changed”: true,
“instance_ids”: [
“i-85170f6a”
],
“instances”: [
{
“ami_launch_index”: “0”,
“architecture”: “x86_64”,
“ebs_optimized”: false,
“hypervisor”: “xen”,
}
],
]
},
{
“changed”: true,
“instance_ids”: [
“i-9c18cf77”
],
“instances”: [
{
“ami_launch_index”: “0”,
“architecture”: “x86_64”,
“ebs_optimized”: false,
“hypervisor”: “xen”,
}
],
]
}
]
}

`

Thanks.

Tim

"The launching of the instances works fine, but I can’t seem to find the right way to use the registered result. "

Looks like there are two arrays here:

ec2.results[0].instances
and
ec2.results[1].instances

So, trivially, you could wait like this:

  • name: Wait for the instances to boot by checking the ssh port
    local_action: wait_for host={{item.public_dns_name}} port=22 delay=60 timeout=320 state=started
    with_items: ec2.results.0.instances

  • name: Wait for the instances to boot by checking the ssh port
    local_action: wait_for host={{item.public_dns_name}} port=22 delay=60 timeout=320 state=started
    with_items: ec2.results.1.instances

Which I realize isn’t perfect, but it’s ok-ish.

An alternative might be to write a role that launches instances into an AZ, and invoke that role twice.

Use this if you only spin up 1 instance in each step of your loop.

`

  • local_action: wait_for port=22 host=“{{ item.instances[0].private_ip }}” search_regex=OpenSSH delay=10
    with_items: “{{ ec2.results }}”

`

If you can limit your instance count to 1 at each of your loop step, you can use this one:

`

local_action: wait_for port=22 host=“{{ item.instances[0].private_ip }}” search_regex=OpenSSH delay=10 with_items: “{{ ec2.results }}”
with_items: “{{ ec2.results }}”

`

I have the same issue, need to instantiate multiple instances in different configuration, possibly more than one instance per configuration. Provisioning the instances works file but I don’t know how to iterate over the result which is an array of hashes and I need to iterate over var.instances.

Is this possible with ansible?