简体   繁体   English

Ansible - 循环和 json_query 的问题

[英]Ansible - issue with loop and json_query's

I am using the ansible URI module to talk to a REST api.我正在使用 ansible URI 模块与 REST api 对话。 I have a task to perform a GET to get me some data that i want to use later on.我有一项任务要执行 GET 以获取一些我稍后要使用的数据。 I want to be able to match a certain variable from the GET to create the path to do a PUT on the REST api.我希望能够匹配来自 GET 的某个变量来创建在 REST api 上执行 PUT 的路径。 My code is as followed我的代码如下

playbook剧本

*host_vars/host.yml * *host_vars/host.yml *

---
inputs:
  - title: "test_input_api"
    type: "org.graylog2.inputs.syslog.udp.SyslogUDPInput"
    global: false
    configuration:
      allow_override_date: false
      bind_address: "0.0.0.0"
      expand_structured_data: false
      force_rdns: false
      number_worker_threads: 8
      override_source: null
      port: 5999
      recv_buffer_size: null
      store_full_message: true
  - title: "test_input_api_2"
    type: "org.graylog2.inputs.syslog.udp.SyslogUDPInput"
    global: false
    configuration:
      allow_override_date: false
      bind_address: "0.0.0.0"
      expand_structured_data: false
      force_rdns: false
      number_worker_threads: 8
      override_source: null
      port: 5998
      recv_buffer_size: null
      store_full_message: true

playbook.yml剧本.yml

---
- name: Configure system
  hosts: graylog
  connection: local
  gather_facts: no
  roles:
    - graylog/inputs

roles/graylog/inputs/tasks/main.yml角色/graylog/inputs/tasks/main.yml

---
- include_tasks: get_inputs.yml
- include_tasks: put_inputs.yml

roles/graylog/inputs/tasks/get_inputs.yml角色/graylog/inputs/tasks/get_inputs.yml

--- 
- name: "API GET System Inputs"
    uri:
      url: http://{{ ansible_host }}:9000/api/system/inputs
      url_username : "{{ system.users.triple_admin.api_token }}"
      url_password: token
      method: GET
      return_content: yes
    register: get_graylog_inputs

- name: Set Fact
  set_fact:
    get_input_id: "{{ get_graylog_inputs.content | from_json | json_query('inputs[?title == `{}`] | [0].id '.format(input.title)) }}"
  loop: "{{ inputs }}"
  loop_control:
    loop_var: input

roles/graylog/inputs/tasks/put_inputs.yml角色/graylog/inputs/tasks/put_inputs.yml

---
  - name: "API PUT System Inputs"
    uri:
      url: http://{{ ansible_host }}:9000/api/system/inputs/{{ get_input_id }}
      url_username : "{{ system.users.triple_admin.api_token }}"
      url_password: token
      headers:
        X-Requested-By: X-Ansible
      method: PUT
      body_format: json
      body: "{{ lookup('template', 'templates/post_template.j2') }}"
      status_code: 201
      return_content: yes
    loop: "{{ inputs }}"
    loop_control:
      loop_var: input

possible issue可能的问题

A double loop statement within the play剧中的双循环语句

As you can see in the get_inputs.yml I do a loop over the inputs dict in the host_vars within the set_fact task to get the ID from the REST api for each input entry that is defined in the host_vars that matches the title.正如您在get_inputs.yml 中看到的,我在 set_fact 任务中对 host_vars 中的输入dict 进行循环,以从 REST api 获取与标题匹配的host_vars中定义的每个输入条目的 ID。

The idea behind this is when i want to change something about the input entry i can do a PUT that builds a path within the task put_inputs.yml the variable URL to the input with the id that is gathered with the GET and set to fact by the get_facts task and then play the PUT task to the rest api and adjust some parameter.这背后的想法是,当我想更改有关输入条目的某些内容时,我可以执行 PUT 在任务put_inputs.yml中构建路径的变量URL到输入的变量URL使用 GET 收集并设置为事实get_facts 任务,然后将 PUT 任务播放到其余 api 并调整一些参数。

But i also need do a loop over the same inputs dict in the host_vars within the put_inputs.yml because if there are changes to multiple entries i want to loop the PUT.但是我还需要在 put_inputs.yml 内的host_vars 中对相同的输入字典进行循环,因为如果对多个条目进行了更改,我想循环 PUT。

The issue is that the get_facts get's both the id values as show below only the last one is being registered as the fact because it's a loop and they get the same name.问题是 get_facts 获得了两个 id 值,如下所示,只有最后一个被注册为事实,因为它是一个循环,并且它们具有相同的名称。

    "ansible_facts": {
        "get_input_id": "61015085eca1554750236084",
        "get_input_titles": "test_input_api"
    },
    "ansible_facts": {
        "get_input_id": "610282d0eca155475024ac91",
        "get_input_titles": "test_input_api_2"

So when the put_inputs.yml task is played ( after the get_inputs.yml ) I end up with the following response from the play which in short is that both times te task is being played ( as per loop ) i get the same get_input_id value.因此,当播放put_inputs.yml任务时(在get_inputs.yml 之后)我最终得到了来自播放的以下响应,简而言之,两次 te 任务正在播放(根据循环)我得到相同的get_input_id值。

loop 1 - this needs to be matched to the title and therefor get id "61015085eca1554750236084"循环 1 - 这需要与标题匹配,因此获取 id "61015085eca1554750236084"

        "title": "test_input_api",
            "url": "http://192.168.21.82:9000/api/system/inputs/610282d0eca155475024ac91",

loop 2循环 2

        "title": "test_input_api_2",
            "url": "http://192.168.21.82:9000/api/system/inputs/610282d0eca155475024ac91",

Question问题

I need to get the ID from the GET because it's needed in the URL in the PUT task to edit a specific "input" entry.我需要从 GET 获取 ID,因为在 PUT 任务的 URL 中需要它来编辑特定的“输入”条目。 But because i need to match the ID to the Title i need to do a loop but this as I said previously results in only getting one ID value as a fact which is being used in the PUT loop for all items in the inputs dict this is not what i need because i need to be able to edit every entry separately based on ID.但是因为我需要将 ID 与 Title 匹配,所以我需要做一个循环,但是正如我之前所说的,这导致只获得一个 ID 值作为一个事实,该值在 PUT 循环中用于输入字典中的所有项目,这是不是我需要的,因为我需要能够根据 ID 分别编辑每个条目。

All help is welcome !欢迎所有帮助!

  1. (not related) You don't need to json_decode the result get_graylog_inputs.content . (不相关)您不需要json_decode结果get_graylog_inputs.content If the server on the over side sends the correct Content-type: application/json header, you should have a get_graylog_inputs.json entry containing the already decoded json result.如果另一端的服务器发送正确的Content-type: application/json标头,您应该有一个包含已解码 json 结果的get_graylog_inputs.json条目。
  2. You don't need to loop twice.你不需要循环两次。 Remove the set_fact loop (which is not correct anyway) in your first file and use the value from your register directly in the second loop.删除第一个文件中的set_fact循环(无论如何都不正确),并直接在第二个循环中使用寄存器中的值。
  3. You did not show any example of your input data so I have to guess a bit here from your jmespath expression... but you basically don't need json_query at all and can stick to generic core ansible filters.您没有显示输入数据的任何示例,因此我必须从您的 jmespath 表达式中猜测一下……但您基本上根本不需要json_query并且可以坚持使用通用核心 ansible 过滤器。

Here is how I see the solution in the second file once you cleaned-up the first:这是清理第一个文件后我在第二个文件中看到的解决方案:

---
  - name: "API PUT System Inputs"
    vars:
      get_input_id: "{{ get_graylog_inputs.json | selectattr('title', '==', item.title) | map(attribute='id') | first }}"
    uri:
      url: http://{{ ansible_host }}:9000/api/system/inputs/{{ get_input_id }}
      url_username : "{{ system.users.triple_admin.api_token }}"
      url_password: token
      headers:
        X-Requested-By: X-Ansible
      method: PUT
      body_format: json
      body: "{{ lookup('template', 'templates/post_template.j2') }}"
      status_code: 201
      return_content: yes
    loop: "{{ inputs }}"
    loop_control:
      loop_var: input

You will probably have to debug and tune the expression to get the input id as I could not do it myself against an example data structure.您可能需要调试和调整表达式以获取输入 id,因为我无法针对示例数据结构自行完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM