Ansible loop over list extracted from dict - ansible

I'm using Ansible 2.9 on RHEL 7.7, and I'm trying to loop over a list which is a value from a dict element. So far I have this var file and play:
ssh_keys:
account: blah
permissions: 600
keys:
- qa-publickeys['1']
- qa-publickeys['2']
- qa-publickeys['3']
the play:
- name: Traversing ssh keys
debug:
msg: "Here's: {{ item }}"
loop: "{{ ['keys'] | map('extract', ssh_keys) | list }}"
The problem is, msg is "msg": "Here's: [u\"qa-publickeys['1']\", u\"qa-publickeys['2']\", u\"qa-publickeys['3']\"]"
Why is it not giving me three outputs, with Here's: qa-publickeys['1'] as the first output, Here's: qa-publickeys['2'] as the second, and finally Here's: qa-publickeys['3'] ?
The list that I present to the loop in this play is not getting looped over, it's just iterating once in one chunk.

You seems to make is really complex for yourself for no apparent reason.
A dictionary in Ansible can be accessed via either the . dot notation or the [] square brackets notation.
Now because .keys() is indeed a built-in method of a dictionary in Python, you cannot use the first notation, but you can use the later one.
Given the playbook:
- hosts: all
gather_facts: no
tasks:
- debug:
msg: "Here's: {{ item }}"
loop: "{{ ssh_keys['keys'] }}"
vars:
ssh_keys:
account: blah
permissions: 600
keys:
- qa-publickeys['1']
- qa-publickeys['2']
- qa-publickeys['3']
This yields the recap:
PLAY [all] *******************************************************************************************************
TASK [debug] *****************************************************************************************************
ok: [localhost] => (item=qa-publickeys['1']) =>
msg: 'Here''s: qa-publickeys[''1'']'
ok: [localhost] => (item=qa-publickeys['2']) =>
msg: 'Here''s: qa-publickeys[''2'']'
ok: [localhost] => (item=qa-publickeys['3']) =>
msg: 'Here''s: qa-publickeys[''3'']'
PLAY RECAP *******************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Related

compare value with list of int in ansible

Want to compare values with list for int and display msg values greater than 15
tasks:
- name: Create a List variable and print it
set_fact:
Continents: ["10","20"]
- name: set fatc
set_fact:
int_list: "{{ Continents|map('int')|list }}"
- debug:
msg: "{{greater than 15}}"
when: "{{int_list}}" > 15
Getting error as below:
The offending line appears to be:
msg: "{{ list }}"
when: "{{int_list}}" > 15
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
Expected Output:
greater than 15
If your goal is to show only those integers in the list that are greater than 15, you can use the select filter:
- hosts: localhost
gather_facts: false
tasks:
- name: Create a list of integers
set_fact:
int_list: [10, 20]
- name: Find integers greater than 15
debug:
msg: "{{ item }}"
loop: "{{ int_list | select('>', 15) }}"
The output of this playbook is:
PLAY [localhost] ***************************************************************
TASK [Create a list of integers] ***********************************************
ok: [localhost]
TASK [Find integers greater than 15] *******************************************
ok: [localhost] => (item=20) => {
"msg": 20
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can achieve the same with two tasks. Change your list to integers. Make the debug task to loop through the Continents variable.
- hosts: localhost
tasks:
- name: Create a variable with a list of integers
set_fact:
Continents: [10, 20]
- debug:
msg: "greater than 15"
loop: "{{ Continents }}"
when: item > 15 ##item becomes each value of the Continents variable. So, 10, 20 and so on.
Gives:
skipping: [localhost] => (item=10)
ok: [localhost] => (item=20) => {
"msg": "greater than 15"
}

Ansible filter filename list with substring list

This seems simple enough but I can't find the ansible/jinja way to do it nor the correct keywords to find some pointers.
There's a list of file names (firstlist) (read from a file if it makes anything easier).
There's a second list (secondlist) with partial filenames to filter the first one. This second list can have elements that don't match.
/tmp/filelist.txt contents:
A-ok.txt
B-ok.txt
C-ok.txt
Tasks extract:
- name: Read filelist
command: cat /tmp/filelist.txt
register: filelist_results
- name: "[FACT] filelist"
set_fact:
firstlist: "{{ filelist_results.stdout_lines }}"
secondlist: ['A', 'C', 'D']
- name: "print it"
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ firstlist }}" # <--- need to filter here?
Would result in looping just:
A-ok.txt
C-ok.txt
If secondlist contained the full filename, adding:
when: item in secondlist
would be enough.
It seems select() is half the answer but I can't find the correct test to match the partial filename from the second list
Take your "filter" list (["A", "C", "D"]) and transform it to a regex of chars to look for ("A|C|D") (using regex_escape on each list element for safety).
use the select filter to retain only element that pass the match test (i.e. the regex is found at the beginning of the expression)
In a nutshell, the following playbook:
---
- hosts: localhost
gather_facts: false
vars:
filelist:
- A-ok.txt
- B-ok.txt
- C-ok.txt
keeplist:
- A
- C
- D
filteredlist: "{{ filelist | select('match', keeplist | map('regex_replace') | join('|')) }}"
tasks:
- debug:
var: filteredlist
gives:
PLAY [localhost] ***********************************************************************************************************************************************************************************************************************
TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"filteredlist": [
"A-ok.txt",
"C-ok.txt"
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Note: Posting my final result in answer form as suggested.
After #Zeitounator this is where I ended up:
---
- hosts: localhost
gather_facts: false
vars:
filelist:
- plugin-test-v1.txt
- plugin-database.txt
- C-ok.txt
keeplist:
- plugin-database
- plugin-test
- plugin-none
regexp: "{{ keeplist | map('regex_escape') | join('|') }}"
filteredlist: "{{ filelist | select('match', regexp) }}"
tasks:
- name: "print it"
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ filteredlist|default(filelist) }}"
Couple points:
extracted the regexp in a separate variable because templating inline was giving me troubles with dash in the pattern
the loop defaults to the full list if the filter ends up empty
Outputs:
PLAY [localhost] *******************************************************************************************************
TASK [print it] ********************************************************************************************************
ok: [localhost] => (item=plugin-test-v1.txt) => {
"msg": "plugin-test-v1.txt"
}
ok: [localhost] => (item=plugin-database.txt) => {
"msg": "plugin-database.txt"
}
PLAY RECAP *************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Ansible hosts to be set to a substring of a passed variable

I have a play like this:
- name: Perform an action on a Runtime
hosts: all
roles:
- role: mule_action_on_Runtime
A variable at invocation (--extra-vars 'mule_runtime=MuleS01-3.7.3-Testing') has a prefix of the host needed (MuleS01). I want to set hosts: MuleS01. How do I do this?
Given that your pattern is always PartIWant-PartIDonCareAbout-AnotherPartAfterOtherDash you could use the split method of Python, then get the first item of the list via the Jinja filter first.
Here is full working playbook as example:
- hosts: local
gather_facts: no
tasks:
- debug:
msg: "{{ mule_runtime.split('-') | first }}"
This yield the recap:
play.yml --extra-vars 'mule_runtime=MuleS01-3.7.3-Testing'
PLAY [local] *******************************************************************
TASK [debug] *******************************************************************
ok: [local] => {
"msg": "MuleS01"
}
PLAY RECAP *********************************************************************
local : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
With the inventory
shell> cat hosts
MuleS01
MuleS02
MuleS03
this playbook
shell> cat pb.yml
- hosts: all
tasks:
- debug:
msg: Set {{ mule_runtime }}
when: mule_runtime.split('-').0 == inventory_hostname
gives
skipping: [MuleS02]
ok: [MuleS01] => {
"msg": "Set MuleS01-3.7.3-Testing"
}
skipping: [MuleS03]

ansible: create a list from comma separated string

I want to create a list from comma separated string to pass to loop in ansible, sometime variable can have only one value also
var1=test1,test2 and it can be var1=test1 also
here is my code
- name: Separate facts
set_fact: groups="{{ var1.split(',') }}"
- name: delete
gcp_compute_instance_group:
name: "{{ item }}"
zone: xxx
project: xxx
auth_kind: serviceaccount
service_account_file: xxx
state: absent
loop: "{{ groups }}"
this doesn't work, how can i achieve my requirement
your filter is correct, you do get a list variable. please see below PB and output:
---
- hosts: localhost
gather_facts: false
vars:
var1: test1,test2
var2: test3
tasks:
- name: Create the list
set_fact:
list_var1: "{{ var1.split(',') }}"
list_var2: "{{ var2.split(',') }}"
- debug:
var: list_var1
- debug:
var: list_var2
result:
[is#orangehat-29 temp]$ ansible-playbook test.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] ***********************************************************************************************************************************************************************************************************************
TASK [Create the list] *****************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"list_var1": [
"test1",
"test2"
]
}
TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"list_var2": [
"test3"
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[is#orangehat-29 temp]$

Ansible json_query outputs list when using a filter expression

I'm running ansible 2.4.0 on OSX.
The following playbook...
---
- hosts: localhost
connection: local
gather_facts: False
vars:
data:
- name: thing1
desc: I am thing 1
- name: thing2
desc: I am thing 2
tasks:
- debug: msg="{{ data|json_query(\"[1].desc\") }}"
- debug: msg="{{ data|json_query(\"[?name=='thing2'].desc\") }}"
Produces the following output:
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "I am thing 2"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": [
"I am thing 2"
]
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0
My question is, why, in the second debug task is the output in a list ([])?
You can add ansible filter first, like so:
tasks:
- debug: msg="{{ data | json_query(\"[?name=='thing2'].desc\") | first }}"
It'll return scalar value.
That's because in JMESPath, which is the implementation behind json_query, an index expression is defined to always return a single value, possibly null (see [1]).
While for the filter expression, which is a projection, an array is assumed to be returned after evaluating the LHS of your query, which may be empty in case no values are matched (see: [2]).

Resources