【问题标题】:Ansible Making json_query / loop conditional with a when clauseAnsible 使用 when 子句使 json_query / 循环成为条件
【发布时间】:2021-04-02 19:58:05
【问题描述】:

我有一些涉及 json_query 的 ansible 代码在我试图使其成为条件的循环中。但我认为对于 when 子句和循环,我有些不理解。

下面的代码工作正常,当条件满足时(IaC.status == 400),问题是当条件不满足时,第二个任务仍然运行,循环尝试处理IaC2,它没有' t 存在,并且任务失败:"Invalid data passed to 'loop', it requires a list, got this instead:

我认为这实际上是条件语句和循环的预期行为:(https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#using-conditionals-in-loops),但描述的跳过整个任务的解决方案是使用空迭代器,但我不知道如何将它与json_query() 语句。

有谁知道我如何才能真正使下面的第二个任务有条件?

    # The preceding code has made a RESTful API call to create a gitlab group, if the group
    # exists the return status is 400, so I need to look it up instead. In which case the
    # following code works fine. The problem is when IaC.status = 201 for some reason the loop 
    # in the 2nd task below tries to run, despite the when clause, and fails 
    # because the variable IaC2 doesn't exist
    - name: or if IaC already exists
      when: IaC.status == 400
      uri: 
        url: https://{{new_hostname}}/api/v4/groups
        method: GET
        headers: 
          Authorization: "Bearer {{token.json.access_token}}"
        body_format: json
        body:
          name: "IaC"
          top_level_only: true
        status_code: 200 
        validate_certs: yes
      register:  IaC2

    - name: json_query to find the IaC group id when status = "{{IaC.status}}"
      when: IaC.status == 400
      debug:
        var: item
      loop: "{{ IaC2 | community.general.json_query(jmesquery) }}"
      vars:
        jmesquery: "json[?name=='IaC'].id"
      register: group_id

【问题讨论】:

  • 无论何时条件是什么,您的循环子句都将始终被解释。此外,即使总是错误的,每次迭代都会测试条件。我怀疑 IaC2 不存在,因为它是一个寄存器。虽然它可能是空的(调试会非常有帮助)。您可以通过在 IaC2 为空或为空时为其分配一个默认的空列表值 ([]) 来解决此问题,以便您的循环表达式返回一个空列表。请参阅default 过滤器及其第二个可选参数 (true)

标签: json loops ansible conditional-statements


【解决方案1】:

你应该以第一个任务为条件你的第二个任务:

- name: json_query to find the IaC group id when status = "{{IaC.status}}"
  when: IaC2 is defined
  debug:
    var: item
  loop: "{{ IaC2 | community.general.json_query(jmesquery) }}"
  vars:
    jmesquery: "json[?name=='IaC'].id"
  register: group_id

我无法在按预期跳过任务的 ansible 2.9.10 上重现您的案例。但是您也可以帮助默认设置。我想这会起作用:

- name: json_query to find the IaC group id when status = "{{IaC.status}}"
  when: IaC2 is defined
  debug:
    var: item
  loop: "{{ IaC2 | community.general.json_query(jmesquery) | default([]) }}"
  vars:
    jmesquery: "json[?name=='IaC'].id"
  register: group_id

【讨论】:

  • 嗨,恐怕这两个都不起作用。一个问题是寄存器变量总是被创建,即使创建它的任务被跳过。如果这有所作为,我正在使用 ansible 2.10.4。
  • 这不起作用,因为正如 OP 的评论中所指出的,IaC2 将始终被定义:无论任务成功、失败还是跳过,都存在一个寄存器。它只是不包含相同的信息 => when: IaC2 is succeededdocs.ansible.com/ansible/latest/user_guide/…
  • 目标是避免“var not defined”错误。这仍然是同样的错误吗?你能用 -vv 发布 ansible-playbook 的输出吗?
【解决方案2】:

我有各种各样的答案。首先有两件事我没有完全理解;

  • register var (IaC2) 始终被创建,即使 uri 任务被跳过。并且 IaC2 具有完全不同的结构,具体取决于该任务是执行还是跳过。
  • 后面的任务中的循环总是被执行,所以第二个任务的when子句毫无意义。

实际问题是 jmesquery 寻找具有特定 json 结构的 IaC2 变量,而在跳过 uri 任务的情况下它没有。

因此,似乎可行的解决方案是检查uri 任务是否被跳过(when: IaC2.skipped is defined),如果它被跳过,则以不会破坏的空列表形式重新定义IaC2循环。

代码示例如下所示。

所以,它有效,但我不禁想到必须有更简单的方法来做到这一点?

    - name: If IaC already exists (IaC.status == 400) then get the list of existing groups.
      when: IaC.status == 400
      uri: 
        url: https://{{new_hostname}}/api/v4/groups
        method: GET
        headers: 
          Authorization: "Bearer {{token.json.access_token}}"
        body_format: json
        body:
          name: "IaC"
          top_level_only: true
        status_code: 200 
        validate_certs: no
      register:  IaC2


    # To avoid breaking the following loop that searches the groups in the case that 
    # the group was created, re-define IaC2 into a form that won't break it.
    - name: Not created group "IaC", so redefine IaC2 var so as not to break the following loop
      when: IaC2.skipped is defined
      set_fact:
        IaC2: '{{ {"json": []} }}'

    - name: json_query to find the IaC group id when status = "{{IaC.status}}"
      #when: IaC.status == 400 << Leave in or comment out, makes no difference
      debug:
        var: item
      loop: "{{ (IaC2 | community.general.json_query(jmesquery)) }}"
      vars:
        jmesquery: "json[?name=='IaC'].id"
      register: group_id
    
    - name: record the IaC group's id (400)
      when: IaC.status == 400      
      set_fact:
        IaC_group_id: "{{group_id.results[0].item}}"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 1970-01-01
    • 2017-11-11
    • 1970-01-01
    相关资源
    最近更新 更多