Ansible: How to create nested dictionary using Jinja2 - ansible

Here is the output.
"result.containers":[
{
"Image":"ca.docker/webproxy:1.0.0",
"Names":[
"/customer1"
]
},
{
"Image":"docker.local/egacustomer:1.0.1",
"Names":[
"/registrator"
]
}
]
I'm trying to get the following output using jinja2
"containerlist"=>{
"webproxy": {
"name": "customer1"
},
"egacustomer": {
"name": "registrator"
}
}
Here is my jinja2 code.
- set_fact:
containerlist: |
{
{% for item in result.containers %}
{{ item.Image.split('/')[-1].split(':')[0] | replace('\n', '') }}
name : {{ item.Names[0][1:] | replace('\n', '') }}
{% endfor %}
}
I get the below output.
"containerlist": "{\nwebproxy\n name : customer1\negacustome\n name : registrator\n}"
Could someone please help me get the desired output. Any help would be greatly appreciated

The data in YAML
result:
containers:
- Image: ca.docker/webproxy:1.0.0
Names:
- /customer1
- Image: docker.local/egacustomer:1.0.1
Names:
- /registrator
The tasks below
- set_fact:
containerlist: "{{ containerlist|default({})|
combine({key: {'name': name}}) }}"
loop: "{{ result.containers }}"
vars:
key: "{{ (item.Image.split(':')|first).split('/')|last }}"
name: "{{ item.Names[0][1:] }}"
- debug:
var: containerlist
give
containerlist:
egacustomer:
name: registrator
webproxy:
name: customer1
But, the result is not a list. It's a dictionary. If you want a list use this
- set_fact:
containerlist: "{{ containerlist|default([]) +
[{key: {'name': name}}] }}"
loop: "{{ result.containers }}"
vars:
key: "{{ (item.Image.split(':')|first).split('/')|last }}"
name: "{{ item.Names[0][1:] }}"
- debug:
var: containerlist
give
containerlist:
- webproxy:
name: customer1
- egacustomer:
name: registrator

Related

how to generate list arguments of ansible task with Jinja2 template?

ansible theforeman.foreman.content_view module has repositories arguments need to be used like this:
- name: "Create or update Fedora content view"
theforeman.foreman.content_view:
username: "admin"
password: "changeme"
server_url: "https://foreman.example.com"
name: "Fedora CV"
organization: "My Cool new Organization"
repositories:
- name: 'Fedora 26'
product: 'Fedora'
I need to generate it dynamically. tried to do like following:
- name: "Create or update content views"
theforeman.foreman.content_view:
username: "{{ foreman.user }}"
password: "{{ foreman.password }}"
server_url: "{{ foreman.url }}"
organization: "{{ org.name }}"
name: "{{ item.0.name }}_content"
repositories: |
- name: '{{ item.1.name }}'
product: "{{ item.0.name }}_repos"
loop: "{{ os|subelements('repos') }}"
loop_control:
label: "{{ item.0.name }}"
this also not worked
- name: "Create or update content views"
theforeman.foreman.content_view:
username: "{{ foreman.user }}"
password: "{{ foreman.password }}"
server_url: "{{ foreman.url }}"
organization: "{{ org.name }}"
name: "{{ item.0.name }}_content"
repositories: |
{% for n in item.0.name %}
- name: '{{ item.1.name }}'
product: "{{ item.0.name }}_repos"
{% endfor %}
loop: "{{ os|subelements('repos') }}"
loop_control:
label: "{{ item.0.name }}"
but it always overwrites previous one and last executed remains. Howcould we achive to generate repositories with loop?
example vars:
os:
- name: alma9
repos:
- name: "almalinux9_base_x86_64"
url: "https://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/"
gpg_key: "RPM-GPG-KEY-AlmaLinux9"
- name: "almalinux9_appstream_x86_64"
url: "https://repo.almalinux.org/almalinux/9/AppStream/x86_64/os/"
gpg_key: "RPM-GPG-KEY-AlmaLinux9"

check if all loop items have been skipped

Is there a way to check if all loop items from a previous step have been skipped?
I want to download the latest files from the GitHub API and compare them to the templated ones. Only the files that have changed will be commited as blobs. Based on the skipped property, I can check what needs to be included in the tree.
But how can I skip the Create tree action when all items in blobs have been skipped?
when: "not skipped(blobs)" in Create tree only for illustration purposes.
- name: Download current files
uri:
url: https://github.com/api/v3/repos{{ repository.path }}/contents{{ item.path }}
user: "{{ API_USER }}"
password: "{{ API_TOKEN }}"
force_basic_auth: yes
status_code: [ 200, 404 ]
register: current_files
loop:
- {path: "/.github/workflows/build.yml"}
- {path: "/.github/workflows/deploy-dev.yml"}
- {path: "/.github/workflows/deploy-int.yml"}
- {path: "/.github/workflows/deploy-prod.yml"}
- name: Commit file blob
uri:
url: https://github.com/api/v3/repos{{ repository.path }}/git/blobs
method: "POST"
user: "{{ API_USER }}"
password: "{{ API_TOKEN }}"
force_basic_auth: yes
body_format: json
status_code: [200, 201]
body: |
{
"encoding": "base64",
"content": "{{ lookup('template', item.src) | b64encode }}",
}
vars:
target_group: "{{ item.target_group }}"
service_deployment_env: "{{ item.service_deployment_env }}"
when: "(lookup('template', item.src) | b64encode) != current_files['results'][index]['json']['content'].replace('\n', '')"
register: blobs
loop:
- { src: 'build.yml.jinja2', dest: '.github/workflows/build.yml', service_deployment_env: '' }
- { src: 'deploy.yml.jinja2', dest: '.github/workflows/deploy-dev.yml', service_deployment_env: 'dev' }
- { src: 'deploy.yml.jinja2', dest: '.github/workflows/deploy-int.yml', service_deployment_env: 'int' }
- { src: 'deploy.yml.jinja2', dest: '.github/workflows/deploy-prod.yml', service_deployment_env: 'prod' }
loop_control:
index_var: index
- name: Create tree
uri:
url: https://github.com/api/v3/repos{{ repository.path }}/git/trees
method: "POST"
user: "{{ API_USER }}"
password: "{{ API_TOKEN }}"
force_basic_auth: yes
body_format: json
status_code: [200, 201]
body: "{{ lookup('template', 'create_tree_body.json.jinja2') }}"
when: "not skipped(blobs)" # HOW IS THIS POSSIBLE??
register: tree
Ok... this was too easy. Apparently, ansible resolves the blobs list by itself, so simply using
when: "blobs is not skipped"
works just fine.

Ansible: playbook to deploy VM (Linux and Windows)

I created this playbook to deploy new VM from template.
Now if I try to deploy a new Linux VM it works correctly, if I try to deploy a Windows WM I received this error:
TASK [Clone the template]
************************************************************************************************************************************* fatal: [localhost]: FAILED! => {"changed": false, "msg": "Failed to
create a virtual machine : A specified parameter was not correct:
spec.identity"}
This is my playbook:
...
- name: Clone the template
vmware_guest:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vsphere_pass_result.user_input }}"
validate_certs: False
name: "{{ vm_name }}"
template: "{{ template_name_sel[tmpl] }}"
datacenter: "{{ datacenter_name }}"
cluster: "{{ cluster_name }}"
folder: "/{{ host_location_sel[loc] }}/{{ vm_env_sel[env] }}"
datastore: "{{ vm_datastore_sel[dstg] }}"
guest_id: "{{ vm_name }}"
networks:
- name: "{{ vm_network_sel[vlan] }}"
ip: "{{ vm_ip_result.user_input }}"
netmask: "{{ vm_mask_result.user_input }}"
gateway: "{{ vm_gw_result.user_input }}"
type: static
dns_servers: "8.8.8.8"
customization:
autologon: yes
dns_servers:
- "{{ vm_dns1_result.user_input }}"
- "{{ vm_dns2_result.user_input }}"
hardware:
memory_mb: "{{ vm_ram_sel[ram] }}"
num_cpus: "{{ vm_cpu_result.user_input }}"
num_cpu_cores_per_socket: "{{ vm_core_result.user_input }}"
state: poweredon
wait_for_ip_address: yes
delegate_to: localhost
register: vm_info
- debug:
var: vm_info
Thanks for the support.

Creating dictionary with same values in all elements

I have dictionary like this:
abc:
xyz1:
url: "{{ url }}"
api_key: "{{ key }}"
xyz2:
url: "{{ url }}"
api_key: "{{ key }}"
xyz3:
url: "{{ url }}"
api_key: "{{ key }}"
I know that all xyz{number} have the same values in url and api_key and will have same values in the future.
I need this nested format, but what will be more elegant way to write this instead the way I did it (which will be quite long with few more elements)?
Create template
shell> cat myvars.yml.j2
abc:
{% for index in range(1, size+1) %}
xyz{{ index }}:
url: "{{ '{{' }} url {{ '}}' }}"
api_key: "{{ '{{' }} key {{ '}}' }}"
{% endfor %}
The playbook
- hosts: localhost
vars:
size: 3
key: mykey
url: myurl
tasks:
- template:
src: myvars.yml.j2
dest: myvars.yml
- include_vars: myvars.yml
- debug:
var: abc
will create file myvars.yml
shel> cat myvars.yml
abc:
xyz1:
url: "{{ url }}"
api_key: "{{ key }}"
xyz2:
url: "{{ url }}"
api_key: "{{ key }}"
xyz3:
url: "{{ url }}"
api_key: "{{ key }}"
and debug will display the included variable
"abc": {
"xyz1": {
"api_key": "mykey",
"url": "myurl"
},
"xyz2": {
"api_key": "mykey",
"url": "myurl"
},
"xyz3": {
"api_key": "mykey",
"url": "myurl"
}
}

Ansible: looping over with multiple {{ items }}

I have an inventory file with the following variables:
vpc_public_net1=["10.30.0.0/24","AZ=a"]
vpc_public_net2=["10.30.1.0/24","AZ=b"]
I can extract AZ value with "{{ item[1].split('=')[1] }}"
I'm having difficulties extracting both subnet and AZ using the same
ansible task
my Ansible code:
- name: Create Public Subnets
ec2_vpc_subnet: state="present"
vpc_id="{{ vpc_id }}"
cidr="{{ item.subnet }}"
az="{{ item.az }}"
region="{{ aws_region }}"
aws_access_key="{{ aws_access_key }}"
aws_secret_key="{{ aws_secret_key }}
Redefine as a dictionary:
vpc_public_net1='{"subnet": "10.30.0.0/24", "az": "a"}'
vpc_public_net2='{"subnet": "10.30.1.0/24", "az": "b"}'
and:
- name: Create Public Subnets
ec2_vpc_subnet:
state: present
vpc_id: "{{ vpc_id }}"
cidr: "{{ item.subnet }}"
az: "{{ item.az }}"
region: "{{ aws_region }}"
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
with_items:
- "{{ vpc_public_net1 }}"
- "{{ vpc_public_net2 }}"

Resources