We recently hit the issue that `osbuild` crashed with:
```
Unable to decode response body "Traceback (most recent call last):
File \"/usr/bin/osbuild\", line 33, in <module>
sys.exit(load_entry_point('osbuild==124', 'console_scripts', 'osbuild')())
File \"/usr/lib/python3.9/site-packages/osbuild/main_cli.py\", line 181, in osbuild_cli
r = manifest.build(
File \"/usr/lib/python3.9/site-packages/osbuild/pipeline.py\", line 477, in build
res = pl.run(store, monitor, libdir, debug_break, stage_timeout)
File \"/usr/lib/python3.9/site-packages/osbuild/pipeline.py\", line 376, in run
results = self.build_stages(store,
File \"/usr/lib/python3.9/site-packages/osbuild/pipeline.py\", line 348, in build_stages
r = stage.run(tree,
File \"/usr/lib/python3.9/site-packages/osbuild/pipeline.py\", line 213, in run
data = ipmgr.map(ip, store)
File \"/usr/lib/python3.9/site-packages/osbuild/inputs.py\", line 94, in map
reply, _ = client.call_with_fds(\"map\", {}, fds)
File \"/usr/lib/python3.9/site-packages/osbuild/host.py\", line 373, in call_with_fds
kind, data = self.protocol.decode_message(ret)
File \"/usr/lib/python3.9/site-packages/osbuild/host.py\", line 83, in decode_message
raise ProtocolError(\"message empty\")
osbuild.host.ProtocolError: message empty
cannot run osbuild: exit status 1" into osbuild result: invalid character 'T' looking for beginning of value
...
input/packages (org.osbuild.files): Traceback (most recent call last):
input/packages (org.osbuild.files): File "/usr/lib/osbuild/inputs/org.osbuild.files", line 226, in <module>
input/packages (org.osbuild.files): main()
input/packages (org.osbuild.files): File "/usr/lib/osbuild/inputs/org.osbuild.files", line 222, in main
input/packages (org.osbuild.files): service.main()
input/packages (org.osbuild.files): File "/usr/lib/python3.11/site-packages/osbuild/host.py", line 250, in main
input/packages (org.osbuild.files): self.serve()
input/packages (org.osbuild.files): File "/usr/lib/python3.11/site-packages/osbuild/host.py", line 284, in serve
input/packages (org.osbuild.files): self.sock.send(reply, fds=reply_fds)
input/packages (org.osbuild.files): File "/usr/lib/python3.11/site-packages/osbuild/util/jsoncomm.py", line 407, in send
input/packages (org.osbuild.files): n = self._socket.sendmsg([serialized], cmsg, 0)
input/packages (org.osbuild.files): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
input/packages (org.osbuild.files): OSError: [Errno 90] Message too long
```
The underlying issue is that the reply of the `map()` call is too
big for the buffer that `jsoncomm` uses. This problem existed before
for the args of map and was fixed by introducing a temporary file
in https://github.com/osbuild/osbuild/pull/1331 (and similarly
before in https://github.com/osbuild/osbuild/pull/824).
This commit writes the return values also into a file. This should
fix the crash above and make the function more symetrical as well.
Alternative/complementary version of
https://github.com/osbuild/osbuild/pull/1833
Closes: HMS-4537
47 lines
1.5 KiB
Python
47 lines
1.5 KiB
Python
import json
|
|
import os
|
|
from unittest.mock import patch
|
|
|
|
from osbuild import inputs
|
|
from osbuild.util.jsoncomm import FdSet
|
|
|
|
|
|
class FakeInputService(inputs.InputService):
|
|
def __init__(self, args): # pylint: disable=super-init-not-called
|
|
# do not call "super().__init__()" here to make it testable
|
|
self.map_calls = []
|
|
|
|
def map(self, _store, origin, refs, target, options):
|
|
self.map_calls.append([origin, refs, target, options])
|
|
return "complex", 2, "reply"
|
|
|
|
|
|
def test_inputs_dispatches_map(tmp_path):
|
|
store_api_path = tmp_path / "api-store"
|
|
store_api_path.write_text("")
|
|
|
|
args_path = tmp_path / "args"
|
|
reply_path = tmp_path / "reply"
|
|
args = {
|
|
"api": {
|
|
"store": os.fspath(store_api_path),
|
|
},
|
|
"origin": "some-origin",
|
|
"refs": "some-refs",
|
|
"target": "some-target",
|
|
"options": "some-options",
|
|
}
|
|
args_path.write_text(json.dumps(args))
|
|
reply_path.write_text("")
|
|
|
|
with args_path.open() as f_args, reply_path.open("w") as f_reply:
|
|
fd_args, fd_reply = os.dup(f_args.fileno()), os.dup(f_reply.fileno())
|
|
fds = FdSet.from_list([fd_args, fd_reply])
|
|
fake_service = FakeInputService(args="some")
|
|
with patch.object(inputs, "StoreClient"):
|
|
r = fake_service.dispatch("map", None, fds)
|
|
assert r == ('{}', None)
|
|
assert fake_service.map_calls == [
|
|
["some-origin", "some-refs", "some-target", "some-options"],
|
|
]
|
|
assert reply_path.read_text() == '["complex", 2, "reply"]'
|