Search code examples
ansibleyamlansible-factsinfoblox

Ansible using a variables file for a loop instead of an explicit loop?


My ansible terminology is so bad that I can't Google a solution to this problem.

I have an infoblox setup that I want to build a series of network containers in. To do this I would normally use a with_items loop but its such a long series of containers that its starting to look silly and confusing.

Here is my current .yaml file config:

# cloud networks
---
- name: configure a network ipv4
  nios_network:
    network: "{{ item.network_container_cidr }}"
    comment: "{{ item.network_comment }}"
    state: present
    provider:
      host: "{{ infoblox_host }}"
      username: "{{ infoblox_username }}"
      password: "{{ infoblox_password }}"
  connection: local
  with_items:
  - { network_container_cidr: 10.195.1.0/24, network_comment: aws_testing_cidr }
  - { network_container_cidr: 10.4.0.0/16,   network_comment: gcp_testing_cidr }
  - { network_container_cidr: 10.192.96.0/20,   network_comment: Dev-VPC }
  - <dozens more cidr's and comments>

Instead of listing out potentially 50 sets of network addresses and comments, I'd like to move them into a variables file of some kind and just loop through the options.

Something like:

Network containers
--- 
- networks:
  network1:
    cidr: 10.195.1.0/24
    comment: aws_testing_vpc
  network2:
    cidr: 10.4.0.0/16
    comment: gcp_testing_cidr
  network3:
    cidr: 10.192.96.0/20
    comment: Dev-VPC
  etc...

And loop through that so my original code would look like:

---
- name: configure a network ipv4
  nios_network: #reference the networks somewhere
    network: "{{ item.network_container_cidr }}"
    comment: "{{ item.network_comment }}"
    state: present
    provider:
      host: "{{ infoblox_host }}"
      username: "{{ infoblox_username }}"
      password: "{{ infoblox_password }}"
  connection: local

Question

I can't figure out how to create a loop to use a variables file like I'm suggesting. How do I create a list of facts and have ansible loop through them to create containers without explicitly using a with_items loop?

Example of Vladimir Botka's solution

- hosts: localhost
  vars_files:
    - /<path to file>/networks.yaml
  tasks:
  - name: configure a network ipv4
    nios_network:
      network: "{{ item.value.cidr }}"
      container: true
      comment: "{{ item.value.comment }}"
      state: present
      provider:
        host: "{{ infoblox_host }}"
        username: "{{ infoblox_username }}"
        password: "{{ infoblox_password }}"
    connection: local
    loop: "{{ networks|dict2items }}"
    loop_control:
      label: "{{ item.key }}"

The .yaml file was exactly the same!


Solution

  • Given the file

    shell> cat networks.yml 
    networks:
      network1:
        cidr: 10.195.1.0/24
        comment: aws_testing_vpc
      network2:
        cidr: 10.4.0.0/16
        comment: gcp_testing_cidr
      network3:
        cidr: 10.192.96.0/20
        comment: Dev-VPC
    

    The play below

    - hosts: localhost
    
      vars_files:
    
        - networks.yml
    
      tasks:
    
        - debug:
            msg: |
              network: "{{ item.value.cidr }}"
              comment: "{{ item.value.comment }}"
          loop: "{{ networks|dict2items }}"
          loop_control:
            label: "{{ item.key }}"
    

    gives

    PLAY [localhost] ******************************************************************************
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => (item=network1) => 
      msg: |-
        network: "10.195.1.0/24"
        comment: "aws_testing_vpc"
    ok: [localhost] => (item=network2) => 
      msg: |-
        network: "10.4.0.0/16"
        comment: "gcp_testing_cidr"
    ok: [localhost] => (item=network3) => 
      msg: |-
        network: "10.192.96.0/20"
        comment: "Dev-VPC"
    
    PLAY RECAP ************************************************************************************
    localhost: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    

    You can use the file in the loop statement

          loop: "{{ (lookup('file', 'networks.yml')|from_yaml).networks|
                     dict2items }}"