2 Ansible task with Stat and include_vars - ansible

wondering if anyone can help us with this.
The end goal is to refresh the variables back into the play from a YAML file which was generated previously if the file exists.
I'm using stat to check if the files exist and this works - 'name: Registering if file exists'. If i debug filecheck i can see the 2 entries in the dataset.
Next im trying to reload the vars from the file -final-dataset-file-1 if the file exists using the when condition - filecheck.stat.exists
- name: Registering if file exists
stat:
path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}/final-dataset-{{ item }}.yml"
loop:
- file-1
- file-2
register: filecheck
- name: IOS - Refreshing final-dataset variables generated by the above tasks in order to service any subsequent tasks
include_vars:
file: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}/final-dataset-{{ item }}.yml"
loop:
- file-1
- file-2
when: filecheck.stat.exists
This is the error i'm seeing
fatal: [router]: FAILED! => {"msg": "The conditional check 'filecheck.stat.exists' failed. The error was: error while evaluating conditional (filecheck.stat.exists): 'dict object' has no attribute 'stat'\n\nThe error appears to be in '/ansible/roles/roles_nane/tasks/report.yml': line 94, 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: IOS - Refreshing final-dataset variables generated by the above tasks in order to service any subsequent tasks\n ^ here\n"}
Its like we need to loop through filecheck for each file/item and match these against the files that are a part of the include_vars items but i'm not sure how to do this.
Any comments would be appreciated.
Cheers

Iterate the results from the previous task e.g.
- include_vars: "{{ item.stat.path }}"
loop: "{{ filecheck.results }}"
when: item.stat.exists

Related

Ansible The conditional check failed. The error was error while evaluating conditional

Why is the conditional check failed ?
My CSV file:
No.,OS,Information
1,**Linux**,CentOS 8.3
2,**Windows**,Windows 2016
---
- name: Test_CSV
hosts: localhost
gather_facts: True
tasks:
- read_csv:
path: test.csv
delimiter: ','
register: servers
- include_tasks: Linux.yml
when: vm.OS == "Linux"
- include_tasks: Windows.yml
when: vm.OS == "Windows"
loop: "{{ servers.list }}"
loop_control:
loop_var: vm
Linux.yml
---
- debug:
msg: "OS = Linux"
Windows.yml
---
- debug:
msg: "OS = Windows"
The error I get is this:
fatal: [localhost]: FAILED! => {
"msg": "The conditional check 'vm.OS == "Linux"' failed. The error was: error while evaluating conditional (vm.OS == to be in '/itoa/condition/20210920/Test_CSV.yml': line 13, column 7, but may\nbe elsewhere in the file depending on the eto be:\n\n\n - include_tasks: Linux.yml\n ^ here\n"
}
or is there another way Please help guide me.
Thanks,
The problem is the loop. You can not loop over two tasks. You have to define a block (maybe this will not work with include_tasks).
BUT anyway what you try to implement is the core functionality of Ansible. Do do not need to loop over hosts. Ansible exists to do this for you.
Define the hosts in your inventory. Add the Linux systems to a group "linux". Add the Windows systems to a group "windows". Use the groups as a "hosts" argument.
Now Ansible will execute the tasks for all hosts.
If you want to use your CSV file as an inventory, you have to write a dynamic inventory script.

How do I use {{ item }} in ansible?

I'm trying to replicate the first with_item example from ansible docs, but I'm facing this error:
fatal: [user#my-vm]: FAILED! => {"msg": "The task includes an option with an undefined variable.
The error was: 'item' is undefined\n\nThe error appears to be in 'path/ansible/playbooks/android-dev.yml': line 4,
column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\n
The offending line appears to be:\n\n tasks:\n - name: Debugging with items\n ^ here\n"}
My code is:
- hosts: test
tasks:
- name: Debugging with items
debug:
msg: "An item: {{ item }}"
with_items:
- 1
- 2
- 3
I'm following the first example of this page to build the task: https://docs.ansible.com/ansible/latest/plugins/lookup/items.html
I've started using ansible now and it may be a simple issue to fix, but I really can't find any solution online
The indentation is wrong. Fix it
- hosts: test
tasks:
- name: Debugging with items
debug:
msg: "An item: {{ item }}"
loop:
- 1
- 2
- 3
Use loop instead of with_items.

Use folder size in conditional

I want to remove a folder only if the size is larger than a certain size. Unfortunately I can't achieve the wanted result with the stat module.
Attempt:
---
- hosts: pluto
tasks:
- stat:
path: /home/ik/.thunderbird
register: folder
- name: Remove .thunderbird folder on host if folder size > 100MiB
file:
path: /home/ik/.thunderbird
state: absent
when: folder.stat.size > 100000000
Error:
fatal: [pluto]: FAILED! => {"msg": "The conditional check 'folder.size > 100000000' failed. The error was: error while evaluating conditional (folder.size > 100000000): 'dict object' has no attribute 'size'\n\nThe error appears to be in '/home/ik/Playbooks/susesetup.yml': line 12, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n register: folder\n - name: Remove .thunderbird folder on host if folder size > 100MiB\n ^ here\n"}
How can I solve this issue?
The size attribute returned by the stat module for a folder does not tell you the size of the folder's contents! It only reports the size of the directory entry, which may depend on a number of factors such as the number of files contained in the directory.
If you're looking to calculate the amount of data contained in a folder, you're going to need to run du or a similar command. The following gets the folder size in 1024 blocks:
---
- hosts: localhost
gather_facts: false
tasks:
- command: du -sk /path/to/some/directory
register: folder_size_raw
- set_fact:
folder_size: "{{ folder_size_raw.stdout.split()[0] }}"
- debug:
msg: "{{ folder_size }}"

Ansible - Loop based on dict with stat not working

I'm currently creating a possibility to auto-obtain a Letsencrypt certificate using my ansible-playbook.
I'd like to check if the /etc/letsencrypt/domain.tld directory exists, when it doesn't, I need to obtain a certificate.
---
- name: LETSENCRYPT | Checking for existing certificates
stat:
path: /etc/letsencrypt/live/{{ item.value.server_name }}
register: le_cert_exists
with_dict: "{{ sites }}"
when: item.value.letsencrypt | default(false) | bool
- name: DEBUG | Output result of le cert exists
debug:
var: le_cert_exists
- name: LETSENCRYPT | Output sites that need a new certificate
debug:
msg: Obtain certificate here
var: item.item
with_items: le_cert_exists.results
when: item.stat.exists is defined and not item.stat.exists
So far it is working, except for the last function. The last task just keeps getting skipped or fails with the following error:
fatal: [-]: FAILED! => {"msg": "The conditional check 'item.stat.exists is defined and not item.stat.exists' failed. The error was: error while evaluating conditional (item.stat.exists is defined and not item.stat.exists): 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'stat'\n\nThe error appears to have been in '/path/to/main.yml': line 13, 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: LETSENCRYPT | Output sites that need a new certificate\n ^ here\n"}
Does anyone has an example of how this could be done easily?
I just need to execute a command when a directory does not exists.
This with_items: le_cert_exists.results is wrong,
this with_items: "{{ le_cert_exists.results }}" is correct.

Expecting dict; got: shell:Error

I am getting the below error
ERROR: expecting dict; got: shell:"ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt" register:the_file
I want to check the folder is exist.
if exist I need to specify some path /mule/acc
if the path does not exist need to point /mule/bcc
The following is ansible playbook
---
# get name of the .txt file
- stat: path=/mule/ansiple/mule-enterprise-standalone-3.4.1
register:the_file
when: the_file.stat.exists == True
- shell:"ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt"
register:the_file
- debug: msg="{{ the_file }}"
- set_fact: app_folder="{{ the_file.stdout | replace('-anchor.txt','') }}"
- debug: msg="{{ app_folder }}"
- debug: msg="{{ the_file.stdout }}"
# delete the .txt file
- name: Delete the anchor.txt file
file: path="{{ the_file.stdout }}" state=absent
# wait until the app folder disappears
- name: Wait for the folder to disappear
wait_for: path="{{ app_folder }}" state=absent
# copy the zip file
- name: Copy the zip file
copy: src="../p" dest="/c"
You almost have the YAML right, but there is one YAML error in your file and that is on the line:
register:the_file
because the line preceding it starts the first element of the toplevel sequence as a mapping through defining a key-value pair based on the colon (':') followed by space, and that cannot be followed by a scalar (or a sequence). If that file was your input, you would have gotten a syntax error by the YAML parser with part of the message looking like:
register:the_file
^
could not find expected ':'
This:
- shell:"ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt"
register:the_file
is perfectly fine YAML. It defines the second element of the top-level sequence to be a scalar string:
shell:"ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt" register:the_file
(you can break scalar strings over multiple lines in YAML).
Now ansible doesn't like that and expects that element, and probably all top-level sequence elements, to be mappings. And for a mapping you need to have a key value pair, which is (like with register:the_file) separated/indicated by a colon-space pair of characters in YAML. So ansible (not YAML) probably wants:
shell: ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt
register: the_file
please note that the quotes around the scalar value ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt are unnecessary in YAML.
There might be other things ansible expects from the structure of the file, but I would start with the above change and see if ansible throws further errors on:
# get name of the .txt file
- stat: path=/mule/ansiple/mule-enterprise-standalone-3.4.1
register: the_file
when: the_file.stat.exists == True
- shell: ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt
register: the_file
- debug: msg="{{ the_file }}"
- set_fact: app_folder="{{ the_file.stdout | replace('-anchor.txt','') }}"
- debug: msg="{{ app_folder }}"
- debug: msg="{{ the_file.stdout }}"
# delete the .txt file
- name: Delete the anchor.txt file
file: path="{{ the_file.stdout }}" state=absent
# wait until the app folder disappears
- name: Wait for the folder to disappear
wait_for: path="{{ app_folder }}" state=absent
# copy the zip file
- name: Copy the zip file
copy: src="../analytic-core-services-mule-3.0.0-SNAPSHOT.zip" dest="/mule/ansiple/mule-enterprise-standalone-3.4.1"
You need to learn YAML syntax. After every colon you are required to add a whitespace. The message comes from the YAML parser, telling you it expected a dictionary:
key1: value1
key2: value2
Instead it found no key-value-pair:
key1:value1
Specifically it complains about this line:
- shell:"ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt"
which should be
- shell: "ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt"
But you have the same issue in two more lines which look like:
register:the_file
and should be :
register: the_file
If in doubt an error comes from Ansible tasks or simply from a YAML parsing error, paste your YAML definition into any online YAML parser.
So much for the format. Now to logical problems:
- stat: path=/mule/ansiple/mule-enterprise-standalone-3.4.1
register: the_file
when: the_file.stat.exists == True
Unless you have the_file already registered from a previous task you didn't show, this can't work. when is the condition to decide if the task should be run. You can not execute a task depending on its outcome. It first has to run before the result is available. At the time the condition is evaluated the_file simply won't exist and this should result in an error, complaining that a None object does not have a key stat or something similar.
Then in the next task you again register the result with the same name.
- shell: "ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt"
register: the_file
This simply will override the previous registered result. Maybe you meant to have the condition from the first task on the second. But even that would not work. A result still will be registered from skipped tasks, simply stating the task was skipped. You either need to store the results in unique vars or check all possible file locations in a single task.
Cleaned up your playbook would look like this:
---
# get name of the .txt file
- stat:
path: /mule/ansiple/mule-enterprise-standalone-3.4.1
register: the_file
when: the_file.stat.exists
- shell: ls /mule/ansiple/mule-enterprise-standalone-3.4.1/*.txt
register: the_file
- debug:
msg: "{{ the_file }}"
- set_fact:
app_folder: "{{ the_file.stdout | replace('-anchor.txt','') }}"
- debug:
msg: "{{ app_folder }}"
- debug:
msg: "{{ the_file.stdout }}"
- name: Delete the anchor.txt file
file:
path: "{{ the_file.stdout }}"
state: absent
- name: Wait for the folder to disappear
wait_for:
path: "{{ app_folder }}"
state: absent
- name: Copy the zip file
copy:
src: ../analytic-core-services-mule-3.0.0-SNAPSHOT.zip
dest: /mule/ansiple/mule-enterprise-standalone-3.4.1
...

Resources