Ansible:- creating LVM with below yaml file - ansible

Below is the main yml file and further it's pointing to disks_config.yml and volumegroup.j2. when i'm playing this playbook, it's skipping below task which is "Print unique disks and volume group details".
Any leads?
name: Load the disk configuration settings
ansible.builtin.include_vars: disks_config.yml
- name:"Print unique disks and volume group details"
ansible.builtin.debug:
var:
- disktypes
- volume_groups
verbosity: 2
# CREATE VOLUME GROUPS BASED ON parameters.yaml
# -------------------------------------+---------------------------------------8
#
- name: "Volume Group creation"
ansible.builtin.lvg:
vg: "{{ ll }}"
pvs: "{{ item.pvs }}"
pesize: 4M
state: present
loop: "{{ volume_groups }}"
register: vgscreated
when:
- tier == "sapos"
- name: "Filter the vg name from vgscreated results"
ansible.builtin.set_fact:
vgcreatedlist: "{{ vgscreated | json_query('results[*].item.vg') }}"
# Debug for testing
- name: "Print vgcreated details"
ansible.builtin.debug:
var:
- vgcreatedlist
- logical_volumes
- vgscreated.results
verbosity: 2
# Debug testing end of line
======================================================================
disk_config.yml:-
disktypes: >-
{{ disks | selectattr('host', 'defined') |
selectattr('host', 'equalto', inventory_hostname) |
map(attribute='type') | sort | unique |
list }}
# Dynamically determine list of volume groups associated with
# the current node.
volume_groups: "{{ lookup ('template', 'volume_groups.j2') }}"
====================================================================
volume_groups.j2:-
{% set vgs = [] %}
{#
Outer Loop: Loop over disk types
#}
{% for disktype in disktypes %}
{% set pvlist = [] %}
{#
Initialise VG dictionary with VG name derived from disk type
#}
{% set vg = {'vg': 'vg_' ~ (disk_type_to_name_map[disktype] |
default(disktype))} %}
{#
Inner Loop: Loop over list of disks that match the execution host and the disk type
Note: '_' used as dummy variable that can be ignored
#}
{% for disk in disks if (disk.host == inventory_hostname) and (disk.type == disktype) %}
{% set _ = pvlist.append('/dev/disk/azure/scsi1/lun' ~ disk.LUN) %}
{% endfor %}
{#
Add list of pvs and diskcount to VG dictionary
Note: '_' used as dummy variable that can be ignored
#}
{% set _ = vg.update({'pvs': pvlist}) %}
{#
Append VG dictionary to list of VGs
Note: '_' used as dummy variable that can be ignored
#}
{% set _ = vgs.append(vg) %}
{% endfor %}
{#
Output List of Dictionaries
#}
{{ vgs }}
#when i'm running the main.yml file it's skipping the above tasks:-
#ASK [**roles-os/1.5-disk-setup** : Print unique disks and volume group details] #********************************************************************************
#Monday 04 October 2021 07:04:14 +0000 (0:00:00.085) 0:00:25.544 ********
#skipping: [vmsxxxxxxx1n1]
#skipping: [vmsxxxxxxx-n0]
#skipping: [vmsxxxxxxx00]
#skipping: [vmsxxxxxxx01]
#skipping: [vmsxxxxxxx02]
Below is the main yml file and further it's pointing to disks_config.yml and volumegroup.j2. when i'm playing this playbook, it's skipping below task which is "Print unique disks and volume group details".

Related

Ansible: how to get the calculated value of key "content" displayed into the playbook output

I am a beginner to ansible.
How can I get the content of the csv file printed in my shell?
I tryed to register the calculated value of content key and to display it via
- ansible.builtin.debug:
msg: "{{ csv_content }}"
in another task, but I cannot see it into my playbook output.
vars:
current_date: "{{ '%Y-%m-%d' | strftime }}"
tasks:
- name: Dump results to /tmp/myfile.csv
copy:
dest: /tmp/mycsv_{{ '%Y-%m-%d' | strftime }}.csv
content: |
{% for host in hosts_list %}
{% ---things--- %}
{% set idm=host.inventory_hostname.split('_')[0].split('-')[1] %}
{% set idm_padded = '%03d' % idm|int %}
{% ---things--- %}
{{ [idm_padded, --things-- ] | map('trim') | join(';') }}
{% --things--- %}
{% endfor %}
vars:
hosts_list: "{{ ansible_play_hosts | map('extract', hostvars) | list }}"
register: csv_content
run_once: yes
- ansible.builtin.debug:
msg: "{{ csv_content }}"
Rather than trying to get the content from the copy task, reverse your logic: render the content into a variable first, then use that variable as the argument to the content key in the copy task:
- hosts: localhost
gather_facts: false
tasks:
- set_fact:
csv_content: |
{% for host in hosts_list %}
{% set idm=2 %}
{% set idm_padded = '%03d' % idm|int %}
{{ [idm_padded, "things" ] | map('trim') | join(';') }}
{% endfor %}
vars:
hosts_list:
- foo
- bar
- baz
run_once: true
- debug:
msg: "{{ csv_content }}"
- name: Dump results to /tmp/myfile.csv
copy:
dest: mycsv_{{ '%Y-%m-%d' | strftime }}.csv
content: "{{ csv_content }}"
run_once: true

Problems with Jinja2 and ansible making a sub dict

I need to read a csv file with diferent IPs and make a dictionary with a jinja2 filter for modificate the IP depending the IPNumber value. The yml file is like:
- read_csv:
path: vms.csv
key: Number
fieldnames: Name,IP1,IP2,IP3,IP4,IPNumber
delimiter: ';'
register: vms
- name: vms to dict
debug:
msg:
- {{'Name':{{ item.value.Name }},
{% if item.value.IPNumber == "1" %}
'IP':{{ item.value.IP1 }},
{% endif %}
{% if item.value.IPNumber == "2"%}
'IP':{{ item.value.IP2 }},
{% endif %}
{% if item.value.IPNumber == "3"%}
'IP':{{ item.value.IP3 }},
{% endif %}
{% if item.value.IPNumber == "4"%}
'IP':{{ item.value.IP4 }},
{% endif %}}}
loop: "{{ vms.dict | dict2items }}"
register: vms2
But I get the error:
The error appears to be in '/etc/ansible/roles/vms.yml': line 17, column 16, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
'Name':{{ item.value.Name}},
{% if item.value.IPNumber == "1" %}
^ here
I know is a syntax problem but I dont guess where the problem is.
I need some help.
The following task should create your dictionary as per your requirement inside a var you can reuse elsewhere. Rename my_ip_dict to whatever suits your project better.
- name: Create my IP dictionary
set_fact:
my_ip_dict: >-
{{
my_ip_dict | default({})
| combine({item.value.Name: item.value['IP' + item.value.IPNumber]})
}}
loop: "{{ vms.dict | dict2items }}"
- name: Check the result:
debug:
var: my_ip_dict
Note that I have dropped all the if/else structures by calling directly the correct field depending on IPNumber. I took for granted it always has a value in the valid scope or the other existing IP* fields. If this is not the case, you can always default that value e.g. item.value['IP' + item.value.IPNumber] | default('N/A')
You should put only variables/expressions within {{ or {%. To me 'Name' looks like normal text and should be outside.
Example:
# Notice the quotes `"` symbol at the beginning and end of debug message
- debug:
msg:
- "Name: {{ item.value.Name }},
{% if item.value.IPNumber == "1" %}
IP: {{ item.value.IP1 }}
# and so on...
{% endif %}"
This at least should address the error message.

Ansible templates and jinja {%block%}

I need to generate a single file on the remote host using multiple template files and Jinja's {% block block_name %} in my Ansible role
For example,
main.conf.j2:
value1 = 123
value2 = 456
{% block test %} {% endblock %}
value3 = 789
{% block example %} {% endblock %}
value4 = abcd
test.conf.j2:
{% block test %}
more text here
{% endblock %}
example.conf.j2
{% block example %}
....
example_param = 'example!'
....
{% endblock %}
What's the next step? I must use {% extends 'nginx.conf.j2' %} in test.conf.j2 and example.conf.j2? And if so - how will look my Ansible task? Or even something else?
If I trying something like this:
- name: Copy config
template:
src: "{{ item }}"
dest: "{{ conf_file_path }}"
with_items:
- "main.conf.j2"
- "test.conf.j2"
- "example.conf.j2"
- "abcd.conf.j2"
it works only for main.conf.j2 and test.conf.j2, but ignores example.conf.j2 and other templates
Q: "What's the next step? I must use {% extends 'nginx.conf.j2' %} ... ?"
A: Yes. extends is needed. For example
- template:
src: test.j2
dest: test
with the templates
shell> cat main.j2
value1 = 123
{% block test %}
value = default value in main.j2
{% endblock %}
value3 = 789
shell> cat test.j2
{% extends 'main.j2' %}
{% block test %}
value = custom value in test.j2
{% endblock %}
gives
shell> cat test
value1 = 123
value = custom value in test.j2
value3 = 789
Q: "How will look my Ansible task?"
- name: Copy config
template:
src: "{{ item }}"
dest: "{{ conf_file_path }}"
with_items:
- "main.conf.j2"
- "test.conf.j2"
- "example.conf.j2"
- "abcd.conf.j2"
A: The loop will repeatedly overwrite the dest file in each iteration. See template.
FWIW. It's possible to use blockinfile and loop the lookup of the templates. For example
- template:
src: main2.j2
dest: test
- blockinfile:
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item }}"
path: test
block: "{{ lookup('template', item) }}"
loop:
- test.conf.j2
- example.conf.j2
with the templates
shell> cat main2.j2
value1 = 123
# BEGIN ANSIBLE MANAGED BLOCK test.conf.j2
value_test = default value in main2.j2
# END ANSIBLE MANAGED BLOCK test.conf.j2
# BEGIN ANSIBLE MANAGED BLOCK example.conf.j2
value_example = default value in main2.j2
# END ANSIBLE MANAGED BLOCK example.conf.j2
value3 = 789
shell> cat test.conf.j2
value_test = custom value in test.conf.j2
shell> cat example.conf.j2
value_example = custom value in example.conf.j2
give
shell> cat test
value1 = 123
# BEGIN ANSIBLE MANAGED BLOCK test.conf.j2
value_test = custom value in test.conf.j2
# END ANSIBLE MANAGED BLOCK test.conf.j2
# BEGIN ANSIBLE MANAGED BLOCK example.conf.j2
value_example = custom value in example.conf.j2
# END ANSIBLE MANAGED BLOCK example.conf.j2
value3 = 789

Creating a comma separated string from a dictionary in Ansible

I want to write an Ansible role to be able to alter a given Kafka topic. I am using a dictionary of key/value pairs.
The command module is then used to execute a Kafka script that take a string of comma separated values. For instance, use app_kafka_topic list:
---
app_kafka_topic:
cleanup.policy :
- "delete"
retention.ms :
- "146800000"
partitions :
- "6"
replication-factor :
- "2"
and create the string:
"cleanup.policy=delete,retention.ms=146800000,partitions=6,replication-factor=2"
This is what I have so far.
- name: Reading the Default Topic Properties
set_fact:
app_kafka_topic_properties_dicts: |
{% set res = [] -%}
{% for key in app_kafka_topic.keys() -%}
{% for value in app_kafka_topic[key] -%}
{% set ignored = res.extend([{'topic_property': key, 'value':value}]) -%}
{%- endfor %}
{%- endfor %}
{{ res }}
- name: Create Topic with Default Properties
command: "{{ kafka_bin_dir }}/{{ kafka_config_script }}
--zookeeper {{ prefix }}-kafka-{{ Kafka_node }}.{{ DNSDomain}}:{{ zookeeper_port }}
--entity-type topics
--alter
--entity-name {{ kafka_topic }}
--add-config
{{ properties }}"
with_items: "{{ app_kafka_topic_properties_dicts }}"
register: createdTopic
vars:
properties: |-
{% for key in app_kafka_topic.keys() %}
{% for value in app_kafka_topic[key] %}
"{{ key }}={{ value }}"
{%- endfor %}
{%- endfor %}
However, the properties variable is not concatenating the values to the end of a string. Is there a way to append the values to a string and separate them by a comma?
Is this the code that you're looking for?
play.yml
- hosts: localhost
gather_facts: no
vars:
string: ""
app_kafka_topic:
cleanup.policy :
- "delete"
retention_ms :
- "146800000"
partitions :
- "6"
replication_factor :
- "2"
tasks:
- set_fact:
string: "{{ string }}{{ (index > 0)|ternary(',','') }}{{ item.key }}={{ item.value[0] }}"
loop: "{{ app_kafka_topic|dict2items }}"
loop_control:
index_var: index
- debug:
var: string
$ ansible-playbook play.yml | grep string
"string": "retention_ms=146800000,cleanup.policy=delete,replication_factor=2,partitions=6"

Merge 2 groups in Ansible

I have 2 host groups in my inventory in ansible as follows:
[loadbalancer-add]
172.23.130.97
172.23.130.98
[loadbalancer-remove]
172.23.130.99
172.23.130.100
I would like to merge these groups to pass them to a loadbalancer API so I can add a server, then remove a server. So I need to merge the groups to create a group as follows:
[loadbalancer]
172.23.130.97
172.23.130.99
172.23.130.98
172.23.130.100
I have the following task but it is not producing the correct output
- name: Merge Dictionaries
gather_facts: false
hosts: localhost
become: true
no_log: false
tasks:
- add_host:
name: "{{ item }}"
ansible_ssh_port: 2020
action: remove
group: loadbalancer
with_items:
- "{{ groups['loadbalancer-remove'] }}"
- "{{ groups['loadbalancer-add'] }}"
delegate_to: localhost
This produces
[loadbalancer]
172.23.130.99
172.23.130.100
172.23.130.97
172.23.130.98
Is it possible to get the output that I require?
Thanks
May be this is what you need:
[loadbalancer-add]
172.23.130.97
172.23.130.98
[loadbalancer-remove]
172.23.130.99
172.23.130.100
[loadbalancer:children]
loadbalancer-remove
loadbalancer-add
So now you could reference as one group
groups['loadbalancer']*
.
I did manage to find a way of doing this. It may not be the best way but here is my solution anyway:
- name: Merge Dictionaries
gather_facts: false
hosts: localhost
no_log: false
vars:
merged_lb_hosts: |
{% if (groups['loadbalancer-add'] | length) >= (groups['loadbalancer-remove'] | length) %}
{% for i in range(0, groups['loadbalancer-add'] | length) -%}
{{ groups['loadbalancer-add'][i] | default('') }}:add|{{ groups['loadbalancer-remove'][i] | default('') }}:remove|
{%- endfor %}
{% else %}
{% for i in range(0, groups['loadbalancer-remove'] | length) -%}
{{ groups['loadbalancer-add'][i] | default('') }}:add|{{ groups['loadbalancer-remove'][i] | default('') }}:remove|
{%- endfor %}
{% endif %}
tasks:
- debug: msg="{{ merged_lb_hosts }}"
- add_host:
name: "{{ item.split(':')[0] }}"
action: "{{ item.split(':')[1] }}"
ansible_ssh_port: 2020
group: loadbalancer
with_items:
- "{{ (merged_lb_hosts | trim()).split('|') }}"
when: "{{item.split(':')[0] != ''}}"
This will take the add and remove groups and merge them into a var called merged_lb_hosts
The add_host task will split this var in it with_items section to create an iterable list.
It feels very hacky but it does the job that I was after

Resources