automationansibledevopsansible-awx

How to use loop items or variable as the parameter key for a module in Ansible


I am writing a role to export configurations from Ansible AWX deployment. I want to loop over the items to export as follows. How is something like this possible?

- name: Export Config
  awx.awx.export:
    "{{ item }}": []
    controller_host: ...
    controller_username: ...
    controller_password: ...
  loop:
  - projects
  - inventory
  - applications
  - credentials 

Solution

  • Whereby it is possible to have dynamic or variable values, it is not possible to have tasks with dynamic parameter keys.

    Even using Templating (Jinja2) with import_tasks module – Import a task list, please take note about What's the difference between include_tasks and import_tasks?, such approach will run into errors.

    A minimal example

    dyn_task.yml

    - shell:
        "{{ parameter }}": "{{ value }}"
    

    main.yml

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        module: shell
        parameter: cmd
        value: exit 1
    
      tasks:
    
      - include_tasks: dyn_task.yml
    

    will result into an error and output of

    TASK [shell] *******************************************************************************************************************************
    fatal: [localhost]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (ansible.legacy.command) module: {{ parameter }}. Supported parameters include: warn, executable, chdir, strip_empty_ends, _raw_params, removes, argv, creates, _uses_shell, stdin_add_newline, stdin."}
    

    as the parameter became not resolved.


    It might be possible via

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        module: shell
        parameter: cmd
        value: exit 1
    
      tasks:
    
      - copy:
          dest: dyn_task.yml
          content: |
            - {{ module }}:
                {{ parameter}}: {{ value }}
    
      - include_tasks: dyn_task.yml
    

    resulting into an correct and expected output of

    TASK [shell] *******************************************************************************************************************************
    fatal: [localhost]: FAILED! => {"changed": true, "cmd": "exit 1", "delta": "0:00:00.010517", "end": "2023-12-14 10:00:00.715979", "msg": "non-zero return code", "rc": 1, "start": "2023-12-14 10:00:00.705462", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
    

    but I would consider this as very bad practice here in this case and recommend to use such not at all. See What are the uses of Self Modifying Code (SMC)?


    Summary

    How to use loop items or variable as the parameter key for a module in Ansible?

    To summarize the above description, either you can't or it is recommended not to do such.

    And for completeness

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        components:
          - projects
          - inventory
          - applicatitons
          - credentials
    
      tasks:
    
      - copy:
          dest: export_awx_{{ item }}.yml
          content: |
            - name: Export AWX Config
              awx.awx.export:
                {{ item }}: []
                controller_host: ...
                controller_username: ...
                controller_password: ...
        loop: "{{ components }}"
    
      - include_tasks: export_awx_{{ item }}.yml
        loop: "{{ components }}"
    

    whereby the dest path needs to be the path under in example /var/lib/awx/projects/.