Ansible register variable in task and use it in template

15.3k views Asked by At

In the Ansible task, how to register a variable so I can use it as check statement in Template. The tasks are:

- name: Check if certificate file exists
  stat: path=/etc/nginx/ssl/{{ sitename }}.pem
  register: ssl_cert_check

- name: Create vhost from template
  template: "src={{ vhost_conf }} dest=/etc/nginx/conf/vhost.conf"

In the template of vhost for listen 80 is always available and I want to add the block for listen 443 only when the certificate is available:

server {
  listen 80;
  ........

}
{% if ssl_cert_check == True %} # This doesn't issue error but doesn't work either
server {
  listen 443;
  ..............
}
{% endif %}

When I run the above case the second server block is not executed, it means only the server listen 80 is printed in the vhost config.

However if I remove the True for if statement and add stat.exists in the template then I get error:

# This issues error
{% if ssl_cert_check.stat.exists %}
server {
  listen 443;
  ..............
}
{% endif %}

The error is: "msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'stat' even though I used stat module before registering the variable.

Is there any other way to pass the variable defined in Ansible task and use it in Jinja2 template?

The value displayed by a - debug: var=ssl_cert_check task before the Create vhost from template is:

"ssl_cert_check": {
        "changed": false, 
        "msg": "All items completed", 
        "results": [
            {
                "_ansible_item_result": true, 
                "_ansible_no_log": false, 
                "changed": false, 
                "invocation": {
                    "module_args": {
                        "checksum_algorithm": "sha1", 
                        "follow": false, 
                        "get_checksum": true, 
                        "get_md5": true, 
                        "mime": false, 
                        "path": "/etc/nginx/ssl/abc.pem"
                    }, 
                    "module_name": "stat"
                }, 
                "item": {
                    ........
                }, 
                "stat": {
                    "exists": false
                }
            }
        ]
    }
2

There are 2 answers

4
techraf On BEST ANSWER

If you look at the ssl_cert_check you have, you will notice the Boolean key exists is stored in the stat dictionary under results list, so in fact you should iterate over the items on the list inside the template.

If what you posted is a consistent example, you can refer to the first item on the list using:

{% if ssl_cert_check.results[0].stat.exists %}

However the way ssl_cert_check is created in your case most likely means:

  • you have some kind of loop in your code
  • sitename is not a scalar value, but a list itself

If the loop ran more times, or you had more than one item on sitename, your results might not be consistent.

You should rather fix the root cause than go with results[0] workaround.

0
lifeofguenter On

Be aware: skipped tasks will still register variable:

- name: Check if certificate file exists
  stat: path=/etc/nginx/ssl/{{ sitename }}.pem
  register: ssl_cert_check

- name: Check if certificate file exists
  stat: path=/etc/nginx/ssl/{{ sitename }}.pem
  register: ssl_cert_check
  when: nonexistent is defined

In this case, register will have the value:

"ssl_cert_check": {
    "changed": false,
    "skip_reason": "Conditional result was False",
    "skipped": true
}

Most probably best to use unique names for each register?