debian-forge/test/mod
David Rheinsberg 803433fb62 api: prevent early output retrieval
Change the API endpoint to prevent retrieving monitor-output from a
running instance. Instead, we require the caller to exit the API context
before querying the monitor-output. This guarantees that the api-thread
was synchronously taken down and scheduled any outstanding events.

This fixes an issue where a side-channel notifies us of a buildroot
exit, but the api-thread has not yet returned from epoll, and thus might
not have dispatched pending I/O events, yet. If we instead wait for the
thread to exit, we have a synchronous shutdown and know that all
*ordered* kernel events must have been handled.

In particular, imagine a build-root program running (like `echo` in the
test_monitor unittest) which writes data to the stdout-pipe and then
immediately exits. The syscall-order guarantees that the data is written
to the pipe before the SIGCHLD is sent (or wait(2) returns). However, we
retrieve the SIGCHLD from our main-thread usually (p.join() in our test,
and BuildRoot() in our main code), while the pipe-reading is done from
an API thread. Therefore, we might end up handling the SIGCHLD first
(just imagine a single-threaded CPU that schedules the main task before
the thread). To avoid this race, we can simply synchronize with the
api-thread. Since we already have this synchronization as part of the
api-thread takedown, it is as simple as stopping the api-thread before
continuing with operations.

Lastly, if a write operation to a pipe was issued, we are guaranteed
that a SIGCHLD synchronization across processes is ordered correctly.
Furthermore, the python event-loop also guarantees that stopping an
event-loop will necessarily dispatch all outstanding events. A read is
guaranteed to be outstanding in our race-scenario, so the read will be
dispatched. The only possible problem is `_output_ready()` only
dispatching a maximum of 4096 bytes. This might need to be fixed
separately. A comment is left in place.
2020-08-13 14:02:27 +02:00
..
__init__.py test: '{. -> ./mod}/test_util_selinux.py' 2020-04-24 15:50:44 +02:00
test_api.py test/api: checks for metadata passing 2020-08-13 10:50:34 +02:00
test_buildroot.py test/buildroot: check selinuxfs is read-only 2020-08-12 16:52:27 +02:00
test_monitor.py api: prevent early output retrieval 2020-08-13 14:02:27 +02:00
test_objectstore.py test/objectstore: proper path concatenation 2020-07-22 09:37:30 +01:00
test_osbuild.py osbuild: unified libdir handling 2020-08-04 09:02:22 +02:00
test_util_ctx.py util/ctx: extract suppress_oserror() 2020-05-11 18:05:12 +02:00
test_util_jsoncomm.py jsoncomm: remove destination from send 2020-07-29 02:16:20 +01:00
test_util_linux.py test: convert to shared helpers 2020-05-13 14:26:05 +02:00
test_util_osrelease.py test: make TestBase inherit unittest.TestCase 2020-06-05 09:27:40 +02:00
test_util_ostree.py osbuild: replace capture_output in subprocess.run 2020-06-09 13:42:35 +02:00
test_util_rmrf.py test: convert to shared helpers 2020-05-13 14:26:05 +02:00
test_util_selinux.py test: '{. -> ./mod}/test_util_selinux.py' 2020-04-24 15:50:44 +02:00