将'curl'命令转换为'ansible.builtin.uri'模块?

3
我有一个文件附件,我正在尝试通过REST API上传到Confluence。我可以通过复制他们的示例使用curl来完成,但是当使用Ansible时失败了,我无法弄清楚原因。
这是curl命令:
curl -u <username>:<password> -X POST -H "X-Atlassian-Token: nocheck" -F "file=@<filepath>" -F "comment=File attached via REST API" https://myconfluenceserver.com/rest/api/content/<page ID>/child/attachment

当然,<> 中的值会被替换为实际值。这个命令执行成功。

这是 Ansible 任务:

ansible.builtin.uri:
  user: "{{ osa_credentials.username }}"
  password: "{{ osa_credentials.password }}"
  url: "{{ url }}"
  method: POST
  headers:
    X-Atlassian-Token: nocheck
  force_basic_auth: yes
  src: "{{ filepath }}"
  validate_certs: no

当我运行curl命令时可以工作,但是使用Ansible时会抛出错误400。以下是完整的错误信息:

fatal: [localhost]: FAILED! => {
    "changed": false,
    "connection": "close",
    "content_language": "en",
    "content_length": "435",
    "content_type": "text/html;charset=utf-8",
    "date": "Thu, 29 Jun 2023 06:34:10 GMT",
    "elapsed": 1,
    "invocation": {
        "module_args": {
            "attributes": null,
            "body": null,
            "body_format": "raw",
            "ca_path": null,
            "ciphers": null,
            "client_cert": null,
            "client_key": null,
            "creates": null,
            "decompress": true,
            "dest": null,
            "follow_redirects": "safe",
            "force": false,
            "force_basic_auth": true,
            "group": null,
            "headers": {
                "Content-Length": 543818,
                "X-Atlassian-Token": "nocheck"
            },
            "http_agent": "ansible-httpget",
            "method": "POST",
            "mode": null,
            "owner": null,
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "remote_src": false,
            "removes": null,
            "return_content": false,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": "<filepath>",
            "status_code": [
                200
            ],
            "timeout": 30,
            "unix_socket": null,
            "unredirected_headers": [],
            "unsafe_writes": true,
            "url": "https://myconfluenceserver.com/rest/api/content/<page ID>/child/attachment",
            "url_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "url_username": "<username>",
            "use_gssapi": false,
            "use_netrc": true,
            "use_proxy": true,
            "user": "<username>",
            "validate_certs": false
        }
    },
    "msg": "Status code was 400 and not [200]: HTTP Error 400: ",
    "redirected": false,
    "server": "Apache",
    "status": 400,
    "url": "https://myconfluenceserver.com/rest/api/content/<page ID>/child/attachment"
}

我错过了什么?


你能分享一下 Ansible 报告的错误吗?在调试模式下会非常有帮助。 - error404
我用完整的任务结果更新了帖子。错误消息只是说状态码为400而不是[200]:HTTP错误400 - jeremywat
你有检查在src: &quot;{{ filepath }}&quot;中定义的响应文件是否包含API所期望的所有内容吗?例如,文件内容的file表单字段和上传评论的comment字段。 Confluence服务器上是否有任何有用的日志可以帮助调试Ansible缺少的问题? - Byob
你能访问Confluence日志吗?也许它会告诉你错误的原因。你还可以尝试添加body_format参数。 - The_Pingu
@Byob 我不确定你所说的“响应文件”是什么意思。src: "{{ filepath }}" 是我作为附件上传的文件。它不包含filecomment或其他任何字段。不幸的是,由于我只是Confluence的用户,我无法访问Confluence日志。 - jeremywat
显示剩余5条评论
2个回答

2
Confluence REST API附件 - 使用哪种内容类型?如何解决HTTP响应代码415?
根据Ansible的uri模块和以下最小示例,可以得出结论。
---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    CONFLUENCE_USER: "user"
    CONFLUENCE_PASSWORD: "test"
    PAGE_ID: "123456789"

  tasks:

  - name: Test REST API - Confluence Attach File
    ansible.builtin.uri:
      user: "{{ CONFLUENCE_USER }}"
      password: "{{ CONFLUENCE_PASSWORD }}"
      url: "https://confluence.example.com/rest/api/content/{{ PAGE_ID }}/child/attachment"
      validate_certs: yes
      method: POST
      headers:
        X-Atlassian-Token: nocheck
      force_basic_auth: yes
      body_format: form-multipart
      body:
        file:
          content: "{{ lookup('file','test.file') }}"
          filename: test.file
    register: result

  - debug:
      var: result.json.results

对Confluence的测试运行将成功导致文件上传和输出

TASK [debug] *********
ok: [localhost] =>
  result.json.results:
  - _expandable:
      ancestors: ''
      body: ''
      children: /rest/api/content/987654321/child
      descendants: /rest/api/content/987654321/descendant
      history: /rest/api/content/987654321/history
      operations: ''
      restrictions: /rest/api/content/987654321/restriction/byOperation
      space: /rest/api/space/~user
    _links:
      download: /download/attachments/123456789/test.file?version=1&modificationDate=1688109306468&api=v2
      self: https://confluence.example.com/rest/api/content/987654321
      webui: /display/~user/StackOverflow?preview=%2F123456789%2F987654321%2Ftest.file
...
    status: current
    title: test.file
    type: attachment
...

那么使用哪种正确的体式,或者实现这个目标的正确方式是什么?使用
      body_format: form-multipart
      body:
        file:
          content: "{{ lookup('file','test.file') }}"
          filename: test.file

并且如man curl中所述

-F, --form <name=content>

(HTTP SMTP IMAP) 对于HTTP协议族,这使得curl模拟了一个填写完整的表单,其中用户已经按下提交按钮。这会导致curl使用Content-Type multipart/form-data根据RFC 2388进行POST数据

文档


-2
如果你将成功的curl命令行放入https://curlconverter.com/ansible/中,它会给出一个稍微不同的URI模块表达方式,我倾向于尝试这个方式,因为它似乎是更准确的翻译。
- name: Curl translate
  uri:
    url: 'https://myconfluenceserver.com/rest/api/content/165/child/attachment'
    method: POST
    body:
      file:
        filename: '<filepath>'
      comment:
        content: 'File attached via REST API'
    body_format: form-multipart
    headers:
      X-Atlassian-Token: nocheck
    url_username: test
    url_password: test
  register: result

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接