summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2015-05-21 18:15:25 +0100
committerSam Thursfield <sam.thursfield@codethink.co.uk>2015-05-21 18:15:25 +0100
commita3bd1ea3de886ec5f88eaee6770bb29c953c32ef (patch)
tree6e2f526ef33adaf7c1b51b5a05575acc50117e21
downloadsandboxlib-a3bd1ea3de886ec5f88eaee6770bb29c953c32ef.tar.gz
Add initial sandboxing tools
sandbox.py lets you create a .aci file (App Container Image) from a tar file, that should run a given command when executed. exec/chroot.py executes a .aci file (App Container Image). I doubt that the produced .aci files are actually compatible with other App Container ('appc') execution tools yet. The executor will also be unable to run all but the simplest applications that are packaged as .aci files. Also, the process of untarring a .tar file to create a .aci, then unpacking the .aci again to run it is very ineffecient. Plus it is missing lots of important features. But, it's a start.
-rw-r--r--exec/chroot.py58
-rw-r--r--sandbox.py69
2 files changed, 127 insertions, 0 deletions
diff --git a/exec/chroot.py b/exec/chroot.py
new file mode 100644
index 0000000..d393d50
--- /dev/null
+++ b/exec/chroot.py
@@ -0,0 +1,58 @@
+# Run a sandbox in a chroot.
+
+
+import contextlib
+import json
+import os
+import shutil
+import subprocess
+import tarfile
+import tempfile
+
+
+@contextlib.contextmanager
+def unpack_app_container_image(image_file):
+ tempdir = tempfile.mkdtemp()
+ try:
+ # FIXME: you gotta be root, sorry.
+ with tarfile.open(image_file, 'r') as tf:
+ tf.extractall(path=tempdir)
+
+ manifest_path = os.path.join(tempdir, 'manifest')
+ rootfs_path = os.path.join(tempdir, 'rootfs')
+
+ with open(manifest_path, 'r') as f:
+ manifest_data = json.load(f)
+
+ yield rootfs_path, manifest_data
+ finally:
+ shutil.rmtree(tempdir)
+
+
+def _run_sandbox_real(rootfs_path, manifest, command=None):
+ # FIXME: you gotta be root.
+ print manifest
+ if command is None:
+ # Use the command from the image
+ command = manifest['app']['exec']
+ if type(command) == str:
+ command = [command]
+ subprocess.call(['chroot', rootfs_path] + command)
+
+
+def run_sandbox(app_container_image=None,
+ rootfs_path=None,
+ manifest=None,
+ command=None):
+ if app_container_image is not None:
+ assert rootfs_path is None and manifest is None, \
+ "You cannot specify a rootfs_path or manifest when running an " \
+ "App Container image."
+ with unpack_app_container_image(app_container_image) as (rootfs_path, manifest):
+ return _run_sandbox_real(rootfs_path, manifest, command=command)
+ else:
+ _run_sandbox_real(rootfs_path, manifest, command=command)
+
+
+run_sandbox(app_container_image='/home/shared/baserock/baserock-minimal.aci',
+ command=['/bin/sh', '-c', 'echo foo && exit 1'])
diff --git a/sandbox.py b/sandbox.py
new file mode 100644
index 0000000..85107ae
--- /dev/null
+++ b/sandbox.py
@@ -0,0 +1,69 @@
+# Make a sandbox for running a command.
+
+# Sandbox could be: a baserock chroot, for the time being.
+
+# Image layout: /rootfs, /manifest
+
+
+import json
+import os
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+
+
+def appc_manifest_for_command(command):
+ '''Fake an appc manifest.'''
+ manifest = {
+ 'acKind': 'ImageManifest',
+ 'acVersion': '0.5.2',
+ 'name': 'temp/temp1',
+ 'labels': [],
+ 'app': {
+ 'exec': command,
+ 'user': 'root',
+ 'group': 'root',
+ 'workingDirectory': '/temp.build',
+ }
+ }
+ return json.dumps(manifest)
+
+def make_sandbox_for_command(command, source_tar, target,
+ actool='/home/shared/baserock/appc-spec/actool/actool'):
+ '''Fake an appc image.
+
+ This is a dumb idea, because you have to unpack a tar, create a tar, then
+ unpack it again to run it.
+
+ Better to have the executor take manifest and rootfs separately.
+
+ '''
+ tempdir = tempfile.mkdtemp()
+
+ try:
+ manifest_path = os.path.join(tempdir, 'manifest')
+ rootfs_path = os.path.join(tempdir, 'rootfs')
+
+ with open(manifest_path, 'w') as f:
+ f.write(appc_manifest_for_command(command))
+
+ os.mkdir(rootfs_path)
+ # FIXME: You've probably got to run this as root.
+ with tarfile.TarFile(source_tar, 'r') as tf:
+ tf.extractall(path=rootfs_path)
+
+ subprocess.check_call(
+ [actool, 'build', tempdir, target],
+ stdout=sys.stdout,
+ stderr=sys.stderr)
+ print 'Created %s' % target
+ finally:
+ shutil.rmtree(tempdir)
+
+
+make_sandbox_for_command(
+ command=['/bin/sh', '-c', '"echo foo && exit 1"'],
+ source_tar='/home/shared/baserock-chroot-src/definitions/baserock-minimal.tar',
+ target='/home/shared/baserock/baserock-minimal.aci')