【问题标题】:how to iterate over list from json in ansible如何在ansible中从json迭代列表
【发布时间】:2020-10-07 08:27:01
【问题描述】:

我尝试将输出注册到一个变量,但我无法按照我想要的方式过滤。

输出:

oc get hpa -o json |jq -r '.items[].spec'
    {
      "maxReplicas": 3,
      "minReplicas": 1,
      "scaleTargetRef": {
        "apiVersion": "apps.openshift.io/v1",
        "kind": "DeploymentConfig",
        "name": "hello-openshift"
      },
      "targetCPUUtilizationPercentage": 70
    }
    {
      "maxReplicas": 4,
      "minReplicas": 2,
      "scaleTargetRef": {
        "apiVersion": "apps/v1",
        "kind": "Deployment",
        "name": "testrhel"
      },
      "targetCPUUtilizationPercentage": 79
    }

将输出注册到变量

- name: check for existing
  shell: oc get hpa -o json |jq -r '.items[].spec'
  register: existing

我想循环 output.name 并将其与另一个变量进行比较。

- name: set_fact
  exist: {% if item.name == newvar and item.kind == newvar2 %}yes{%else%}no{%endif%}
  loop:
    - "{{ existing }}" 

- name: task
  shell: do something
  when: exist == yes

提前致谢。

编辑: 目前我正在使用下面来比较变量。

- name: Get existing hpa output
  shell: oc get hpa -o json -n {{ namespace }} |jq -r '.'
  register: tempvar
      
- name: set hpa variable to fact
  set_fact:
  existing_deploy: "{{ tempvar.stdout}}"

- name: Comparing existing hpa to new config
  set_fact:
    hpa_exist: "{% if deploy_type == item.spec.scaleTargetRef.kind|lower and deploy_name == item.spec.scaleTargetRef.name|lower %}yes{% else %}no{% endif %}"
  with_items:
    - "{{ existing_deploy['items'] }}"

但是当我尝试使用条件时变量被覆盖

- name: task a
  include_tasks: a.yml
  when: hpa_exist
    
- name: task b
  include_tasks: b.yml
  when: not hpa_exist

deploymentconfig/hello-openshift 条件总是失败,即使它是真的。导致执行任务 b,这是不应该的

【问题讨论】:

  • 您是否调试了existing 的内容以查看其确切的结构/内容,然后尝试相应地使用它?提示:由于您是从 shell 注册的,它将包含一个 existing.stdout 条目,其中可能包含您要查找的确切数据。提示 2:ansible 有一个 from_json 过滤器来解析 json 的文本表示。提示 3:您的实际输出不是有效的 json。

标签: json loops ansible


【解决方案1】:

查看shell 模块的documentation
stdout 上的 shell 的输出将在 <var>.stdout 中(因此在您的情况下为 existing.stdout。)

一旦你得到它,你显然有json 作为文本,但你想解析它。为此,请使用from_json 过滤器,如this answer 所示。

总结你的任务应该是这样的:

- name: set_fact
  set_fact:
    exist: {% if item['scaleTargetRef']['name'] == newvar and item['scaleTargetRef']['kind']  == newvar2 %}yes{% else %}no{% endif %}
  loop: "{{ existing.stdout | from_json}}" 

但是你的输出需要是一个有效的列表,所以基本上,它需要看起来像这样:

    [{
      "maxReplicas": 3,
      "minReplicas": 1,
      "scaleTargetRef": {
        "apiVersion": "apps.openshift.io/v1",
        "kind": "DeploymentConfig",
        "name": "hello-openshift"
      },
      "targetCPUUtilizationPercentage": 70
    },
    {
      "maxReplicas": 4,
      "minReplicas": 2,
      "scaleTargetRef": {
        "apiVersion": "apps/v1",
        "kind": "Deployment",
        "name": "testrhel"
      },
      "targetCPUUtilizationPercentage": 79
    }]

但您实际上可能有一个逻辑错误,因为您正在循环遍历列表并每次都覆盖变量exist。所以你最终会得到一个变量exist,它将保存最后一次迭代的值。
如果您需要每次迭代的输出,请查看如何register variables with a loop

如果你想对每个满足条件的物品做一些事情,你可以这样做:

- name: check for existing
  shell: oc get hpa -o json | jq -r '.items[].spec'
  register: existing

- name: include tasks a
  include_tasks: a.yml
  when:
    - deploy_type == item['scaleTargetRef']['kind'] | lower
    - deploy_name == item['scaleTargetRef']['name'] | lower
  loop: "{{  existing.stdout | from_json }}"

- name: include tasks b
  include_tasks: b.yml
  when: (deploy_type != item['scaleTargetRef']['kind'] | lower) or
        (deploy_name != item['scaleTargetRef']['name'] | lower)
  loop: "{{  existing.stdout | from_json }}" 

在这种情况下,您不需要任何 set_fact 的东西。

【讨论】:

  • 一种更好的“ansiblich”方式来编写表达式 IMO:exist: "{{ ((item['scaleTargetRef']['name'] == newvar) and (item['scaleTargetRef']['kind'] == newvar2)) | bool }}"
  • 谢谢,我确实遇到了你提到的最后一次迭代总是覆盖的问题。我一直在阅读链接并进行了测试,但仍然无法实现我想要做的事情。我想做shell: something when: existshell: something else when: not exist
  • @sloweriang 查看我上次的编辑,对您有帮助吗?
  • soory 不,我只是越来越困惑。查看我的编辑..当前我正在使用 set_fact: var.stdout 但我仍然让变量被最后一次迭代覆盖
  • @sloweriang 我根据您的编辑修改了最后一个示例。您需要解析 json,并且需要对列表中的每个项目进行导入,因此您需要在 import 语句处进行循环。如果列表中有多个项目匹配相同的条件,则最后一次编辑可能会多次导入任务。我真的不明白你想要做什么,所以不知道这是否是一个问题。
猜你喜欢
  • 1970-01-01
  • 2016-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多