Reputation: 67
im new to ansible , i have this task that on deployment , it changes the ownership of the application files Recursively.
- name: Recursively change ownership
file:
path: "{{ $PATH }}"
state: directory
recurse: yes
owner: "{{ $USER }}"
group: "{{ $USER }}"
notify:
- Restart $service
when: deploy == "true"
I have a specific app folder binded to aws EFS , that's shared between different apps and i don't want to change the ownership for this folder. I tried to add :
fail :
when : ' "/$specific_folder " in {{ $PATH }} '
but it fails the whole task , also i can't remove the recurse because it fails the app to access other files. Any ideas ?
Upvotes: 0
Views: 7842
Reputation: 68144
Given the treeshell> pwd
/scratch/tmp8/test-992
shell> tree apps
apps
├── app1
│ └── app
├── app2
│ └── app
├── app3
│ └── app
├── file1
└── file2
shell> ls -la apps | grep app
drwxrwxr-x 2 user1 user1 4096 Sep 5 13:55 app1
drwxrwxr-x 2 user1 user1 4096 Sep 5 13:55 app2
drwxrwxr-x 2 user1 user1 4096 Sep 5 13:55 app3
shell> find apps -type f | xargs ls -la
-rw-rw-r-- 1 user1 user1 0 Sep 5 13:55 apps/app1/app
-rw-rw-r-- 1 user1 user1 0 Sep 5 13:55 apps/app2/app
-rw-rw-r-- 1 user1 user1 0 Sep 5 13:55 apps/app3/app
-rw-r--r-- 1 user1 user1 0 Sep 5 17:51 apps/file1
-rw-r--r-- 1 user1 user1 0 Sep 5 17:51 apps/file2
Declare the variables
user: user2
path: apps
exclude: [app2, app3]
root: "{{ playbook_dir }}"
root_path: "{{ root }}/{{ path }}"
Find the files and directories
- name: Find any
find:
path: "{{ root_path }}"
file_type: any
recurse: true
register: any
and declare the variables
dirs_exclude: "{{ [root_path]|product(exclude)|map('join', '/')|list }}"
any_select: "{{ any.files|rejectattr('path', 'regex', dirs_exclude|join('|')) }}"
Change the ownership
- name: Change ownership of dirs and files
file:
state: "{{ item.isdir|ternary('directory', 'file') }}"
path: "{{ item.path }}"
owner: "{{ user }}"
group: "{{ user }}"
loop: "{{ any_select }}"
when: item.isdir or item.isreg
Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
become: true
vars:
user: user2
path: apps
exclude: [app2, app3]
root: "{{ playbook_dir }}"
root_path: "{{ root }}/{{ path }}"
dirs_exclude: "{{ [root_path]|product(exclude)|map('join', '/')|list }}"
any_select: "{{ any.files|rejectattr('path', 'regex', dirs_exclude|join('|')) }}"
tasks:
- name: Find any
find:
path: "{{ root_path }}"
file_type: any
recurse: true
register: any
- name: Change ownership of dirs and files
file:
state: "{{ item.isdir|ternary('directory', 'file') }}"
path: "{{ item.path }}"
owner: "{{ user }}"
group: "{{ user }}"
loop: "{{ any_select }}"
loop_control:
label: "{{ item.path }}"
when: item.isdir or item.isreg
Run the playbook in check and diff mode to see what will happen
shell> ansible-playbook pb.yml --check --diff
PLAY [localhost] *****************************************************************************
TASK [Find any] ******************************************************************************
ok: [localhost]
TASK [Change ownership of dirs and files] ****************************************************
--- before
+++ after
@@ -1,3 +1,3 @@
-group: 1003
-owner: 1003
+group: 1004
+owner: 1004
path: /export/scratch/tmp8/test-992/apps/file2
changed: [localhost] => (item=/export/scratch/tmp8/test-992/apps/file2)
--- before
+++ after
@@ -1,3 +1,3 @@
-group: 1003
-owner: 1003
+group: 1004
+owner: 1004
path: /export/scratch/tmp8/test-992/apps/file1
changed: [localhost] => (item=/export/scratch/tmp8/test-992/apps/file1)
--- before
+++ after
@@ -1,3 +1,3 @@
-group: 1003
-owner: 1003
+group: 1004
+owner: 1004
path: /export/scratch/tmp8/test-992/apps/app1
changed: [localhost] => (item=/export/scratch/tmp8/test-992/apps/app1)
--- before
+++ after
@@ -1,3 +1,3 @@
-group: 1003
-owner: 1003
+group: 1004
+owner: 1004
path: /export/scratch/tmp8/test-992/apps/app1/app
changed: [localhost] => (item=/export/scratch/tmp8/test-992/apps/app1/app)
PLAY RECAP ***********************************************************************************
localhost: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Upvotes: 2
Reputation: 838
The file module doesn't recognise subdirectories:
/tmp/testdir
├── folder1
├── folder2
└── specific_folder
- name: Recursively change ownership
file:
path: /tmp/testdir/
state: directory
recurse: yes
owner: "{{ user }}"
group: "{{ user }}"
changed: [localhost] => {
"changed": true,
"diff": {
"after": {
"path": "/tmp/testdir/"
},
"before": {
"path": "/tmp/testdir/"
}
},
"gid": 0,
"group": "root",
"invocation": {
"module_args": {
"owner": "root",
"path": "/tmp/testdir/",
"recurse": true,
"state": "directory",
}
},
"mode": "0755",
"owner": "root",
"path": "/tmp/testdir/",
"size": 4096,
"state": "directory",
"uid": 0
}
So we should find a way to get a list of subdirectories, which is find module
---
- hosts: localhost
gather_facts: no
vars:
user: root
path: /tmp/testdir/
tasks:
- name: list directories
find:
paths: "{{ path }}"
file_type: any
register: directories
Output(shrinked):
ok: [localhost] => {
"changed": false,
"examined": 3,
"files": [
{
"mode": "0755",
"path": "/tmp/testdir/folder1",
"pw_name": "root",
},
{
"mode": "0755",
"path": "/tmp/testdir/folder2",
"pw_name": "root",
},
{
"mode": "0755",
"path": "/tmp/testdir/specific_folder",
"pw_name": "root",
}
],
"invocation": {
},
"matched": 3,
"msg": "All paths examined",
"skipped_paths": {}
Now we got the output as an array calles files
in the register directories
.
We can loop over the attribute path
and set a condition to skip the task if the path includes name of the excluded directory.
---
- hosts: localhost
gather_facts: no
vars:
user: root
path: /tmp/testdir/
exclude_dir: specific_folder
tasks:
- name: list directories
find:
paths: "{{ path }}"
file_type: any
register: directories
- name: Recursively change ownership
file:
path: "{{ item.path }}"
state: directory
owner: "{{ user }}"
group: "{{ user }}"
loop: "{{ directories.files }}"
notify:
- Restart service
when:
- deploy
- exclude_dir not in item.path
TASK [Recursively change ownership] *****************************************
ok: [localhost] => (item={'path': '/tmp/testdir/folder1', ....})
ok: [localhost] => (item={'path': '/tmp/testdir/folder2', ....})
skipping: [localhost] => (item={'path': '/tmp/testdir/specific_folder', ...})
Upvotes: 1
Reputation: 301
You can look for all files and directories in your parent folder with the 'find' module. Then, you pass the result as a list to a loop in a 'file' task. The 'file' task should test every item in the loop to check it does not belong to the excluded folder.
- name: "Find all files and folders in {{ PATH }}"
find:
path: "{{ PATH }}"
file_type: any
recurse: true
register: folder_contents
- name: Recursively change ownership
file:
path: "{{ item.path }}"
owner: "{{ USER }}"
group: "{{ USER }}"
loop: "{{ folder_contents.files }}"
notify:
- Restart service
when:
- deploy
- item.path is not search(excluded_folder_name)
vars:
- excluded_folder_name: 'foobar'
Voilà!
Upvotes: 3