Search code examples
dictionaryvariablesansible

Ansible how to create list of dictionary keys


I am probably missing something simple. I have the dictionary in vars.yml

    deploy_env:
      dev:
        schemas:
          year1:
            - main
            - custom
          year2:
            - main
            - custom
            - security
          year3:
            - main
            - custom

Then in my playbook.yml, I have something like

    - set_fact:
        years: "{{ deploy_env.dev.schemas }}"
    
    - name: Create schemas
      shell: "mysql ....params go here... {{ item }}"
      with_nested:
        - "{{ years }}"

The above works fine if schemas in vars.yml were a simple list ie:

    deploy_env:
      dev:
        schemas:
          - year1
          - year2
          - year3

But as soon as I add additional items under each year (making this a dictionary(?) I start getting errors on the line:

       - "{{ years }}

I basically want to populate {{ years }} with year1,year2,year3 values for this task.

I've looked at many examples but everything I looked at was soo complex and it was about how to create dictionaries which is not helpful.


Solution

  • It is possible to create a list of the dictionary's keys. For example,

        - set_fact:
            years: "{{ deploy_env.dev.schemas.keys()|list }}"
        - debug:
            var: item
          loop: "{{ years }}"
    

    gives (abridged)

        item: year1
        item: year2
        item: year3
    

    Note: The method key() is redundant in the above expression. By default, a dictionary conversion to a list returns the list of the dictionary's keys. For example, the below iteration gives the same result

          loop: "{{ deploy_env.dev.schemas | list }}"
    

    See: Python dictionary keys() Method


    List vs Dictionary

    Quoting from the question:

    "... I add additional items under each year (making this a dictionary(?) ..."

    Adding items doesn't change a list to a dictionary. A dash - in YAML introduces an item of a list.

    Example of a list:

        schemas:
          - year1
          - year2
          - year3
    

    Example of a list of hashes with single lists:

        schemas:
          - year1:
              - main
              - custom
          - year2:
              - main
              - custom
              - security
          - year3:
              - main
              - custom
    

    Example of a dictionary:

        schemas:
          year1:
            - main
            - custom
          year2:
            - main
            - custom
            - security
          year3:
            - main
            - custom
    

    Notes:

    • Some filters convert a dictionary when used as an argument where a list is expected, to the list of its keys. For example, the filter difference manipulates lists
        - debug:
            msg: "{{ deploy_env.dev.schemas|difference(['year2']) }}"
    

    gives

    msg:
      - year1
      - year3
    

    • Example of a complete playbook for testing
    - hosts: localhost
    
      vars:
    
        deploy_env:
          dev:
            schemas:
              year1: [main, custom]
              year2: [main, custom, security]
              year3: [main, custom]
    
      tasks:
    
        - set_fact:
            years: "{{ deploy_env.dev.schemas.keys()|list }}"
        - debug:
            var: item
          loop: "{{ years }}"
    
        - debug:
            msg: "{{ deploy_env.dev.schemas|difference(['year2']) }}"