external dict in ansible - ansible

I'm trying to use external dictionary with somehow "mapped" variables:
one_changes:
key1: value1
key2: value2
key3: value3
In my playbook I'm using vars_files which is recognized. Now, how do I do something like this:
name: variables_one
replace:
dest=/one/file.php
regexp="{{ one_changes.key }}"
replace="{{ one_changes.value }}"
with_items:
- one_changes
I cannot for sake of god figure it out since few hours. There are many variables for many files so I'd like to keep them mapped separately.

There is a chapter about this in documentation.
First, mind the indentation in your yaml file:
one_changes:
key1: value1
key2: value2
key3: value3
Second, use with_dict:
- name: variables_one
replace:
dest: /one/file.php
regexp: "{{ item.key }}"
replace: "{{ item.value }}"
with_dict: "{{ one_changes }}"

Related

How can I convert `key=value` file into Ansible facts?

I've got a file containing a few lines of simple shell-style (key=value, no whitespace or special characters) assignments. How would I go about converting this to a set of top-level facts using ansible.builtin.set_fact? expandvars looks like it might be relevant, but I can't find any examples or even any decent documentation.
For example, given the configuration file
shell> cat conf.ini
key1=alpha=beta=charlie
key2=value2
key3= value3
The variable below
config_vars: "{{ dict(lookup('file', 'conf.ini').split('\n')|
map('split', '=', 1)|
map('map', 'trim')) }}"
expands to
config_vars:
key1: alpha=beta=charlie
key2: value2
key3: value3
You can remove the last map/trim filter from the pipe if you're sure there are no spaces in the configuration file. But, to be on the safe side, I'd keep it.
Config file at the remote host
The solution in the previous section works at the controller only because the lookup plugins execute at the localhost. Fetch the files first if they are at the remote hosts. For example, given the configuration files
shell> ssh admin#test_11 cat /tmp/conf.ini
key1=alpha=beta=charlie
key2=value2
key3= value3
shell> ssh admin#test_12 cat /tmp/conf.ini
key1=value1
key2= value2
key3=alpha=beta=charlie
the playbook below
- hosts: test_11,test_12
vars:
conf_ini_path: "conf_ini/{{ inventory_hostname }}/tmp/conf.ini"
config_vars: "{{ dict(lookup('file', conf_ini_path).split('\n')|
map('split', '=', 1)|
map('map', 'trim')) }}"
tasks:
- fetch:
dest: conf_ini
src: /tmp/conf.ini
- debug:
var: config_vars
gives (abridged)
TASK [debug] ***********************************************
ok: [test_11] =>
config_vars:
key1: alpha=beta=charlie
key2: value2
key3: value3
ok: [test_12] =>
config_vars:
key1: value1
key2: value2
key3: alpha=beta=charlie
Alow no value
For example, given the configuration file
shell> cat conf.ini
key1=alpha=beta=charlie
key2=value2
key3= value3
key4
The variable below
config_vars: "{{ dict(lookup('file', 'conf.ini').split('\n')|
map('split', '=', 1)|
map('map', 'trim')|
map('json_query', '[]|[[0], [1]]')) }}"
expands to
config_vars:
key1: alpha=beta=charlie
key2: value2
key3: value3
key4: null

Ansible, create list of dictionaries from list of dictionaries, with specific subkey containing dictionary

I'm trying to create a list of dictionaries, from a list of dictionaries which contains a key with a dictionary as a value. So, I want a list of dictionaries each with the contents of that key.
Starting from:
orig_dictionary:
- key1:
name: key1val_a
extra_a: test
key2:
name: key2val_a
extra_a: test
- key1:
name: key1val_a
key2:
name: key2val_a
- key2:
name: key2val_a
extra_b: test
I'm tying to get,
new_dictionary:
- name: key2val_a
extra_a: test
- name: key2val_a
- name: key2val_a
extra_b: test
I've used map with an extract filter followed by the list filter, but I end up getting a string for some reason. Using jinja2 style filters, how can I do this?
If you want to get the last items from the dictionaries the task below
- set_fact:
new_dictionary: "{{ new_dictionary|d([]) + [item.0[item.1]] }}"
with_together:
- "{{ orig_dictionary }}"
- "{{ orig_dictionary|map('last')|list }}"
gives the expected result
new_dictionary:
- extra_a: test
name: key2val_a
- name: key2val_a
- extra_b: test
name: key2val_a
Selecting the key2 attribute would be trivial. The task below gives the same result
- set_fact:
new_dictionary: "{{ orig_dictionary|map(attribute='key2')|list }}"
The module set_fact is not needed. Put the declaration of the variable new_dictionary where you want to. Optionally, you can use also Jinja to create the list, e.g.
_new_dictionary: |
{% for i in orig_dictionary %}
- {{ i[i|last] }}
{% endfor %}
new_dictionary: "{{ _new_dictionary|from_yaml }}"
The order in Python dictionaries is a moving target. See for example Are dictionaries ordered in Python 3.6+?

ansible run multiple commands with mutiple variables

I'm having the folowing ansible task:
- name: Task1
command: "{{ item }}"
with_dict:
- { key1: "aaa", key2: "aaa-file"}
- { key1: "bbb", key2: "bbb-fie"}
- ...
loop:
- cd /home/{{ dict.key1 }}
- rm -f {{ dict.key2 }}
It's just a concocted example but what I'm trying to achieve is the following:
run all commands with the first entry values from with_dict, then run all commands with the second entry values from the with_dict etc.
I've looked over with_nested, but not sure if it helps.
There are at least two ways to perform this.
First : one command line
- name: Task1
command: "cd /home/{{ item.key1 }} && rm -f {{ item.key2 }}"
with_items:
- key1: "aaa"
key2: "aaa-file"
- key1: "bbb"
key2: "bbb-fie"
- ...
If you really wants to perform a cd command, use this :
- name: Task1
command: "rm -f {{ item.key2 }}"
args:
chdir: "/home/{{ item.key1 }}"
with_items:
- key1: "aaa"
key2: "aaa-file"
- key1: "bbb"
key2: "bbb-fie"
- ...
Second : use two tasks
- name: Task1
command: "cd /home/{{ item.key1 }}"
with_items:
- key1: "aaa"
key2: "aaa-file"
- key1: "bbb"
key2: "bbb-fie"
- ...
- name: Task2
command: "rm -f {{ item.key2 }}"
with_items:
- key1: "aaa"
key2: "aaa-file"
- key1: "bbb"
key2: "bbb-fie"
- ...
In this case, I suggest you to define a variable with your list, at play level for example :
- hosts: app_servers
vars:
my_list:
- key1: "aaa"
key2: "aaa-file"
- key1: "bbb"
key2: "bbb-fie"
- ...
tasks:
- name: Task1
command: "cd /home/{{ item.key1 }}"
with_items: "{{ my_list }}"
- name: Task2
command: "rm -f {{ item.key2 }}"
with_items: "{{ my_list }}"

How to use loop and with_nested together in ansible

I have the vars defined like this-
vars:
values:
- key1: value1
key2:
- value1.1
- value1.2
- key1: value2
key2:
- value2.1
- value2.2
Want to iterate on key1 with corresponding values in key2
I am running ansible 2.7.10 with python 2.7.10. Here is what I have written in my task based on some suggestions I found online-
(used with_subelements)
- name: test loops
debug:
msg: "This is key1: {{ item.0.key1 }}, and here is corresponding key2 element {{ item.1 }}"
with_subelements:
- values
- key2
Expected output:
This is key1: value1, and here is corresponding key2 element value1.1
This is key1: value1, and here is corresponding key2 element value1.2
This is key1: value2, and here is corresponding key2 element value2.1
This is key1: value2, and here is corresponding key2 element value2.2
Error I get when I execute the playbook:
fatal: [localhost]: FAILED! => {"msg": "subelements lookup expects a dictionary, got 'values'"}
Any ideas how to achieve this?
Correct syntax is
with_subelements:
- "{{ values }}"
- key2
, or Migrated from with_X to loop
loop: "{{ values|subelements('key2') }}"
The play below
- hosts: localhost
vars:
values:
- key1: value1
key2:
- value1.1
- value1.2
- key1: value2
key2:
- value2.1
- value2.2
tasks:
- debug:
msg: "{{ item.0.key1 }} - {{ item.1 }}"
with_subelements:
- "{{ values }}"
- key2
gives (abridged):
"msg": "value1 - value1.1"
"msg": "value1 - value1.2"
"msg": "value2 - value2.1"
"msg": "value2 - value2.2"

Ansible Loop for One list over another

I have two lists
I am trying to iterate over the loop in ansible. I want the users list to iterate over all the environments.
I have a command like below where i want to run the following combinations
"az role assignment {{ username }} {{ env }}"
az role assignment john dev
az role assignment john qa
az role assignment john uat ...etc
Can you any one please help me
You need to use nested loops:
https://docs.ansible.com/ansible/2.4/playbooks_loops.html#nested-loops
- name: do command
command: az role assignment {{item[0]}} {{item[1]}}
with_nested:
- - john
- paul
- - dev
- qa
- ua
---
- hosts: localhost
gather_facts: no
vars:
objs:
- { key1: value1, key2: [ value2, value3] }
- { key1: value4, key2: [ value5, value6] }
tasks:
- name: create directories
file: path="{{ item.key1 }}" state=directory
with_items:
objs
- name: create files
file: path="{{ item.0.key1 }}/{{ item.1 }}" state=touch
with_subelements:
- objs
- key2

Resources