ansible.builtin.uri 模块 - 读取 JSON 文件内容并将其格式化为要在负载中使用的字符串

ansible.builtin.uri module - Read and format JSON file content as a string to use in payload

我正在尝试使用 ansible.builtin.lookup plugin in order to read a JSON file from the local directory and then pass it as the payload to the ansible.builtin.uri 模块向 URI 端点发送 POST 消息。

以下是我的 JSON 文件的内容 (config.json):

    {
      "Configuration": {
        "Components": [
          {
            "Name": "A",
            "Attributes": [
              {
                "Name": "A1",
                "Value": "1",
                "Set On Import": "True",
                "Comment": "Read and Write"
              },
              {
                "Name": "A2",
                "Value": "2",
                "Set On Import": "True",
                "Comment": "Read and Write"
              }
            ]
          }
        ]
      }
    }

我需要将上面的 JSON 内容作为有效载荷中的以下字符串发送到 ansible.builtin.uri 模块:

"{\"Configuration\": {\"Components\": [{\"Name\": \"A\", \"Attributes\": [{\"Name\": \"A1\", \"Value\": \"1\", \"Set On Import\": \"True\", \"Comment\": \"Read and Write\"}, {\"Name\": \"A2\", \"Value\": \"2\", \"Set On Import\": \"True\", \"Comment\": \"Read and Write\"}]}]}}"

我正在尝试使用带有 to_json 过滤器的查找插件来读取和格式化 JSON 内容。以下是我的剧本:

- name: import scp
  ansible.builtin.uri:
    url: "https://{{ inventory_hostname }}/api/config/actions/import"
    user: "{{ user }}"
    password: "{{ password }}"
    method: POST
    headers:
      Accept: "application/json"
      Content-Type: "application/json"
    body:
      Parameters:
        Type: "LOCAL_FILE"
        Target: "ALL"
        IgnoreCertificateWarning: "Enabled"
      Buffer: "{{ lookup('file', 'config.json') | to_json }}"
    body_format: json
    status_code: 202
    validate_certs: no
    force_basic_auth: yes

但是,uri 模块双重转义所有换行符和制表符。以下是我 运行 剧本时有效载荷的发送方式:

    "invocation": {
        "module_args": {
            "attributes": null,
            "body": {
                "Buffer": "\"{\n\t\\"Configuration\\": {\n\t\t\\"Components\\": [\n\t\t\t{\n\t\t\t\t\\"Name\\": \\"A\\",\n\t\t\t\t\\"Attributes\\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\\"Name\\": \\"A1\\",\n\t\t\t\t\t\t\\"Value\\": \\"1\\",\n\t\t\t\t\t\t\\"Set On Import\\": \\"True\\",\n\t\t\t\t\t\t\\"Comment\\": \\"Read and Write\\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\\"Name\\": \\"A2\\",\n\t\t\t\t\t\t\\"Value\\": \\"2\\",\n\t\t\t\t\t\t\\"Set On Import\\": \\"True\\",\n\t\t\t\t\t\t\\"Comment\\": \\"Read and Write\\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n}\"",
                "Parameters": {
                    "IgnoreCertificateWarning": "Enabled",
                    "Type": "LOCAL_FILE",
                    "Target": "ALL"
                },
            },
            "body_format": "json",
...
    },

能否请您告诉我如何使用 uri 模块格式化有效负载?感谢任何帮助。

已编辑(2021 年 5 月 11 日): 我按照@mdaniel 在他的回复中的建议进行了更改,并使用了 string 过滤器而不是 to_json。根据建议的更改,我可以看到 JSON 被正确格式化为带有换行符 ('\n') 和制表符 ('\t') 的字符串。我尝试使用 replace 过滤器删除 \n\t 字符。但是,现在整个字符串被转换回 JSON.

以下是单独使用 string 过滤器时的剧本和输出:

...
        body:
          Parameters:
            Type: "LOCAL_FILE"
            Target: "ALL"
            IgnoreCertificateWarning: "Enabled"
          Buffer: "{{ lookup('file', 'config.json') | string }}"
$ ansible-playbook import_file.yml -i hosts --tags

...
            "body": {
                "HostPowerState": "On",
                "Buffer": "{\n\t\"Configuration\": {\n\t\t\"Components\": [\n\t\t\t{\n\t\t\t\t\"Name\": \"A\",\n\t\t\t\t\"Attributes\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"Name\": \"A1\",\n\t\t\t\t\t\t\"Value\": \"1\",\n\t\t\t\t\t\t\"Set On Import\": \"True\",\n\t\t\t\t\t\t\"Comment\": \"Read and Write\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"Name\": \"A2\",\n\t\t\t\t\t\t\"Value\": \"2\",\n\t\t\t\t\t\t\"Set On Import\": \"True\",\n\t\t\t\t\t\t\"Comment\": \"Read and Write\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n}",
                "Parameters": {
                    "IgnoreCertificateWarning": "Enabled",
                    "Type": "LOCAL_FILE",
                    "Target": "ALL"
                },
            },

以下是将 replace 过滤器与 string 过滤器结合使用时的剧本和输出:

...
        body:
          Parameters:
            Type: "LOCAL_FILE"
            Target: "ALL"
            IgnoreCertificateWarning: "Enabled"
          Buffer: "{{ lookup('file', 'config.json') | string | replace('\n', '') | replace('\t', '') }}"
...

$ ansible-playbook import_file.yml -i hosts --tags

...
            "body": {
                "Buffer":  {
                    "Configuration": {
                        "Components": [
                            {
                                "Attributes": [
                                    {
                                        "Comment": "Read and Write",
                                        "Name": "A1",
                                        "Set On Import": "True",
                                        "Value": "1"
                                    },
                                    {
                                        "Comment": "Read and Write",
                                        "Name": "A2",
                                        "Set On Import": "True",
                                        "Value": "2"
                                    }
                                ],
                                "Name": "A"
                            }
                        ]
                    }
                },
                "Parameters": {
                    "IgnoreCertificateWarning": "Enabled",
                    "Type": "LOCAL_FILE",
                    "Target": "ALL"
                },
            },
...

关于如何从字符串中删除 \n\t 字符的任何指示?

您已经在 dict 值上使用了 to_json,该值本身将被 to_json 编辑; ansible 无法通过 HTTP 传输 python dict,因此任何还不是字符串的 yaml 结构都需要先转换为

你想要的只是那个查找结果(它将 return 一个 str,而不是一个 dict),然后 ansible 将应用 to_json 到由于上述原因 body: 的全部价值

但是,因为 ansible 试图“提供帮助”,它会自动将找到的以 { back 开头的 yaml 值强制转换为 dict——这就是为什么你只需要通过 | string 过滤器发送 lookup 的结果来加强 ansible 是的,你确实希望它保持 str上下文

...

    body:
      Parameters:
        Type: "LOCAL_FILE"
        Target: "ALL"
        IgnoreCertificateWarning: "Enabled"
      Buffer: "{{ lookup('file', 'config.json') | string }}"

更新答案方法

鉴于 dict 强制转换仍然是一个问题的评论讨论,并且领先的 space 涉及 OP,另一种方法是完全构建实际的有效负载结构, 并且在传输之前仅“JSON-ify”它,以使 ansible 和 jinja 在同一页面上关于数据类型:

- name: import scp
  vars:
    body_dict:
      Parameters:
        Type: "LOCAL_FILE"
        Target: "ALL"
        IgnoreCertificateWarning: "Enabled"
      # this will be filled in before submission
      # Buffer:
    whitespace_free_config_json: >-
          {{ lookup('file', 'config.json') 
          | regex_replace('[\t\n]', '')
          | string
          }}
  ansible.builtin.uri:
    ...
    body: >-
      {{ body_dict
      | combine({"Buffer": whitespace_free_config_json})
      | to_json }}
    body_format: json
    status_code: 202