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 | 
