Reputation: 384
I am trying to create multiple directories (with different names) and files inside each directory.
I have a variable named directories that contains directory and file names like this:
directories:
- directory: dir1
static_files:
files:
- file1
- file2
- directory: dir2
static_files:
files:
- file1
- file2
This is the workaround I was able to come up with using with_subelments but with two tasks which seems working. However, I believe there must be a solution with only one task to achieve this.
- name: Creates directories
file:
path: "/tmp/{{ item[0].directory }}"
state: directory
recurse: yes
mode: 0755
owner: user
group: group
become: true
with_subelements:
- "{{ directories }}"
- static_files.files
- name: Creates files
file:
path: "/tmp/{{ item[0].directory }}/{{ item[1] }}"
state: touch
mode: 0644
owner: user
group: group
become: true
with_subelements:
- "{{ directories }}"
- static_files.files
I might be missing a module that can do the job. I also tried to leverage this solution without any luck How to create directory and file inside the same directory in ansible using single task
My question is, how can this be achieve, if possible, with a single task? Any other solution and approach would also be great.
Expected result:
/tmp/dir1/file1
/tmp/dir1/file2
/tmp/dir2/file1
/tmp/dir2/file2
Any help is greatly appreciated.
Upvotes: 1
Views: 1036
Reputation: 67959
Create the structure
my_files: |
{% filter from_yaml %}
{% for dir in directories %}
- [{{ dir.directory}}, directory]
{% for file in dir.static_files.files %}
- [{{ dir.directory }}/{{ file }}, touch]
{% endfor %}
{% endfor %}
{% endfilter %}
gives
my_files:
- [dir1, directory]
- [dir1/file1, touch]
- [dir1/file2, touch]
- [dir2, directory]
- [dir2/file1, touch]
- [dir2/file2, touch]
The iteration of the list
- file:
path: "/tmp/{{ item.0 }}"
state: "{{ item.1 }}"
loop: "{{ my_files }}"
creates the directories and the files
TASK [file] ***************************************************************
changed: [localhost] => (item=['dir1', 'directory'])
changed: [localhost] => (item=['dir1/file1', 'touch'])
changed: [localhost] => (item=['dir1/file2', 'touch'])
changed: [localhost] => (item=['dir2', 'directory'])
changed: [localhost] => (item=['dir2/file1', 'touch'])
changed: [localhost] => (item=['dir2/file2', 'touch'])
shell> tree /tmp/dir1
/tmp/dir1
├── file1
└── file2
0 directories, 2 files
shell> tree /tmp/dir2
/tmp/dir2
├── file1
└── file2
0 directories, 2 files
This task is not idempotent. When you run it again the files will be touched and both the access and modification time will be updated. Set the parameters access_time and modification_time to 'preserve' if you don't want to change the times
my_files: |
{% filter from_yaml %}
{% for dir in directories %}
- [{{ dir.directory}}, directory]
{% for file in dir.static_files.files %}
- [{{ dir.directory }}/{{ file }}, touch, preserve, preserve]
{% endfor %}
{% endfor %}
{% endfilter %}
gives
my_files:
- [dir1, directory]
- [dir1/file1, touch, preserve, preserve]
- [dir1/file2, touch, preserve, preserve]
- [dir2, directory]
- [dir2/file1, touch, preserve, preserve]
- [dir2/file2, touch, preserve, preserve]
Make the parameters access_time and modification_time optional
- file:
path: "/tmp/{{ item.0 }}"
state: "{{ item.1 }}"
access_time: "{{ item.2|d(omit) }}"
modification_time: "{{ item.3|d(omit) }}"
loop: "{{ my_files }}"
This makes the task idempotent
TASK [file] ***************************************************************
ok: [localhost] => (item=['dir1', 'directory'])
ok: [localhost] => (item=['dir1/file1', 'touch', 'preserve', 'preserve'])
ok: [localhost] => (item=['dir1/file2', 'touch', 'preserve', 'preserve'])
ok: [localhost] => (item=['dir2', 'directory'])
ok: [localhost] => (item=['dir2/file1', 'touch', 'preserve', 'preserve'])
ok: [localhost] => (item=['dir2/file2', 'touch', 'preserve', 'preserve'])
Example of a complete playbook for testing
- hosts: localhost
vars:
directories:
- directory: dir1
static_files:
files:
- file1
- file2
- directory: dir2
static_files:
files:
- file1
- file2
my_files: |
{% filter from_yaml %}
{% for dir in directories %}
- [{{ dir.directory}}, directory]
{% for file in dir.static_files.files %}
- [{{ dir.directory }}/{{ file }}, touch, preserve, preserve]
{% endfor %}
{% endfor %}
{% endfilter %}
tasks:
- debug:
var: my_files
- file:
path: "/tmp/{{ item.0 }}"
state: "{{ item.1 }}"
access_time: "{{ item.2|d(omit) }}"
modification_time: "{{ item.3|d(omit) }}"
loop: "{{ my_files }}"
Upvotes: 7