Creating dictionary with same values in all elements - ansible

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"
}
}

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: How to create nested dictionary using Jinja2

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

ansible-playbook when conditions on uri module

I have ansbile playbook code :
- name: Send file to server
uri:
url: "{{ url }}:{{ port }}/application/{{ item | basename }}"
method: POST
body: "{{ lookup('file','{{ item }}') }}"
force_basic_auth: yes
status_code: 201
body_format: json
with_fileglob: "{{ tmp_dir)_for_files }}/configs/*"
register: code_result
until: code_result.status == 201
retries: "{{ uri_retries }}"
delay: "{{ uri_delays }}"
What I need to achieve is that file will be uploaded to the sever only if the is not already there.
Here is my approach to this problem
- name: Get file from server
uri:
url: "{{ url }}:{{ port }}/application/{{ item | basename }}"
method: GET
body: "{{ lookup('file','{{ item }}') }}"
force_basic_auth: yes
status_code: 404
body_format: json
with_fileglob: "{{ tmp_dir }}/configs/*"
register: get_code_result
ignore_errors: true
- name: Send file to server
uri:
url: "{{ url }}:{{ port }}/application/{{ item.item | basename }}"
method: POST
body: "{{ lookup('file','{{ item.item }}') }}"
force_basic_auth: yes
status_code: 201
body_format: json
with_items:
- "{{ get_code_result.results }}"
when: item.status == 404
register: code_result
until: code_result.status == 201
retries: "{{ uri_retries }}"
delay: "{{ uri_delays }}"
It appears to be working

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