Skip to content

Ansible Nested Loop with List and Dictionary

https://www.linkedin.com/in/gineesh/ https://twitter.com/GiniGangadharan

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.

Disclaimer: The views expressed and the content shared are those of the author and do not reflect the views of the author’s employer or techbeatly platform.


https://www.linkedin.com/in/gineesh/ https://twitter.com/GiniGangadharan
Gineesh Madapparambath is the founder of techbeatly and he is the author of the book - 𝗔𝗻𝘀𝗶𝗯𝗹𝗲 𝗳𝗼𝗿 𝗥𝗲𝗮𝗹-𝗟𝗶𝗳𝗲 𝗔𝘂𝘁𝗼𝗺𝗮𝘁𝗶𝗼𝗻. He has worked as a Systems Engineer, Automation Specialist, and content author. His primary focus is on Ansible Automation, Containerisation (OpenShift & Kubernetes), and Infrastructure as Code (Terraform). (aka Gini Gangadharan - iamgini.com)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.