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.
Related
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?
In Ansible I've used register to save the results of a task in the variable services.
It has this structure:
"stdout_lines": [
"arp-ethers.service \u001b[1;31mdisabled\u001b[0m",
"auditd.service \u001b[1;32menabled \u001b[0m",
"autovt#.service \u001b[1;31mdisabled\u001b[0m",
"blk-availability.service \u001b[1;31mdisabled\u001b[0m"]
and I would like to receive this:
{
"arp-ethers.service": "disabled",
"auditd.service": "enabled",
"autovt#.service": "disabled",
"blk-availability.service":"disabled"
}
I'd like to use a subsequent set_fact task to generate a new variable with a dictionary, but I'm going round in circles with no luck so far.
- name: Collect all services for SYSTEMD
raw: systemctl list-unit-files --type=service --no-pager -l --no-legend`
register: services
changed_when: false
- debug:
var: services
- debug:
msg: "{{ item.split()[0]|to_json }} : {{ item.split()[1]|to_json }}"
with_items:
- "{{ services.stdout_lines }}"
- name: Populate fact list_services for SYSTEMD
set_fact:
cacheable: yes
list_services: "{{ list_services|default({}) | combine ( {item.split()[0]|to_json: item.split()[1]|to_json} ) }}"
with_items: "{{ services.stdout_lines }}"
This return :
FAILED! => {"msg": "|combine expects dictionaries, got u'arp-ethers.service \\x1b[1;31mdisabled\\x1b[0m\\r\\nauditd.service \\x1b[1;32menabled \\x1b[0m\\r\\nautovt#.service \\x1b[1;31mdisabled\\x1b[0m\\r\\nblk-availability.service \\x1b[1;31mdisabled\\x1b[0m\\r\\n'"}
What you want is to switch list-unit-files into json output using --output=json (yes, that's a link to the journalctl man page, because the systemctl one links there)
roughly like this, although I didn't test it:
- name: Collect all services for SYSTEMD
raw: systemctl --output=json list-unit-files --type=service
register: services_json
changed_when: false
- set_fact:
services: '{{ services_json.stdout | from_json }}'
Use service_facts. For example
- service_facts:
- set_fact:
dict_services: "{{ dict(ansible_facts.services|
dict2items|
json_query('[].[key, value.status]')) }}"
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 }}"
I have two files, one with 2 dict and another playbook that use those dict.
Vars file:
data: {path: ~/prod/iac/playbook/test.conf, conf: test2}
vagrant: {path: ~/prod/iac/playbook/test.conf/test2.conf, conf: test4}
and the playbook:
---
- hosts: localhost
tasks:
- name: Include var for nginx config
include_vars:
file: ~/prod/iac/playbook/vars.yml
name: conf_vars
- name: overide doc configuration
shell: echo "{{ item[path] }}" > test.conf
with_items: " {{ conf_vars }}"
My vars is correctly loaded but i can't get the dict value...
Any idea ?
conf_vars is a dictionary, with_items is to be used with lists.
You may want to use with_dict:
- name: overide doc configuration
shell: echo "{{ item.value[path] }}" > test.conf
with_dict: "{{ conf_vars }}"
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']