Debug for the winners !
source link: https://arrfab.net/posts/2013/Oct/31/debug-for-the-winners/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Recently I had to dive back into Ansible playbooks I wrote (quite) some time ago. I had to add some logic to generate different application templates based on facts/packages being installed on the managed nodes. Long story short (I'll not describe the use case here as it's quite complex), I decided that injecting directly some kind of logic in the Jinja2 templates was enough .. but not.
Let's take a very simplified example here (don't even look at the tasks but rather at the logic explained how to get there, once again this is a 'stupid' playbook) :
--- - hosts: localhost connection: local user: root vars: - myrole: httpserver tasks: - name: registering a variable only if myrole is httpserver command: /bin/rpm -q --qf '%{version}' httpd register: httpd_version when: myrole == 'httpserver' - name: pushing the generated template template: src=../templates/logic.txt.j2 dest=/tmp/logic.txt handlers:
Now let's have a look at the (very) simple logic.txt.j2 :
{% if httpd_version is defined -%} You're using an Apache http server version : {{ httpd_version.stdout> }} {% else %} You're not using an http server, or not defined in the ansible> machine role {% endif -%}
Easy, and it seems it was working when myrole was indeed httpserver :
cat /tmp/logic.txt You're using an Apache http server version : 2.2.15
But things didn't work as expected when myrole was something else, like for example dbserver
TASK: [registering a variable only if myrole is httpserver] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* skipping: [localhost] TASK: [pushing the generated template] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* fatal: [localhost] =\> {'msg': "One or more undefined variables: 'dict' object has no attribute 'stdout'", 'failed': True}
hmm, as the register: task was skipped, I was wondering why it then complained about the httpd_version.stdout as I thought that httpd_version wasn't defined .. but I was wrong : even if 'skipped' the variable exists for that host. I quickly discovered it when adding a debug task in between the other tasks in my playbook :
- debug: msg="this is http_version value {{ httpd_version }}"
Now let's see what can be wrong :
TASK: [debug msg="this is http_version value {{httpd_version}}"] \*\*\*\*\*\*\*\*\*\*\*\*\*\* ok: [localhost] =\> {"msg": "this is http_version value {u'skipped': True, u'changed': False}"}
Very interesting : so even when skipped, the variable httpd_version is still "registered" by the register: feature but marked as skipped.
Let's so change our "logic" in the Jinja2 template then ! :
{% if httpd_version.skipped -%} You're not using an http server, or not defined in the ansible machine role {% else %} You're using an Apache http server version : {{ httpd_version.stdout }} {% endif -%}
And now it works in all cases ..
It's a (very,very,very) simplified example, but you get the idea and using the debug module (don't forget to call ansible-playbook with -vvv to see those messages too !) can quickly show you where your issue is when having to troubleshoot something. As Patrick Debois was saying : "you gotta love Ansible for its simplicity" :-)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK