1

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

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.

1

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.

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.