Merge ~ack/maas:1951398-cli-encode-as-file-3.1 into maas:3.1

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: f1e792df727eb623cca45544b2ba3a05b90a62c9
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ack/maas:1951398-cli-encode-as-file-3.1
Merge into: maas:3.1
Diff against target: 84 lines (+19/-17)
2 files modified
src/maascli/api.py (+16/-15)
src/maascli/tests/test_api.py (+3/-2)
Reviewer Review Type Date Requested Status
Alberto Donato (community) Approve
MAAS Lander Approve
Review via email: mp+412072@code.launchpad.net

Commit message

LP:1951398 keep @= parameters as uploaded files for POST actions

When @= is used in the CLI to read a parameter from file, only read the content
directly if the action is GET or DELETE, otherwise pass it as a file, so that
it gets multipart-encoded correctly (the filename= parameter is set in the
Content-Disposition header).

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b 1951398-cli-encode-as-file-3.1 lp:~ack/maas/+git/maas into -b 3.1 lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: f1e792df727eb623cca45544b2ba3a05b90a62c9

review: Approve
Revision history for this message
Alberto Donato (ack) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maascli/api.py b/src/maascli/api.py
2index a82f5c7..c533f1f 100644
3--- a/src/maascli/api.py
4+++ b/src/maascli/api.py
5@@ -198,7 +198,7 @@ class Action(Command):
6 if what == "=":
7 return name, value
8 elif what == "@=":
9- return name, partial(open, value)
10+ return name, partial(open, value, "rb")
11 else:
12 raise AssertionError("Unrecognised separator %r" % what)
13 else:
14@@ -222,25 +222,26 @@ class Action(Command):
15 tuples (see `name_value_pair`) to pack into the body or
16 query, depending on the type of request.
17 """
18- params_in_qs = method in ("GET", "DELETE")
19 query = [("op", op)] if op else []
20
21+ headers, body = [], None
22+
23 def slurp(opener):
24- with opener("r" if params_in_qs else "rb") as fd:
25+ with opener() as fd:
26 return fd.read()
27
28- # read content for file-based parameters
29- data = [
30- (key, slurp(value) if callable(value) else value)
31- for key, value in data
32- ]
33-
34- headers, body = [], None
35- if params_in_qs:
36- query.extend(data)
37- elif data:
38- message = build_multipart_message(data)
39- headers, body = encode_multipart_message(message)
40+ if method in ("GET", "DELETE"):
41+ query.extend(
42+ (name, slurp(value) if callable(value) else value)
43+ for name, value in data
44+ )
45+ body, headers = None, []
46+ else:
47+ if data is None or len(data) == 0:
48+ body, headers = None, []
49+ else:
50+ message = build_multipart_message(data)
51+ headers, body = encode_multipart_message(message)
52
53 uri = urlparse(uri)._replace(query=urlencode(query)).geturl()
54 return uri, body, headers
55diff --git a/src/maascli/tests/test_api.py b/src/maascli/tests/test_api.py
56index 402bdc2..12ae2c3 100644
57--- a/src/maascli/tests/test_api.py
58+++ b/src/maascli/tests/test_api.py
59@@ -2,6 +2,7 @@
60 # GNU Affero General Public License version 3 (see the file LICENSE).
61
62 from base64 import b64encode
63+from functools import partial
64 import http.client
65 import json
66 import sys
67@@ -698,7 +699,7 @@ class TestPayloadPreparationWithFiles:
68 # command-line causes name_value_pair() to return a `name,
69 # opener` tuple, where `opener` is a callable that returns an
70 # open file handle.
71- data = [(parameter, payload_file.open)]
72+ data = [(parameter, partial(payload_file.open, "rb"))]
73 return parameter, contents, data
74
75 @pytest.mark.parametrize("op", [None, "action"])
76@@ -718,7 +719,7 @@ class TestPayloadPreparationWithFiles:
77 "Content-Type: application/octet-stream",
78 "MIME-Version: 1.0",
79 "Content-Transfer-Encoding: base64",
80- f'Content-Disposition: form-data; name="{parameter}"',
81+ f'Content-Disposition: form-data; name="{parameter}"; filename="{parameter}"',
82 b64encode(contents).decode("ascii"),
83 ]
84 for line in content_lines:

Subscribers

People subscribed via source and target branches