2

I have to process output from CloudFormation Outputs that is:

Ansible code that produces this output:

- debug: 
  var: stack.stack_outputs

Output:

ok: [localhost] => {
  "stack.stack_outputs": {
    "Roles": "webserver balancer dbserver",
    "dbserver": "54.0.1.1 54.0.1.2",
    "balancer": "54.0.2.3",
    "webserver": "54.0.2.5 54.0.2.7 54.0.3.1"
}}

With that, I want to create 3 (dynamic number!) groups named accordingly filled with appropriate IPs.

Ansible code that I want to HELP WITH:

- name: fill roles with proper hosts
  local_action: add_host hostname={{item}} groupname={{role}}
  with_whatever: ?...?

In pseudo ansible python it would look like this:

for role in stack.stack_outputs.Roles.split():                           # Python
  for ip in stack.stack_outputs[role].split():                           # Python
    local_action: add_host hostname={{ip}} groupname={{role}}            # Ansible

Note:

The way to do it for these three roles statically is obviously:

- name: fill role WEBSERVER
  local_action: add_host hostname={{item}} groupname=webserver
  with_items: stack.stack_outputs.webserver.split()
- name: fill role DBSERVER
  local_action: add_host hostname={{item}} groupname=dbserver
  with_items: stack.stack_outputs.dbserver.split()
- name: fill role BALANCER
  local_action: add_host hostname={{item}} groupname=balancer
  with_items: stack.stack_outputs.balancer.split()

I want to do it dynamically, is it even possible in Ansible?
Yes, I can use shell module to hack it putting everything in temporary file and then looping over that; but is there a better solution?

Thanks for any suggestions.

1

2 Answers 2

2

It can be done using nested loops and includes, example of working script test.yml:

---
- hosts: localhost
  vars:
  - stack:
      stack_outputs:
        Roles: "webserver balancer dbserver"
        dbserver: "54.0.1.1 54.0.1.2"
        balancer: "54.0.2.3"
        webserver: "54.0.2.5 54.0.2.7 54.0.3.1"

  tasks:
  - debug: var=stack.stack_outputs

  - include: dynamic.yml
      host_group={{ item.key }}
      group_ips={{ item.value }}
    with_dict: "{{ stack.stack_outputs }}"

dynamic.yml:

---
- debug:
    msg="Group is {{ host_group }} and ip is {{ item2 }}"
  when: item2|ipaddr
  with_items: "{{ group_ips.split() }}"
  loop_control:
    loop_var: item2

Example of running using ansible-playbook 2.1.2.0:

ansible-playbook test.yml 
 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [localhost] ***************************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => {
    "stack.stack_outputs": {
        "Roles": "webserver balancer dbserver", 
        "balancer": "54.0.2.3", 
        "dbserver": "54.0.1.1 54.0.1.2", 
        "webserver": "54.0.2.5 54.0.2.7 54.0.3.1"
    }
}

TASK [include] *****************************************************************
included: /home/say/tmp/ansible/dynamic.yml for localhost
included: /home/say/tmp/ansible/dynamic.yml for localhost
included: /home/say/tmp/ansible/dynamic.yml for localhost
included: /home/say/tmp/ansible/dynamic.yml for localhost

TASK [debug] *******************************************************************
ok: [localhost] => (item=None) => {
    "item_foo": "54.0.2.5", 
    "msg": "Group is webserver and ip is 54.0.2.5"
}
ok: [localhost] => (item=None) => {
    "item_foo": "54.0.2.7", 
    "msg": "Group is webserver and ip is 54.0.2.7"
}
ok: [localhost] => (item=None) => {
    "item_foo": "54.0.3.1", 
    "msg": "Group is webserver and ip is 54.0.3.1"
}

TASK [debug] *******************************************************************
ok: [localhost] => (item=None) => {
    "item_foo": "54.0.2.3", 
    "msg": "Group is balancer and ip is 54.0.2.3"
}

TASK [debug] *******************************************************************
skipping: [localhost] => (item=None) 
skipping: [localhost] => (item=None) 
skipping: [localhost] => (item=None) 

TASK [debug] *******************************************************************
ok: [localhost] => (item=None) => {
    "item_foo": "54.0.1.1", 
    "msg": "Group is dbserver and ip is 54.0.1.1"
}
ok: [localhost] => (item=None) => {
    "item_foo": "54.0.1.2", 
    "msg": "Group is dbserver and ip is 54.0.1.2"
}

PLAY RECAP *********************************************************************
localhost                  : ok=9    changed=0    unreachable=0    failed=0 

You need Ansible 2.1 or above to run it.

0

Logic that complicated shouldn't exist in a playbook or task list. Consider using dynamic inventories, so you can write a script that returns JSON complete with group membership information. If you really want to handle the data munging in a playbook, you can use a custom filter, which still cleans up the playbook significantly.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .