Ansible 仅在文件存在时包含任务

Ansible include task only if file exists

我试图仅在文件存在的情况下包含该文件。如果我角色的用户需要,这允许在现有 "tasks/roles" 之间自定义 "tasks/roles"。我发现了这个:

- include: ...
  when: condition

但是 Ansible 文档指出:

"All the tasks get evaluated, but the conditional is applied to each and every task" - http://docs.ansible.com/playbooks_conditionals.html#applying-when-to-roles-and-includes

所以

- stat: path=/home/user/optional/file.yml
  register: optional_file
- include: /home/user/optional/file.yml
  when: optional_file.stat.exists

如果被包含的文件不存在,将会失败。我想可能还有另一种机制允许用户向现有食谱添加任务。我不能让用户在我的之后添加角色,因为他们无法控制顺序:他们的角色将在我的之后执行。

如果我没记错的话,即使 when 语句为假,你还想继续剧本吗?

如果是,请在when:

后添加这一行
ignore_errors: True

因此您的任务将如下所示:

- stat: path=/home/user/optional/file.yml
  register: optional_file
- include: /home/user/optional/file.yml
  when: optional_file.stat.exists
  ignore_errors: True

如果我正确理解您的问题,或者可以提供进一步帮助,请告诉我。谢谢

到目前为止我想出的最佳选择是:

- include: "{{ hook_variable | default(lookup('pipe', 'pwd') ~ '/hooks/empty.yml') }}"

它不完全是 "if-exists",但它为您角色的用户提供了相同的结果。在您的角色和一个默认的空文件中创建一些变量。 Jinja 过滤器 "default" 和 "lookup" 负责在未设置变量的情况下回退到空文件。

为方便起见,用户可以使用 {{ playbook_dir }} 变量来设置路径:

hook_variable: "{{ playbook_dir }}/hooks/tasks-file.yml" 

我可以在这里花时间了解 bash ansible 的错误处理规定,但简而言之,你是对的,由于所述原因,你不能将 stat 模块用于此目的。

对于大多数 ansible 问题,最简单的解决方案是在 ansible 之外进行。例如

- shell: test -f /home/user/optional/file.yml     # or use -r if you're too particular.
  register: optional_file
  failed_when: False
- include: /home/user/optional/file.yml
  when: optional_file.rc == 0
- debug: msg="/home/user/optional/file.yml did not exist and was not included"
  when: optional_file.rc != 0

* 添加 failed_when 以避免主机在文件不存在时被排除在进一步的任务之外。

我使用类似的东西,但用于文件模块,对我来说诀窍是检查变量定义,尝试类似的东西:

when: optional_file.stat.exists is defined and optional_file.stat.exists

只有当变量存在时,任务才会运行。

感谢大家的帮助!在今天的 Ansible 中终于尝试了所有回复和我自己的问题代码后,我正在回答我自己的问题:ansible 2.0.1.0

我的原始代码现在似乎可以工作了,除了我正在寻找的可选文件在我的本地机器上,所以我不得不 运行 stat through local_action 并为该特定任务设置 become: no,因此 ansible 不会尝试在我的本地机器上执行 sudo 并出现错误:"sudo: a password is required\n"

- local_action: stat path=/home/user/optional/file.yml
  register: optional_file
  become: no
- include: /home/user/optional/file.yml
  when: optional_file.stat.exists

with_first_found 条件可以在没有 statlocal_action 的情况下完成此操作。此条件将遍历本地文件列表并执行任务,并将 item 设置为第一个存在的文件的路径。 在 with_first_found 选项中包含 skip: true 将防止文件不存在时失败。

示例:

- hosts: localhost
  connection: local
  gather_facts: false

  tasks:
    - include: "{{ item }}"
      with_first_found:
        - files:
            - /home/user/optional/file.yml
          skip: true

使用 ansible-2.1.0,我可以在我的剧本中使用这样的片段:

- hosts: all
  gather_facts: false
  tasks:
    - name: Determine if local playbook exists
      local_action: stat path=local.yml
      register: st

- include: local.yml
  when: st.stat.exists

local.yml 不存在时,我没有得到 errors/failures,并且执行剧本(作为剧本,意味着它从 hosts: 行开始,等等)

您可以在任务级别执行相同的操作,而不是使用类似的代码。 使用 stat 似乎可以正常工作。

还可以选择为此使用 Jinja2 过滤器:

 - set_fact: optional_file="/home/user/optional/file.yml"

 - include: ....
   when: optional_file|exists

在 Ansible 2.5 及更高版本中,可以使用这样的测试来完成:

- include: /home/user/optional/file.yml
  when: "'/home/user/optional/file.yml' is file"

更多详情:https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html#testing-paths