'How can I compare a remote file with a reference on controller without failing the playbook when different?
I have a very peculiar problem, in my code I have to compare ansible value with customer expected value and customer expected un_matched value, however the final playbook output should be failed =0 instead of failed =1.
The code is:
- name: show file contents of customer-expects.txt
debug:
msg: "{{ lookup('file', '/customer-expects.txt') }}"
- shell: cat /etc/issue
register: issue
changed_when: false
ignore_errors: yes
- assert:
that:
- lookup('file', '/customer-expects.txt') == issue.stdout
success_msg: "matched! {{ lookup('file', '/customer-expects.txt') }} = {{ issue.stdout }}"
- name: show file contents customer-expects_unmatched.txt
debug:
msg: "{{ lookup('file', '/customer-expects_unmatched.txt') }}"
- shell: cat /etc/issue
register: issue
changed_when: false
ignore_errors: yes
- assert:
that:
- lookup('file', '/customer-expects_unmatched.txt') == issue.stdout
fail_msg: "unmatched! {{ lookup('file', '/customer-expects_unmatched.txt') }} = {{ issue.stdout }}"
success_msg: "matched! {{ lookup('file', '/customer-expects.txt') }} = {{ issue.stdout }}"
Output is:
[root@ansible-master /]# ansible-playbook tab8.role.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [This output is for Tab-8 of Function Design document] *********
TASK [Gathering Facts] **********************************************
ok: [ansible-client1]
TASK [issue_tab8 : show file contents of customer-expects.txt] ******
ok: [ansible-client1] => {
"msg": ""
}
TASK [issue_tab8 : shell] *******************************************
ok: [ansible-client1] => {"changed": false, "cmd": "cat /etc/issue", "delta": "0:00:00.005200", "end": "2022-01-25 14:17:57.070688", "rc": 0, "start": "2022-01-25 14:17:57.065488", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [issue_tab8 : assert] ******************************************
ok: [ansible-client1] => {
"changed": false,
"msg": "matched! = "
}
TASK [issue_tab8 : show file contents customer-expects_unmatched.txt] *
ok: [ansible-client1] => {
"msg": "abc"
}
TASK [issue_tab8 : shell] *******************************************
ok: [ansible-client1] => {"changed": false, "cmd": "cat /etc/issue", "delta": "0:00:00.004603", "end": "2022-01-25 14:17:57.674059", "rc": 0, "start": "2022-01-25 14:17:57.669456", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [issue_tab8 : assert] ******************************************
fatal: [ansible-client1]: FAILED! => {
"assertion": "lookup('file', '/customer-expects_unmatched.txt') == issue.stdout",
"changed": false,
"evaluated_to": false,
"msg": "unmatched! abc = "
}
PLAY RECAP **********************************************************
ansible-client1 : ok=6 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Solution 1:[1]
You are taking this the wrong way and make it unnecessarily complicated IMO.
You have to understand that laying out a playbook in ansible consists of describing the state in which you want to find the target machine. In this particular situation, you want to describe the state in which you want to find a particular file on the target. This is basically done with a task using the copy module. Once you have done that, knowing if the file is similar or different is just a matter of command line switches or task options.
For more on the below explanation see Validating tasks
Ansible has a check_mode which will let you run an entire playbook just to verify what it would do. You can also unconditionally apply that mode to a single task so that it always runs as a check (check_mode: true), or always makes changes to the remote target however the playbook was called (check_mode: false). We are interested here in the first form.
Similarly, ansible has a diff possibility that will let you see what are the differences between the state you described and the modification it (should have to) apply on the target to reach that state.
An example whith your above scenario. I made the test targeting my local machine only but you can get the exact same result on any remote target.
First let's create the reference file we want to check against in our ansible directory.
mkdir -p files
echo "I'm the reference file" > files/ansible_reference.txt
For the example, I'll now create one identical and one different file on our target so that we can compare both cases:
echo "I'm the reference file" > /tmp/ansible_similar.txt
echo "I'm a different file" > /tmp/ansible_different.txt
This is the playbook compare.yml
---
- name: compare remote file to a local reference
hosts: localhost
gather_facts: false
vars:
local_reference: ansible_reference.txt
remote_files_2_check:
- /tmp/ansible_similar.txt
- /tmp/ansible_different.txt
tasks:
- name: Dry run a copy with diff to check if remote file is aligned
copy:
src: "{{ local_reference }}"
dest: "{{ item }}"
check_mode: true
diff: true
loop: "{{ remote_files_2_check }}"
Which gives:
$ ansible-playbook compare.yml
PLAY [compare remote file to a local reference] *****************************
TASK [Dry run a copy with diff to check if remote file is aligned] **********
ok: [localhost] => (item=/tmp/ansible_similar.txt)
--- before: /tmp/ansible_different.txt
+++ after: /home/user/ansible_project/files/ansible_reference.txt
@@ -1 +1 @@
-I'm a different file
+I'm the reference file
changed: [localhost] => (item=/tmp/ansible_different.txt)
PLAY RECAP ******************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notes:
- Although Ansible reports
changedfor the different file this is only what would happen. Since we are in dry-run for the given task, the above will not change your target. You can run it any number of times, it will report the same result as long as you don't change the reference or the target state. - I you are not happy with the default reporting of the task, you can register the result, explore its content and use it in subsequent tasks to meet your exact requirement.
- Note that the above may report a difference on the permission of the target file. You may have to tune this in the copy module to avoid false positive.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
