Commit 28ea60be authored by Julien Muchembled's avatar Julien Muchembled

wrapper: new private-tmpfs option, private-dev-shm deprecated

parent 5118c476
from __future__ import print_function from __future__ import print_function
import errno
import sys import sys
import os import os
import signal import signal
...@@ -50,7 +51,7 @@ def _libc(): ...@@ -50,7 +51,7 @@ def _libc():
return mount, unshare return mount, unshare
def generic_exec(args, extra_environ=None, wait_list=None, def generic_exec(args, extra_environ=None, wait_list=None,
pidfile=None, reserve_cpu=False, private_dev_shm=None, pidfile=None, reserve_cpu=False, private_tmpfs=(),
#shebang_workaround=False, # XXX: still needed ? #shebang_workaround=False, # XXX: still needed ?
): ):
args = list(args) args = list(args)
...@@ -83,7 +84,7 @@ def generic_exec(args, extra_environ=None, wait_list=None, ...@@ -83,7 +84,7 @@ def generic_exec(args, extra_environ=None, wait_list=None,
if wait_list: if wait_list:
_wait_files_creation(wait_list) _wait_files_creation(wait_list)
if private_dev_shm: if private_tmpfs:
mount, unshare = _libc() mount, unshare = _libc()
CLONE_NEWNS = 0x00020000 CLONE_NEWNS = 0x00020000
CLONE_NEWUSER = 0x10000000 CLONE_NEWUSER = 0x10000000
...@@ -93,7 +94,13 @@ def generic_exec(args, extra_environ=None, wait_list=None, ...@@ -93,7 +94,13 @@ def generic_exec(args, extra_environ=None, wait_list=None,
with open('/proc/self/setgroups', 'wb') as f: f.write('deny') with open('/proc/self/setgroups', 'wb') as f: f.write('deny')
with open('/proc/self/uid_map', 'wb') as f: f.write('%s %s 1' % (uid, uid)) with open('/proc/self/uid_map', 'wb') as f: f.write('%s %s 1' % (uid, uid))
with open('/proc/self/gid_map', 'wb') as f: f.write('%s %s 1' % (gid, gid)) with open('/proc/self/gid_map', 'wb') as f: f.write('%s %s 1' % (gid, gid))
mount('tmpfs', '/dev/shm', 'tmpfs', 0, 'size=' + private_dev_shm) for size, path in private_tmpfs:
try:
os.mkdir(path)
except OSError as e:
if e.errno != errno.EEXIST:
raise
mount('tmpfs', path, 'tmpfs', 0, 'size=' + size)
if extra_environ: if extra_environ:
env = os.environ.copy() env = os.environ.copy()
......
...@@ -43,7 +43,8 @@ from six.moves.urllib.parse import urlunparse ...@@ -43,7 +43,8 @@ from six.moves.urllib.parse import urlunparse
import pkg_resources import pkg_resources
import zc.buildout from zc.buildout import easy_install, UserError
from zc.recipe.egg import Egg
from slapos.recipe.librecipe import shlex from slapos.recipe.librecipe import shlex
...@@ -85,8 +86,7 @@ class GenericBaseRecipe(object): ...@@ -85,8 +86,7 @@ class GenericBaseRecipe(object):
def getWorkingSet(self): def getWorkingSet(self):
"""If you want do override the default working set""" """If you want do override the default working set"""
egg = zc.recipe.egg.Egg(self.buildout, 'slapos.cookbook', egg = Egg(self.buildout, 'slapos.cookbook', self.options.copy())
self.options.copy())
requirements, ws = egg.working_set() requirements, ws = egg.working_set()
return ws return ws
...@@ -156,10 +156,20 @@ class GenericBaseRecipe(object): ...@@ -156,10 +156,20 @@ class GenericBaseRecipe(object):
args = itertools.chain(map(repr, args), args = itertools.chain(map(repr, args),
map('%s=%r'.__mod__, six.iteritems(kw))) map('%s=%r'.__mod__, six.iteritems(kw)))
return zc.buildout.easy_install.scripts( return easy_install.scripts(
[(filename, module, function)], self._ws, sys.executable, [(filename, module, function)], self._ws, sys.executable,
path, arguments=', '.join(args))[0] path, arguments=', '.join(args))[0]
def parsePrivateTmpfs(self):
private_tmpfs = []
for line in (self.options.get('private-tmpfs') or '').splitlines():
if line:
x = line.split(None, 1)
if len(x) != 2:
raise UserError("failed to split %r into size and path" % line)
private_tmpfs.append(tuple(x))
return private_tmpfs
def createWrapper(self, path, args, env=None, **kw): def createWrapper(self, path, args, env=None, **kw):
"""Create a wrapper script for process replacement""" """Create a wrapper script for process replacement"""
assert args assert args
......
...@@ -38,7 +38,7 @@ class Recipe(GenericBaseRecipe): ...@@ -38,7 +38,7 @@ class Recipe(GenericBaseRecipe):
:param lines hash-files: list of buildout-generated files to be checked by hash :param lines hash-files: list of buildout-generated files to be checked by hash
:param lines hash-existing-files: list of existing files to be checked by hash :param lines hash-existing-files: list of existing files to be checked by hash
:param str pidfile: path to pidfile ensure exclusivity for the process :param str pidfile: path to pidfile ensure exclusivity for the process
:param str private-dev-shm: size of private /dev/shm, using user namespaces :param lines private-tmpfs: list of "<size> <path>" private tmpfs, using user namespaces
:param bool reserve-cpu: command will ask for an exclusive CPU core :param bool reserve-cpu: command will ask for an exclusive CPU core
""" """
...@@ -72,13 +72,17 @@ class Recipe(GenericBaseRecipe): ...@@ -72,13 +72,17 @@ class Recipe(GenericBaseRecipe):
raise UserError( raise UserError(
"hash-files must only list files that are generated by buildout:" "hash-files must only list files that are generated by buildout:"
"\n " + "\n ".join(self._existing)) "\n " + "\n ".join(self._existing))
args = shlex.split(self.options['command-line']) options = self.options
wait_files = self.options.get('wait-for-files') args = shlex.split(options['command-line'])
pidfile = self.options.get('pidfile') wait_files = options.get('wait-for-files')
private_dev_shm = self.options.get('private-dev-shm') pidfile = options.get('pidfile')
private_tmpfs = self.parsePrivateTmpfs()
private_dev_shm = options.get('private-dev-shm') # BBB
if private_dev_shm:
private_tmpfs.append((private_dev_shm, '/dev/shm'))
environment = {} environment = {}
for line in (self.options.get('environment') or '').splitlines(): for line in (options.get('environment') or '').splitlines():
line = line.strip() line = line.strip()
if line: if line:
k, v = line.split('=', 1) k, v = line.split('=', 1)
...@@ -89,9 +93,9 @@ class Recipe(GenericBaseRecipe): ...@@ -89,9 +93,9 @@ class Recipe(GenericBaseRecipe):
kw['wait_list'] = wait_files.split() kw['wait_list'] = wait_files.split()
if pidfile: if pidfile:
kw['pidfile'] = pidfile kw['pidfile'] = pidfile
if private_dev_shm: if private_tmpfs:
kw['private_dev_shm'] = private_dev_shm kw['private_tmpfs'] = private_tmpfs
if self.isTrueValue(self.options.get('reserve-cpu')): if self.isTrueValue(options.get('reserve-cpu')):
kw['reserve_cpu'] = True kw['reserve_cpu'] = True
return self.createWrapper(self.getWrapperPath(), return self.createWrapper(self.getWrapperPath(),
args, environment, **kw) args, environment, **kw)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment