Saravanan Selvaraj
Saravanan Selvaraj

Reputation: 97

Ansible template loop

I'm trying to loop a dictionary and set a variable. This is what I have in my template file.

{% for item in db_server() %}
    {% if item.name in fqdn.stdout and item.mysql == "mysql-5-5-28" %}
        {% set version = "mysql-5.5.28-linux2.6-x86_64" %}
    {% elif item.name in fqdn.stdout and item.mysql == "mysql-5-1-51" %}
        {% set version = "mysql-5.1.51-linux-x86_64-glibc23" %}
    {% endif %}
{% endfor %}

My var file is

db_server:
  - name: "test1"
    mysql: "mysql_5_5_28"
  - name: "test2"
    mysql: "mysql_5_5_28"
  - name: "test3"
    mysql: "mysql_5_5_28"

I'm getting an error

fatal: [st-cms-db2]: FAILED! => {
    "changed": false, 
    "msg": "AttributeError: 'list' object has no attribute '__call__'"
}

I'm new to ansible templates. I wrote this by googling. Please be kind...

Upvotes: 2

Views: 1294

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 67984

You might want to put the logic into a dictionary instead of the Jinja template. For example, create the dictionary

    versions:
      mysql_5_5_28: mysql-5.5.28-linux2.6-x86_64
      mysql_5_1_51: mysql-5.1.51-linux-x86_64-glibc23

Then the playbook below implements the logic

shell> cat pb.yml
- hosts: localhost
  vars:
    versions:
      mysql_5_5_28: mysql-5.5.28-linux2.6-x86_64
      mysql_5_1_51: mysql-5.1.51-linux-x86_64-glibc23
    db_server:
      - name: "test1"
        mysql: "mysql_5_5_28"
      - name: "test2"
        mysql: "mysql_5_5_28"
      - name: "test3"
        mysql: "mysql_5_1_51"
  tasks:
    - debug:
        msg: "{{ item.name }} {{ versions[item.mysql] }}"
      loop: "{{ db_server }}"
      # when: item.name in fqdn.stdout

gives

shell> ansible-playbook pb.yml | grep msg
  msg: test1 mysql-5.5.28-linux2.6-x86_64
  msg: test2 mysql-5.5.28-linux2.6-x86_64
  msg: test3 mysql-5.1.51-linux-x86_64-glibc23

Fit the inventory and other conditions (e.g. fqdn.stdout) to your needs. Putting the names and versions into a dictionary would simplify the code further. For example,

    db_server:
      test1:
        mysql: "mysql_5_5_28"
      test2:
        mysql: "mysql_5_5_28"
      test3:
        mysql: "mysql_5_1_51"

Then the playbook below implements the logic for multiple hosts

shell> cat pb.yml
- hosts: test1,test2,test3
  gather_facts: false
  vars:
    versions:
      mysql_5_5_28: mysql-5.5.28-linux2.6-x86_64
      mysql_5_1_51: mysql-5.1.51-linux-x86_64-glibc23
    db_server:
      test1:
        mysql: "mysql_5_5_28"
      test2:
        mysql: "mysql_5_5_28"
      test3:
        mysql: "mysql_5_1_51"
  tasks:
    - set_fact:
        version: "{{ versions[db_server[inventory_hostname].mysql] }}"
    - debug:
        msg: "{{ inventory_hostname }} {{ version }}"

gives the same result

shell> ansible-playbook pb.yml | grep msg
  msg: test2 mysql-5.5.28-linux2.6-x86_64
  msg: test1 mysql-5.5.28-linux2.6-x86_64
  msg: test3 mysql-5.1.51-linux-x86_64-glibc23

If you still want to proceed with the template try the task and the template below

    - set_fact:
        version: "{{ lookup('template', 'template.j2') }}"
shell> cat template.j2
{% for item in db_server %}
{% if item.name in fqdn.stdout and item.mysql == "mysql_5_5_28" %}
"mysql-5.5.28-linux2.6-x86_64"
{% elif item.name in fqdn.stdout and item.mysql == "mysql_5_1_51" %}
"mysql-5.1.51-linux-x86_64-glibc23"
{% endif %}
{% endfor %}

Upvotes: 1

Related Questions