How to assign an array to a variable in an Ansible

2020-02-16 15:46发布

In a playbook I got the following code:

---
- hosts: db
  vars:
    postgresql_ext_install_contrib: yes
    postgresql_pg_hba_passwd_hosts: ['10.129.181.241/32']
...

I would like to replace the value of postgresql_pg_hba_passwd_hosts with all of my webservers private ips. I understand I can get the values like this in a template:

{% for host in groups['web'] %}
   {{ hostvars[host]['ansible_eth1']['ipv4']['address'] }}
{% endfor %}

What is the simplest/easiest way to assign the result of this loop to a variable in a playbook? Or is there a better way to collect this information in the first place? Should I put this loop in a template?

Additional challenge: I'd have to add /32 to every entry.

5条回答
2楼-- · 2020-02-16 16:28

You can use jinja2 filters:

{{ groups['nodes']|map('extract', hostvars, ['ansible_eth1','ipv4', 'address']) |list }}

will return a list of ip addresses. i.e.

---
- hosts: db
  vars:
    postgresql_ext_install_contrib: yes
    postgresql_pg_hba_passwd_hosts: {{ groups['nodes']|map('extract', hostvars, ['ansible_eth1','ipv4', 'address']) |list }}
...

Does not include the challange (appending /32). But it should also be possible somehow with jinja2 filters.

Reqiures ansible version >= 2.1

查看更多
家丑人穷心不美
3楼-- · 2020-02-16 16:31

To add '/32' to the address, you can use the Ansible ipaddr filter (converting to CIDR notation).

{{ ip_addresses|ipaddr('host') }}
查看更多
劳资没心,怎么记你
4楼-- · 2020-02-16 16:35

You can assign a list to variable by set_fact and ansible filter plugin.

Put custom filter plugin to filter_plugins directory like this:

(ansible top directory)
site.yml
hosts
filter_plugins/
    to_group_vars.py

to_group_vars.py convert hostvars into list that selected by group.

from ansible import errors, runner
import json

def to_group_vars(host_vars, groups, target = 'all'):
    if type(host_vars) != runner.HostVars:
        raise errors.AnsibleFilterError("|failed expects a HostVars")

    if type(groups) != dict:
        raise errors.AnsibleFilterError("|failed expects a Dictionary")

    data = []
    for host in groups[target]:
        data.append(host_vars[host])
    return data

class FilterModule (object):
    def filters(self):
        return {"to_group_vars": to_group_vars}

Use like this:

---
- hosts: all
  tasks:
  - set_fact:
      web_ips: "{{hostvars|to_group_vars(groups, 'web')|map(attribute='ansible_eth0.ipv4.address')|list }}"
  - debug:
      msg: "web ip is {{item}}/32"
    with_items: web_ips
查看更多
Emotional °昔
5楼-- · 2020-02-16 16:38

in playbook:

vars:
     - arrayname:
        - name: itemname
          value1: itemvalue1
          value2: itemvalue2
        - name: otheritem
          value1: itemvalue3
          value2: itemvalue4

in template: (example is of type ini file, with sections, keys and values):

{% for item in arrayname %}
[{{ item.name }}]
key1 = {{ item.value1 }}
key2 = {{ item.value2 }}
{% endfor %}

This should render the template as:

[itemname]
key1 = itemvalue1
key2 = itemvalue2
[otheritem]
key1 = itemvalue3
key2 = itemvalue4
查看更多
唯我独甜
6楼-- · 2020-02-16 16:40

Variables can be represented as standard YAML structures so you can assign a list value to a key like this:

---
- hosts: db
  vars:
    postgresql_ext_install_contrib: yes
    postgresql_pg_hba_passwd_hosts:
      - '10.129.181.241/32'
      - '1.2.3.0/8'
查看更多
登录 后发表回答