I have a shell command in ansible, that changes some file. But most of the time, file stays the same.
What is a preferred way to compare the content of the file before/after shell command and set task changed property?
Q: "Compare the content of the file before/after the shell command and set task changed."
A: Make the script report the changes, register the output of the shell command, and test changed_when.
For example, the task below sets a random environment variable RANDOM_TEXT and writes it to the file /tmp/test.ansible. If the file changes the script will report changed. Because of the potentially failing diff you have to set ignore_errors: true
- shell: "sh -c 'cp /tmp/test.ansible /tmp/test.ansible.orig;
echo $RANDOM_TEXT > /tmp/test.ansible;
if (diff /tmp/test.ansible.orig /tmp/test.ansible > /dev/null);
then echo not changed;
else echo changed;
fi'"
environment:
RANDOM_TEXT: "{{ lookup('random_choice', 'AAA', 'BBB') }}"
ignore_errors: true
register: result
changed_when: result.stdout == 'changed'
Example of a complete playbook for testing
- hosts: localhost
tasks:
- shell: "sh -c 'cp /tmp/test.ansible /tmp/test.ansible.orig;
echo $RANDOM_TEXT > /tmp/test.ansible;
if (diff /tmp/test.ansible.orig /tmp/test.ansible > /dev/null);
then echo not changed;
else echo changed;
fi'"
environment:
RANDOM_TEXT: "{{ lookup('random_choice', 'AAA', 'BBB') }}"
ignore_errors: true
register: result
changed_when: result.stdout == 'changed'
- debug:
var: result
Related
How do we check for a registered variable if only one of the two conditions turns out to be true having the same registered variable?
Below is my playbook that executes only one of the two shell modules.
- name: Check file
shell: cat /tmp/front.txt
register: myresult
when: Layer == 'front'
- name: Check file
shell: cat /tmp/back.txt
register: myresult
when: Layer == 'back'
- debug:
msg: data was read from back.txt and print whatever
when: Layer == 'back' and myresult.rc != 0
- debug:
msg: data was read from front.txt and print whatever
when: Layer == 'front' and myresult.rc != 0
Run the above playbook as
ansible-playbook test.yml -e Layer="front"
I do get error that says myresult does not have an attribute rc. What is the best way to print debug one statements based on the condition met?
I tried myresult is changed but that too does not help. Can you please suggest.
Use ignore_errors: true and change the task order. Try as below.
- name: Check file
shell: cat /tmp/front.txt
register: myresult
when: Layer == 'front'
- debug:
msg: data was read from front.txt and print whatever
when: not myresult.rc
ignore_errors: true
- name: Check file
shell: cat /tmp/back.txt
register: myresult
when: Layer == 'back'
- debug:
msg: data was read from back.txt and print whatever
when: not myresult.rc
ignore_errors: true
So far I can see using a when in ansible to determin whether to run a task but do I have to define 2 tasks to run the alternative option..
example - if I want to run the following task then run the debug task, i need to run two tasks or existStatus will not have been defined for the debug statement. Can I not use some sort of if else statement rather than include 2 separate tasks?
- name: Print user does not exist status
shell: echo 'user does not exist'
when: kafka_configs_result.stdout_lines[1] == '1'
register: existStatus
- name: Print user does not exist status
shell: echo 'user already exists so could not be created'
when: kafka_configs_result.stdout_lines[1] == '0'
register: existStatus
- debug: msg="{{ existStatus.stdout_lines }}"
You can do this in one single task without having to go through an unneeded shell execution. A simple way is to use a test and the ternary filter
I added the var section simply for readability. You can make a long one liner if you wish.
- debug:
vars:
exists_test: "{{ kafka_configs_result.stdout_lines[1] == '1' }}"
msg_exists: "user already exists so could not be created"
msg_notexists: "user does not exist"
msg: "{{ exists_test | ternary(msg_notexists, msg_exists) }}"
You can write something like this to utilize if-loop
- set_fact: build="{% if '<something>' in <something> %}<VALUE>{% else %}<VALUE>{% endif %}"
I have a playbook which is repeating one task, shell is invoked from ansible task, but it does not exit successful on completion of task and repeating the shell instructions again.
Playbook:
---
hosts: dev-servers
tasks:
- name: clean up directoty
shell: rm -rf /opt/data/latest/*
- name: copy the file
copy: src=/home/data/metadata.zip dest=/opt/data
- name: Change directoty
shell: cd /opt/data
- name: copy the file
copy: src=/root/Run_Build.sh dest=/opt/deployment_scripts
- name: permission
shell: chmod +x /opt/deployment_scripts/Run_Build.sh
- name: deploy
command: sh /opt/deployment_scripts/Run_Build.sh
run_once: true
register: result
- debug: msg="{{ result.stdout }}"
- debug: msg="{{ result.stderr }}"
Run_Build.sh:
#!/bin/bash
Jboss_logs=/opt/jboss/jboss-eap-6.4/standalone/log/server.log
for i in {1..100}; do
sleep 10
if [ -f $Jboss_logs/server.log ]; then
if grep -e 'Deployed "deploy.war"' $Jboss_logs/server.log ; then
echo "Code successfully deployed"
exit 0
else
echo "*****************************************************************************"
echo " JBOSS is still loading deployment - please be patient .... Loading again in 10 sec"
echo "*****************************************************************************"
fi
else
echo "server log file has not been created yet, please wait for sometime."
fi
done
I am trying to check group ownership of all the directory named "deployments" inside path. To do this I am using for loop with find command and store all the deployments dir in variable. And then using grep I am checking whether there is any deviation. Below is my task. The problem is that the Its not working and even if group ownership is different its not detecting it.
How can i check and fix how the command i am passing in shell module is running correctly by shell module.
---
- name: deployment dir group ownership check
shell: for i in `find /{{ path }} -name deployments -type d -print`;do ls -ld $i | grep -v 'sag';done > /dev/null 2>&1; echo $?
register: find_result
delegate_to: "{{ pub_server }}"
changed_when: False
ignore_errors: true
tags:
- deployment_dir
- debug: var=find_result
- name: status of the group in deployments dir
shell: echo "Success:Deployments dir is owned by sag group in {{ path }} in server {{ pub_server }}" >> groupCheck.log
when: find_result.stdout == "1"
changed_when: False
tags:
- deployment_dir
- name: status of the group in deployments dir
shell: echo "Fail:Deployments dir is NOT owned by sag group in {{ path }} in server {{ pub_server }}" >> groupCheck.log
changed_when: False
when: find_result.stdout == "0"
tags:
- deployment_dir
Why you use that shell with find?
You can stat the folder and then get the UID and GID for set those permissions...
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- stat:
path: /tmp
register: tmp
- debug: msg="Uid {{ tmp.stat.uid }} - Guid {{ tmp.stat.gid }}"
Playbook run:
PLAY ***************************************************************************
TASK [stat] ********************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "Uid 0 - Guid 0"
}
Tmp folder:
14:17:17 kelson#local:/# ls -la /
drwxrwxrwt 23 root root 4096 Mai 14 14:17 tmp
Using that line of thinking, you can use the find module, register the output and use stat with your results to seek every folder permissions or set those you want...
I am running several shell commands in an ansible playbook that may or may not modify a configuration file.
One of the items in the playbook is to restart the service. But I only want to do this if a variable is set.
I am planning on registering a result in each of the shell tasks, but I do not want to overwrite the variable if it is already set to 'restart_needed' or something like that.
The idea is the restart should be the last thing to go, and if any of the commands set the restart variable, it will go, and if none of them did, the service will not be restarted. Here is an example of what I have so far...
tasks:
- name: Make a backup copy of file
copy: src={{ file_path }} dest={{ file_path }}.{{ date }} remote_src=true owner=root group=root mode=644 backup=yes
- name: get list of items
shell: |
grep <file>
register: result
- name: output will be 'restart_needed'
shell: |
NUM=14"s"; if [ "${NUM}" != "s" ]; then sed -i "${NUM}/no/yes/g" {{ file_path }}; echo "restart_needed"; else echo "nothing_changed" ; fi
with_items: "{{ result.stdout_lines }}"
register: output
- name: output will be 'nothing_changed'
shell: |
NUM="s"; if [ "${NUM}" != "s" ]; then sed -i "${NUM}/no/yes/g" {{ file_path }}; echo "restart_needed"; else echo "nothing_changed" ;; fi
with_items: "{{ result.stdout_lines }}"
register: output
- name: Restart service
service: name=myservice enabled=yes state=restarted
In the above example, the variable output will be set to restart_needed after the first task but then will be changed to 'nothing_changed' in the second task.
I want to keep the variable at 'restart_needed' if it is already there and then kick off the restart service task only if the variable is set to restart_needed.
Thanks!
For triggering restarts, you have two options: the when statement or handlers.
When statement example:
tasks:
- name: check if string "foo" exists in somefile
shell: grep -q foo somefile
register: result
- name: restart service
service:
name: myservice
enabled: yes
state: restarted
when: result.rc == 0
Handlers example:
tasks:
- name: check if string "foo" exists in somefile
shell: grep -q foo somefile
register: result
changed_when: "result.rc == 0"
notify: restart service
handlers:
- name: restart service
service:
name: myservice
enabled: yes
state: restarted