I try to find a way to assert the mode of a file.
I tried to used
- name: file status
stat: path=/opt/et/test.txt
- assert:
that:
- "st.stat.mode == 644"
But obtain always an error, I don't see why ...
my goal is to check if the file have the right permission
I can see a couple of reasons why your example may not be working:
You are missing register in the stat task.
The comparison in assert should for "0644"
If you change these two things, then you should have something like below. I have added custom messages to display on "success" or "failure":
- stat:
path: '/opt/et/test.txt'
register: st
- assert:
that:
- "st.stat.mode == '0644'"
success_msg: 'File has correct permissions.'
fail_msg: 'File permissions are incorrect.'
You can use the file module.
This will work like stat (see docs).
- name: file status
file:
path: /opt/et/test.txt
Or if you want to set the correct mode, in case it is wrong, use this:
- name: file status
file:
path: /opt/et/test.txt
mode: '0664'
You can also set ownership, group etc.
You can try something like this:
-
name: Check file
#hosts: all
hosts: 127.0.0.1
connection: local
tasks:
- name: "Check stat"
stat:
path: /home/path/to/file
register: st
# the following task will execute when the file has the desired permissions 0755 in this case
- name: "Assert rights"
debug:
msg: "File has {{ st.stat.mode }}"
when: st.stat.mode == "0775"
Related
I need to use Ansible modules to check if a the file exist, and if it doesn't, then create it and write some data in to it.
If the file exists then check the content, which I am trying to write, is present in that file.
If the content is not present, write the content into it.
If the content is present then do nothing.
My playbook below is not working.
Any suggestions on this?
- hosts: all
tasks:
- name: check for file
stat:
path: "{{item}}"
register: File_status
with_items:
- /etc/x.conf
- /etc/y.conf
- name: Create file
file:
path: "{{item}}"
state: touch
with_items:
- /etc/x.conf
- /etc/y.conf
when: not File_status.stat.exists
- name: add content
blockinfile:
path: /etc/x.conf
insertafter:EOF
block: |
mydata=something
Can you help me with the modules and conditions which can achieve my desired output?
The following will:
Create the file if it does not exist and report changed
Add the block at the end of file if it does not exists and report changed, i.e.
# BEGIN ANSIBLE MANAGED BLOCK
mydata=something
mydata2=somethingelse
# END ANSIBLE MANAGED BLOCK
Update the block wherever it is in the file if the content changed and report changed (see the marker option if you have several blocks to manage in the same file, and dont forget {mark} in there if you change it).
Do nothing if the block is up-to-date anywhere in the file and report ok.
Please read the module documentation for more info
---
- name: blockinfile example
hosts: localhost
gather_facts:false
tasks:
- name: Update/create block if needed. Create file if not exists
blockinfile:
path: /tmp/testfile.conf
block: |
mydata=something
mydata2=somethingelse
create: true
Here is the possible way to achieve your requirements.
- hosts: localhost
tasks:
- name: Create file
copy:
content: ""
dest: "{{item}}"
force: no
with_items:
- /etc/x.conf
- /etc/y.conf
- name: add content
blockinfile:
path: "{{ item.file_name }}"
insertafter: EOF
block: |
"{{ item.content }}"
loop:
- { file_name: '/etc/x.conf', content: 'mydata=something' }
- { file_name: '/etc/y.conf', content: 'mydata=hey something' }
I have written this playbook, in order to check if some repos exist in /etc/yum.repos.d/, but I am not sure if it is correct. Is it correct?
- name: Check that the repos exists
stat:
path: /etc/yum.repos.d/{{ item }}
with_items:
- "rhel-mc.repo"
- "epel-mc.repo"
- "redhat.repo"
register: stat_result
debug:
msg: "Repo file exists..."
when: stat_result.stat.exists
debug:
msg: "Repo file not found"
when: stat_result.stat.exists == False
It almost is perfect!
Make sure module options are the only things aligned inside the module, everything else should be outside of it. These include:
with_items
when
register
You need to ensure you wrap the {item} in single quotes, wrapping the entire path works fine here.
You forgot the dashes for the debugs.
Finally, ansible lint will fail if you compare to True or False so instead I would not before the conditional.
- name: Check that the repos exists
stat:
path: '/etc/yum.repos.d/{{ item }}'
with_items:
- "rhel-mc.repo"
- "epel-mc.repo"
- "redhat.repo"
register: stat_result
- debug:
msg: "Repo file exists..."
when: stat_result.stat.exists
- debug:
msg: "Repo file not found"
when: not stat_result.stat.exists
You can also use the module assert to check for a condition and based on the result display different messages. Something like this:
- name: Check that the repos exists
stat:
path: '/etc/yum.repos.d/{{ item }}'
with_items:
- "rhel-mc.repo"
- "epel-mc.repo"
- "redhat.repo"
register: stat_result
- assert:
that: stat_result.stat.exists
success_msg: "Repo file exists..."
fail_msg: "Repo file not found"
You don't have to wrap path with quotes but it is a good practice in programming in general, to wrap strings in quotes, especially when (in Ansible) it contains a variable.
I just want to know about how to check the file exists or not any directory via ansible code. I have tried with stat module with path "*.test" already but it did not working.
Below is my trying:
- name: Check license file exist or not
stat:
path: /var/www/vb_backup/vb/*.test
register: license
becuase path in stat module needs specific file or directory. I want everyone to help me on this.
Thank you in advance.
Ansible version: ansible 2.8.7
Use module find. For example
- find:
paths: /var/www/vb_backup/vb
patterns: "*.test"
register: result
- debug:
msg: "No files found."
when: result.matched == 0
- debug:
msg: "File found: {{ item.path }}"
loop: "{{ result.files }}"
You can use find module and assert module.
- name: Find files
find:
paths: /var/www/vb_backup/vb
patterns: *.test'
register: output
- name: message
assert:
that:
- output.matched
fail_msg: "File not found"
success_msg: "File found"
This should do the work.
path: "{{/var/www/vb_backup/vb/*.test}}"
you can use find module like this
find:
paths: /var/www/vb_backup/vb/
patterns: *.test
then you can invoke matched files
I have to check whether a file exists in /etc/. If the file exists then I have to skip the task.
Here is the code I am using:
- name: checking the file exists
command: touch file.txt
when: $(! -s /etc/file.txt)
You can first check that the destination file exists or not and then make a decision based on the output of its result:
tasks:
- name: Check that the somefile.conf exists
stat:
path: /etc/file.txt
register: stat_result
- name: Create the file, if it doesnt exist already
file:
path: /etc/file.txt
state: touch
when: not stat_result.stat.exists
The stat module will do this as well as obtain a lot of other information for files. From the example documentation:
- stat: path=/path/to/something
register: p
- debug: msg="Path exists and is a directory"
when: p.stat.isdir is defined and p.stat.isdir
This can be achieved with the stat module to skip the task when file exists.
- hosts: servers
tasks:
- name: Ansible check file exists.
stat:
path: /etc/issue
register: p
- debug:
msg: "File exists..."
when: p.stat.exists
- debug:
msg: "File not found"
when: p.stat.exists == False
In general you would do this with the stat module. But the command module has the creates option which makes this very simple:
- name: touch file
command: touch /etc/file.txt
args:
creates: /etc/file.txt
I guess your touch command is just an example? Best practice would be to not check anything at all and let ansible do its job - with the correct module. So if you want to ensure the file exists you would use the file module:
- name: make sure file exists
file:
path: /etc/file.txt
state: touch
Discovered that calling stat is slow and collects a lot of info that is not required for file existence check.
After spending some time searching for solution, i discovered following solution, which works much faster:
- raw: test -e /path/to/something && echo -n true || echo -n false
register: file_exists
- debug: msg="Path exists"
when: file_exists.stdout == "true"
You can use Ansible stat module to register the file, and when module to apply the condition.
- name: Register file
stat:
path: "/tmp/test_file"
register: file_path
- name: Create file if it doesn't exists
file:
path: "/tmp/test_file"
state: touch
when: file_path.stat.exists == False
Below is the ansible play which i used to remove the file if the file exists on OS end.
- name: find out /etc/init.d/splunk file exists or not'
stat:
path: /etc/init.d/splunk
register: splunkresult
tags:
- always
- name: 'Remove splunk from init.d file if splunk already running'
file:
path: /etc/init.d/splunk
state: absent
when: splunkresult.stat.exists == true
ignore_errors: yes
tags:
- always
I have used play condition as like below
when: splunkresult.stat.exists == true --> Remove the file
you can give true/false based on your requirement
when: splunkresult.stat.exists == false
when: splunkresult.stat.exists == true
I find it can be annoying and error prone to do a lot of these .stat.exists type checks. For example they require extra care to get check mode (--check) working.
Many answers here suggest
get and register
apply when register expression is true
However, sometimes this is a code smell so always look for better ways to use Ansible, specifically there are many advantages to using the correct module. e.g.
- name: install ntpdate
package:
name: ntpdate
or
- file:
path: /etc/file.txt
owner: root
group: root
mode: 0644
But when it is not possible use one module, also investigate if you can register and check the result of a previous task. e.g.
# jmeter_version: 4.0
- name: Download Jmeter archive
get_url:
url: "http://archive.apache.org/dist/jmeter/binaries/apache-jmeter-{{ jmeter_version }}.tgz"
dest: "/opt/jmeter/apache-jmeter-{{ jmeter_version }}.tgz"
checksum: sha512:eee7d68bd1f7e7b269fabaf8f09821697165518b112a979a25c5f128c4de8ca6ad12d3b20cd9380a2b53ca52762b4c4979e564a8c2ff37196692fbd217f1e343
register: download_result
- name: Extract apache-jmeter
unarchive:
src: "/opt/jmeter/apache-jmeter-{{ jmeter_version }}.tgz"
dest: "/opt/jmeter/"
remote_src: yes
creates: "/opt/jmeter/apache-jmeter-{{ jmeter_version }}"
when: download_result.state == 'file'
Note the when: but also the creates: so --check doesn't error out
I mention this because often these less-than-ideal practices come in pairs i.e. no apt/yum package so we have to 1) download and 2) unzip
Hope this helps
I use this code and it works fine for folders and files. Just make sure there is no trailing spaces after the folder name. If folder exists , the file_exists.stdout will be "true" otherwise it will just be an empty string ""
- name: check filesystem existence
shell: if [[ -d "/folder_name" ]]; then echo "true"; fi
register: file_exists
- name: debug data
debug:
msg: "Folder exists"
when: file_exists.stdout == "true"
vars:
mypath: "/etc/file.txt"
tasks:
- name: checking the file exists
command: touch file.txt
when: mypath is not exists
A note on relative paths to complement the other answers.
When doing infrastructure as code I'm usually using roles and tasks that accept relative paths, specially for files defined in those roles.
Special variables like playbook_dir and role_path are very useful to create the absolute paths needed to test for existence.
You can use shell commands to check if file exists
- set_fact:
file: "/tmp/test_file"
- name: check file exists
shell: "ls {{ file }}"
register: file_path
ignore_errors: true
- name: create file if don't exist
shell: "touch {{ file }}"
when: file_path.rc != 0
I'm trying to include a file only if it exists. This allows for custom "tasks/roles" between existing "tasks/roles" if needed by the user of my role. I found this:
- include: ...
when: condition
But the Ansible docs state that:
"All the tasks get evaluated, but the conditional is applied to each and every task" - http://docs.ansible.com/playbooks_conditionals.html#applying-when-to-roles-and-includes
So
- stat: path=/home/user/optional/file.yml
register: optional_file
- include: /home/user/optional/file.yml
when: optional_file.stat.exists
Will fail if the file being included doesn't exist. I guess there might be another mechanism for allowing a user to add tasks to an existing recipe. I can't let the user to add a role after mine, because they wouldn't have control of the order: their role will be executed after mine.
The with_first_found conditional can accomplish this without a stat or local_action. This conditional will go through a list of local files and execute the task with item set to the path of the first file that exists.
Including skip: true on the with_first_found options will prevent it from failing if the file does not exist.
Example:
- hosts: localhost
connection: local
gather_facts: false
tasks:
- include: "{{ item }}"
with_first_found:
- files:
- /home/user/optional/file.yml
skip: true
Thanks all for your help! I'm aswering my own question after finally trying all responses and my own question's code back in today's Ansible: ansible 2.0.1.0
My original code seems to work now, except the optional file I was looking was in my local machine, so I had to run stat through local_action and set become: no for that particular tasks, so ansible wouldn't attempt to do sudo in my local machine and error with: "sudo: a password is required\n"
- local_action: stat path=/home/user/optional/file.yml
register: optional_file
become: no
- include: /home/user/optional/file.yml
when: optional_file.stat.exists
In Ansible 2.5 and above, it can be done using tests like this:
- include: /home/user/optional/file.yml
when: "'/home/user/optional/file.yml' is file"
More details: https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html#testing-paths
I using something similar but for the file module and what did the trick for me is to check for the variable definition, try something like:
when: optional_file.stat.exists is defined and optional_file.stat.exists
the task will run only when the variable exists.
If I am not wrong, you want to continue the playbook even the when statement false?
If so, please add this line after when:
ignore_errors: True
So your tasks will be look like this:
- stat: path=/home/user/optional/file.yml
register: optional_file
- include: /home/user/optional/file.yml
when: optional_file.stat.exists
ignore_errors: True
Please let me know, if I understand your question correctly, or can help further. Thanks
I could spend time here to bash ansible's error handling provisions, but in short, you are right and you can't use stat module for this purpose due to stated reasons.
Simplest solution for most ansible problems is to do it outside ansible. E.g.
- shell: test -f /home/user/optional/file.yml # or use -r if you're too particular.
register: optional_file
failed_when: False
- include: /home/user/optional/file.yml
when: optional_file.rc == 0
- debug: msg="/home/user/optional/file.yml did not exist and was not included"
when: optional_file.rc != 0
* failed_when added to avoid host getting excluded from further tasks when the file doesn't exist.
Using ansible-2.1.0, I'm able to use snippets like this in my playbook:
- hosts: all
gather_facts: false
tasks:
- name: Determine if local playbook exists
local_action: stat path=local.yml
register: st
- include: local.yml
when: st.stat.exists
I get no errors/failures when local.yml does not exist, and the playbook is executed (as a playbook, meaning it starts with the hosts: line, etc.)
You can do the same at the task level instead with similar code.
Using stat appears to work correctly.
There's also the option to use a Jinja2 filter for that:
- set_fact: optional_file="/home/user/optional/file.yml"
- include: ....
when: optional_file|exists
The best option I have come up with so far is this:
- include: "{{ hook_variable | default(lookup('pipe', 'pwd') ~ '/hooks/empty.yml') }}"
It's not exactly an "if-exists", but it gives users of your role the same result. Create a few variables within your role and a default empty file. The Jinja filters "default" and "lookup" take care of falling back on the empty file in case the variable was not set.
For convenience, a user could use the {{ playbook_dir }} variable for setting the paths:
hook_variable: "{{ playbook_dir }}/hooks/tasks-file.yml"