Tristan Van Berkom pushed to branch master at BuildStream / buildstream
Commits:
-
081dcafa
by Richard Maw at 2018-09-18T13:22:38Z
-
d0425608
by Richard Maw at 2018-09-18T13:22:38Z
-
8430fdc7
by Richard Maw at 2018-09-18T13:22:38Z
-
d8450166
by Tristan Van Berkom at 2018-09-18T13:50:15Z
6 changed files:
- buildstream/_fuse/hardlinks.py
- buildstream/_fuse/mount.py
- buildstream/sandbox/_mount.py
- buildstream/sandbox/_sandboxchroot.py
- + tests/integration/project/elements/integration.bst
- tests/integration/shell.py
Changes:
| ... | ... | @@ -42,9 +42,10 @@ from .mount import Mount |
| 42 | 42 |
#
|
| 43 | 43 |
class SafeHardlinks(Mount):
|
| 44 | 44 |
|
| 45 |
- def __init__(self, directory, tempdir):
|
|
| 45 |
+ def __init__(self, directory, tempdir, fuse_mount_options={}):
|
|
| 46 | 46 |
self.directory = directory
|
| 47 | 47 |
self.tempdir = tempdir
|
| 48 |
+ super().__init__(fuse_mount_options=fuse_mount_options)
|
|
| 48 | 49 |
|
| 49 | 50 |
def create_operations(self):
|
| 50 | 51 |
return SafeHardlinkOps(self.directory, self.tempdir)
|
| ... | ... | @@ -121,7 +122,7 @@ class SafeHardlinkOps(Operations): |
| 121 | 122 |
st = os.lstat(full_path)
|
| 122 | 123 |
return dict((key, getattr(st, key)) for key in (
|
| 123 | 124 |
'st_atime', 'st_ctime', 'st_gid', 'st_mode',
|
| 124 |
- 'st_mtime', 'st_nlink', 'st_size', 'st_uid'))
|
|
| 125 |
+ 'st_mtime', 'st_nlink', 'st_size', 'st_uid', 'st_rdev'))
|
|
| 125 | 126 |
|
| 126 | 127 |
def readdir(self, path, fh):
|
| 127 | 128 |
full_path = self._full_path(path)
|
| ... | ... | @@ -87,6 +87,9 @@ class Mount(): |
| 87 | 87 |
# User Facing API #
|
| 88 | 88 |
################################################
|
| 89 | 89 |
|
| 90 |
+ def __init__(self, fuse_mount_options={}):
|
|
| 91 |
+ self._fuse_mount_options = fuse_mount_options
|
|
| 92 |
+ |
|
| 90 | 93 |
# mount():
|
| 91 | 94 |
#
|
| 92 | 95 |
# User facing API for mounting a fuse subclass implementation
|
| ... | ... | @@ -184,7 +187,8 @@ class Mount(): |
| 184 | 187 |
# Run fuse in foreground in this child process, internally libfuse
|
| 185 | 188 |
# will handle SIGTERM and gracefully exit it's own little main loop.
|
| 186 | 189 |
#
|
| 187 |
- FUSE(self.__operations, self.__mountpoint, nothreads=True, foreground=True, nonempty=True)
|
|
| 190 |
+ FUSE(self.__operations, self.__mountpoint, nothreads=True, foreground=True, nonempty=True,
|
|
| 191 |
+ **self._fuse_mount_options)
|
|
| 188 | 192 |
|
| 189 | 193 |
# Explicit 0 exit code, if the operations crashed for some reason, the exit
|
| 190 | 194 |
# code will not be 0, and we want to know about it.
|
| ... | ... | @@ -30,7 +30,7 @@ from .._fuse import SafeHardlinks |
| 30 | 30 |
# Helper data object representing a single mount point in the mount map
|
| 31 | 31 |
#
|
| 32 | 32 |
class Mount():
|
| 33 |
- def __init__(self, sandbox, mount_point, safe_hardlinks):
|
|
| 33 |
+ def __init__(self, sandbox, mount_point, safe_hardlinks, fuse_mount_options={}):
|
|
| 34 | 34 |
scratch_directory = sandbox._get_scratch_directory()
|
| 35 | 35 |
# Getting _get_underlying_directory() here is acceptable as
|
| 36 | 36 |
# we're part of the sandbox code. This will fail if our
|
| ... | ... | @@ -39,6 +39,7 @@ class Mount(): |
| 39 | 39 |
|
| 40 | 40 |
self.mount_point = mount_point
|
| 41 | 41 |
self.safe_hardlinks = safe_hardlinks
|
| 42 |
+ self._fuse_mount_options = fuse_mount_options
|
|
| 42 | 43 |
|
| 43 | 44 |
# FIXME: When the criteria for mounting something and it's parent
|
| 44 | 45 |
# mount is identical, then there is no need to mount an additional
|
| ... | ... | @@ -82,7 +83,7 @@ class Mount(): |
| 82 | 83 |
@contextmanager
|
| 83 | 84 |
def mounted(self, sandbox):
|
| 84 | 85 |
if self.safe_hardlinks:
|
| 85 |
- mount = SafeHardlinks(self.mount_origin, self.mount_tempdir)
|
|
| 86 |
+ mount = SafeHardlinks(self.mount_origin, self.mount_tempdir, self._fuse_mount_options)
|
|
| 86 | 87 |
with mount.mounted(self.mount_source):
|
| 87 | 88 |
yield
|
| 88 | 89 |
else:
|
| ... | ... | @@ -100,12 +101,12 @@ class Mount(): |
| 100 | 101 |
#
|
| 101 | 102 |
class MountMap():
|
| 102 | 103 |
|
| 103 |
- def __init__(self, sandbox, root_readonly):
|
|
| 104 |
+ def __init__(self, sandbox, root_readonly, fuse_mount_options={}):
|
|
| 104 | 105 |
# We will be doing the mounts in the order in which they were declared.
|
| 105 | 106 |
self.mounts = OrderedDict()
|
| 106 | 107 |
|
| 107 | 108 |
# We want safe hardlinks on rootfs whenever root is not readonly
|
| 108 |
- self.mounts['/'] = Mount(sandbox, '/', not root_readonly)
|
|
| 109 |
+ self.mounts['/'] = Mount(sandbox, '/', not root_readonly, fuse_mount_options)
|
|
| 109 | 110 |
|
| 110 | 111 |
for mark in sandbox._get_marked_directories():
|
| 111 | 112 |
directory = mark['directory']
|
| ... | ... | @@ -113,7 +114,7 @@ class MountMap(): |
| 113 | 114 |
|
| 114 | 115 |
# We want safe hardlinks for any non-root directory where
|
| 115 | 116 |
# artifacts will be staged to
|
| 116 |
- self.mounts[directory] = Mount(sandbox, directory, artifact)
|
|
| 117 |
+ self.mounts[directory] = Mount(sandbox, directory, artifact, fuse_mount_options)
|
|
| 117 | 118 |
|
| 118 | 119 |
# get_mount_source()
|
| 119 | 120 |
#
|
| ... | ... | @@ -35,6 +35,9 @@ from . import Sandbox, SandboxFlags |
| 35 | 35 |
|
| 36 | 36 |
|
| 37 | 37 |
class SandboxChroot(Sandbox):
|
| 38 |
+ |
|
| 39 |
+ _FUSE_MOUNT_OPTIONS = {'dev': True}
|
|
| 40 |
+ |
|
| 38 | 41 |
def __init__(self, *args, **kwargs):
|
| 39 | 42 |
super().__init__(*args, **kwargs)
|
| 40 | 43 |
|
| ... | ... | @@ -67,7 +70,8 @@ class SandboxChroot(Sandbox): |
| 67 | 70 |
|
| 68 | 71 |
# Create the mount map, this will tell us where
|
| 69 | 72 |
# each mount point needs to be mounted from and to
|
| 70 |
- self.mount_map = MountMap(self, flags & SandboxFlags.ROOT_READ_ONLY)
|
|
| 73 |
+ self.mount_map = MountMap(self, flags & SandboxFlags.ROOT_READ_ONLY,
|
|
| 74 |
+ self._FUSE_MOUNT_OPTIONS)
|
|
| 71 | 75 |
root_mount_source = self.mount_map.get_mount_source('/')
|
| 72 | 76 |
|
| 73 | 77 |
# Create a sysroot and run the command inside it
|
| 1 |
+kind: manual
|
|
| 2 |
+depends:
|
|
| 3 |
+- base.bst
|
|
| 4 |
+ |
|
| 5 |
+public:
|
|
| 6 |
+ bst:
|
|
| 7 |
+ integration-commands:
|
|
| 8 |
+ - |
|
|
| 9 |
+ echo noise >/dev/null
|
| ... | ... | @@ -342,3 +342,13 @@ def test_sysroot_workspace_visible(cli, tmpdir, datafiles): |
| 342 | 342 |
])
|
| 343 | 343 |
assert result.exit_code == 0
|
| 344 | 344 |
assert result.output == workspace_hello
|
| 345 |
+ |
|
| 346 |
+ |
|
| 347 |
+# Test system integration commands can access devices in /dev
|
|
| 348 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
| 349 |
+def test_integration_devices(cli, tmpdir, datafiles):
|
|
| 350 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
| 351 |
+ element_name = 'integration.bst'
|
|
| 352 |
+ |
|
| 353 |
+ result = execute_shell(cli, project, ["true"], element=element_name)
|
|
| 354 |
+ assert result.exit_code == 0
|
