Use folder size in conditional - ansible

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 }}"

Related

Reference a variable from another file

I have a play
---
- hosts: all
name: Full install with every component
gather_facts: no
roles:
- oracle_client
- another_role
- and_so_on
where each of the roles has a dependency on a single common role which is supposed to load all vairable I will require later:
- name: Include all default extension files in vars/all and all nested directories and save the output in test
include_vars:
dir: all
name: test
- debug:
msg: "{{test}}"
the common role folder structure has
common
vars
all
ansible.yml
common.yml
oracle_client.yml
where common.yml specifies a app_drive: "D:" and then oracle_client.yml tries to do oracle_base: "{{ app_drive }}\\app\\oracle"
At runtime I get
fatal: [10.188.27.27]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'app_drive' is undefined\n\nThe error appears to be in '<ansible-project-path>/roles/common/tasks/main.yml': line 18, 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 - debug:\n ^ here\n"}
Per documentation "the files are sorted alphabetically before being loaded." so I was expecting to have access to a varible from another file? How should I do this instead?
TLDR;
I want to to load all my variables from one place but have them logically splits (I went for separate files) but cross reference the splits. How is that best done?
Looks like it works as I expect it to and in my example above it is the
- debug:
msg: "{{test}}
part that fails.

2 Ansible task with Stat and include_vars

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

How to fix Ansible error: " conflicting action statements: include, file"

I get some error on the include statement. I have two simple playbooks, but cannot find the problem.
files.yml:
---
- name: create leading path
file:
path: "{{ path }}"
state: directory
- name: touch the file
file:
path: "{{ path + '/' + file }}"
state: touch
include.yml:
---
- name: touch files
hosts: localhost
gather_facts: false
tasks:
- include: files.yaml
path: /tmp/foo
file: herp
If I run include.yml I get this error:
ERROR! conflicting action statements: include, file
The error appears to be in '/home/ansible/mastering_ansible/touch.yml': line 7, column 13, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- include: files.yml
^ here
The module include is "free-form" only i.e. it has no attributes. The error is the result of the wrong syntax
tasks:
- include: files.yaml
path: /tmp/foo
file: herp
Correct
tasks:
- include: files.yaml
If you have trouble with paths see Search paths in Ansible and optionally use Special variables. For example
- include: "{{ playbook_dir }}/tasks/files.yaml"
Notes
files.yml is not a playbook.
The error message is "/home/ansible/mastering_ansible/touch.yml': line 7, column 13 ...", but there is no touch.yml among the posted code.
If the module include had attributes path and file the correct indentation would have been
- include: files.yaml
path: /tmp/foo
file: herp
See Including and Importing for details.

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.

ansible rsync or copy a randomly named file to a remote machine

I am using ansible 2.1 to either rsync or copy a file from the host machine to a remote one. The file is in a directory but has a random string as part of its name. I have tried using ls -d to get the name via the shell command and tried to register this value but apparently, the syntax I am using is causing the role to fail. Any thoughts on what I might be doing wrong?
---
- name: copying file to server
- local_action: shell cd /tmp/directory/my-server/target/
- local_action: shell ls -d myfile*.jar
register: test_build
- debug: msg={{ test_build.stdout }}
- copy: src=/tmp/directory/my-server/target/{{ test_build.stdout }} dest=/home/ubuntu/ owner=ubuntu group=ubuntu mode=644 backup=yes
become: true
become_user: ubuntu
become_method: sudo
exception
fatal: [testserver]: FAILED! => {"failed": true, "reason": "no action detected in task. This often indicates a misspelled module name, or incorrect module path.\n\nThe error appears to have been in '/home/user/test/roles/test-server/tasks/move.yml': line 2, 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: transferring file to server\n ^ here\n\n\nThe error appears to have been in '/home/user/test/roles/test-server/tasks/synchronize.yml': line 2, 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: transferring artifact to server\n ^ here\n"}
You should avoid shell commands if possible, it is Ansible anti-pattern.
In your case you can use fileglob lookup like follows:
- name: Copy file
copy:
src: "{{ lookup('fileglob','/tmp/directory/my-server/target/myfile*.jar', wantlist=true) | first }}"
dest: /home/ubuntu/
owner: ubuntu
group: ubuntu
mode: 644
backup: yes
If you 100% sure that there is only one such file, you can omit wantlist=true and | first – I used it as a safe net to filter only first entry, if there are many.
You need to simplify your commands. You also do not want to put a hyphen before a module name. This will cause a syntax error as it won't be able to identify that module as an action. You can only invoke one module per task. For example, this will not work;
- name: task one
copy: src=somefile dest=somefolder/
copy: src=somefile2 dest=somefolder2/
The two would need to be split into two separate tasks. The same for your playbook. Do the following:
- name: copying file to server
local_action: "shell ls -d /tmp/directory/my-server/target/myfile*.jar"
register: test_build
- debug: msg={{ test_build.stdout }}
- name: copy the file
copy: src={{ test_build.stdout }} dest=/home/ubuntu/ owner=ubuntu group=ubuntu mode=644 backup=yes
If possible, insert "become" in your playbook not in your tasks/main.yml file, unless you only want to use become for these two tasks and will be adding more tasks to the same playbook later on.
Note: The debug msg line is completely optional. It doesn't affect the results of the playbook in any way, all it will do is show you the folder/file name that was found as a result of the shell "ls" command.

Resources