summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJürg Billeter <j@bitron.ch>2020-02-27 14:31:18 +0000
committerJürg Billeter <j@bitron.ch>2020-02-27 14:31:18 +0000
commit7eceaa91a57a82c822cb07a3dd02155f20d3ea09 (patch)
treeaa94ef962d4f8e6553ae1b82af8947045fa66226
parent5b2abcf66f6c05cce9b08c12e4129eab3164085f (diff)
parent9cf7a8ad0bdc3bdc235fe52407fd82ba5ebc6063 (diff)
downloadbuildstream-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.py35
-rw-r--r--src/buildstream/storage/_casbaseddirectory.py24
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