Home > Net >  Unable to get variable in Ansible Jinja template of a different / dynamic host
Unable to get variable in Ansible Jinja template of a different / dynamic host

Time:10-29

I have a variable final_delegate that determines the hosts depending upon user passed parameter -e perform_action=nslookup

- name: "Play 1"
  hosts: localhost
  tasks:

   - set_fact:
       final_delegate: "{{ 'localhost' if perform_action in 'telnetcurlnslookuptracerouteget_ip_address' else 'dest_nodes' }}"


- name: "Play 2"
  hosts: "{{ hostvars.localhost.final_delegate }}"
  tasks:

   - name: Run command
     ignore_errors: yes
     command:  ls -ltr /tmp/all.pdf
     register: cmdoutput

   - name: Creating body template
     template:
       src: "{{ playbook_dir }}/body.html.j2"
       dest: "{{ playbook_dir }}/body.html.tmp"
     delegate_to: localhost

Here is my body.html.j2

 <tr>
    <td>{{ inventory_hostname }}</td>
    <td><pre>{{ hostvars.[inventory_hostname].cmdoutput.stdout_lines | join('\n') }}</pre></td>
  </tr>

I get the below error:

An exception occurred during task execution. To see the full traceback, use -vvv. The error was:   </tr>
fatal: [localhost]: FAILED! => {"changed": false, "msg": "AnsibleError: template error while templating string: expected name or number. String:  <tr>\n    <td>{{ inventory_hostname }}</td>\n    <td><pre>{{ hostvars.[inventory_hostname].cmdoutput.stdout_lines | join('\\n') }}</pre></td>\n    </tr>\n\n"}

I also tried the following:

1.
    <td><pre>{{ hostvars.[hostvars.localhost.final_delegate].cmdoutput.stdout_lines | join('\n') }}</pre></td>
2.
    <td><pre>{{ hostvars.['hostvars.localhost.final_delegate'].cmdoutput.stdout_lines | join('\n') }}</pre></td>

Maybe I'm not getting the syntax right. Can you please suggest?

CodePudding user response:

This...

hostvars.[inventory_hostname]

...is not valid Jinja syntax. When referencing a variable attribute, you have two options:

  1. Dot notation: item.attribute

  2. Bracket notation: item["attribute"]

When you want to reference an attribute whose name is contained in a variable, you need the second (bracket) syntax, so:

hostvars[inventory_hostname].cmdoutput.stdout_lines

If it helps, this runs without errors when I run it locally (whether or not /tmp/all.pdf exists):

- name: "Play 1"
  hosts: localhost
  vars:
    perform_action: something
  tasks:
   - set_fact:
       final_delegate: "{{ 'localhost' if perform_action in 'telnetcurlnslookuptracerouteget_ip_address' else 'dest_nodes' }}"


- name: "Play 2"
  hosts: "{{ hostvars.localhost.final_delegate }}"
  tasks:

   - name: Run command
     ignore_errors: true
     command:  ls -ltr /tmp/all.pdf
     register: cmdoutput

   - name: Creating body template
     template:
       src: "body.html.j2"
       dest: "body.html.tmp"
     delegate_to: localhost

Using the fixed template:

 <tr>
    <td>{{ inventory_hostname }}</td>
    <td><pre>{{ hostvars[inventory_hostname].cmdoutput.stdout_lines | join('\n') }}</pre></td>
  </tr>

Note that you don't need to use hostvars in the above template; you could write instead:

 <tr>
    <td>{{ inventory_hostname }}</td>
    <td><pre>{{ cmdoutput.stdout_lines | join('\n') }}</pre></td>
  </tr>
  • Related