Registered variable passed to set_fact not working with another set_fact using Jinja2 condions

I have a playbook that runs a task, registers a variable. Sets a fact from that registered variables output. It later imports a role, within that role it has another set_fact using JINJA2 conditions with a for loop over the fact set in the playbook. The issue is, it appears the JINJA2 templating is being compiled before the set_fact in the playbook takes place. If I set that fact variable manually or hard code it, it works just fine.

Is this a bug or unknown issue with JINJA2 templating?

playbook:

- hosts: all
  gather_facts: false
  pre_tasks:

    - name: Show Hostname
      ansible.windows.win_powershell:
        script: |
          $returnname = "$($env:ComputerName).$((Get-WMIObject Win32_ComputerSystem).Domain)"
          return $returnname
      register: dns_hostname

    - name: Set umpire_common_name
      ansible.builtin.set_fact:
        common_name: "{{ dns_hostname.output[0] | default(inventory_hostname) }}"

    - name: Set umpire_common_name
      ansible.builtin.set_fact:
        umpire_common_name: "{{ umpire_common_name | default([]) + [common_name] }}"

  roles:
    - { role: umpire, umpire_debug: true, umpire_create_cert: true, umpire_dry_run: true, umpire_pfx: true }

The set_fact from the task inside the umpire fole.

- name: Determine umpire commands
  ansible.builtin.set_fact:
    umpire_cmd: >-
      {%- set cmd_list = [] -%}
      {% if umpire_common_name is defined and variable|length > 0 %}
        {%- for cn in umpire_common_name -%}
        {%- if umpire_chain is defined and umpire_chain == true -%}{%- set chain_flag = '--include-ca-chain' -%}{%- else -%}{%- set chain_flag = '' -%}{%- endif -%}
        {%- if umpire_format is defined and umpire_format|length > 0 -%}{%- set format_flag = '-f={{ umpire_format }}' -%}{%- else -%}{%- set format_flag = '' -%}{%- endif -%}
        {%- set cmd_flags = format_flag ~ ' ' ~ chain_flag -%}
        {%- if umpire_dry_run is defined and umpire_dry_run -%}
          {%- set _ = cmd_list.extend(['cert_umpire universal certificates create {{ playbook_dir }}/' ~ cn ~ '.yml -a {{ playbook_dir }}/auth.yml -e {{ cert_umpire_domain }} ' ~ cmd_flags | trim ~ ' -d']) -%}
        {%- else -%}
          {%- set _ = cmd_list.extend(['cert_umpire universal certificates create {{ playbook_dir }}/' ~ cn ~ '.yml -a {{ playbook_dir }}/auth.yml -e {{ cert_umpire_domain }} ' ~ cmd_flags | trim]) -%}
        {% endif %}
        {%- endfor -%}
      {% endif %}
      {{ cmd_list }}

The issue is it doesn’t like the fact umpire_common_name is used in the template. If I hard code, or use umpire_common_name: ["{{ansible_inventory}}"] or set it in my inv file it works. It’s only when I try to set it through/after a regsitered var.

This isn’t really enough information to try to replicate your issue or explain what’s happening. At a minimum we need to see either the code you’re running or the output that results, preferably both.

Updated with some of the code.

What actual error do you get? I don’t see any way that it would complain about umpire_common_name, but right after that where you have variable|length > 0 is very suspect.

The issue isn’t that the set_fact is failing or erroring, its that it isn’t populating the variables. Even ones that are default like playbook_dir. That length > 0 guard was just added during testing, you can ignore it. It’s not in the original code.

The error happens when it goes to run the command that the set_fact is trying to generate.

failed: [node1.test.net -> localhost] (item=cert_umpire universal certificates create "{{ playbook_dir }}"/node1.test.net.yml -a "{{ playbook_dir }}"/auth.yml -e "{{ cert_umpire_domain }}"-f={{ umpire_format }} -d) => {
    "ansible_loop_var": "item",
    "changed": true,
    "cmd": [
        "cert_umpire",
        "universal",
        "certificates",
        "create",
        "{{ playbook_dir }}/node1.test.net.yml",
        "-a",
        "{{ playbook_dir }}/auth.yml",
        "-e",
        "{{ cert_umpire_domain }}-f={{",
        "umpire_format",
        "}}",
        "-d"
    ],
    "delta": "0:00:00.568428",
    "end": "2023-12-06 09:09:28.108163",
    "invocation": {
        "module_args": {
            "_raw_params": "cert_umpire universal certificates create \"{{ playbook_dir }}\"/node1.test.net.yml -a \"{{ playbook_dir }}\"/auth.yml -e \"{{ cert_umpire_domain }}\"-f={{ umpire_format }} -d",
            "_uses_shell": false,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true
        }
    },
    "item": "cert_umpire universal certificates create \"{{ playbook_dir }}\"/node1.test.net.yml -a \"{{ playbook_dir }}\"/auth.yml -e \"{{ cert_umpire_domain }}\"-f={{ umpire_format }} -d",
    "msg": "non-zero return code",
    "rc": 1,
    "start": "2023-12-06 09:09:27.539735",
    "stderr": "Expected '--environment' to be one of corporate, cernerasp, federal; got {{ cert_umpire_domain }}-f={{",
    "stderr_lines": [
        "Expected '--environment' to be one of corporate, cernerasp, federal; got {{ cert_umpire_domain }}-f={{"
    ],
    "stdout": "",
    "stdout_lines": []
}

The issue I’m seeing seems like this but I’m not sure how to get around it or if its possible. jinja2

You should not be nesting moustaches here. {{ }} never belongs inside other Jinja delimiters.

{%- set _ = cmd_list.extend(['cert_umpire universal certificates create ' ~ playbook_dir ~ '/' ~ cn ~ '.yml -a ' ~ playbook_dir ~ '/auth.yml -e ' ~ cert_umpire_domain ~ ' ' ~ cmd_flags | trim ~ ' -d']) -%}

1 Like

Thanks, I’ll give that a try.

That worked. Thanks for the help.