Reputation: 25
I have a folder containing a list of named tasks-files and want to include them based on a specific selector.
Eg.
inventory_dir
| stacks
| tasks
| app1.yml
| app2.yml
| app3.yml
The Selector can be a list, and can contain elements that doesn't have a taskfile.
I'm trying different approaches to reach my goal, but
- name: tentative 1
block:
- name: Tasks to execute always
include_tasks: ./generic-tasks.yml
- name: Include specific tasks for specific selector
include_tasks:
file: "{{ inventory_dir }}/stacks/tasks/{{ item }}.yml"
loop:
- '{{ SELECTOR }}'
Here I cannot use a stat task, because I don't know in advance what is the value of {{ item }} (and I cannot loop over a block). So this will fail in case the selector doesn't have a taskfile.
To avoid this I tried to do the contrary: looping over the folder content, and filtering by selector.
- name: Include specific tasks for specific selector
include_tasks:
file: "{{ item }}"
loop: "{{ lookup('fileglob', '{{ inventory_dir }}/stacks/tasks/*.yml',wantlist=True) }}"
when: "item|regex_replace("(?:\/[ \w]+){1,}\/([ \w]+)(?:\.yml)", "\1") in SELECTOR"
But it fail, probably because of the "in" check failing. (The regexp is working correctly anyway).
Do you have a better strategy?
Upvotes: 0
Views: 970
Reputation: 44799
You can use the find
module and put it inside a block. This will fit on a single include level.
- hosts: localhost
gather_facts: false
vars:
include_file_list: >
{{ (SELECTOR | d([], true)) | map('regex_replace', '^(.*)$', '\1.yml') }}
tasks:
- when: include_file_list | length > 0
block:
- name: check which files exist based on selector
find:
paths:
- '{{ inventory_dir }}'
patterns: "{{ include_file_list }}"
register: check_task_files
- name: include existing task files
include_tasks: "{{ item.path }}"
loop: "{{ check_task_files.files }}"
Meanwhile, note that this will basically only succeed when targeting localhost as find
runs on the target host. If you ever run this on a remote target you might get errors because either:
So although a bit more complicated to read/understand, the following which will only look for files on the controller using the fileglob
lookup is more appropriate.
The template expression to aggregate found files is needed because python glob does not understand the curly braces notation and we need to expand and search for each possible path ourselves. (i.e. /some/path/{a,b,c}.yml
will not return any matches)
- hosts: all
gather_facts: false
vars:
include_file_list: >
{{ (SELECTOR | d([], true)) | map('regex_replace', '^(.*)$', inventory_dir ~ '/stacks/tasks/\1.yml') }}
found_files: >
{%- set found = [] -%}
{%- for path in include_file_list -%}
{{ found.append(q('fileglob', path)) }}
{%- endfor -%}
{{ found | flatten}}
tasks:
- name: include existing files
include_tasks: "{{ item }}"
loop: "{{ found_files }}"
Upvotes: 0
Reputation: 25
I found a solution, using a separate task-file.
main.yml
- name: tentative 1
block:
- name: Tasks to execute always
include_tasks: ./generic-tasks.yml
- name: Include specific tasks for specific selector
include_tasks:
file: "specific-tasks.yml"
loop:
- '{{ SELECTOR }}'
specific-tasks.yml
- name: Check for file existence
stat:
path: "{{ inventory_dir }}/stacks/tasks/{{item}}.yml"
register: "taskfile"
delegate_to: localhost
become: false
- name: Include tasks specific to this stack
include_tasks:
file: "{{ inventory_dir }}/stacks/tasks/{{ item }}.yml"
when: "taskfile.stat.exists"
- name: Unregister taskfile
set_fact:
taskfile: ''
I'm still posting this in case there are better strategies
Upvotes: 0