Ansible Nested Loop with List and Dictionary
- Most Demanding DevOps Skills You Should Learn in 2021 - February 2, 2021
- System Reboot with Ansible Reboot Module - January 18, 2021
- How To Get Hands-On Experience in AWS - January 4, 2021
Ansible loops are simple and powerful with mixed data. You will sure say “awesome” when you realize the easiness with loops.
During our technical discussions, we came across a use case for nested loops inside a playbook. Nested loops are easy but we need to be careful when we need some paired values inside the loop.
In below example, user want to update windows registry; 4 values per each port.
HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\<YOUR_PROTOCOL>\<SERVER_OR_CLIENT> -Name <Enabled_OR_DisabledByDefault> -Value <0_or_1> -Type DWord
So the protocol, server/client, Enable/DesabledByDefault and Value will be changed in loops. Let’s say if we have 3 protocols to be changed,
Lets create variables for the same.
protocol:
- 'PCT 1.0'
- 'SSL 2.0'
- 'SSL 3.0'
srvtype:
- 'Server'
- 'Client'
Since, Enable/DesabledByDefault coming with value pair, we will put into a dictionary as below.
regname:
- myname: 'Enabled'
type:
- name: 'Enabled'
value: 0
- myname: 'DisabledByDefault'
type:
- name: 'DisabledByDefault'
value: 1
Before I execute, I just want to print the value and see if its working correctly. For that purpose I have created a task with debug module as below.
tasks:
- name: check loop1
debug:
msg: 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols{{item[0]}}{{item[1]}} -Name {{ item[2]["myname"] }} -Value {{ item.2.type.0.value }} -Type DWord'
with_nested:
- '{{ protocol }}'
- '{{ srvtype }}'
- '{{ regname }}'
I have just run it to see the output.
$ ansible-playbook usecase-nested-loop-with-dictionary.yml
PLAY [nested] *
TASK [check loop1] ****
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Server -Name Enabled -Value 0 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Server -Name DisabledByDefault -Value 1 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Client -Name Enabled -Value 0 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Client -Name DisabledByDefault -Value 1 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server -Name Enabled -Value 0 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server -Name DisabledByDefault -Value 1 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client -Name Enabled -Value 0 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client -Name DisabledByDefault -Value 1 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server -Name Enabled -Value 0 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server -Name DisabledByDefault -Value 1 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client -Name Enabled -Value 0 -Type DWord"
}
ok: [localhost] => (item=None) => {
"msg": "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client -Name DisabledByDefault -Value 1 -Type DWord"
}
PLAY RECAP
localhost : ok=1 changed=0 unreachable=0 failed=0
Let’s create the actual task with win_regedit module to update registry.
- name: Update Windows Reg
win_regedit:
path: 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols{{item[0]}}{{item[1]}}'
name: '{{ item[2]["myname"] }}'
data: '{{ item.2.type.0.value }}'
type: dword
with_nested:
- '{{ protocol }}'
- '{{ srvtype }}'
- '{{ regname }}'
And here see my final playbook.
# Loop to get 3 protocols x 2 servertype x 2 Names&Value (12 combinations)
# We need 12 combinations but Name and Value are pairs, hence used a dictionary
- name: Loop to get 3 protocols x 2 servertype x 2 Names&Value (12 combinations)
hosts: winteldbservers
gather_facts: no
vars:
regname:
- myname: 'Enabled'
type:
- name: 'Enabled'
value: 0
- myname: 'DisabledByDefault'
type:
- name: 'DisabledByDefault'
value: 1
protocol:
- 'PCT 1.0'
- 'SSL 2.0'
- 'SSL 3.0'
srvtype:
- 'Server'
- 'Client'
tasks:
- name: check loop1
debug:
msg: 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols{{item[0]}}{{item[1]}} -Name {{ item[2]["myname"] }} -Value {{ item.2.type.0.value }} -Type DWord'
with_nested:
- '{{ protocol }}'
- '{{ srvtype }}'
- '{{ regname }}'
- name: Update Windows Reg
win_regedit:
path: 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols{{item[0]}}{{item[1]}}'
name: '{{ item[2]["myname"] }}'
data: '{{ item.2.type.0.value }}'
type: dword
with_nested:
- '{{ protocol }}'
- '{{ srvtype }}'
- '{{ regname }}'
You may move these variables to a variable file or create a role for the same for easy handling.
You may find the playbook here.