From 60511c2a082d3da5e371db60f1482c766c33a727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Vydra?= <80331839+vydrazde@users.noreply.github.com> Date: Tue, 9 Sep 2025 18:09:28 +0200 Subject: [PATCH] Fix uri form-multipart to not overwrite filename to allow retries (#85010) --- .../85010-uri-multipart-file-on-retry.yml | 2 ++ lib/ansible/plugins/action/uri.py | 6 ++++-- test/integration/targets/uri/tasks/main.yml | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/85010-uri-multipart-file-on-retry.yml diff --git a/changelogs/fragments/85010-uri-multipart-file-on-retry.yml b/changelogs/fragments/85010-uri-multipart-file-on-retry.yml new file mode 100644 index 00000000000..d2404606889 --- /dev/null +++ b/changelogs/fragments/85010-uri-multipart-file-on-retry.yml @@ -0,0 +1,2 @@ +bugfixes: + - uri - fix form-multipart file not being found when task is retried (https://github.com/ansible/ansible/issues/85009) diff --git a/lib/ansible/plugins/action/uri.py b/lib/ansible/plugins/action/uri.py index 851340c1d0c..61ba39b0fad 100644 --- a/lib/ansible/plugins/action/uri.py +++ b/lib/ansible/plugins/action/uri.py @@ -7,6 +7,7 @@ from __future__ import annotations import collections.abc as _c import os +from copy import deepcopy from ansible.errors import AnsibleActionFail from ansible.module_utils.parsing.convert_bool import boolean @@ -53,7 +54,8 @@ class ActionModule(ActionBase): raise AnsibleActionFail( 'body must be mapping, cannot be type %s' % body.__class__.__name__ ) - for field, value in body.items(): + new_body = deepcopy(body) + for field, value in new_body.items(): if not isinstance(value, _c.MutableMapping): continue content = value.get('content') @@ -70,7 +72,7 @@ class ActionModule(ActionBase): value['filename'] = tmp_src self._transfer_file(filename, tmp_src) self._fixup_perms2((self._connection._shell.tmpdir, tmp_src)) - kwargs['body'] = body + kwargs['body'] = new_body new_module_args = self._task.args | kwargs diff --git a/test/integration/targets/uri/tasks/main.yml b/test/integration/targets/uri/tasks/main.yml index 4ab625f9db9..62748d7591f 100644 --- a/test/integration/targets/uri/tasks/main.yml +++ b/test/integration/targets/uri/tasks/main.yml @@ -477,6 +477,25 @@ register: multipart_invalid failed_when: '"failed to parse body as form-multipart: value must be a string, or mapping, cannot be type" not in multipart_invalid.msg' +- name: multipart/form-data with file and retry + uri: + url: https://{{ httpbin_host }}/post + method: POST + body_format: form-multipart + body: + file: + filename: formdata.txt + retries: 1 + delay: 0.01 + register: result + failed_when: result is failed or result.attempts == 1 + +- name: Assert multipart/form-data with file and retry + assert: + that: + - result.json.files.file | b64decode == '_multipart/form-data_\n' + - result.attempts == 2 + - name: Validate invalid method uri: url: https://{{ httpbin_host }}/anything