How to add nested dictionary to dynamic host in Ansible - dictionary

I have application details in respective vars like below. For example, myapp1 in "QA" environment would look like the below:
cat myapp1_QA.yml
---
APP_HOSTS:
- myapphost7:
- logs:
- /tmp/web/apphost7_access
- /tmp/web/apphost7_error
- myapphost9:
- logs:
- /tmp/web/apphost9_access
- /tmp/web/apphost9_error
- /tmp/web/apphost9_logs
WEB_HOSTS:
- mywebhost7:
- logs:
- /tmp/webserver/webhost7.pid
In this example I wish to create a dynamic host containing the 3 hosts
myapphost7
myapphost9
mywebhost7
and each host has variable log which can be looped to get the file paths:
Below is my ansible play:
---
- hosts: localhost
tasks:
- include_vars:
file: "{{ playbook_dir }}/{{ appname }}_{{ myenv }}.yml"
- name: Dsiplay dictionary data
debug:
msg: "{{ item[logs] }}"
loop: "{{ APP_HOSTS }}"
I get the below error:
ansible-playbook read.yml -e appname=myapp1 -e myenv=QA
TASK [Dsiplay dictionary data] *********************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'logs' is undefined\n\nThe error appears to be in '/root/read.yml': line 8, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Dsiplay dictionary data\n ^ here\n"}
My requirement is to store "myapphost7", "myapphost9", "mywebhost7" in group using add_hosts: hosts: while a variable logs: having the list of log files.
Note: if no hosts mywebhost7 is defined under WEB_HOSTS: or APP_HOSTS: then nothing should be added to the dynamic host.
Can you please suggest?

Related

how to check 777 permission in multiple directory by ansible

For a single directory my script is running fine, but how to check the same for multiple directories?
Code for a single directory:
---
- name: checking directory permission
hosts: test
become: true
tasks:
- name: Getting permission to registered var 'p'
stat:
path: /var/SP/Shared/
register: p
- debug:
msg: "permission is 777 for /var/SP/Shared/
when: p.stat.mode == "0777" or p.stat.mode == "2777" or p.stat.mode == "4777"
Reading stat_module shows that there is no parameter for recursion. Testing with_fileglob: did not gave the expected result.
So it seems you would need to loop over the directories in a way like
- name: Get directory permissions
stat:
path: "{{ item }}"
register: result
with_items:
- "/tmp/example"
- "/tmp/test"
tags: CIS
- name: result
debug:
msg:
- "{{ result }}"
tags: CIS
but I am sure there can be still more advanced solutions found.

Ansible - how to retrieve value from dict passing in the list in extra vars

So this is my dilemma... I am requiring a user to enter the name of a database (i.e. dbx) and the location (canada or america) through extra-vars (-e "dc=canada" -e "dbname=dbx". From that, I am going read the vars
vars:
dbx:
canada:
dbu: db1
home: /u01/app/oracle
america:
dbu: db2
home: /u01/app/oracle
to get the dbu. The dbu will then be compared to databases running on the host
- name: see if db is running on this host
command: echo database is running here
when: dbu == item.database_name
with_items:
- "{{custom python module}}"
I can get the value if I put
- name: output
register: x
debug:
msg: "{{ dbx[dc].dbu }}"
However if I change dbx to the value of dbname, it errors out.
Hope that makes sense.
Thanks Zeitounator and lxop.
By adding another nested loop info:
I was able to get the result by your suggestion:
{{ info[g_db][dc].dbu }}

Ansible include_vars into dictionary

In my ansible playbook, I read a list of directories into a list. I then want to read a "config.yml" file from each of these directories and put their content into dictionary, so that I can reference the config-data via the directory name from that dictionary.
The first part is no problem, but I cannot get the second part to work:
Step 1, load directories:
- name: Include directories
include_vars:
file: /main-config.yml
name: config
Step 2, load configs from directories:
- name: load deploymentset configurations
include_vars:
file: /path/{{ item }}/config.yml
name: "allconfs.{{ item }}" ## << This is the problematic part
with_items:
- "{{ config.dirs }}"
I tried different things like "allconfs['{{ item }}'], but none seemed to work. The playbook completed successfully, but the data was not in the dictionary.
I also tried defining the outer dictionary beforehand, but that did not work either.
The config files themselves are very simple:
/main-config.yml:
dirs:
- dir1
- dir2
- dir3
/path/dir1/config.yml:
some_var: "some_val"
another_var: "another val"
I want to be able to then access the values of the config.yml files like this:
{{ allconfs.dir1.some_var }}
UPDATE to try Konstantins approach:
- name: load deploymentset configurations
include_vars:
file: /repo/deploymentsets/{{ item }}/config.yml
name: "default_config"
with_items:
- "{{ config.deploymentsets }}"
register: default_configs
- name: combine configs
set_fact:
default_configs: "{{ dict(default_configs.results | json_query('[].[item, ansible_facts.default_config]')) }}"
Error message:
fatal: [127.0.0.1]: FAILED! => {"failed": true, "msg": "Unexpected templating type error occurred on ({{ dict(default_configs.results | json_query('[].[item, ansible_facts.default_config]')) }}): <lambda>() takes exactly 0 arguments (1 given)"}
Here is a piece of code from one of my projects with similar functionality:
- name: Load config defaults
include_vars:
file: "{{ item }}.yml"
name: "default_config"
with_items: "{{ config_files }}"
register: default_configs
tags:
- configuration
- name: Combine configs into one dict
# Здесь мы делаем словарь вида
# default_configs:
# config_name_1: { default_config_object }
# config_name_2: { default_config_object }
# config_name_3: { default_config_object }
# ...
set_fact:
default_configs: "{{ dict(default_configs.results | json_query('[].[item, ansible_facts.default_config]')) }}"
tags:
- configuration
default_config is a dummy var to temporary load var data.
The trick is to use register: default_configs with include_vars and parse it with the following task stripping out unnecessary fields.
AFAIK it isn't possible to create a single dictionary that encompasses multiple include_vars. From my testing it would create separate dictionaries for each included directory. Here's what you can do instead.
Remove allconfs. from your variable name.
- name: load deploymentset configurations
include_vars:
file: /path/{{ item }}/config.yml
name: "{{ item }}"
with_items:
- "{{ config.dirs }}"
You can then either access variables directly with
debug:
msg: "{{ dir1.some_var }}"
with_items: "{{ config.dirs }}"
Or if you need to loop through all variables in your included directories use this (hoisted from Ansible: how to construct a variable from another variable and then fetch it's value).
debug:
msg: "{{ hostvars[inventory_hostname][item].some_var }}"
with_items: "{{ config.dirs }}"

How to find in an ansible (yaml) dictionary a key from his value?

I have this dictionary:
MyClouds:
Devwatt:
ExternalNetwork: PublicRSC
Flavors:
- Flavor_1cpu_1gb: Devwatt_1cpu_1gb
- Flavor_1cpu_2gb: Devwatt_1cpu_2gb
- Flavor_1cpu_4gb: Devwatt_1cpu_4gb
Fuga:
ExternalNetwork: Internet
Flavors:
- Flavor_1cpu_1gb: Fuga_1cpu_1gb
- Flavor_1cpu_2gb: Fuga_1cpu_2gb
- Flavor_1cpu_4gb: Fuga_1cpu_4gb
- Flavor_1cpu_8gb: Fuga_1cpu_8gb
I have to migrate from one Openstack cloud to another, and one of my problem is to find correspondances between flavors.
I want to find which flavor (key) has the value "Devwatt_1cpu_2gb" in "Devwatt", and after get the value of the same key in "Fuga"
I tried a lot of solution (with-dict, when, jija filters, json_query) but I can't find a way to do that.
Please, may you help me ?
Inspired by Eric's answer and this usefull resource, I, finally, used this solution:
I changed a little bit my data structure and put it in a file matrice.yml:
MyClouds:
Devwatt:
ExternalNetwork: PublicRSC
Flavors:
- name: Flavor_1cpu_1gb
FlavorName: Devwatt_1cpu_1gb
- name: Flavor_2cpu_1gb
FlavorName: Devwatt_2cpu_1gb
- name: Flavor_1cpu_2gb
FlavorName: Devwatt_1cpu_2gb
Fuga:
ExternalNetwork: Internet
Flavors:
- name: Flavor_1cpu_1gb
FlavorName: Fuga_1cpu_1gb
- name: Flavor_2cpu_1gb
FlavorName: Fuga_2cpu_1gb
- name: Flavor_1cpu_2gb
FlavorName: Fuga_1cpu_2gb
then I used these filters in my playbook:
---
- hosts: localhost
connection: local
gather_facts: false
vars:
SourceFlavorName: "Devwatt_2cpu_1gb"
tasks:
- name: get flavors matrice
include_vars:
file: matrice.yml
- name: Get generic name from flavor name of source cloud
debug:
msg: "{{ MyClouds.Devwatt.Flavors | selectattr('FlavorName','search','^'+ SourceFlavorName +'$') |map (attribute='name') | list }}"
register: result
- name: Get flavor name for target cloud from generic name
debug:
msg: "{{ MyClouds.Fuga.Flavors | selectattr('name','search','^'+ result.msg[0] +'$') |map (attribute='FlavorName') | list }}"
With this solution I can have any number of clouds and find easily correspondances between flavor from one source cloud to target cloud.
Why not using a simple mapping using a dict where keys are "Devwatt" flavors and values are "Fuga" flavors, like this :
---
- hosts: localhost
vars:
FlavorsMapping:
Devwatt_1cpu_1gb: Fuga_1cpu_1gb
Devwatt_1cpu_2gb: Fuga_1cpu_2gb
Devwatt_1cpu_4gb: Fuga_1cpu_4gb
tasks:
- debug:
var: FlavorsMapping['Devwatt_1cpu_2gb']

Salt: text file to variable and use the same variable in state file to find&replace

I've run into an issue I havent been able to solve:
I have a file(/etc/osci) that I use on all of my servers as an name for our monitoring(zabbix)
I've created a state file that pushes a template configuration file to the server and and reads the content of /etc/osci to a variable. The next step would be to use that same variable with 'file.replace' function to search for a string and replace it with the variable.
uusnimi=$(cat /etc/osci):
cmd.run
/etc/zabbix_agentd.conf:
file.managed:
- source: salt://base/streamingconf/zabbix/zabbix_agentd.conf
- mode: 644
change_hostname_zabbix:
file.replace:
- name: /etc/zabbix_agentd.conf
- pattern: 'Hostname='
- repl: 'Hostname=$uusnimi'
Now when executing the state file echoing the variable in the target server it provides me the right output:
echo $uusnimi
Server1
but for the life of me I can't figure out how to escape the last line of the above code so it would insert the value not the '$uusnimi' string
Use uusnimi as a jinja variable.
{% set uusnimi = salt['cmd.shell']('cat /etc/osci') %}
/etc/zabbix_agentd.conf:
file.managed:
- source: salt://base/streamingconf/zabbix/zabbix_agentd.conf
- mode: 644
change_hostname_zabbix:
file.replace:
- name: /etc/zabbix_agentd.conf
- pattern: 'Hostname='
- repl: 'Hostname={{ uusnimi }}'

Resources