Ansible: exclude item(s) from lookup result - ansible

The following Ansible play:
- name: Fetch domains
vars:
domain_lines: "{{ lookup('file', domain_file).splitlines() }}"
debug:
msg: "Domains: {{ domain_lines }}"
reads and splits the lines from the following "domain_file":
test1.domain.tld
# test2.domain.tld
test3.domain.tld
test4.domain.tld
This works nicely. But now I'd like to skip/remove the lines starting with a hashtag. What's the best way to achieve this?

Use reject. The play below
- set_fact:
domain_selected: "{{ domain_lines|reject('regex', '^#(.*)$')|list }}"
- debug:
var: domain_selected
gives
"domain_selected": [
"test1.domain.tld",
"test3.domain.tld",
"test4.domain.tld"
]

Related

Ansible: Output of 'loop' with 'register' module

I'm trying to get the output of my Ansible script using register module but the loop I'm using is probably causing some issue.
Whats a default way of using register module with loop?
Code:
---
- name:
hosts:
gather_facts:
tasks:
- name: Execute file
ansible.builtin.shell:
environment:
"setting environment"
register: output
loop:
"value"
- debug:
vars: output.std_lines
Whats a default way of using register module with loop?
It is just registering the result.
The only difference will be, that a single task will provide you just with an dictionary result (or output in your example) and registering in a loop will provide with a list result.results (or output.results in your example). To access the .stdout_lines you will need to loop over the result set .results too.
You may have a look into the following example playbook which will show some aspects of Registering variables, Loops, data structures, dicts and lists and type debugging.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Create STDOUT output (single)
command: 'echo "1"'
register: result
- name: Show full result (single)
debug:
var: result
- name: Show '.stdout' (single)
debug:
msg: "The result in '.stdout': {{ result.stdout }} is of type {{ result.stdout | type_debug }}"
- name: Create STDOUT output (loop)
command: 'echo "{{ item }}"'
register: result
loop: [1, 2, 3]
loop_control:
label: "{{ item }}"
- name: Show full result (loop)
debug:
var: result
- name: Show '.stdout' (loop)
debug:
msg: "The result in '.stdout': {{ item.stdout }} is of type {{ item.stdout | type_debug }}"
loop: "{{ result.results }}"
loop_control:
label: "{{ item.item }}"
By running it and going through the output you can get familiar with the differences in your tasks.
Further Q&A
Register Variables in Loop in an Ansible Playbook
Ansible: loop, register, and stdout
Register variables in loop in Ansible playbook
... and many more here on SO.

Ansible how to get equivalent of nested for-loop in playbook

I am writing an ansible-playbook and am trying to accomplish the following:
there are the existing directories /home/user1 , /home/user2, ... , /home/user20
in each of these directories I want to create subdirectories /foo1 , ... , /foo5
Now I COULD just make use of a with_nested loop, where I provide two lists with all the indices that I need, but that is just silly.
Instead, I would like to define two number-ranges or -sequences and the relevant task is then looped over using the value-pairs from their cartesian product.
Is that reasonably possible and if so how do I go about it?
See ansible-doc -t lookup sequence and Forcing lookups to return lists e.g.
- debug:
msg: "Create /home/user{{ item.0 }}/foo{{ item.1 }}"
with_nested:
- "{{ query('sequence', 'start=1 end=3') }}"
- "{{ query('sequence', 'start=1 end=2') }}"
gives
msg: Create /home/user1/foo1
msg: Create /home/user1/foo2
msg: Create /home/user2/foo1
msg: Create /home/user2/foo2
msg: Create /home/user3/foo1
msg: Create /home/user3/foo2
The parametrized task below gives the same result
- debug:
msg: "Create /home/user{{ item.0 }}/foo{{ item.1 }}"
with_nested:
- "{{ query('sequence', user_range) }}"
- "{{ query('sequence', dir_range) }}"
vars:
user_start: 1
user_end: 3
user_range: "start={{ user_start }} end={{ user_end }}"
dir_start: 1
dir_end: 2
dir_range: "start={{ dir_start }} end={{ dir_end }}"

set path when file exists in Ansible yml code

I'm trying to set a var only when a file exists, here is one of my attempts
---
- hosts: all
tasks:
- stat:
path: '{{ srch_path_new }}/bin/run'
register: result
- vars: srch_path="{{ srch_path_new }}"
when: result.stat.exists
This also didn't work
- vars: srch_path:"{{ srch_path_new }}"
The task you are looking for is called set_fact: and is the mechanism ansible uses to declare arbitrary "host variables", sometimes called "hostvars", or (also confusingly) "facts"
The syntax would be:
- set_fact:
srch_path: "{{ srch_path_new }}"
when: result.stat.exists
Also, while vars: is a legal keyword on a Task, its syntax is the same as set_fact: (or the vars: on the playbook): a yaml dictionary, not a key:value pair as you had. For example:
- debug:
msg: hello, {{ friend }}
vars:
friend: Jane Doe
and be aware that vars: on a task exist only for that task

Ansible: Access facts set by set_fact

I need to be able to set variables using tasks in Ansible. I use set_fact for this, but cannot seem to access the fact I set with this. What is wrong with the code below:
- name: kludge1
set_fact: fake_y = "{{ [] }}"
- name: Loop
debug:
msg: "{{ item }}"
with_items: "{{ fake_y }}"
You have spaces before and after =...
- name: kludge1
set_fact: fake_y="{{ [] }}"
Avoid var= shortcut syntax. Use original YAML syntax instead, it gives less errors:
- name: kludge1
set_fact:
fake_y: "{{ [] }}"

Adding field to dict items

Consider the following play. What I am trying to do is add a field, tmp_path which is basically the key and revision appended together to each element in the scripts dict.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
scripts:
a.pl:
revision: 123
b.pl:
revision: 456
tasks:
- with_dict: "{{ scripts }}"
debug:
msg: "{{ item.key }}_{{ item.value.revision }}"
# - with_items: "{{ scripts }}"
# set_fact: {{item.value.tmp_path}}="{{item.key}}_{{item.value.revision}}"
# - with_items: "{{ scripts }}"
# debug:
# msg: "{{ item.value.tmp_path }}"
...
Obviously the commented code doesn't work, any idea how I can get this working? Is it possible to alter the scripts dict directly, or should I somehow be creating a new dict to reference instead?
By the way welcome to correct the terminology for what I am trying to do.
OK, I think I got a solution (below), at least to let me move forwards with this. Disadvantages are it has removed the structure of my dict and also seems a bit redundant having to redefine all the fields and use a new variable, If anyone can provide a better solution I will accept that instead.
---
- hosts: localhost
connection: local
gather_facts: no
vars:
scripts:
a.pl:
revision: 123
b.pl:
revision: 456
tasks:
- with_dict: "{{ scripts }}"
debug:
msg: "{{ item.key }}_{{ item.value.revision }}"
- with_dict: "{{ scripts }}"
set_fact:
new_scripts: "{{ (new_scripts | default([])) + [ {'name': item.key, 'revision': item.value.revision, 'tmp_path': item.key ~ '_' ~ item.value.revision}] }}"
# - debug:
# var: x
# - with_dict: "{{ scripts }}"
- with_items: "{{ new_scripts }}"
debug:
msg: "{{ item.tmp_path }}"
...
BTW credit to the following question which pointed me in the right direction:
Using Ansible set_fact to create a dictionary from register results

Resources