Ansible: do not run shell command if a file exists - ansible

I would like to do the following in an Ansible playbook:
- name: "Generate variant html report"
shell: "<my command>"
with_items: "{{ variants | default([]) }}"
when: ({{ folderReports }}/{{ item }}).exists == False
Inside the when, I need a way to create the file path, and determine if it exists or not. I tried to use the "(" ")" to surround my first expression, but it doesn't seem to be working:
2016-10-13 16:22:48,130 p=94292 u=sautomation | fatal: [localhost]: FAILED! => {"failed": true, "msg": "The conditional check '({{ folderReports }}/{{ item }}).exists == True' failed. The error was: template error while templating string: unexpected '/'. String: {% if (/opt/diff-test1.diff).exists == True %} True {% else %} False {% endif %}\n\nThe error appears to have been in '/opt/ansible/roles/stats/tasks/main.yml': line 45, 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: \"Generate report\"\n ^ here\n"}

To prevent a task from executing if a specified file already exists, use creates parameter of the shell module:
- name: "Generate variant html report"
shell: "<my command>"
args:
creates: "{{ folderReports }}/{{ item }}"
with_items: "{{ variants | default([]) }}"
You get an error because .exists, in your conditional, checks if a variable (fact) exist, not a file on the target node.

Related

How to use a combination of variable and a string in ansible when condition?

I want to search for a combination of a string and a file in a particular command output and if both exists then skip the task
Here my data_dir variable value is /data/dbdata/test
- name: Extracting existing selinux context
shell: "semanage fcontext -l -C|grep -i {{data_dir|dirname}}"
register: selin_context
- name: Setting Selinux context for data and log dir
command: "semanage fcontext -a -t {{item.name}} {{item.dirpath|dirname}}(/.*)?"
with_items:
- { name: 'postgresql_db' , dirpath: "{{data_dir}}" }
when: "'postgresql_db' and {{data_dir}} not in selin_context.stdout'
If i try above then getting below error
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: 'postgresql_db' and
{{data_dir}} not in selin_context.stdout
fatal: [pgdbsql-02]: FAILED! => {
"msg": "The conditional check ''postgresql_db' and {{data_dir|dirname}} not in selin_context.stdout' failed. The error was: template error while templating string: unexpected '/'. String: {% if 'postgresql_db' and /data/dbdata not in selin_context.stdout %} True {% else %} False {% endif %}\n\nThe error appears to be in '/home/ec2-user/ansible/pgdb/roles/pgdb/tasks/main.yml': line 56, 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: Setting Selinux context for data and log dir\n ^ here\n"
Please guide me how to handle this?

ansible using hostname as a condition

I have an HA setup that I am building. I am using Ansible 2.9.11. I need to search the hostname and if it is the b side copy the backup config over. I have tried the following code and it is not working. Or is there a different way to accomplish this?
[WARNING]: conditional statements should not include jinja2 templating
delimiters such as {{ }} or {% %}. Found: 'b' in {{ inventory_hostname
}} fatal: [dev-sca02b]: FAILED! => {"msg": "The conditional check ''b'
in {{ inventory_hostname }}' failed. The error was: error while
evaluating conditional ('b' in {{ inventory_hostname }}): 'dev' is
undefined\n\nThe error appears to be in
'/Users/user1/Documents/Ansible/sca_fusion.yaml': line 134, 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: "Change
keepalived to backup"\n ^ here\n"}
- name: "Change keepalived to backup"
replace:
path: /etc/keepalived/keepalived.conf
regexp: "MASTER"
replace: "BACKUP"
when: "'b' in {{ inventory_hostname }}"
That warning should point you to the main source of your problem:
WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}.
A when condition is already in an implicit jinja templating context, so you don't need to create one explicitly. You want:
- name: "Change keepalived to backup"
replace:
path: /etc/keepalived/keepalived.conf
regexp: "MASTER"
replace: "BACKUP"
when: "'b' in inventory_hostname"

Ansible: how to check if a variable is being loaded in a playbook?

I'm trying to write a playbook that will load vars from a group vars file then check if a variable exists
my playbook is like this:
---
- hosts: "{{ target }}"
roles:
- app
tasks:
- name: alert if variable does not exist
fail:
msg: "{{ item }} is not defined"
when: "{{ item }}" is not defined
with_items:
- country
- city
- street
...
My inventory file contains
[app]
ansible-slave1
ansible-slave2
[db]
ansible-db
[multi:children]
app
db
and I have the roles/app/vars/main.yml containing
country: "France"
city: "Paris"
What I was expecting is the playbook to output "street is not defined" but I have a syntax issue I can't resolve
[vagrant#ansible-master vagrant]$ ansible-playbook --inventory-file=ansible_master_hosts test_variables.yml --extra-vars "target=ansible-slave1" --syntax-check
ERROR! Syntax Error while loading YAML.
The error appears to have been in '/vagrant/test_variables.yml': line 10, column 24, but may be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
msg: "{{ item }} is not defined"
when: "{{ item }}" is not defined
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
I'd be happy with any hints.
Thanks
You have "" in invalid place of "when" statement. This should be like this:
msg: "{{ item }} is not defined"
when: "{{ item }} is not defined"
So the output will be:
failed: [hostname] (item=street) => {"changed": false, "item": "street", "msg": "street is not defined"}
there is on open issue conditional is defined fails to capture undefined var .
as a workaround I'd suggest to change the where condition to the following:
when: "{{ item }}" == ""

How to register with_items and act on conditional check result for each item

I'd like to register the contents of bashrc for two users and edit as/if required. My play is as follows.
- name: Check bashrc
shell: cat {{ item }}/.bashrc
register: bashrc
with_items:
- "{{ nodepool_home }}"
- "{{ zuul_home }}"
- name: Configure bashrc
shell:
cmd: |
cat >> {{ item }}/.bashrc <<EOF
STUFF
EOF
with_items:
- "{{ nodepool_home }}"
- "{{ zuul_home }}"
when: '"STUFF" not in bashrc.stdout'
It fails as follows:
fatal: [ca-o3lscizuul]: FAILED! => {"failed": true, "msg": "The conditional check '\"STUFF\" not in bashrc.stdout' failed. The error was: error while evaluating conditional (\"STUFF\" not in bashrc.stdout): Unable to look up a name or access an attribute in template string ({% if \"STUFF\" not in bashrc.stdout %} True {% else %} False {% endif %}).\nMake sure your variable name does not contain invalid characters like '-': argument of type 'StrictUndefined' is not iterable\n\nThe error appears to have been in '/root/openstack-ci/infrastructure-setup/staging/zuul/create-user.yml': line 35, 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: Configure bashrc\n ^ here\n"}
I think, if I understand your requirement correctly, you can use the 'lineinfile' or 'blockinfile' modules and save yourself the hassle of testing for the existence of the content:
- name: Noddy example data
set_fact:
single_line: "STUFF"
multi_line: |
STUFF
STUFF
profile_dirs:
- "{{ nodepool_home }}"
- "{{ zuul_home }}"
- name: Ensure STUFF exists in file
lineinfile:
path: "{{ item }}/.bashrc"
line: "{{ single_line }}"
loop: "{{ profile_dirs }}"
- name: Ensure block of STUFF exists in file
blockinfile:
path: "{{ item }}/.bashrc"
block: "{{ multi_line }}"
loop: "{{ profile_dirs }}"
Both modules give a lot more control and you can find their docs here: lineinfile | blockinfile

[WARNING]: when statements should not include jinja2 templating delimiters

I was wondering what is the correct syntax for when statements?
I have this playbook:
- set_fact:
sh_vlan_id: "{{ output.response|map(attribute='vlan_id')|list|join(',') }}"
- name: create vlans
ios_config:
provider: "{{ provider }}"
parents: vlan {{ item.id }}
lines: name {{ item.name }}
with_items: "{{ vlans }}"
register: result
when: '"{{ item.id }}" not in sh_vlan_id'
And, running it, gives me a warning but it still runs through. I am not sure if this is correct or not.
TASK [set_fact] ************************************************
ok: [acc_sw_01]
TASK [create vlans] ***********************************************
[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: "{{ item.id }}" not in sh_vlan_id
skipping: [acc_sw_01] => (item={u'id': 10, u'name': u'voice-1'})
skipping: [acc_sw_01] => (item={u'id': 101, u'name': u'data-2'})
skipping: [acc_sw_01] => (item={u'id': 100, u'name': u'data-1'})
changed: [acc_sw_01] => (item={u'id': 11, u'name': u'voice-2'})
If I remove the curly braces around item.id in the when statement:
when: item.id not in sh_vlan_id
It gives me an error:
TASK [set_fact] ***************************************************
ok: [acc_sw_01]
TASK [create vlans] ***********************************************
fatal: [acc_sw_01]: FAILED! => {"failed": true, "msg": "The conditional check 'item.id not in sh_vlan_id' failed. The error was: Unexpected templating type error occurred on ({% if item.id not in sh_vlan_id %} True {% else %} False {% endif %}): coercing to Unicode: need string or buffer, int found\n\nThe error appears to have been in '/ansible/cisco-ansible/config_tasks/vlan.yml': line 16, 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: create vlans\n ^ here\n"}
I'm using ansible 2.3.0 (devel cbedc4a12a).
The correct syntax is to not include Jinja delimiters ({{ ... }}) as indicated by the warning. Your condition doesn't work otherwise because the types are not compatible.
You could try type coercion:
when: 'item.id | string not in sh_vlan_id'
See: https://jinja.palletsprojects.com/en/3.1.x/templates/#builtin-filters
Another example for reference ..
- name: Sudoers | update sudoers file and validate
lineinfile: "dest=/etc/sudoers
insertafter=EOF
line='{{ item.username }} ALL=(ALL) NOPASSWD: ALL'
regexp='^{{ item.username }} .*'
state=present"
when: '{{ item.use_sudo }} == True'
with_items: '{{users}}'
I was getting below orning.
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: "{{ item.use_sudo}}" == True
After making the below changes into the playbook it works fine.
- name: Sudoers | update sudoers file and validate
lineinfile: "dest=/etc/sudoers
insertafter=EOF
line='{{ item.username }} ALL=(ALL) NOPASSWD: ALL'
regexp='^{{ item.username }} .*'
state=present"
when: 'item.use_sudo|bool'
with_items: '{{users}}'
UPD: if you use variable type boolean that == True not need
Braces must be removed when calling a variable in a when clause.
In this example, we install the urbackup client only if it is not already installed or if the version already present is different from the version contained in the variable.
urbackup_client_version is a variable defined in the playbook:
vars:
- urbackup_client_version: 2.5.22
then we check in a role if urbackup is already installed.
- name: Is UrBackup already installed?
shell: urbackupclientctl --version
register: urbackup_enable
failed_when: urbackup_enable.rc != 1 and urbackup_enable.rc != 127
It is necessary to position the variable with braces in the wget command but you have to remove them in the when clause:
- name: UrBackup client installation
shell: 'TF=$(mktemp) && wget "https://hndl.urbackup.org/Client/latest/UrBackup%20Client%20Linux%20{{urbackup_client_version}}.sh" -O $TF && sudo sh $TF; rm -f $TF'
when:
- action == 'install'
- urbackup_enable.rc == 127 or (urbackup_enable.rc == 1 and urbackup_client_version not in urbackup_enable.stdout)

Resources