richardmaw-codethink pushed to branch richardmaw/distinguish-sandboxing-build-fail at BuildStream / buildstream
Commits:
-
350c6796
by Tristan Van Berkom at 2018-10-08T10:44:47Z
-
3ca487b8
by Chandan Singh at 2018-10-08T18:25:39Z
-
49df3d75
by Chandan Singh at 2018-10-08T18:58:54Z
-
d827dfae
by Angelos Evripiotis at 2018-10-09T09:12:45Z
-
9590e8ae
by Angelos Evripiotis at 2018-10-09T09:12:45Z
-
6d02e269
by Angelos Evripiotis at 2018-10-09T09:12:45Z
-
3ed26a47
by Angelos Evripiotis at 2018-10-09T09:12:45Z
-
5b22d850
by Angelos Evripiotis at 2018-10-09T09:12:45Z
-
ac0776f8
by Tristan Van Berkom at 2018-10-09T09:36:33Z
-
885bd946
by Tristan Van Berkom at 2018-10-09T09:39:24Z
-
120d8c73
by Tristan Van Berkom at 2018-10-09T09:45:23Z
-
0e11a8d0
by Richard Maw at 2018-10-09T16:23:25Z
-
e93d7112
by Richard Maw at 2018-10-09T16:23:25Z
-
d850d1ee
by Richard Maw at 2018-10-09T16:23:25Z
6 changed files:
- CONTRIBUTING.rst
- buildstream/_platform/linux.py
- buildstream/sandbox/_sandboxbwrap.py
- contrib/bst-docker-import
- tests/integration/sandbox-bwrap.py
- tests/testutils/site.py
Changes:
... | ... | @@ -14,7 +14,7 @@ if no issue already exists. |
14 | 14 |
|
15 | 15 |
For policies on how to submit an issue and how to use our project labels,
|
16 | 16 |
we recommend that you read the `policies guide
|
17 |
-<https://gitlab.com/BuildStream/nosoftware/alignment/blob/master/BuildStream_policies.md>`_
|
|
17 |
+<https://gitlab.com/BuildStream/nosoftware/alignment/blob/master/BuildStream_policies.md>`_.
|
|
18 | 18 |
|
19 | 19 |
|
20 | 20 |
.. _contributing_fixing_bugs:
|
... | ... | @@ -192,6 +192,21 @@ code readability by being overly restrictive on line length for instance. |
192 | 192 |
The pep8 linter will run automatically when :ref:`running the test suite <contributing_testing>`.
|
193 | 193 |
|
194 | 194 |
|
195 |
+Line lengths
|
|
196 |
+''''''''''''
|
|
197 |
+Regarding laxness on the line length in our linter settings, it should be clarified
|
|
198 |
+that the line length limit is a hard limit which causes the linter to bail out
|
|
199 |
+and reject commits which break the high limit - not an invitation to write exceedingly
|
|
200 |
+long lines of code, comments, or API documenting docstrings.
|
|
201 |
+ |
|
202 |
+Code, comments and docstrings should strive to remain written for approximately 80
|
|
203 |
+or 90 character lines, where exceptions can be made when code would be less readable
|
|
204 |
+when exceeding 80 or 90 characters (often this happens in conditional statements
|
|
205 |
+when raising an exception, for example). Or, when comments contain a long link that
|
|
206 |
+causes the given line to to exceed 80 or 90 characters, we don't want this to cause
|
|
207 |
+the linter to refuse the commit.
|
|
208 |
+ |
|
209 |
+ |
|
195 | 210 |
.. _contributing_documenting_symbols:
|
196 | 211 |
|
197 | 212 |
Documenting symbols
|
... | ... | @@ -255,6 +270,11 @@ comments and docstrings. |
255 | 270 |
*Since: 1.2*
|
256 | 271 |
"""
|
257 | 272 |
|
273 |
+.. note::
|
|
274 |
+ |
|
275 |
+ Python does not support docstrings on instance variables, but sphinx does
|
|
276 |
+ pick them up and includes them in the generated documentation.
|
|
277 |
+ |
|
258 | 278 |
**Internal instance variable**::
|
259 | 279 |
|
260 | 280 |
def __init__(self, context, element):
|
... | ... | @@ -389,7 +409,7 @@ on a Python class in BuildStream:: |
389 | 409 |
# Implementation of the "frobbish" abstract method
|
390 | 410 |
# defined by the parent Bar class.
|
391 | 411 |
#
|
392 |
- return True
|
|
412 |
+ return True
|
|
393 | 413 |
|
394 | 414 |
################################################
|
395 | 415 |
# Public Methods #
|
... | ... | @@ -430,7 +450,7 @@ on a Python class in BuildStream:: |
430 | 450 |
# Returns:
|
431 | 451 |
# (int): The count of this foo
|
432 | 452 |
#
|
433 |
- def set_count(self, count):
|
|
453 |
+ def get_count(self, count):
|
|
434 | 454 |
|
435 | 455 |
return self._count
|
436 | 456 |
|
... | ... | @@ -444,7 +464,7 @@ on a Python class in BuildStream:: |
444 | 464 |
# Even though these are private implementation
|
445 | 465 |
# details, they still MUST have API documenting
|
446 | 466 |
# comments on them.
|
447 |
-
|
|
467 |
+ |
|
448 | 468 |
# _do_frobbing()
|
449 | 469 |
#
|
450 | 470 |
# Does the actual frobbing
|
... | ... | @@ -479,10 +499,10 @@ reference on how the PEP-8 defines public and non-public. |
479 | 499 |
|
480 | 500 |
A private symbol must be denoted by a leading underscore.
|
481 | 501 |
|
482 |
-* When a class can have subclasses (for example, the ``Sandbox`` or ``Platform``
|
|
502 |
+* When a class can have subclasses, then private symbols should be denoted
|
|
503 |
+ by two leading underscores. For example, the ``Sandbox`` or ``Platform``
|
|
483 | 504 |
classes which have various implementations, or the ``Element`` and ``Source``
|
484 |
- classes which plugins derive from), then private symbols should be denoted
|
|
485 |
- by two leading underscores.
|
|
505 |
+ classes which plugins derive from.
|
|
486 | 506 |
|
487 | 507 |
The double leading underscore naming convention invokes Python's name
|
488 | 508 |
mangling algorithm which helps prevent namespace collisions in the case
|
... | ... | @@ -521,7 +541,7 @@ In order to disambiguate between: |
521 | 541 |
|
522 | 542 |
* Symbols which are publicly accessible details of the ``Element`` class, can
|
523 | 543 |
be accessed by BuildStream internals, but must remain hidden from the
|
524 |
- *"Public API Surface"*
|
|
544 |
+ *"Public API Surface"*.
|
|
525 | 545 |
|
526 | 546 |
* Symbols which are private to the ``Element`` class, and cannot be accessed
|
527 | 547 |
from outside of the ``Element`` class at all.
|
... | ... | @@ -571,7 +591,7 @@ is found at ``_artifactcache/artifactcache.py``. |
571 | 591 |
|
572 | 592 |
Imports
|
573 | 593 |
~~~~~~~
|
574 |
-Module imports inside BuildStream are done with relative ``.`` notation
|
|
594 |
+Module imports inside BuildStream are done with relative ``.`` notation:
|
|
575 | 595 |
|
576 | 596 |
**Good**::
|
577 | 597 |
|
... | ... | @@ -613,12 +633,12 @@ which exposes an instance variable is the only one in control of the value of th |
613 | 633 |
variable.
|
614 | 634 |
|
615 | 635 |
* If an instance variable is public and must be modified; then it must be
|
616 |
- modified using a :ref:`mutator <contributing_accessor_mutator>`
|
|
636 |
+ modified using a :ref:`mutator <contributing_accessor_mutator>`.
|
|
617 | 637 |
|
618 | 638 |
* Ideally for better encapsulation, all object state is declared as
|
619 | 639 |
:ref:`private instance variables <contributing_public_and_private>` and can
|
620 | 640 |
only be accessed by external classes via public :ref:`accessors and mutators
|
621 |
- <contributing_accessor_mutator>`
|
|
641 |
+ <contributing_accessor_mutator>`.
|
|
622 | 642 |
|
623 | 643 |
.. note::
|
624 | 644 |
|
... | ... | @@ -705,10 +725,10 @@ In BuildStream, we use the term *"Abstract Method"*, to refer to |
705 | 725 |
a method which **can** be overridden by a subclass, whereas it
|
706 | 726 |
is **illegal** to override any other method.
|
707 | 727 |
|
708 |
-* Abstract methods are allowed to have default implementations
|
|
728 |
+* Abstract methods are allowed to have default implementations.
|
|
709 | 729 |
|
710 | 730 |
* Subclasses are not allowed to redefine the calling signature
|
711 |
- of an abstract method, or redefine the API contract in any way
|
|
731 |
+ of an abstract method, or redefine the API contract in any way.
|
|
712 | 732 |
|
713 | 733 |
* Subclasses are not allowed to override any other methods.
|
714 | 734 |
|
... | ... | @@ -783,7 +803,7 @@ BstError parameters |
783 | 803 |
When raising ``BstError`` class exceptions, there are some common properties
|
784 | 804 |
which can be useful to know about:
|
785 | 805 |
|
786 |
-* **message:** The brief human readable error, will be formatted on one line in the frontend
|
|
806 |
+* **message:** The brief human readable error, will be formatted on one line in the frontend.
|
|
787 | 807 |
|
788 | 808 |
* **detail:** An optional detailed human readable message to accompany the **message** summary
|
789 | 809 |
of the error. This is often used to recommend the user some course of action, or to provide
|
... | ... | @@ -959,9 +979,9 @@ symbols to a minimum, this is important for both |
959 | 979 |
|
960 | 980 |
When anyone visits a file, there are two levels of comprehension:
|
961 | 981 |
|
962 |
-* What do I need to know in order to *use* this object
|
|
982 |
+* What do I need to know in order to *use* this object.
|
|
963 | 983 |
|
964 |
-* What do I need to know in order to *modify* this object
|
|
984 |
+* What do I need to know in order to *modify* this object.
|
|
965 | 985 |
|
966 | 986 |
For the former, we want the reader to understand with as little effort
|
967 | 987 |
as possible, what the public API contract is for a given object and consequently,
|
... | ... | @@ -986,9 +1006,9 @@ well documented and minimal. |
986 | 1006 |
|
987 | 1007 |
When adding new API to a given object for a new purpose, consider whether
|
988 | 1008 |
the new API is in any way redundant with other API (should this value now
|
989 |
-go into the constructor, since we use it more than once ? could this
|
|
1009 |
+go into the constructor, since we use it more than once? could this
|
|
990 | 1010 |
value be passed along with another function, and the other function renamed,
|
991 |
-to better suit the new purposes of this module/object ?) and repurpose
|
|
1011 |
+to better suit the new purposes of this module/object?) and repurpose
|
|
992 | 1012 |
the outward facing API of an object as a whole every time.
|
993 | 1013 |
|
994 | 1014 |
|
... | ... | @@ -1168,7 +1188,7 @@ The BuildStream documentation style is as follows: |
1168 | 1188 |
* Cross references should be of the form ``:role:`target```.
|
1169 | 1189 |
|
1170 | 1190 |
* Explicit anchors can be declared as ``.. _anchor_name:`` on a line by itself.
|
1171 |
-
|
|
1191 |
+ |
|
1172 | 1192 |
* To cross reference arbitrary locations with, for example, the anchor ``anchor_name``,
|
1173 | 1193 |
always provide some explicit text in the link instead of deriving the text from
|
1174 | 1194 |
the target, e.g.: ``:ref:`Link text <anchor_name>```.
|
... | ... | @@ -1251,23 +1271,23 @@ Documentation Examples |
1251 | 1271 |
The examples section of the documentation contains a series of standalone
|
1252 | 1272 |
examples, here are the criteria for an example addition.
|
1253 | 1273 |
|
1254 |
-* The example has a ``${name}``
|
|
1274 |
+* The example has a ``${name}``.
|
|
1255 | 1275 |
|
1256 |
-* The example has a project users can copy and use
|
|
1276 |
+* The example has a project users can copy and use.
|
|
1257 | 1277 |
|
1258 |
- * This project is added in the directory ``doc/examples/${name}``
|
|
1278 |
+ * This project is added in the directory ``doc/examples/${name}``.
|
|
1259 | 1279 |
|
1260 |
-* The example has a documentation component
|
|
1280 |
+* The example has a documentation component.
|
|
1261 | 1281 |
|
1262 | 1282 |
* This is added at ``doc/source/examples/${name}.rst``
|
1263 | 1283 |
* A reference to ``examples/${name}`` is added to the toctree in ``doc/source/examples.rst``
|
1264 | 1284 |
* This documentation discusses the project elements declared in the project and may
|
1265 |
- provide some BuildStream command examples
|
|
1266 |
- * This documentation links out to the reference manual at every opportunity
|
|
1285 |
+ provide some BuildStream command examples.
|
|
1286 |
+ * This documentation links out to the reference manual at every opportunity.
|
|
1267 | 1287 |
|
1268 |
-* The example has a CI test component
|
|
1288 |
+* The example has a CI test component.
|
|
1269 | 1289 |
|
1270 |
- * This is an integration test added at ``tests/examples/${name}``
|
|
1290 |
+ * This is an integration test added at ``tests/examples/${name}``.
|
|
1271 | 1291 |
* This test runs BuildStream in the ways described in the example
|
1272 | 1292 |
and assert that we get the results which we advertize to users in
|
1273 | 1293 |
the said examples.
|
... | ... | @@ -1294,17 +1314,17 @@ The ``.run`` file format is just another YAML dictionary which consists of a |
1294 | 1314 |
|
1295 | 1315 |
Each *command* is a dictionary, the members of which are listed here:
|
1296 | 1316 |
|
1297 |
-* ``directory``: The input file relative project directory
|
|
1317 |
+* ``directory``: The input file relative project directory.
|
|
1298 | 1318 |
|
1299 |
-* ``output``: The input file relative output html file to generate (optional)
|
|
1319 |
+* ``output``: The input file relative output html file to generate (optional).
|
|
1300 | 1320 |
|
1301 | 1321 |
* ``fake-output``: Don't really run the command, just pretend to and pretend
|
1302 | 1322 |
this was the output, an empty string will enable this too.
|
1303 | 1323 |
|
1304 |
-* ``command``: The command to run, without the leading ``bst``
|
|
1324 |
+* ``command``: The command to run, without the leading ``bst``.
|
|
1305 | 1325 |
|
1306 | 1326 |
* ``shell``: Specifying ``True`` indicates that ``command`` should be run as
|
1307 |
- a shell command from the project directory, instead of a bst command (optional)
|
|
1327 |
+ a shell command from the project directory, instead of a bst command (optional).
|
|
1308 | 1328 |
|
1309 | 1329 |
When adding a new ``.run`` file, one should normally also commit the new
|
1310 | 1330 |
resulting generated ``.html`` file(s) into the ``doc/source/sessions-stored/``
|
... | ... | @@ -1402,7 +1422,7 @@ a subdirectory beside your test in which to store data. |
1402 | 1422 |
When creating a test that needs data, use the datafiles extension
|
1403 | 1423 |
to decorate your test case (again, examples exist in the existing
|
1404 | 1424 |
tests for this), documentation on the datafiles extension can
|
1405 |
-be found here: https://pypi.python.org/pypi/pytest-datafiles
|
|
1425 |
+be found here: https://pypi.python.org/pypi/pytest-datafiles.
|
|
1406 | 1426 |
|
1407 | 1427 |
Tests that run a sandbox should be decorated with::
|
1408 | 1428 |
|
... | ... | @@ -44,6 +44,7 @@ class Linux(Platform): |
44 | 44 |
self._local_sandbox_available = self._have_fuse and self._have_good_bwrap
|
45 | 45 |
|
46 | 46 |
self._die_with_parent_available = _site.check_bwrap_version(0, 1, 8)
|
47 |
+ self._json_status_available = _site.check_bwrap_version(0, 3, 2)
|
|
47 | 48 |
|
48 | 49 |
if self._local_sandbox_available:
|
49 | 50 |
self._user_ns_available = self._check_user_ns_available()
|
... | ... | @@ -91,6 +92,7 @@ class Linux(Platform): |
91 | 92 |
# Inform the bubblewrap sandbox as to whether it can use user namespaces or not
|
92 | 93 |
kwargs['user_ns_available'] = self._user_ns_available
|
93 | 94 |
kwargs['die_with_parent_available'] = self._die_with_parent_available
|
95 |
+ kwargs['json_status_available'] = self._json_status_available
|
|
94 | 96 |
return SandboxBwrap(*args, **kwargs)
|
95 | 97 |
|
96 | 98 |
def _check_user_ns_available(self):
|
... | ... | @@ -17,6 +17,8 @@ |
17 | 17 |
# Authors:
|
18 | 18 |
# Andrew Leeming <andrew leeming codethink co uk>
|
19 | 19 |
# Tristan Van Berkom <tristan vanberkom codethink co uk>
|
20 |
+import collections
|
|
21 |
+import json
|
|
20 | 22 |
import os
|
21 | 23 |
import sys
|
22 | 24 |
import time
|
... | ... | @@ -24,7 +26,8 @@ import errno |
24 | 26 |
import signal
|
25 | 27 |
import subprocess
|
26 | 28 |
import shutil
|
27 |
-from contextlib import ExitStack
|
|
29 |
+from contextlib import ExitStack, suppress
|
|
30 |
+from tempfile import TemporaryFile
|
|
28 | 31 |
|
29 | 32 |
import psutil
|
30 | 33 |
|
... | ... | @@ -53,6 +56,7 @@ class SandboxBwrap(Sandbox): |
53 | 56 |
super().__init__(*args, **kwargs)
|
54 | 57 |
self.user_ns_available = kwargs['user_ns_available']
|
55 | 58 |
self.die_with_parent_available = kwargs['die_with_parent_available']
|
59 |
+ self.json_status_available = kwargs['json_status_available']
|
|
56 | 60 |
|
57 | 61 |
def run(self, command, flags, *, cwd=None, env=None):
|
58 | 62 |
stdout, stderr = self._get_output()
|
... | ... | @@ -159,24 +163,31 @@ class SandboxBwrap(Sandbox): |
159 | 163 |
gid = self._get_config().build_gid
|
160 | 164 |
bwrap_command += ['--uid', str(uid), '--gid', str(gid)]
|
161 | 165 |
|
162 |
- # Add the command
|
|
163 |
- bwrap_command += command
|
|
164 |
- |
|
165 |
- # bwrap might create some directories while being suid
|
|
166 |
- # and may give them to root gid, if it does, we'll want
|
|
167 |
- # to clean them up after, so record what we already had
|
|
168 |
- # there just in case so that we can safely cleanup the debris.
|
|
169 |
- #
|
|
170 |
- existing_basedirs = {
|
|
171 |
- directory: os.path.exists(os.path.join(root_directory, directory))
|
|
172 |
- for directory in ['tmp', 'dev', 'proc']
|
|
173 |
- }
|
|
174 |
- |
|
175 |
- # Use the MountMap context manager to ensure that any redirected
|
|
176 |
- # mounts through fuse layers are in context and ready for bwrap
|
|
177 |
- # to mount them from.
|
|
178 |
- #
|
|
179 | 166 |
with ExitStack() as stack:
|
167 |
+ pass_fds = ()
|
|
168 |
+ # Improve error reporting with json-status if available
|
|
169 |
+ if self.json_status_available:
|
|
170 |
+ json_status_file = stack.enter_context(TemporaryFile())
|
|
171 |
+ pass_fds = (json_status_file.fileno(),)
|
|
172 |
+ bwrap_command += ['--json-status-fd', str(json_status_file.fileno())]
|
|
173 |
+ |
|
174 |
+ # Add the command
|
|
175 |
+ bwrap_command += command
|
|
176 |
+ |
|
177 |
+ # bwrap might create some directories while being suid
|
|
178 |
+ # and may give them to root gid, if it does, we'll want
|
|
179 |
+ # to clean them up after, so record what we already had
|
|
180 |
+ # there just in case so that we can safely cleanup the debris.
|
|
181 |
+ #
|
|
182 |
+ existing_basedirs = {
|
|
183 |
+ directory: os.path.exists(os.path.join(root_directory, directory))
|
|
184 |
+ for directory in ['tmp', 'dev', 'proc']
|
|
185 |
+ }
|
|
186 |
+ |
|
187 |
+ # Use the MountMap context manager to ensure that any redirected
|
|
188 |
+ # mounts through fuse layers are in context and ready for bwrap
|
|
189 |
+ # to mount them from.
|
|
190 |
+ #
|
|
180 | 191 |
stack.enter_context(mount_map.mounted(self))
|
181 | 192 |
|
182 | 193 |
# Ensure the cwd exists
|
... | ... | @@ -194,7 +205,7 @@ class SandboxBwrap(Sandbox): |
194 | 205 |
|
195 | 206 |
# Run bubblewrap !
|
196 | 207 |
exit_code = self.run_bwrap(bwrap_command, stdin, stdout, stderr,
|
197 |
- (flags & SandboxFlags.INTERACTIVE))
|
|
208 |
+ (flags & SandboxFlags.INTERACTIVE), pass_fds)
|
|
198 | 209 |
|
199 | 210 |
# Cleanup things which bwrap might have left behind, while
|
200 | 211 |
# everything is still mounted because bwrap can be creating
|
... | ... | @@ -242,10 +253,24 @@ class SandboxBwrap(Sandbox): |
242 | 253 |
# a bug, bwrap mounted a tempfs here and when it exits, that better be empty.
|
243 | 254 |
pass
|
244 | 255 |
|
256 |
+ if self.json_status_available:
|
|
257 |
+ json_status_file.seek(0, 0)
|
|
258 |
+ child_exit_code = None
|
|
259 |
+ for line in json_status_file:
|
|
260 |
+ with suppress(json.decoder.JSONDecodeError):
|
|
261 |
+ o = json.loads(line)
|
|
262 |
+ if isinstance(o, collections.abc.Mapping) and 'exit-code' in o:
|
|
263 |
+ child_exit_code = o['exit-code']
|
|
264 |
+ break
|
|
265 |
+ if child_exit_code is None:
|
|
266 |
+ raise SandboxError("`bwrap' terminated during sandbox setup with exitcode {}".format(exit_code),
|
|
267 |
+ reason="bwrap-sandbox-fail")
|
|
268 |
+ exit_code = child_exit_code
|
|
269 |
+ |
|
245 | 270 |
self._vdir._mark_changed()
|
246 | 271 |
return exit_code
|
247 | 272 |
|
248 |
- def run_bwrap(self, argv, stdin, stdout, stderr, interactive):
|
|
273 |
+ def run_bwrap(self, argv, stdin, stdout, stderr, interactive, pass_fds):
|
|
249 | 274 |
# Wrapper around subprocess.Popen() with common settings.
|
250 | 275 |
#
|
251 | 276 |
# This function blocks until the subprocess has terminated.
|
... | ... | @@ -321,6 +346,7 @@ class SandboxBwrap(Sandbox): |
321 | 346 |
# The default is to share file descriptors from the parent process
|
322 | 347 |
# to the subprocess, which is rarely good for sandboxing.
|
323 | 348 |
close_fds=True,
|
349 |
+ pass_fds=pass_fds,
|
|
324 | 350 |
stdin=stdin,
|
325 | 351 |
stdout=stdout,
|
326 | 352 |
stderr=stderr,
|
... | ... | @@ -93,10 +93,10 @@ echo "INFO: Checking out $element ..." >&2 |
93 | 93 |
$bst_cmd checkout --tar "$element" "$checkout_tar" || die "Failed to checkout $element"
|
94 | 94 |
echo "INFO: Successfully checked out $element" >&2
|
95 | 95 |
|
96 |
-echo "INFO: Importing Docker image ..."
|
|
96 |
+echo "INFO: Importing Docker image ..." >&2
|
|
97 | 97 |
"${docker_import_cmd[@]}" "$checkout_tar" "$docker_image_tag" || die "Failed to import Docker image from tarball"
|
98 |
-echo "INFO: Successfully import Docker image $docker_image_tag"
|
|
98 |
+echo "INFO: Successfully import Docker image $docker_image_tag" >&2
|
|
99 | 99 |
|
100 |
-echo "INFO: Cleaning up ..."
|
|
100 |
+echo "INFO: Cleaning up ..." >&2
|
|
101 | 101 |
rm "$checkout_tar" || die "Failed to remove $checkout_tar"
|
102 |
-echo "INFO: Clean up finished"
|
|
102 |
+echo "INFO: Clean up finished" >&2
|
1 | 1 |
import os
|
2 | 2 |
import pytest
|
3 | 3 |
|
4 |
+from buildstream._exceptions import ErrorDomain
|
|
5 |
+ |
|
4 | 6 |
from tests.testutils import cli_integration as cli
|
5 | 7 |
from tests.testutils.integration import assert_contains
|
6 |
-from tests.testutils.site import HAVE_BWRAP
|
|
8 |
+from tests.testutils.site import HAVE_BWRAP, HAVE_BWRAP_JSON_STATUS
|
|
7 | 9 |
|
8 | 10 |
|
9 | 11 |
pytestmark = pytest.mark.integration
|
... | ... | @@ -29,3 +31,32 @@ def test_sandbox_bwrap_cleanup_build(cli, tmpdir, datafiles): |
29 | 31 |
# Here, BuildStream should not attempt any rmdir etc.
|
30 | 32 |
result = cli.run(project=project, args=['build', element_name])
|
31 | 33 |
assert result.exit_code == 0
|
34 |
+ |
|
35 |
+ |
|
36 |
+@pytest.mark.skipif(not HAVE_BWRAP, reason='Only available with bubblewrap')
|
|
37 |
+@pytest.mark.skipif(not HAVE_BWRAP_JSON_STATUS, reason='Only available with bubblewrap supporting --json-status-fd')
|
|
38 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
39 |
+def test_sandbox_bwrap_distinguish_setup_error(cli, tmpdir, datafiles):
|
|
40 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
41 |
+ element_name = 'sandbox-bwrap/non-executable-shell.bst'
|
|
42 |
+ |
|
43 |
+ result = cli.run(project=project, args=['build', element_name])
|
|
44 |
+ result.assert_task_error(error_domain=ErrorDomain.SANDBOX, error_reason="bwrap-sandbox-fail")
|
|
45 |
+ |
|
46 |
+ |
|
47 |
+@pytest.mark.integration
|
|
48 |
+@pytest.mark.skipif(not HAVE_BWRAP, reason='Only available with bubblewrap')
|
|
49 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
50 |
+def test_sandbox_bwrap_return_subprocess(cli, tmpdir, datafiles):
|
|
51 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
52 |
+ element_name = 'sandbox-bwrap/command-exit-42.bst'
|
|
53 |
+ |
|
54 |
+ cli.configure({
|
|
55 |
+ "logging": {
|
|
56 |
+ "message-format": "%{element}|%{message}",
|
|
57 |
+ },
|
|
58 |
+ })
|
|
59 |
+ |
|
60 |
+ result = cli.run(project=project, args=['build', element_name])
|
|
61 |
+ result.assert_task_error(error_domain=ErrorDomain.ELEMENT, error_reason=None)
|
|
62 |
+ assert "sandbox-bwrap/command-exit-42.bst|Command 'exit 42' failed with exitcode 42" in result.stderr
|
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 |
import os
|
5 | 5 |
import sys
|
6 | 6 |
|
7 |
-from buildstream import utils, ProgramNotFoundError
|
|
7 |
+from buildstream import _site, utils, ProgramNotFoundError
|
|
8 | 8 |
|
9 | 9 |
try:
|
10 | 10 |
utils.get_host_tool('bzr')
|
... | ... | @@ -33,8 +33,10 @@ except (ImportError, ValueError): |
33 | 33 |
try:
|
34 | 34 |
utils.get_host_tool('bwrap')
|
35 | 35 |
HAVE_BWRAP = True
|
36 |
+ HAVE_BWRAP_JSON_STATUS = _site.check_bwrap_version(0, 3, 2)
|
|
36 | 37 |
except ProgramNotFoundError:
|
37 | 38 |
HAVE_BWRAP = False
|
39 |
+ HAVE_BWRAP_JSON_STATUS = False
|
|
38 | 40 |
|
39 | 41 |
try:
|
40 | 42 |
utils.get_host_tool('lzip')
|