Jinja2 循环内的未定义变量 - 试图访问索引

Undefined variable inside Jinja2 loop - trying to access an index

我有一个主剧本,运行还有另外 3 个剧本作为我的用户终止流程的一部分。这是手册:

---
- name: "Playbook: Terminate user"
  hosts: localhost
  gather_facts: True

  roles:
   - { role: common, tags: ['always'] }
   - { role: terminate_user, tags: ['terminate_user', 'never'] }

- name: "Playbook: Terminate storage"
  hosts: storage
  gather_facts: False
  roles:
   - { role: terminate_storage, tags: ['terminate_storage', 'always'] }

- name: "Playbook: User environment"
  hosts: localhost
  gather_facts: False

  roles:
    - { role: common,
        tags: ['always'],
      }

    - { role: send_email,
        tags: ['send_email', 'always']
      }

我正在尝试在我的 send_email 剧本中打印出 storage 剧本的输出。它看起来像这样:

- name: Logical block of home-storage tasks
  block:
  - name: Check if home folder exists
    stat:
      path: "{{ hostvars[inventory_hostname].fspath }}/{{ username }}"
    register: home_dir_details

  - name: Move user home folder to terminated home folder
    command: mv {{ hostvars[inventory_hostname].fspath }}/{{ username }} "{{ hostvars[inventory_hostname].fspath }}/terminated/{{ username }}"
    when: home_dir_details.stat.exists
    register: storage_moved

  - name: Printing and debugging
    ansible.builtin.debug:
      msg: "{{ storage_moved }}"
  when: 
    - hostvars[inventory_hostname].fsname is search("home")

在电子邮件模板中,我正在打印 storage_moved 变量,如下所示:

{% for host in groups['storage'] %}
{{ hostvars[host]['storage_moved'] }}
{% endfor %}

输出看起来不错,这正是我在 playbook 中看到的 运行(第一个被故意跳过):

{'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False'} 
{'changed': True, 'end': '2021-10-21 12:47:13.363691', 'stdout': '', 'cmd': ['mv', '/path/user', '/path/terminated/user'], 'rc': 0, 'start': '2021-10-21 12:47:13.357842', 'stderr': '', 'delta': '0:00:00.005849', 'stdout_lines': [], 'stderr_lines': [], 'failed': False} 

在我的 storage 主机中,我只配置了 2 个服务器,所以打印 2 个字典看起来没问题。

我的问题是,当我尝试访问 cmd 变量时,我无法访问或不知道如何访问。例如,我认为这应该有效:

{% for host in groups['storage'] %}
{{ hostvars[host]['storage_moved'][loop.index] }}
{% endfor %}

我得到一个错误:"msg": "The task includes an option with an undefined variable. The error was: dict object has no element 1

所以我尝试了这样的事情:

{% for host in groups['storage'] %}
{{ hostvars[host]['storage_moved']['cmd'] }}
{% endfor %}

但效果不佳,出现以下错误:"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'cmd'

我不确定应该如何访问该变量。

抱歉,误读了您的问题。让我再试一次。 :) 在您的示例中,您提供以下内容:

{'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False'} 
{'changed': True, 'end': '2021-10-21 12:47:13.363691', 'stdout': '', 'cmd': ['mv', '/path/user', '/path/terminated/user'], 'rc': 0, 'start': '2021-10-21 12:47:13.357842', 'stderr': '', 'delta': '0:00:00.005849', 'stdout_lines': [], 'stderr_lines': [], 'failed': False}

您的第一个结果记录了一个跳过的任务,因此字典不包含 cmd 键。

试试改成这样:

{% for host in groups['storage'] %}
{{ hostvars[host]['storage_moved']['cmd'] | default('skipped') }}
{% endfor %}

default 过滤器将在指定变量未定义的情况下提供一个值。这会改善情况吗?

{'changed': False, 'skipped': True, 'skip_reason': 'Conditional result was False'} 
{'changed': True, 'end': '2021-10-21 12:47:13.363691', 'stdout': '', 'cmd': ['mv', '/path/user', '/path/terminated/user'], 'rc': 0, 'start': '2021-10-21 12:47:13.357842', 'stderr': '', 'delta': '0:00:00.005849', 'stdout_lines': [], 'stderr_lines': [], 'failed': False}

仔细查看示例循环中的第一个输出结果,即从跳过的任务返回的结果:您是否在任何地方看到 cmd 属性?那么,答案是:没有。所以你报告的错误实际上是预期的。

您需要管理您要查找的属性不存在的情况。一种简单的解决方案是提供默认值,但您可以根据自己的具体要求找到自己的默认值。

{% for host in groups['storage'] %}
{{ hostvars[host]['storage_moved']['cmd'] | default('No command was played') }}
{% endfor %}