Ansible: A registered variable is undefined when even after debug shows it's contents - linux

Ansuble Register Variables
I have task list where I register output from a shell task. The shell command lists a directory and then pipes the output to grep. The task works and I get the output I wanted. Eariler in the playbook SVN source files are checked outed and transferred to {{ DestRemoteDir }} directory. The code in question builds a list from the output of the command. I take those lists to set various other facts later in the playbook. [ Mapping a list of Debian packages in a specific order of 2nd list with Ansible ] (I know of ansible's find module, but I found "ls -1" far easier to use.)
Playbook (tasks/main.yml)
## use List -1 to find the file names for the deb files.| grep
## It stays, The tasks work as expected.
- name: Find the needed deb files
shell: "ls -1 {{ DestRemoteDir }} | grep .*.deb" # Local dir
register: Deb_List
ignore_errors: yes
delegate_to: 127.0.0.1 #localhosts
- name: Find the needed IXAD list file
shell: "ls -1 {{ DestRemoteDir }} | grep IA-XD" # Local dir
register: IXAD_List_Source
ignore_errors: yes
delegate_to: 127.0.0.1 #localhosts
- name: Print the Deblist for IX-AD
debug:
msg:
- "Deb file list: {{ Deb_List.stdout_lines }}"
- "IXAD file {{ IXAD_List_Source.stdout_lines }}"
- name: Print if undefined Deb_list
debug:
msg: "Deb_List is not real"
when: Deb_list is undefined
- name: Print if undefined Deb_list.stdout_lines
debug:
msg: "Deb_List.stdout_lines is not real"
when: Deb_list.stdout_lines is undefined
Output
changed: [AnsibleTest2 -> 127.0.0.1] => {
"changed": true,
"cmd": "ls -1 /home/ansible/IA-XD | grep .*.deb",
***
"invocation": {
"module_args": {
***
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "iaxd_1.2.7.6-15_all.deb\niaxdautocfg_1.0.0.0_all.deb\nlibjpegdeb7u1_amd64.deb\nopenjdk-6-jre_610-1~deb7u1_amd64.deb\nopenjdk-6-jre-headless_610-1~deb7u1_amd64.deb\nopenjdk-610-1~deb7u1_all.deb",
"stdout_lines": [
"iaxd_1.2.7.6-15_all.deb",
"iaxdautocfg_1.0.0.0_all.deb",
"libjpeg7u1_amd64.deb",
"openjdk-6-jre_610-1~deb7u1_amd64.deb",
"openjdk-6-jre-headless_610-1~deb7u1_amd64.deb",
"openjdk-6-jre-lib_610-1~deb7u1_all.deb"
]
}
changed: [AnsibleTest2 -> 127.0.0.1] => {
"changed": true,
"cmd": "ls -1 /home/ansible/IA-XD | grep IA-XD",
"invocation": {
"module_args": {
"_raw_params": "ls -1 /home/ansible/IA-XD | grep IA-XD",
***
}
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "IA-XD_List",
"stdout_lines": [
"IA-XD_List"
]
}
Debug
ok: [AnsibleTest2] => {
"msg": [
"Deb file list: [u'iaxd_1.2.7.6-15_all.deb',u'iaxdautocfg_1.0.0.0_all.deb',u'libjpegdeb7u1_amd64.deb',u'openjdk-6-jre_610-1~deb7u1_amd64.deb',u'openjdk-6-jre-headless_610-1~deb7u1_amd64.deb',u'openjdk-610-1~deb7u1_all.deb']",
"IXAD file [u'IA-XD_List']"
]
}
Above both "stdout_lines": [ "IA-XD_List" ] and "stdout_lines": [ "iaxd_1.2.7.6-15_all.deb",...] are ready.
So from the debug task I see that the variables are there and defined (Or so I thought). But when I test to see if there if the shell command failed.
Error Message
The status clearly shows that Deb_List is undefined. why?
I just debug thad value of that variable.
TASK [server_iaxd_install : Print if undefined Deb_list] *********************************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:64
Tuesday 25 February 2020 11:50:12 +0100 (0:00:00.222) 0:00:07.890 ******
ok: [AnsibleTest2] => {
"msg": "Deb_List is not real"
}
Read vars_file '/home/ansible/.ssh/SudoPassKey'
Try to test the key data I want "Deb_list.stdout_lines", Ansible errors as the variable is not there.
TASK [server_iaxd_install : Print if undefined Deb_list.stdout_lines] ********************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:69
Tuesday 25 February 2020 11:50:12 +0100 (0:00:00.197) 0:00:08.087 ******
fatal: [AnsibleTest2]: FAILED! => {
"msg": "The conditional check 'Deb_list.stdout_lines is undefined' failed. The error was: error while evaluating conditional (Deb_list.stdout_lines is undefined): 'Deb_list' is undefined\n\nThe error appears to have been in '/home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml': line 69, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Print if undefined Deb_list.stdout_lines\n ^ here\n"
}
Either this is a "forest for the trees" (I can't see the obvious) error or an annoying quirk of Ansible that I need to kluge around.

Yes, it was a "forest for the trees" (I can't see the obvious) error.
After looking for the error, I change the code.
- name: Print if undefined Deb_List
debug:
msg: "Deb_List is not real"
when: Deb_List is undefined
- name: Print if undefined Deb_List.stdout_lines
debug:
msg: "Deb_List.stdout_lines is not real"
when: Deb_List.stdout_lines is undefined
And now the output is far better:
TASK [server_iaxd_install : Print if undefined Deb_List] *********************************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:77
Tuesday 25 February 2020 16:00:34 +0100 (0:00:00.242) 0:00:08.013 ******
skipping: [AnsibleTest2] => {}
Read vars_file '/home/ansible/.ssh/SudoPassKey'
TASK [server_iaxd_install : Print if undefined Deb_List.stdout_lines] ********************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:82
Tuesday 25 February 2020 16:00:34 +0100 (0:00:00.065) 0:00:08.078 ******
skipping: [AnsibleTest2] => {}

Related

Ansible tasks after delegate_to:127.0.0.1 are skipped

My code is as below, I am reading from a local csv file use those values for tasks on remote hosts
---
- name: Empty Topics
hosts: remote_host
gather_facts: no
vars:
kafka_topics: /bin/kafka-topics
bootstrap_server: "list_of_broker_hosts"
retention_ms: 604800000
command_config: /etc/kafka/client.properties
kafka_log_dirs: /usr/bin/kafka-log-dirs
#ansible_connection: ssh
#ansible_user: ansible
#ansible_become: true
tasks:
- name: "Reading Topic Names"
read_csv:
path: topics_list.csv
register: topics
delegate_to: 127.0.0.1
- name: "Setting Topic Retention to 0"
become: yes
become_user: root
shell:
{{ kafka_topics }} --bootstrap_server {{bootstrap_server}} --alter --topic "{{ item.topic_name }}" --config retention.ms=0 --command_config #{{command_config}}
#touch /tmp/producer_test_1
loop: "{{ topics.list }}"
- name: "waiting for size to go zero "
become: yes
become_user: root
shell:
topic_size=1
while [ $topic_size -ne 0 ]
do
topic_size=`{{kafka_log_dirs}} --command_config {{command_config}} --bootstrap_server {{bootstrap_server}} --topic-list "{{ item.topic_name }}" --describe | grep -oP '(?<=size":)\d+' | awk '{ sum += $1 } END { print sum }' `
sleep 40
done
loop: "{{ topics.list }}"
- name : "Setting Topic Retention to 7"
become: yes
become_user: root
shell:
#{{ kafka_topics }} --bootstrap_server {{bootstrap_server}} --alter --topic "{{ item.topic_name }}" --config retention.ms={{retention_ms}} --command_config {{command_config}}
#touch /tmp/producer_test_2
loop: "{{ topics.list }}"
here the tasks after first task "Reading Topic Names" are skipped , if I remove this task, they succeed but that means I have to hard code values on subsequent tasks
execution log as below. How can I avoid this. current ansible version is 2.9.19 This playbook had previously worked as is on ansible version 2.9.6 in my previous organization, not sure what settings may be changed in my new company.
I tried delegate_to: localhost as well as delegate_to: 127:0:0:1
ansible#localhost[~] $ ansible-playbook empty_topics.pb -i /home/ansible/inv_sit.yml -l all
PLAY [Empty Topics] ***********************************************************************************************************
TASK [Reading Topic Names] ****************************************************************************************************
ok: [remotehost]
TASK [Setting Topic Retention to 0] *******************************************************************************************
TASK [waiting for size to go zero] ********************************************************************************************
TASK [Setting Topic Retention to 7] *******************************************************************************************
PLAY RECAP ********************************************************************************************************************
remotehost : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
ansible#localhost[~] $ ansible-playbook empty_topics.pb -i /home/ansible/inv_sit.yml -l all -vvv
ansible-playbook 2.9.19
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 3.6.8 (default, Jun 14 2022, 12:54:58) [GCC 8.5.0 20210514 (Red Hat 8.5.0-10)]
Using /etc/ansible/ansible.cfg as config file
host_list declined parsing /home/ansible/inv_sit.yml as it did not pass its verify_file() method
script declined parsing /home/ansible/inv_sit.yml as it did not pass its verify_file() method
Parsed /home/ansible/inv_sit.yml inventory source with ini plugin
Skipping callback 'actionable', as we already have a stdout callback.
Skipping callback 'counter_enabled', as we already have a stdout callback.
Skipping callback 'debug', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'dense', as we already have a stdout callback.
Skipping callback 'full_skip', as we already have a stdout callback.
Skipping callback 'json', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'null', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.
Skipping callback 'selective', as we already have a stdout callback.
Skipping callback 'skippy', as we already have a stdout callback.
Skipping callback 'stderr', as we already have a stdout callback.
Skipping callback 'unixy', as we already have a stdout callback.
Skipping callback 'yaml', as we already have a stdout callback.
PLAYBOOK: empty_topics.pb *****************************************************************************************************
1 plays in empty_topics.pb
PLAY [Empty Topics] ***********************************************************************************************************
META: ran handlers
TASK [Reading Topic Names] ****************************************************************************************************
task path: /home/ansible/empty_topics.pb:18
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: ansible
<127.0.0.1> EXEC /bin/sh -c 'echo ~ansible && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/ansible/.ansible/tmp `"&& mkdir "` echo /home/ansible/.ansibl e/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492 `" && echo ansible-tmp-1672893960.0795922-3957982-94418260356492="` echo /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492 `" ) && sleep 0'
Using module file /usr/lib/python3.6/site-packages/ansible/modules/files/read_csv.py
<127.0.0.1> PUT /home/ansible/.ansible/tmp/ansible-local-3957970ixug96xw/tmpn373dahz TO /home/ansible/.ansible/tmp/ansible-tmp- 1672893960.0795922-3957982-94418260356492/AnsiballZ_read_csv.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492/ /home/ ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492/AnsiballZ_read_csv.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/libexec/platform-python /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-944 18260356492/AnsiballZ_read_csv.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/ansible/.ansible/tmp/ansible-tmp-1672893960.0795922-3957982-94418260356492/ > /dev/ null 2>&1 && sleep 0'
ok: [remotehost] => {
"changed": false,
"dict": {},
"invocation": {
"module_args": {
"delimiter": null,
"dialect": "excel",
"fieldnames": null,
"key": null,
"path": "topics_list.csv",
"skipinitialspace": null,
"strict": null,
"unique": true
}
},
"list": []
}
TASK [Setting Topic Retention to 0] *******************************************************************************************
task path: /home/ansible/empty_topics.pb:23
TASK [waiting for size to go zero] ********************************************************************************************
task path: /home/ansible/empty_topics.pb:31
TASK [Setting Topic Retention to 7] *******************************************************************************************
task path: /home/ansible/empty_topics.pb:42
META: ran handlers
META: ran handlers
PLAY RECAP ********************************************************************************************************************
remotehost : ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
ansible#localhost[~] $
I tried delegate_to: localhost as well as delegate_to: 127:0:0:1
As suggested by β.εηοιτ.βε, I checked the csv file, although there were contents , it was missing the header row, hence the issue. Now with header row added to the csv file, the code works.

Running the following 2 bash commands in Ansible [duplicate]

This question already has answers here:
Difference between sh and Bash
(11 answers)
shell module: Bash <(process substitution) with ansible
(3 answers)
Closed 6 months ago.
I'm trying to create a playbook that incorporates the following 2 commands and due to their special characters, i cant get it to work. Is there a list of special characters i need to account for in ansible using a bash command?
- name: If file exists compare new users.txt
shell: >
diff -q users.txt <(getent passwd | awk -F: '{ print $1 }') 1>/dev/null; error="$?"
getent passwd | awk -F: '{ print $1 }' > users.txt
The error is
fatal: [localhost]: FAILED! => {
"changed": true,
"cmd": "diff -q users.txt <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"\n",
"delta": "0:00:00.002893",
"end": "2022-08-19 23:43:07.324939",
"invocation": {
"module_args": {
"_raw_params": "diff -q users.txt <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"\n",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"msg": "non-zero return code",
"rc": 1,
"start": "2022-08-19 23:43:07.322046",
"stderr": "/bin/sh: -c: line 0: syntax error near unexpected token `('\n/bin/sh: -c: line 0: `diff -q users.txt <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"'",
"stderr_lines": [
"/bin/sh: -c: line 0: syntax error near unexpected token `('",
"/bin/sh: -c: line 0: `diff -q users.txt <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"'"
],
"stdout": "",
"stdout_lines": []
}
Q: "Update the list of users in /tmp/users.txt if the list differs from those in /etc/passwd."
A: Use the module getent to read /etc/passwd. For example,
- name: Create dictionary ansible_facts.getent_passwd
ansible.builtin.getent:
database: passed
Next, read the file. Set changed_when: false to keep the play idempotent
- name: Create list users.stdout_lines from /tmp/users.txt
command: cat /tmp/users.txt
register: users
changed_when: false
Compare the lists and update the file if needed
- copy:
dest: /tmp/users.txt
content: |
{% for user in ansible_facts.getent_passwd.keys() %}
{{ user }}
{% endfor %}
when: diff|length > 0
vars:
diff: ansible_facts.getent_passwd.keys()|list|
difference(users.stdout_lines)
Example of a complete playbook for testing
- hosts: localhost
tasks:
- name: Create dictionary ansible_facts.getent_passwd
ansible.builtin.getent:
database: passwd
- ansible.builtin.debug:
var: ansible_facts.getent_passwd.keys()|list
when: debug|d(false)|bool
- name: Create list users.stdout_lines from /tmp/users.txt
command: cat /tmp/users.txt
register: users
changed_when: false
- ansible.builtin.debug:
var: users.stdout_lines
when: debug|d(false)|bool
- name: Update /tmp/users.txt
copy:
dest: /tmp/users.txt
content: |
{% for user in ansible_facts.getent_passwd.keys() %}
{{ user }}
{% endfor %}
when: new_users|length > 0
vars:
new_users: "{{ ansible_facts.getent_passwd.keys()|
difference(users.stdout_lines) }}"
Example of the update
If I remove the users admin, user1, and user2 from the file, the play gives (abridged) in --diff mode
shell> ansible-playbook pb.yml -CD
TASK [Update /tmp/users.txt] ************************************************
--- before: /tmp/users.txt
+++ after: /home/tester/.ansible/tmp/ansible-local-903563m7yp2ywc/tmpvm5fd7j2
## -50,4 +50,7 ##
libvirt-qemu
libvirt-dnsmasq
asadmin
+admin
+user1
+user2
_chrony
changed: [localhost]
Q: "Detect new users that were added."
A: Report new users in the block. For example,
- hosts: localhost
gather_facts: false
tasks:
- name: Create dictionary ansible_facts.getent_passwd
ansible.builtin.getent:
database: passwd
- ansible.builtin.debug:
var: ansible_facts.getent_passwd.keys()|list
when: debug|d(false)|bool
- name: Create list users.stdout_lines from /tmp/users.txt
command: cat /tmp/users.txt
register: users
changed_when: false
- ansible.builtin.debug:
var: users.stdout_lines
when: debug|d(false)|bool
- name: Report new users and update file
block:
- name: Report new users
debug:
msg: "New users: {{ new_users }}"
- name: Update /tmp/users.txt
copy:
dest: /tmp/users.txt
content: |
{% for user in ansible_facts.getent_passwd.keys() %}
{{ user }}
{% endfor %}
when: new_users|length > 0
vars:
new_users: "{{ ansible_facts.getent_passwd.keys()|
difference(users.stdout_lines) }}"

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
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 changed for 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.

Why can't I capture an environment variable with Ansible?

I am trying to get and print the value of a given environment variable (ENV_VAR):
$ cat ~/.bash_profile
ENV_VAR=Updated
ENV_VAR2=Updated
$ source ~/.bash_profile && echo $ENV_VAR
Updated
I can successfully retrieve it via terminal, however by using the Ansible playbook below I get an error:
# YAML
---
- hosts: all
vars:
env_var: "{{ lookup('env','ENV_VAR') }}"
tasks:
- name: Add/Update an environment variable to the remote user's shell
lineinfile:
dest: ~/.bash_profile
regexp: '^ENV_VAR='
line: "ENV_VAR=Updated2"
- name: Get the value of the environment variable we just added
shell: source ~/.bash_profile && echo $ENV_VAR
register: env_var_updated
- name: Print the value of the environment variable
debug:
msg: "var1: {{ env_var }} - var2 {{ env_var_updated.stdout }}"
Executing:
$ ansible-playbook playbook.yml
PLAY [all] *********************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************
ok: [192.168.0.222]
TASK [Add/Update an environment variable to the remote user's shell] ***********************************************
ok: [192.168.0.222]
TASK [Get the value of the environment variable we just added] *****************************************************
fatal: [192.168.0.222]: FAILED! => {"changed": true, "cmd": "source ~/.bash_profile && echo $ENV_VAR", "delta": "0:00:00.002337", "end": "2020-12-02 10:20:21.963968", "msg": "non-zero return code", "rc": 127, "start": "2020-12-02 10:20:21.961631", "stderr": "/bin/sh: 1: source: not found", "stderr_lines": ["/bin/sh: 1: source: not found"], "stdout": "", "stdout_lines": []}
PLAY RECAP *********************************************************************************************************
192.168.0.222 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Results after execution:
$ cat ~/.bash_profile
ENV_VAR=Updated2
ENV_VAR2=Updated
$ source ~/.bash_profile && echo $ENV_VAR
Updated2
I am logged as the same user (In the terminal window and SSH for Ansible)
As shown by the following guide:
https://docs.ansible.com/ansible/2.5/modules/shell_module.html
Ansible shell actually runs in /bin/sh and not /bin/bash. You can specify the shell as /bin/bash through:
- name: Get the value of the environment variable we just added
shell: source ~/.bash_profile && echo $ENV_VAR
register: env_var_updated
args:
executable: /bin/bash

Ansible: Unexpected templating type error: expected string or buffer

I have a register with the following contents:
ok: [hostname] => {
"changed": false,
"msg": {
"changed": true,
"cmd": "cd /tmp\n ./status.sh dev",
"delta": "0:00:00.023660",
"end": "2018-11-28 17:46:05.838934",
"rc": 0,
"start": "2018-11-28 17:46:05.815274",
"stderr": "",
"stderr_lines": [],
"stdout": "application is not running. no pid file found",
"stdout_lines": [
"application is not running. no pid file found"
]
}
}
When i see the substring "not" in the register's stdout, i want to trigger another task:
- name: Starting Application As Requested
shell: /tmp/start.sh
when: operation_status.stdout | search('not')
However, i see this error in my triggered task
fatal: [host]: FAILED! => {
"failed": true,
"msg": "The conditional check 'operation_status.stdout | search('not')' failed. The error was: Unexpected templating type error occurred on ({% if operation_status.stdout | search('not') %} True {% else %} False {% endif %}): expected string or buffer\n\nThe error appears to have been in '/path/to/ansible_playbook.yml': line 46, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Starting Application As Requested\n ^ here\n"
I only see this error when adding the when condition. Without it, my playbook succeeds. What am i doing wrong here?
Version details:
ansible 2.3.0.0
python version = 2.6.6 (r266:84292, Aug 9 2016, 06:11:56) [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)]
This error occurs when the variable (in your case operation_status.stdout) is undefined. Maybe the status.sh script doesn't write to stdout when the service is running.
Can you put a debug task and print the value of this variable before the task with "when"?
- name: Debug print value of operation_status.stdout
debug:var=operation_status.stdout
You can also try and modify the when condition to be:
- name: Starting Application As Requested
shell: /tmp/start.sh
when: "'not' in operation_status.stdout"

Resources