Ansible when condition fails each time - ansible

I have written an ansibe playbook to check if oswatcher is installed. if not, install it.
shell script to check the software is installed
#!/bin/bash
#Validation check that checks if oswatcher is installed
oswatcher=$(rpm -qa | grep "^oswatcher*" || echo "not_installed")
echo "$oswatcher"
this play here checks the shell scripts output and validates if it has to run the install play or not
- name: Execute script to check if oswatcher is installed
script: "{{ oswatch_home }}/version_details.sh"
register: oswatcher
- name: Print the Output
debug:
msg: "You can think the Application is installed, it is {{ oswatcher.stdout }}"
- include: oswatch-install.yml
when: oswatcher.stdout == "not_installed"
Please see the output
PLAY [integration] *******************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************
ok: [xxxxxx]
ok: [xxxxxx]
TASK [app/oswatch : Execute script to check if oswatcher is installed] ***************************************************************
changed: [xxxxx1]
changed: [xxxxx2]
TASK [app/oswatch : Print the Output] ************************************************************************************************
ok: [xxxxxx1] => {
"changed": false,
"msg": "You can think the Application is installed, it is oswatcher-7.3.3-2.el6.noarch\r\n"
}
ok: [xxxxxx2] => {
"changed": false,
"msg": "You can think the Application is installed, it is not_installed\r\n"
}
TASK [app/oswatch : create project directory "/tmp/oswatch"] *************************************************************************
skipping: [xxxxxx1]
skipping: [xxxxxx2]
My logic matches not_installed and validates whether to run the install play or not, It even prints it perfect not able to understand the hiccup.

Change the task to below and see if it is serving the purpose.If it is still not working, please run your playbook with -vvv and post complete output.
- include: oswatch-install.yml
when: "not_installed" in oswatcher.stdout

Related

Rerunning same Ansible task a few times

I am trying to implement a task that runs in a loop, for example, ten times.
Currently, the task runs only once.
I am trying something like the following:
my_role/tasks/main.yaml
---
- set_fact:
counter: 0
- name: "Iteration"
import_task: my_task.yaml
until: counter <= 10
...
my_role/tasks/my_task.yaml
---
- name: "task 1"
...
- name: "task 2"
...
- set_fact:
counter=={{ counter | int + 1 }}
...
I expected "task 1" and "task 2" to run ten times.
I would be happy to get some ideas on how to implement such loop.
You should use include_tasks module and loop over it.
my_role/tasks/main.yaml
---
- name: "Iteration"
ansible.builtin.include_tasks:
file: my_task.yaml
with_sequence: start=1 end=10
...
my_role/tasks/my_task.yaml
---
- name: "task 1"
...
- name: "task 2"
...
...
Ansible is an automation tool that is commonly used to configure and manage servers, networks, and other IT infrastructure. One of the key features of Ansible is its idempotence, which means that running the same task multiple times on the same system should produce the same end result, regardless of how many times the task is run.
Here is a plan on how to rerun the same Ansible task multiple times:
Create or open an existing Ansible playbook. A playbook is a YAML file that contains one or more plays, which are a list of tasks that are executed on a specific set of hosts.
Define the task that you want to rerun in the playbook using the Ansible modules. These modules are pre-built scripts that can perform specific actions on the remote systems, such as installing software, creating users, and configuring services.
Run the playbook using the ansible-playbook command. You can run the playbook on one or more specific hosts by specifying the -l option, or on all the hosts defined in your inventory file by using the -i option.
Ansible uses the idempotence feature to make sure that the same task is executed only once on the same host. If the task has already been executed and the state of the host hasn't changed, Ansible will not execute the task again.
If you want to force the task to rerun even if the state of the host hasn't changed, you can use the --force-handlers or --force-rerun options when running the ansible-playbook command.
To check the results of the tasks, you can check the log files generated by Ansible or the output of the ansible-playbook command.
Here is an example of how to run the same task multiple times using ansible-playbook command:
ansible-playbook playbook.yml --extra-vars "var1=value1 var2=value2"
You can run this command as many times as you want and Ansible will make sure that the task is executed only once, unless you use the --force-handlers or --force-rerun options.
Please note that if the task is modifying a state of the host, rerunning the task will have an effect and will change the state of the host.
How to implement task(s) that runs in a loop?
To do so, you may have a look into Loops and a minimal example like
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Example loop
debug:
msg: "{{ item }}"
loop: "{{ range(1, 11) | list }}"
register: result
resulting into an output of
TASK [Example loop] **********
ok: [localhost] => (item=1) =>
msg: 1
ok: [localhost] => (item=2) =>
msg: 2
ok: [localhost] => (item=3) =>
msg: 3
ok: [localhost] => (item=4) =>
msg: 4
ok: [localhost] => (item=5) =>
msg: 5
ok: [localhost] => (item=6) =>
msg: 6
ok: [localhost] => (item=7) =>
msg: 7
ok: [localhost] => (item=8) =>
msg: 8
ok: [localhost] => (item=9) =>
msg: 9
ok: [localhost] => (item=10) =>
msg: 10
whereby it is possible to replace the current single task debug against an import_task for a task file.
Further Documentation
Extended loop variables
What's the difference between include_tasks and import_tasks?

playbook runs with ansible-playbook successfully but does nothing in ansible tower

I have ansible installed on the Windows Subsystem for Linux. This version is 2.9.6.
I also have an ansible tower that is version 3.7.2 which has Ansible version 2.9.27.
I basically use the ansible installation on my WSL to play with and debug playbooks to get them working. Once they are working, I upload them to my Git Repository and pull them into the Ansible Tower for execution.
I am still fairly new to Ansible so perhaps this is a very simple issue. I have a playbook that runs just fine on my ansible (2.9.6) WLS environment.
When I run the same playbook in my Ansible Tower, it doesn't run any tasks.
The playbook is fairly simple. I want to use it to change the password on a local Windows account. The playbook is in a file named change_user_password.yml. The contents are shown below:
- name: Change user password
hosts: all
tasks:
- name: Include OS-specific variables.
include_vars: "{{ ansible_os_family }}.yml"
- name: Print OS Family
debug:
msg: "Ansible OS family is {{ ansible_os_family }}"
- name: Print uname
debug:
msg: "Uname variable is {{ uname }}"
- name: Print newpass
debug:
msg: "Newpass variable is {{ newpass }}"
- name: Change pwd (Redhat).
ping:
when: ansible_os_family == 'RedHat'
- name: Change pwd (Debian).
ping:
when: ansible_os_family == 'Debian'
- name: Change pwd (Windows).
win_user:
name: "{{ uname }}"
password: "{{ newpass }}"
when: ansible_os_family == 'Windows'
When run on the command line with ansible-playbook in my WSL environment I pass in the --extra-vars for uname and newpass variables as shown below:
ansible-playbook -i ../hosts.ini --limit cssvr-prod change_user_password.yml --extra-vars="uname=myadmin newpass=test1234TEST"
Output typically looks like this:
PLAY [Change user password] ***************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************
ok: [cssvr-prod]
TASK [Include OS-specific variables.] *****************************************************************************************************************************************************************
ok: [cssvr-prod]
TASK [Print OS Family] ********************************************************************************************************************************************************************************
ok: [cssvr-prod] => {
"msg": "Ansible OS family is Windows"
}
TASK [Print uname] ************************************************************************************************************************************************************************************
ok: [cssvr-prod] => {
"msg": "Uname variable is myadmin"
}
TASK [Print newpass] **********************************************************************************************************************************************************************************
ok: [cssvr-prod] => {
"msg": "Newpass variable is test1234TEST"
}
TASK [Change pwd (Redhat).] ***************************************************************************************************************************************************************************
skipping: [cssvr-prod]
TASK [Change pwd (Debian).] ***************************************************************************************************************************************************************************
skipping: [cssvr-prod]
TASK [Change pwd (Windows).] **************************************************************************************************************************************************************************
changed: [cssvr-prod]
PLAY RECAP ********************************************************************************************************************************************************************************************
cssvr-prod : ok=6 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
When I run this playbook from Ansible Tower, I add uname and newpass as extra variables in the Extra Variables box on the Template for this play. I add the cssvr-prod host in the Limit box. When I run it, no tasks are run. NOTE: The warning below is expected, the inventory and groups are imported from Azure. Some of our Azure resource groups have hyphens in their name which apparently is illegal in the ansible hosts file as a group name.
Using /etc/ansible/ansible.cfg as config file
SSH password:
[WARNING]: Invalid characters were found in group names but not replaced, use
-vvvv to see details
PLAY [all] *********************************************************************
PLAY RECAP *********************************************************************
I'm pulling what little hair I have left out trying to figure out why the code behaves this way on Tower.

echo message based on ansible stdout value

Team,
Not sure why my message with echo is not getting printed. I want to print a text if command that ran before for stopping process was successful.
In my case am checking for apache2 process status. Basically, if stdout is empty it passed and if stderr exists it failed. I also referred this link but no luck..
https://stackoverflow.com/questions/26142343/ansible-conditional-based-on-stdout-of-result
- name: stop apache2 process
command: systemctl stop apache2
ignore_errors: no
changed_when: false
register: service_apache2_status
become: true
- debug:
var: service_apache2_status.stdout
- name: Check if apache2 stopped
command: echo "Successfully Stopped Apache2"
# when: service_apache2_status.stdout == " "
when: service_apache2_status.stdout | length == 0
Actual output:
TASK [diskcache_prerequisites : stop apache2 process] **********************************************************************************
ok: [localhost]
TASK [diskcache_prerequisites : debug] *************************************************************************************************
ok: [localhost] => {
"service_apache2_status.stdout": ""
}
TASK [diskcache_prerequisites : Check if apache2 stopped] ******************************************************************************
changed: [localhost]
expected output:
TASK [diskcache_prerequisites : Check if apache2 stopped] ******************************************************************************
changed: [localhost]
Successfully Stopped Apache2
You don't need the "check if apache2 stopped" at all if you use the systemd module instead of trying to use command: to call systemctl by hand
As for your question: if you want to see output, that's what - debug: msg="Successfully stopped Apache2" is for; the command: module is not a general purpose debugging tool, it's for running commands

ansible playbook run a task only once

I need to run a task ,set a flag and the second time the play runs run the task only if the flag is not set
Play at a later stage
- name: Dump all databases
mysql_db:
state: dump
name: all
target: /root/mysql_all.sql
when: ansible_local.mysql.replication.setup is not defined
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom fact stating mysql is setup
template:
src: mysql.fact.j2
dest: /etc/ansible/facts.d/mysql.fact
The problem is that the fist time this play runs its throwing an error.
FAILED! => {"failed": true, "msg": "The conditional check 'ansible_local.mysql.replication.setup is not defined' failed. The error was: error while evaluating conditional (ansible_local.mysql.replication.setup is not defined): 'ansible_local' is undefined
What is the best way to run a task only in the first run and skip for subsequent runs.
you should make a task prior that registers if /root/mysql_all.sql exists then add it to your when clause.
Example:
- name: check if dump exists
stat:
path: /root/mysql_all.sql
register: mysqldump
- name: Dump all databases
mysql_db:
state: dump
name: all
target: /root/mysql_all.sql
when:
- ansible_local.mysql.replication.setup is not defined
- mysqldump.stat.exists == true
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom fact stating mysql is setup
template:
src: mysql.fact.j2
dest: /etc/ansible/facts.d/mysql.fact
One option is to utilize the fact cache. When enabled, you can set cacheable facts in your play and check for them.
Fact caching always takes place. There are various fact cache plug-ins available of which the memory plug-in is the default, and json file and redis cache are the most popular. You can only set one plug-in. Refer to
https://docs.ansible.com/ansible/latest/plugins/cache.html
When you want to explore with the json file you can set the environment variables as follows:
export ANSIBLE_CACHE_PLUGIN=jsonfile
export ANSIBLE_CACHE_PLUGIN_CONNECTION="~/ansiblefactcache"
In your play book you can check for facts and set them as cacheable, Refer to
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
A small example playbook.yaml:
- name: Example Fact Cache Playbook
hosts: all
gather_facts: false # the default is true; it gathers various host facts
tasks:
- name: Runs when examplefact equals something
debug:
msg: "Runs when examplefact equals something"
when: ansible_facts['examplefact'] is defined and ansible_facts['examplefact'] == "something"
- name: Does not run when examplefact equals something
debug:
msg: "does not run when examplefact equals something"
when: ansible_facts['examplefact'] is not defined or ansible_facts['examplefact'] != "something"
- name: Set the examplefact to something
set_fact:
examplefact: "something"
cacheable: true
Note the usage of the cacheable instruction. When true the fact goes into the cache.
After having run this small playbook you will notice the creation of a localhost file in your home's subfolder ansiblefactcache which contains your cached facts.
Also note the usage of the gather_facts instruction. The default being true will scan your machine for various details such as environment variables, network details, etc. All are cached. You can play with it and see the localhost file being populated with it.
You can also try to edit the localhost file yourself or even delete it and run the play again.
I used the following inventory file inventory.yaml:
all:
hosts:
localhost:
ansible_connection: local
And I run ansible as follows:
ansible-playbook playbook.yaml -i inventory.yaml -vvv
First run yields the following:
PLAY [Example Fact Cache Playbook] ********************************************************************************************************************************************************************************
TASK [Runs when examplefact equals something] *********************************************************************************************************************************************************************
skipping: [localhost]
TASK [Does not run when examplefact equals something] *************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "does not run when examplefact equals something"
}
TASK [Set the examplefact to something] ***************************************************************************************************************************************************************************
ok: [localhost]
Second run yields the following:
PLAY [Example Fact Cache Playbook] ********************************************************************************************************************************************************************************
TASK [Runs when examplefact equals something] *********************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Runs when examplefact equals something"
}
TASK [Does not run when examplefact equals something] *************************************************************************************************************************************************************
skipping: [localhost]
TASK [Set the examplefact to something] ***************************************************************************************************************************************************************************
ok: [localhost]

Ansible via Ansible Pull can't find file in `template: validate="stat %s"`

When using Ansible through Ansible Pull, the template directive's validate step fails to find the file specified by %s.
"No such file" error reported by ansible-pull:
TASK [ssh : place ssh config file] *********************************************
fatal: [localhost]: FAILED! => {
"changed": true,
"cmd": "sshd -t -f /home/nhooey/.ansible/tmp/ansible-tmp-1453485441.94-279324955743/source",
"failed": true,
"msg": "[Errno 2] No such file or directory",
"rc": 2
}
Problematic template directive:
- name: place ssh config file
template:
src: etc/ssh/sshd_config
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: 0644
validate: 'sshd -t -f %s'
This happens with either Ansible 1.9.4 or 2.0.0.2 from (Python 2.7's Pip) and only when using Ansible Pull. Running ansible-playbook locally after manually checking out the repository works fine.
Unfortunately I'm not able to reproduce this error in the trivial case with a sample repository that I created.
Failure to reproduce error with simple test case:
$ virtualenv .venv && source .venv/bin/activate && pip install ansible
$ ansible-pull --directory /tmp/ansible-test \
--url https://github.com/nhooey/ansible-pull-template-validate-bug.git playbook.yaml
Starting Ansible Pull at 2016-01-22 13:14:51
/Users/nhooey/git/github/nhooey/ansible-pull-template-validate-bug/.venv/bin/ansible-pull \
--directory /tmp/ansible-test \
--url https://github.com/nhooey/ansible-pull-template-validate-bug.git \
playbook.yaml
localhost | SUCCESS => {
"after": "07bb13992910e0efe30d071d5f5a2a2e88251045",
"before": "07bb13992910e0efe30d071d5f5a2a2e88251045",
"changed": false
}
[WARNING]: provided hosts list is empty, only localhost is available
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [Delete template file] ****************************************************
changed: [localhost]
TASK [Test template validation] ************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0
Playbook that won't fail in the simple test case above:
---
- hosts: localhost
tasks:
- name: Delete template file
file:
path: /tmp/file
state: absent
- name: Test template validation
template:
src: file
dest: /tmp/file
validate: 'ls %s'
It seems like there could be a problem with the timing around when ansible-pull creates and deletes temporary files in Ansible.
What's happening?
It's saying that it can't find sshd because it's not in the path. Silly me...

Resources