Select with_items 以 Ansible 任务中的每个项目为条件?

Select with_items with conditional on each item in Ansible task?

我有一个需要根据群集位置 selected 的代理列表。例如,我的集群名称是 'abc' 和 'def'。集群上的所有节点都以集群名称开头(例如 abc1023.net 表示 abc 等)

我想 select 基于当前 inventory_hostname 的 pip 代理,并在参数中提供它。我尝试按照以下代码在地图中使用 with_items 和 'creating' 的 when 条件:

- name: run pip on proxy
  pip:
    name: <package_name>
    extra_args: "--proxy item.proxy"
  when: "item.when"
  with_items:
    - {proxy: 'http:abc_proxy:port', when: "'abc' in {{inventory_hostname|lower}}"}
    - {proxy: 'http:def_proxy:port', when: "'def' in {{inventory_hostname|lower}}"}

我面临的问题是这种情况总是被认为是正确的。我尝试将 when: "'abc' in {{inventory_hostname|lower}}" 替换为 when: false,这确实有效。也就是说,使它成为一个明确的 false 实际上 returns false 但当我检查字符串引号中的条件时却不是。我认为如果它包含任何值,则在地图内时被认为是真实的。

如何在 when 映射中明确检查此条件?删除引号无济于事,因为它会引发语法错误:

We could be wrong, but this one looks like it might be an issue
with missing quotes.  Always quote template expression brackets when
they start a value. For instance:

    with_items:
      - {{ foo }}

Should be written as:

    with_items:
      - "{{ foo }}"

exception type: <class 'yaml.parser.ParserError'> 

尝试了其他解决方案

  1. 在任务中添加了变量
- name: run pip on proxy
  vars:
    abc_status: "{{ true if 'abc' in {{inventory_hostname|lower}} else false }}"
    def_status: "{{ true if 'def' in {{inventory_hostname|lower}} else false }}"
  pip:
    name: <package_name>
    extra_args: "--proxy item.proxy"
  when: "item.when"
  with_items:
    - {proxy: 'http:abc_proxy:port', when: abc_status}
    - {proxy: 'http:def_proxy:port', when: def_status}

2.Added任务set_fact

- set_fact:
    abc_status: true
  when: inventory_hostname|lower is match('abc.*')

- set_fact:
    def_status: true
  when: inventory_hostname|lower is match('def.*')
  1. 测试了错误案例
    我在abc集群上通过以下方式测试了false case:
- name: run pip on proxy
  vars:
    abc_status: "{{ true if 'abc' in {{inventory_hostname|lower}} else false }}"
    def_status: "{{ true if 'def' in {{inventory_hostname|lower}} else false }}"
  pip:
    name: <package_name>
    extra_args: "--proxy item.proxy"
  when: "item.when"
  with_items:
    - {proxy: 'http:def_proxy:port', when: def_status}

这应该总是失败,因为代理以及 when 条件正在检查 def 集群,而它是 运行 在 abc 集群上。但我得到以下 Ansible 输出:

TASK [<project> : run pip on proxy] ************************************************
changed: [abc1023.net] => (item={u'when': u'def_status', u'proxy': u'http:def_proxy:port'})

这也是我使用其他尝试过的解决方案时总是得到的结果。

问题

即使尝试了上述不同的解决方案,when: "item.when" 始终 return 正确(即使它应该 return 错误)。我怎样才能解决这个问题?有没有更好的解决方案来实现我的用例? 为了完整起见,我使用的是 ansible 2.4.1.0.

TL;DR;

在这里,您试图评估 string "item.when" 是一个布尔值 true,因为它是一个非空的字符串将导致 true 语句。
删除 when 条件周围的双引号,您应该可以开始了。


你从 Ansible 得到的警告是关于 when 并且只有这个语句,它总是一个原始的 Jinja2 表达式。

This is easy to do in Ansible with the when clause, which contains a raw Jinja2 expression without double curly braces (see group_by – Create Ansible groups based on facts).

来源:https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#the-when-statement,强调,我的。

根据您的实际操作手册,可能的解决方案可能是:

- name: run pip on proxy
  pip:
    name: <package_name>
    extra_args: "--proxy {{ item.proxy }}"
  when: item.proxy_ref in inventory_hostname|lower
  with_items:
    - proxy: 'http:abc_proxy:port'
      proxy_ref: 'abc'
    - proxy: 'http:def_proxy:port'
      proxy_ref: 'def'

另一个可能是:

- name: run pip on proxy
  pip:
    name: <package_name>
    extra_args: "--proxy {{ item.proxy }}"
  when: item.when
  with_items:
    - proxy: 'http:abc_proxy:port'
      when: "{{ 'abc' in inventory_hostname|lower }}"
    - proxy: 'http:def_proxy:port'
      when: "{{ 'def' in inventory_hostname|lower }}"

所以,简而言之,在这里,你试图评估 string "item.when" 是一个布尔值,即 true,它是,因为,非空字符串将导致 true 语句。
删除 when 条件周围的双引号,您应该可以开始了。

PS:尽可能不要将 JSON 语法与 YAML 语法混合使用

Q: "Is there any better solution to implement my use case?"

A: 连接代理可能会更好。例如

- name: run pip on proxy
  pip:
    name: "{{ package_name }}"
    extra_args: "--proxy {{ my_proxy }}"
  vars:
    my_prefix: "{{ inventory_hostname[0:3] }}"
    my_proxy: "{{ 'http:' ~ my_prefix ~ '_proxy:port' }}"