1

I'm setting up a bunch of up to 150 temporary EC2 servers for a hands-on tutorial session.

I'm successfully creating EC2 inventory dynamically and running roles against the instances that are created to configure everything, but I need to set a straightforward hostname for each one. To that end I have a file that contains a simple list of names that I want to use for the hostnames. This is in my playbook:

---
- hosts: localhost
  connection: local
  gather_facts: false

  tasks:
    - name: Provision a set of instances
      ec2:
        key_name: ubuntu
        instance_type: t2.micro
        image: "{{ ami_id }}"
        wait: true
        exact_count: {{ server_count }}
        count_tag:
          Name: Tutorial
        instance_tags:
          Name: Tutorial
        groups: ['SSH', 'Web']
      register: ec2

    - name: Add all instance public IPs to host group
      add_host: hostname={{ item.public_ip }} groups=ec2hosts
      loop: "{{ ec2.instances }}"

    - name: Set a host name for each instance in DNS
      route53:
        zone: {{ tutorial_domain }}
        record: "name.{{ tutorial_domain }}"
        state: present
        type: A
        ttl: 120
        value: {{ item.public_ip }}
        wait: yes
      loop: "{{ ec2.instances }}"

It really comes down to that record: "name.{{ tutorial_domain }}" line - how can I look up a name in my list of names and use it as a hostname, turning name into {{ some_dynamic_name }}?

I have seen the lookup plugins, but they all seem to be focused on looping over the entire contents of some external file - but I'm already looping over the list of servers, and that list may be shorter than the list of names (e.g. I may have only 10 servers). Ideally I want to read the list of names into an array once, then use the index from the server loop to pick the name (i.e. so the 3rd server would get the 3rd name). How do I do that in ansible? Or is there a better approach?

2

You can use the zip filter to combine your list of instances with a list of names, like this:

---
- hosts: localhost
  gather_facts: false
  vars:
    tutorial_domain: example.com
    ec2:
      instances:
        - public_ip: 1.2.3.4
        - public_ip: 2.3.4.5

    names:
      - blue-duck
      - red-panda

  tasks:
    - debug:
        msg:
          route53:
            zone: "{{ tutorial_domain }}"
            record: "{{ item.1 }}.{{tutorial_domain}}"
            state: present
            type: A
            ttl: 120
            value: "{{ item.0.public_ip }}"
            wait: yes
      loop: "{{ ec2.instances|zip(names)|list }}"

In older versions of Ansible, you would accomplish the same thing with a with_together loop.

  • Thank you. This works nicely. A hitch I've since run into is that if I want to add more instances later, the host names will restart from the beginning, so I guess I would need to calculate an offset into the names array to skip existing hosts. – Synchro Apr 7 at 23:55
0

Another approach would be to use loop index to loop over multiple lists. This way, it will be easier to add offset in the list.

- set_fact:
    ips: ['1.2.3.4', '5.6.7.8']
    hostnames: ['host1', 'host2']
- debug:
    msg: "ip={{ ips[index] }}, hostname={{ hostnames[index] }}"
  loop: "{{ ips }}"
  loop_control:
    index_var: index

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.