Site icon techbeatly

Ansible Nested Loop with List and Dictionary

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.

Exit mobile version