Search code examples
ansibleincludejson-query

How to pass ansible_query results to an included_task


I wish to extract a virtual-machine name and os-type from a list in my vars/main.xml file. I wish to pass the virtual-machine name and os-type to an include-tasks file that has tasks to include vars from a vars file named <name.yml> and then include a task based upon the os-type.

I can succesfully extract a list of machine names and their associated os-types, but I don't know to pass them on and reference them in the included task file.

vars/main.yml

    vm_on_host:
      baseserver:
        - name: server1
          vm:
          - name: vm1
            os: fedora
        - name: server2
          vm:
          - name: vm2
            os: fedora
          - name: vm3
            os: ubuntu

tasks/yml

    - name: "Include createServer.yml"
      include_tasks: createServer.yml
      loop: "{{ vm_on_host | json_query(cs_query) }}"
      loop_control:
        loop_var: csVar
      vars:
        cs_query: "baseserver[?name=='server2'].vm[*].{name: name, os: os}"

tasks/createServer.yml

    - name: Inside createServer.yml
      debug:
        msg: "Inside createServer.yml"

    - name: Include vars for this server (name)
      include_vars: "{{ csVar }}.name"

    - name: Include tasks for this os (os)
      include_vars: "{{ csVar }}.os"
    

Results:

    TASK [masterConfig : Display name and os from server2] *************************************************************************************************
    ok: [localhost] => (item=[{'name': 'vm2', 'os': 'fedora'}, {'name': 'vm3', 'os': 
    'ubuntu'}]) => {
        "ansible_loop_var": "osVar",
        "osVar": [
            {
                "name": "vm2",
                "os": "fedora"
            },
            {
                "name": "vm3",
                "os": "ubuntu"
            }
        ]
    }

    TASK [masterConfig : Include createServer.yml] *********************************************************************************************************
    included: /home/jwhimpel/ansible/roles/masterConfig/tasks/createServer.yml for localhost

    TASK [masterConfig : Inside createServer.yml] **********************************************************************************************************
    ok: [localhost] => {
        "msg": "Inside createServer.yml"
    }

    TASK [masterConfig : Include vars for this server (name)] **********************************************************************************************
    fatal: [localhost]: FAILED! => {"ansible_facts": {}, "ansible_included_var_files": [], 
    "changed": false, "message": "Could not find or access '[{'name': 'vm2', 'os': 
    'fedora'}, {'name': 'vm3', 'os': 'ubuntu'}].name'\nSearched 
    in:\n\t/home/jwhimpel/ansible/roles/masterConfig/vars/[{'name': 'vm2', 'os': 'fedora'}, 
    {'name': 'vm3', 'os': 
    'ubuntu'}].name\n\t/home/jwhimpel/ansible/roles/masterConfig/[{'name': 'vm2', 'os': 
    'fedora'}, {'name': 'vm3', 'os': 
    'ubuntu'}].name\n\t/home/jwhimpel/ansible/roles/masterConfig/tasks/vars/[{'name': 'vm2', 
    'os': 'fedora'}, {'name': 'vm3', 'os': 
    'ubuntu'}].name\n\t/home/jwhimpel/ansible/roles/masterConfig/tasks/[{'name': 'vm2', 
    'os': 'fedora'}, {'name': 'vm3', 'os': 
    'ubuntu'}].name\n\t/home/jwhimpel/ansible/vars/[{'name': 'vm2', 'os': 'fedora'}, 
    {'name': 'vm3', 'os': 'ubuntu'}].name\n\t/home/jwhimpel/ansible/[{'name': 'vm2', 'os': 
    'fedora'}, {'name': 'vm3', 'os': 'ubuntu'}].name on the Ansible Controller.\nIf you are 
    using a module and expect the file to exist on the remote, see the remote_src option"}

I would like the logical result to be:

  1. import vars from vm2.yml
  2. execute tasks from fedora.yml
  3. import vars from vm3.yml
  4. execute tasks from ubuntu.yml

Any suggestions would be greatly appreciated.


Solution

  • Couple of things to be changed:

    • As seen from the error, json_query is returning a list of single item with two dicts and the loop is picking up the item and passing it to the includes task. Flattening returned list will give the dicts directly which can be looped through.
    • For including tasks, you need to use include_tasks.
    • Fix the reference to name and os attributes from csVar dict.
    • Add .yml extension to include .yml files (vars and tasks).

    tasks/main.yml

    - name: "Include createServer.yml"
      include_tasks: createServer.yml
      loop: "{{ vm_on_host | json_query(cs_query) | flatten }}"
      loop_control:
        loop_var: csVar
      vars:
        cs_query: "baseserver[?name=='server2'].vm[*].{name: name, os: os}"
    

    tasks/createServer.yml

    - name: Include vars for this server (name)
      include_vars: "{{ csVar.name }}.yml"
    
    - name: Include tasks for this os (os)
      include_tasks: "{{ csVar.os }}.yml"
    

    Finally, put the corresponding files under vars/ and tasks/ directories.

    vars/
    ├── main.yml
    ├── vm2.yml
    └── vm3.yml
    
    tasks/
    ├── createServer.yml
    ├── fedora.yml
    ├── main.yml
    └── ubuntu.yml