Score:0

Using a variable inside an Ansible loop

cn flag

I am trying to get data from json data (below) using a loop with a variable (instead of hard coding a value). In the json data (below), 'cluster' can change therefore I cannot simply use: loop: "{{ drs_rule_jsondata.drs_rule_info.cluster }}" -- which works as I expect it would and produces the expected results.

However, when I use the play below (using vars in the loop and when {{ cluster_info.name }} = cluster), I get "msg": "'dict object' has no attribute 'drs_rule_jsondata.drs_rule_info.cluster'". The confusing part is, it produces the same syntax as the one that works.... should using vars this way in the loop not work? Is there another way to get the expected results given the 'cluster' can change?

Play:

- name: Set drs rule info
  set_fact:
    drs_rule: "{{ drs_rule|default([]) + [ {
      'rule_name': item | json_query('rule_name'),
      'rule_affinity': item | json_query('rule_affinity'),
      'rule_vms': item | json_query('rule_vms[*]')
      } ] }}"
  vars:
    path: drs_rule_jsondata.drs_rule_info
    cluster_name: "{{ cluster_info.name }}"
  loop: "{{ vars[path + '.' + cluster_name] }}"

json data:

{
  "ansible_facts": {
    "drs_rule_jsondata": {
      "changed": false,
      "drs_rule_info": {
        "cluster": [
          {
            "rule_affinity": true,
            "rule_enabled": true,
            "rule_key": 1,
            "rule_mandatory": null,
            "rule_name": "DEMO_REP_DRS_1",
            "rule_type": "vm_vm_rule",
            "rule_uuid": "522d41eb-4acb-afbf-9f37-15a1651ccf45",
            "rule_vms": [
              "VM1",
              "VM2",
              "VM3",
              "VM4"
            ]

        ]
      },
      "failed": false
    }
  },
  "_ansible_no_log": false,
  "changed": false
}

Expected results:

{
  "drs_rule": [
    {
      "rule_name": "DEMO_REP_DRS_1",
      "rule_affinity": true,
      "rule_vms": [
        "VM1",
        "VM2",
        "VM3",
        "VM4"
      ]
    }
  ]
}
Score:0
cn flag

Here is what ultimately worked in the end (which I though I had already tried):

              set_fact:
                drs_rule: "{{ drs_rule|default([]) + [ {
                  'rule_name': item | json_query('rule_name'),
                  'rule_affinity': item | json_query('rule_affinity'),
                  'rule_vms': item | json_query('rule_vms[*]')
                  } ] }}"
              vars:
                cluster_name: "{{ cluster_info.name }}"
              loop: "{{ drs_rule_jsondata.drs_rule_info[cluster_name] }}"
Score:0
pt flag

This expression doesn't make sense:

vars[path + '.' + cluster_name]

Here you're asking for a variable with the literal name drs_rule_jsondata.drs_rule_info.<value of cluster_name>, but there is no such variable -- that's not even a valid variable name.

You don't need to use vars here in any case; you can just refer to the top-level dns_rule_jsondata variable directly.

It's also not clear why you're using json_query in your playbook, since you're only asking for individual, static keys.

I think what you're trying to do is this:

- hosts: localhost
  gather_facts: false
  vars:
    cluster_info:
      name: cluster
    drs_rule_jsondata:
      changed: false
      drs_rule_info:
        cluster:
          - rule_affinity: true
            rule_enabled: true
            rule_key: 1
            rule_mandatory: null
            rule_name: DEMO_REP_DRS_1
            rule_type: vm_vm_rule
            rule_uuid: 522d41eb-4acb-afbf-9f37-15a1651ccf45
            rule_vms:
              - VM1
              - VM2
              - VM3
              - VM4

  tasks:
  - name: Set drs rule info
    set_fact:
      drs_rule: >-
        {{
           drs_rule + [
             {
            'rule_name': item.rule_name,
            'rule_affinity': item.rule_affinity,
            'rule_vms': item.rule_vms
            }
          ]
        }}
    vars:
      drs_rule: []
      cluster_name: "{{ cluster_info.name }}"
    loop: "{{ drs_rule_jsondata.drs_rule_info[cluster_name] }}"

  - debug:
      var: drs_rule

Running the above playbook produces as output:


PLAY [localhost] ***************************************************************

TASK [Set drs rule info] *******************************************************
ok: [localhost] => (item={'rule_affinity': True, 'rule_enabled': True, 'rule_key': 1, 'rule_mandatory': None, 'rule_name': 'DEMO_REP_DRS_1', 'rule_type': 'vm_vm_rule', 'rule_uuid': '522d41eb-4acb-afbf-9f37-15a1651ccf45', 'rule_vms': ['VM1', 'VM2', 'VM3', 'VM4']})

TASK [debug] *******************************************************************
ok: [localhost] => {
    "drs_rule": [
        {
            "rule_affinity": true,
            "rule_name": "DEMO_REP_DRS_1",
            "rule_vms": [
                "VM1",
                "VM2",
                "VM3",
                "VM4"
            ]
        }
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
cn flag
Thanks for your help, larsks. Here is where I got the idea to try to use vars: https://stackoverflow.com/questions/29276198/ansible-how-to-construct-a-variable-from-another-variable-and-then-fetch-its-v. Using your playbook gave me: {"msg": "Unexpected templating type error occurred on ({{ drs_rule|default([]) + [ { 'rule_name': item.rule_name, 'rule_affinity': item.rule_affinity, 'rule_vms': item.rule_vms } ] }}): can only concatenate str (not \"list\") to str"}. And I don't uderstand the point of using drs_rules: []. Neverthless, I got there with your help so thank you.
pt flag
The point of setting `drs_rules: []` in the `vars:` section of the task is that it lets us drop the use of the `default` filter in `set_fact`. The playbook I've posted here runs without errors (and produces the output shown in the answer).
cn flag
Ah, kinda figured it was the same as using default in set_fact. And I'm going to guess why your playbook worked for you but not me, is because I am pulling from json and your vars are not json. Again, thanks for your help.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.