Ansible yaml anchors and jinja2 templating - ansible

how do I overwrite the disk attribute while also not hardcoding the number of disks?
This is what I want it (the tasks/main.yml of that role) to do, but it fails with an syntax error and also requires hardcoding the number of disks:
---
- name: anchors
when: false
debug:
new_disk:
- &new_disk
size_gb: 80
type: thin
datastore: '{{ item.datastore }}'
- name: Deploy usage001 vms
loop: '{{ vms.usage001 }}
vmware_guest:
disk:
- <<: *new_disk
- <<: *new_disk
'{{ item.disk[0] }}'
- <<: *new_disk
'{{ item.disk[1] }}
Where item looks like:
vms:
usage001:
disk:
- size_gb: 1000
- size_gb: 600
usage002:
(...)

The documentation for <<, the Merge Key Language Independent Type states:
The “<<” merge key is used to indicate that all the keys of one or more specified maps should be inserted into the current map.
But you specify the anchor new-disk on a sequence instead of map.
You probably want to do:
new_disk:
- &new_disk
size_gb: 80
type: thin
datastore: '{{ item.datastore }}'
You seem to want select size_gb: 1000 from your item, but as the quotes are outside of your jinja2 syntax the substitution, if it works, will result in:
- <<: *new_disk
'size_gb: 1000'
and for that to work it has to be:
- <<: *new_disk
size_gb: 1000
so make sure you get rid of those quotes.
The selection using item.disk[0] given your item seems strange as well, I would have expected something like item.vms.usage001.disk[0] but that might be my lack of jinja2 specific knowledge.

Related

Ansible Compare registered variables and set fact

I'm rather newish to ansible and podman, and don't have a full grasp of python. So, I came up to a bit of a block on how to gather a list of container images on a system, and remove them. However only remove the image if no running container is using that image.
My initial tasks, which does work, looks like this:
- name: Gather facts about all container images
containers.podman.podman_image_info:
register: image_info
- name: remove images no longer used
containers.podman.podman_image:
name: "{{ item.Id }}"
state: absent
loop: "{{ image_info.images }}"
loop_control:
label: "{{ item.Id }}"
ignore_errors: true
However, This is not perfect, as the task will fail once it gets to an image that is in use, this is why ignore_errors: true is set. I also do not want the large block of error output (about 200+ lines) this provides when it does fail. Overall this does what I intended it to.
My next step in this "evolution" of code is how to remove the large error output without using no_log: true or anything similar, if possible. My thought is to compare a list of the image IDs I'm all ready gathering, to that of the running containers images. I updated the code to gather information on the containers on the system.
- name: Gather facts about all container images
containers.podman.podman_image_info:
register: image_info
- name: gather container info
containers.podman.podman_container_info:
register: container_info
- name: remove images no longer used
containers.podman.podman_image:
name: "{{ item.Id }}"
state: absent
loop: "{{ image_info.images }}"
loop_control:
label: "{{ item.Id }}"
ignore_errors: true
Then debugging the output of the container_info variable I do see the image ID, which ends up something like container_info.containers[0].Image as a variable I can use. My thought now is that I can use this to remove the image IDs that are in use from the list of images I have.
Here is my block, I'm not sure how I can, create this new image list with the info I have. I know I'll have to use set_facts for this, but is it possible to loop though two different lists in a task? Or am I overthinking this and a simpler way exists that I'm not aware of. All I really want to do is avoid needing to use ignore_errors in my code.
Update:
I have setting the facts down. which looks like the following in my playbook:
- name: Setting facts for image IDs
set_fact:
image_id: "{{ image_info.images | json_query('[].Id') }}"
- name: Setting fact for Container image ID
set_fact:
container_id: "{{ container_info.containers | json_query('[].Image') }}"
This ends up giving me the following info when debuged.
TASK [docker-host : debug image_id] ***********************************************************************************************************************************************************************
ok: [dtest05] =>
image_id:
- 4bc0467496b6c7a60543069c570ef0e1be4565d25cb2bc7d524600a5fe0d3b8f
- c223664c734cbbc7213a4312af596b37a5bf5e55f93526bcb34e527efc9c4d5b
- dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6
- e911c149c0ca46a11a8b6eb604439e972685ec25abfde07eb1cdb272a9c0d1a9
- eb40451959b6c5f4aebb2b687a589a58370faab9b15faa43c0aea8d711155b9e
TASK [docker-host : debug container_id] *******************************************************************************************************************************************************************
ok: [dtest05] =>
container_id:
- dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6
I think I just need to set another fact that will remove duplicates.
Update2: Created another fact to "merge" the two other facts. Full playbook looks like this:
- name: Gather facts about all container images
containers.podman.podman_image_info:
register: image_info
- name: gather container info
containers.podman.podman_container_info:
register: container_info
- name: Setting Facts for Image IDs
set_fact:
image_id: "{{ image_info.images | json_query('[].Id') }}"
container_id: "{{ container_info.containers | json_query('[].Image') }}"
- name: Merging facts
set_fact:
merged_ids: "{{ image_id }} + {{ container_id }}"
Then the merged_id variable outputs the following:
merged_ids:
- 4bc0467496b6c7a60543069c570ef0e1be4565d25cb2bc7d524600a5fe0d3b8f
- c223664c734cbbc7213a4312af596b37a5bf5e55f93526bcb34e527efc9c4d5b
- dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6
- e911c149c0ca46a11a8b6eb604439e972685ec25abfde07eb1cdb272a9c0d1a9
- eb40451959b6c5f4aebb2b687a589a58370faab9b15faa43c0aea8d711155b9e
- dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6
I can see the duplicate IDs in the list. How do I remove the duplicate IDs from the merged_ids variable list?
There's a problem with your "Merging facts" tasks. You're not creating a merged list of values; you are in fact concatenating two strings. You want:
- name: Merging facts
set_fact:
merged_ids: "{{ image_id + container_id }}"
There is a unique filter you can use to unique-ify a list:
- name: Merging facts
set_fact:
merged_ids: "{{ image_id + container_id | unique }}"

Ansible loop with dict as ansible_loop_var key/value; error `argument 'release_values' is of type <class 'str'> and we were unable to convert to dict`

I'm trying to use the kubernetes.core.helm module in a loop with the following code:
- name: Install Helm charts
kubernetes.core.helm:
name: "{{ item.name }}"
chart_ref: "{{ item.ref }}"
namespace: apps
create_namespace: yes
wait: yes
kubeconfig: "{{ kubeconfig.path }}"
values: "{{ item.values | default(omit) }}"
loop:
- name: appA
ref: repo/appA
values:
installCRDs: true
- name: appB
ref: "https://<fqdn>/chart_appB.tgz"
- name: appC
ref: "https://<fqdn>/chart_appC.tgz"
I'm getting the error (on all 3 iterations):
argument 'release_values' is of type <class 'str'> and we were unable to convert to dict: dictionary requested, could not parse JSON or key=value.
How can I make this loop work with the values key passed as an actual dictionary?
I have tried all kinds of different jinja filters, or different syntax's, changed the name of the key values to another, but basically keep getting the same error.
EDIT:
I also tried removing default(omit) entirely in combination with the list below, but it made no difference.
[...]
loop:
- name: appA
ref: repo/appA
values:
installCRDs: true
- name: appB
ref: "https://<fqdn>/chart_appB.tgz"
values: ~
- name: appC
ref: "https://<fqdn>/chart_appC.tgz"
values: ~
Turns out it was a combination of wrong syntax of default(omit) and using a reserved keyword (.values being a shorthand for .values()).
Issue resolved :)

Deploying multiple VM's with different number of disk each VM's need's

I have playbook for deploying multiple VM's with multiple disk it's working fine..
But when I deploying multiple VM's with different number of disk each VM's need's in this situation I tried condition's in playbook but it's not working as I expected..
for example below is requirements
APP : 2 disk
DB: 3 disk
I'm passing through disk variables from my inventory files..
look like below
APP guest_disk1='100' guest_disk2='200'
DB guest_disk1='100' guest_disk2='200' guest_disk3='300'
I modified my playbook with when condition like these
vmware_guest:
....
name: '{{ inventory_hostname }}'
disk:
- size_gb: '{{ guest_disk1 }}'
type: thin
datastore: '{{ datastore1 }}'
when: '"APP or DB" in inventory_hostname'
- size_gb: '{{ guest_disk2 }}'
type: thin
datastore: '{{ datastore1 }}'
when: '"APP or DB" in inventory_hostname
- size_gb: '{{ guest_disk3 }}'
type: thin
datastore: '{{ datastore1 }}'
when: '"DB" in inventory_hostname'
When I ran the playbook got below error msg
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: No JSON object could be decoded
Syntax Error while loading YAML.
did not find expected key
The error appears to be in '/opt/myagent/avi/ansible/ansible-deploy-vmware-vm2/roles/vm/tasks/main.yml': line 44, column 13, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
when: '"APP or DB" in inventory_hostname'
- size_gb: '{{ guest_disk2 }}'
^ 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 }}"
I tired this condition in disk task itself but it's still same error
vmware_guest:
....
name: '{{ inventory_hostname }}'
disk:
- size_gb: '{{ guest_disk1 }}'
type: thin
datastore: '{{ datastore1 }}'
when: '"APP or DB" in inventory_hostname'
- size_gb: '{{ guest_disk2 }}'
type: thin
datastore: '{{ datastore1 }}'
when: '"APP or DB" in inventory_hostname'
- size_gb: '{{ guest_disk3 }}'
type: thin
datastore: '{{ datastore1 }}'
when: '"DB" in inventory_hostname'
When I comment out the when condition in playbook it's deploying DB only. not APP it's failed with undefined variables for guest_disk3 because of in my inventory I didn't defined any variables for guest_disk3 for APP.. (I need 2 disk only for APP )
Thanks for advance
Your example is not a valid yaml/task/playbook sample. Moreover, your data structure is far from ideal to deal with this. Don't create independent vars, use lists. If you want to DRY and limit verbosity, you can apply override values to all disks if you always have the same options
All-in-one example inventory:
all:
vars:
datastore1: someds
disk_override_values:
type: thin
datastore: "{{ datastore1 }}"
guest_disks: "{{ disk_sizes | map('combine', disk_override_values) | list }}"
hosts:
app:
disks_sizes:
- size: 100
- size: 200
db:
disks_sizes:
- size: 100
- size: 200
- size: 300
Example task (didn't test the vmware tasks, I don't have an infra for that)
- name: create guest
vmware_guest:
name: '{{ inventory_hostname }}'
disk: "{{ guest_disk }}"
delegate_to: localhost

jinja variable substitution inside blockinfile module

I'm looking to use variables inside blockinfile block and so I made this playbook:
- name: New user
hosts: all
gather_facts: false
become: yes
become_user: root
vars:
nome_utente: pippo
dominio: pluto.it
gruppo: root
tasks:
- name: Add new user
blockinfile:
dest: /root/ansible/users.yml
backup: yes
block: |
'{{ nome_utente }}'#'{{ dominio }}':
gruppo: '{{ gruppo }}'
but I get the following error:
ERROR! Syntax Error while loading YAML.
found character that cannot start any token
The error appears to be in '/home/francesco/test.yml': line 16, column 27, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
block: |
'{{ nome_utente }}'#'{{ dominio }}':
^ 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 }}"
Sorry but I cannot find in any documentation if blockinfile supports jinja templating inside block module.
Do you have any ideas?
The indentation of the block is wrong. See examples and fix it
- name: Add new user
blockinfile:
dest: /root/ansible/users.yml
backup: yes
block: |
'{{ nome_utente }}'#'{{ dominio }}':
gruppo: '{{ gruppo }}'
See Popular Editors that support auto-indentation and syntax highlighting.

iterate over list of dictionaries within with_nested list

I have the following with_nested:
- name: Create solr schema for solr_cores
uri:
url: http://{{ cassandra_cluster_ips.split(',') | random }}:8983/solr/admin/cores?action={{ solr_core_action }}&core={{ item[1] }}.{{ item[0] }}
timeout: "{{ solr_create_timeout }}"
sudo: True
with_nested:
- "{{ solr_cores }}"
- "{{ client_names }}"
I want to change to my extra vars from:
#solr_cores: ['dom_chunk_meta', 'dom', 'tra_chunk_meta','tra','dom_difference_results','me_output']
#solr_core_action: "reload"
to:
solr_cores: [{‘dom_difference_results’:‘create’}, {‘dom’:‘reload’},
{‘tra’:‘reload’}, {‘me_output’:‘reload’}]
I looked at subelements, but don’t know how to pass it as a simple dictionary list so that I can set them into uri up to access it.
I am not 100% sure what you are trying to do but with_dict might be the one to use. If this doesn't work for you, comment and I will adjust the answer.
In your vars/inventory:
solr:
- name: core1
create_timeout: 30
action: reload
- name: core2
action: create
create_timeout: 60
In your playbook:
- name: Create solr schema for solr_cores
uri:
url: http://{{ cassandra_cluster_ips.split(',') | random }}:8983/solr/admin/cores?action={{ item.value.core_action }}&core={{ item.value.name }}.{{ item.value.other }}
timeout: "{{ item.value.create_timeout }}"
sudo: True
with_dict: "{{ solr }}"

Resources