diff options
author | Jürg Billeter <j@bitron.ch> | 2020-02-27 14:31:18 +0000 |
---|---|---|
committer | Jürg Billeter <j@bitron.ch> | 2020-02-27 14:31:18 +0000 |
commit | 7eceaa91a57a82c822cb07a3dd02155f20d3ea09 (patch) | |
tree | aa94ef962d4f8e6553ae1b82af8947045fa66226 | |
parent | 5b2abcf66f6c05cce9b08c12e4129eab3164085f (diff) | |
parent | 9cf7a8ad0bdc3bdc235fe52407fd82ba5ebc6063 (diff) | |
download | buildstream-7eceaa91a57a82c822cb07a3dd02155f20d3ea09.tar.gz |
Merge branch 'juerg/reapi-readonly' into 'master'
_sandboxreapi.py: Support read-only root
See merge request BuildStream/buildstream!1825
-rw-r--r-- | src/buildstream/sandbox/_sandboxreapi.py | 35 | ||||
-rw-r--r-- | src/buildstream/storage/_casbaseddirectory.py | 24 |
2 files changed, 48 insertions, 11 deletions
diff --git a/src/buildstream/sandbox/_sandboxreapi.py b/src/buildstream/sandbox/_sandboxreapi.py index 19c599197..c8d2be70b 100644 --- a/src/buildstream/sandbox/_sandboxreapi.py +++ b/src/buildstream/sandbox/_sandboxreapi.py @@ -57,7 +57,9 @@ class SandboxREAPI(Sandbox): # Ensure directories required for sandboxed execution exist for directory in ["dev", "proc", "tmp"]: - vdir.descend(directory, create=True) + vsubdir = vdir.descend(directory, create=True) + if flags & SandboxFlags.ROOT_READ_ONLY: + vsubdir._set_subtree_read_only(False) # Create directories for all marked directories. This emulates # some of the behaviour of other sandboxes, which create these @@ -66,13 +68,32 @@ class SandboxREAPI(Sandbox): mount_sources = self._get_mount_sources() for mark in self._get_marked_directories(): directory = mark["directory"] - if directory in mount_sources: - continue - # Create each marked directory - vdir.descend(*directory.split(os.path.sep), create=True) - read_write_directories.append(directory) - if not flags & SandboxFlags.ROOT_READ_ONLY: + if directory in mount_sources: + # Bind mount + mount_point = directory + mount_source = mount_sources[mount_point] + + # Ensure mount point exists in sandbox + mount_point_components = mount_point.split(os.path.sep) + if not vdir._exists(*mount_point_components): + if os.path.isdir(mount_source): + # Mounting a directory, mount point must be a directory + vdir.descend(*mount_point_components, create=True) + else: + # Mounting a file or device node, mount point must be a file + parent_vdir = vdir.descend(*mount_point_components[:-1], create=True) + parent_vdir._create_empty_file(mount_point_components[-1]) + else: + # Read-write directory + marked_vdir = vdir.descend(*directory.split(os.path.sep), create=True) + read_write_directories.append(directory) + if flags & SandboxFlags.ROOT_READ_ONLY: + marked_vdir._set_subtree_read_only(False) + + if flags & SandboxFlags.ROOT_READ_ONLY: + vdir._set_subtree_read_only(True) + else: # The whole sandbox is writable read_write_directories = [os.path.sep] diff --git a/src/buildstream/storage/_casbaseddirectory.py b/src/buildstream/storage/_casbaseddirectory.py index 3ab11a6ed..51d9909fd 100644 --- a/src/buildstream/storage/_casbaseddirectory.py +++ b/src/buildstream/storage/_casbaseddirectory.py @@ -140,6 +140,7 @@ class CasBasedDirectory(Directory): self.__digest = None self.index = {} self.parent = parent + self.__node_properties = [] self._reset(digest=digest) def _reset(self, *, digest=None): @@ -156,6 +157,8 @@ class CasBasedDirectory(Directory): except FileNotFoundError as e: raise VirtualDirectoryError("Directory not found in local cache: {}".format(e)) from e + self.__node_properties = list(pb2_directory.node_properties) + for entry in pb2_directory.directories: self.index[entry.name] = IndexEntry(entry.name, _FileType.DIRECTORY, digest=entry.digest) for entry in pb2_directory.files: @@ -214,7 +217,7 @@ class CasBasedDirectory(Directory): self.__invalidate_digest() def _create_empty_file(self, name): - digest = self.cas_cache.add_object(buffer="") + digest = self.cas_cache.add_object(buffer=b"") entry = IndexEntry(name, _FileType.REGULAR_FILE, digest=digest) self.index[name] = entry @@ -759,6 +762,10 @@ class CasBasedDirectory(Directory): # Create updated Directory proto pb2_directory = remote_execution_pb2.Directory() + if self.__node_properties: + node_properties = sorted(self.__node_properties, key=lambda prop: prop.name) + pb2_directory.node_properties.extend(node_properties) + for name, entry in sorted(self.index.items()): if entry.type == _FileType.DIRECTORY: dirnode = pb2_directory.directories.add() @@ -794,18 +801,27 @@ class CasBasedDirectory(Directory): subdir = self.descend(*path[:-1], follow_symlinks=follow_symlinks) target = subdir.index.get(path[-1]) if target is not None: - if target.type == _FileType.REGULAR_FILE: - return True - elif follow_symlinks and target.type == _FileType.SYMLINK: + if follow_symlinks and target.type == _FileType.SYMLINK: linklocation = target.target newpath = linklocation.split(os.path.sep) if os.path.isabs(linklocation): return subdir.find_root()._exists(*newpath, follow_symlinks=True) return subdir._exists(*newpath, follow_symlinks=True) + else: + return True return False except VirtualDirectoryError: return False + def _set_subtree_read_only(self, read_only): + self.__node_properties = list(filter(lambda prop: prop.name != "SubtreeReadOnly", self.__node_properties)) + node_property = remote_execution_pb2.NodeProperty() + node_property.name = "SubtreeReadOnly" + node_property.value = "true" if read_only else "false" + self.__node_properties.append(node_property) + + self.__invalidate_digest() + def __invalidate_digest(self): if self.__digest: self.__digest = None |