Add lxc container support.
This commit is contained in:
parent
1be03eb458
commit
b3d352c601
14
docs/api.rst
14
docs/api.rst
|
@ -712,6 +712,20 @@ Router Class
|
||||||
Filename or complete path to the Docker binary. ``PATH`` will be
|
Filename or complete path to the Docker binary. ``PATH`` will be
|
||||||
searched if given as a filename. Defaults to ``docker``.
|
searched if given as a filename. Defaults to ``docker``.
|
||||||
|
|
||||||
|
.. method:: lxc (container, lxc_attach_path=None, \**kwargs)
|
||||||
|
|
||||||
|
Construct a context on the local machine within an LXC container. The
|
||||||
|
``lxc-attach`` program must be available.
|
||||||
|
|
||||||
|
Accepts all parameters accepted by :py:meth:`local`, in addition to:
|
||||||
|
|
||||||
|
:param str container:
|
||||||
|
Existing container to connect to. Defaults to ``None``.
|
||||||
|
:param str lxc_attach_path:
|
||||||
|
Filename or complete path to the ``lxc-attach`` binary. ``PATH``
|
||||||
|
will be searched if given as a filename. Defaults to
|
||||||
|
``lxc-attach``.
|
||||||
|
|
||||||
.. method:: sudo (username=None, sudo_path=None, password=None, \**kwargs)
|
.. method:: sudo (username=None, sudo_path=None, password=None, \**kwargs)
|
||||||
|
|
||||||
Construct a context on the local machine over a ``sudo`` invocation.
|
Construct a context on the local machine over a ``sudo`` invocation.
|
||||||
|
|
|
@ -488,6 +488,7 @@ class Importer(object):
|
||||||
'docker',
|
'docker',
|
||||||
'fakessh',
|
'fakessh',
|
||||||
'fork',
|
'fork',
|
||||||
|
'lxc',
|
||||||
'master',
|
'master',
|
||||||
'parent',
|
'parent',
|
||||||
'service',
|
'service',
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Copyright 2017, David Wilson
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software without
|
||||||
|
# specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import mitogen.core
|
||||||
|
import mitogen.parent
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Stream(mitogen.parent.Stream):
|
||||||
|
create_child_args = {
|
||||||
|
# If lxc-attach finds any of stdin, stdout, stderr connected to a TTY,
|
||||||
|
# to prevent input injection it creates a proxy pty, forcing all IO to
|
||||||
|
# be buffered in <4KiB chunks. So ensure stderr is also routed to the
|
||||||
|
# socketpair.
|
||||||
|
'merge_stdio': True
|
||||||
|
}
|
||||||
|
|
||||||
|
container = None
|
||||||
|
lxc_attach_path = 'lxc-attach'
|
||||||
|
|
||||||
|
def construct(self, container, lxc_attach_path=None, **kwargs):
|
||||||
|
super(Stream, self).construct(**kwargs)
|
||||||
|
if container:
|
||||||
|
self.container = container
|
||||||
|
if lxc_attach_path:
|
||||||
|
self.lxc_attach_path = lxc_attach_apth
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
super(Stream, self).connect()
|
||||||
|
self.name = 'lxc.' + self.container
|
||||||
|
|
||||||
|
def get_boot_command(self):
|
||||||
|
bits = [
|
||||||
|
self.lxc_attach_path,
|
||||||
|
'--clear-env',
|
||||||
|
'--name', self.container,
|
||||||
|
'--',
|
||||||
|
]
|
||||||
|
return bits + super(Stream, self).get_boot_command()
|
|
@ -243,10 +243,17 @@ def create_socketpair():
|
||||||
return parentfp, childfp
|
return parentfp, childfp
|
||||||
|
|
||||||
|
|
||||||
def create_child(args):
|
def create_child(args, merge_stdio=False):
|
||||||
"""
|
"""
|
||||||
Create a child process whose stdin/stdout is connected to a socket.
|
Create a child process whose stdin/stdout is connected to a socket.
|
||||||
|
|
||||||
|
:param args:
|
||||||
|
Argument vector for execv() call.
|
||||||
|
:param bool merge_stdio:
|
||||||
|
If :data:`True`, arrange for `stderr` to be connected to the `stdout`
|
||||||
|
socketpair, rather than inherited from the parent process. This may be
|
||||||
|
necessary to ensure that not TTY is connected to any stdio handle, for
|
||||||
|
instance when using LXC.
|
||||||
:returns:
|
:returns:
|
||||||
`(pid, socket_obj, :data:`None`)`
|
`(pid, socket_obj, :data:`None`)`
|
||||||
"""
|
"""
|
||||||
|
@ -257,11 +264,17 @@ def create_child(args):
|
||||||
# O_NONBLOCK from Python's future stdin fd.
|
# O_NONBLOCK from Python's future stdin fd.
|
||||||
mitogen.core.set_block(childfp.fileno())
|
mitogen.core.set_block(childfp.fileno())
|
||||||
|
|
||||||
|
if merge_stdio:
|
||||||
|
extra = {'stderr': childfp}
|
||||||
|
else:
|
||||||
|
extra = {}
|
||||||
|
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
args=args,
|
args=args,
|
||||||
stdin=childfp,
|
stdin=childfp,
|
||||||
stdout=childfp,
|
stdout=childfp,
|
||||||
close_fds=True,
|
close_fds=True,
|
||||||
|
**extra
|
||||||
)
|
)
|
||||||
childfp.close()
|
childfp.close()
|
||||||
# Decouple the socket from the lifetime of the Python socket object.
|
# Decouple the socket from the lifetime of the Python socket object.
|
||||||
|
@ -696,12 +709,13 @@ class Stream(mitogen.core.Stream):
|
||||||
return zlib.compress(minimize_source(source), 9)
|
return zlib.compress(minimize_source(source), 9)
|
||||||
|
|
||||||
create_child = staticmethod(create_child)
|
create_child = staticmethod(create_child)
|
||||||
|
create_child_args = {}
|
||||||
name_prefix = 'local'
|
name_prefix = 'local'
|
||||||
|
|
||||||
def start_child(self):
|
def start_child(self):
|
||||||
args = self.get_boot_command()
|
args = self.get_boot_command()
|
||||||
try:
|
try:
|
||||||
return self.create_child(args)
|
return self.create_child(args, **self.create_child_args)
|
||||||
except OSError:
|
except OSError:
|
||||||
e = sys.exc_info()[1]
|
e = sys.exc_info()[1]
|
||||||
msg = 'Child start failed: %s. Command was: %s' % (e, Argv(args))
|
msg = 'Child start failed: %s. Command was: %s' % (e, Argv(args))
|
||||||
|
@ -994,6 +1008,9 @@ class Router(mitogen.core.Router):
|
||||||
self._context_by_id[context.context_id] = context
|
self._context_by_id[context.context_id] = context
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def lxc(self, **kwargs):
|
||||||
|
return self.connect('lxc', **kwargs)
|
||||||
|
|
||||||
def docker(self, **kwargs):
|
def docker(self, **kwargs):
|
||||||
return self.connect('docker', **kwargs)
|
return self.connect('docker', **kwargs)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue