Search code examples
loopstemplatesvariablesansiblejinja2

How can I make the email template show different variables results separated by loops?


The main problem is that when the playbook starts looping it only shows the last loops api "Lun_name" results and it doesn't show the looped in results before it.

This gets the names and variables of the array and passes through the playbook.

- name: luns report
  include_tasks:  api.yml
  loop: "{{ array_lookup_list | selectattr('name') }}"

Then it goes through the array host names and registers the response from the api.

api.yml

- name: access the Unity API
  uri:
    url: "https://{{ item.endpoint_host }}:443/api/types/lun/instances?"
    user: "{{ item.endpoint_user }}"
    password: "{{ item.endpoint_pass }}"
    body_format: json
    method: GET
    force_basic_auth: true
    validate_certs: false
    headers:
      Accept: application/json
      Content-Type: application/json
      X-EMC-REST-CLIENT: true
  register: api_result

- name: Lun Name
  set_fact:
    lun_name: "{{ api_result | json_query(jmesquery) }}"
  vars:
    jmesquery: '*.entries[].content.name'

Then it goes through this template to email.

template

<body>

        <div class="instructions">
            List of unassigned LUNs from named arrays:
        </div>
    {% for name in array_lookup_list | selectattr('name') %}
        <h3>  </h3>

        <table width="80%" class="dataframe">
        <thead>
            <tr>
              <!-- shows the array name it came from -->
                <th width="20%"> {{ name.name }} </th>


            </tr>
        </thead>
        <tbody>

            <tr>

                <td>
                <!-- shows the lun name -->
                {{ lun_name }} </br>

                </td>

            </tr>

        </tbody>
        </table>
    {% endfor %}
</body>

And it shows this result in the email:

enter image description here

I was expecting it to show different lun names from each array but only shows the last array lun name.


Solution

  • Please note that without a proper minimal reproducible example to test against, the below might suffer from slight errors that would not match your exact data structure, might not lead to the exact desired result, and could produce errors you will have to fix in your environment


    The global problem is that you are not looping at the correct level and that you are incorrectly using set_fact (which is actually unneeded in this specific case).

    To understand the below, you probaby want to read (at least) Registering variables with loop

    Below is one possible solution which can be adapted to better suit your requirements.

    1. Don't loop over your api.yml file, include it just once. Pass the list of names to the included file as a var
      - name: luns report
        include_tasks:  api.yml
        vars:
          lookup_names: "{{ array_lookup_list | selectattr('name') }}"
      
    2. Modify the api.yml included file as follows:
       - name: access the Unity API
         uri:
           url: "https://{{ item.endpoint_host }}:443/api/types/lun/instances?"
           user: "{{ item.endpoint_user }}"
           password: "{{ item.endpoint_pass }}"
           body_format: json
           method: GET
           force_basic_auth: true
           validate_certs: false
           headers:
             Accept: application/json
             Content-Type: application/json
             X-EMC-REST-CLIENT: true
         register: lun_lookup
         loop: "{{ lookup_names }}"
      
    3. Modify the email template as follow (truncated to only need changed lines)
      <body>
          <div class="instructions">
              List of unassigned LUNs from named arrays:
          </div>
          {% for lun_info in lun_lookup.results %}
          {% set array_name = lun_info.item %}
          {% set lun_names = lun_info | json_query('*.entries[].content.name') %}
          <table width="80%" class="dataframe">
              <thead>
                  <tr>
                      <!-- shows the array name it came from -->
                      <th width="20%"> {{ array_name}} </th>
                  </tr>
              </thead>
              <tbody>
                  <tr>
                      <td>
                          <!-- shows the lun names as list dumped to a string -->
                          {{ lun_names }} </br>
                      </td>
                  </tr>
              </tbody>
          </table>
          {% endfor %}
      </body>