Support LXD; closes #339.
This commit is contained in:
parent
4077182fb2
commit
81c8156965
|
@ -569,10 +569,10 @@ additional differences exist that may break existing playbooks.
|
||||||
LXC
|
LXC
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Like `lxc <https://docs.ansible.com/ansible/2.6/plugins/connection/lxc.html>`_
|
Connect to classic LXC containers, like `lxc
|
||||||
and `lxd <https://docs.ansible.com/ansible/2.6/plugins/connection/lxd.html>`_
|
<https://docs.ansible.com/ansible/2.6/plugins/connection/lxc.html>`_ except
|
||||||
except connection delegation is supported, and ``lxc-attach`` is always used
|
connection delegation is supported, and ``lxc-attach`` is always used rather
|
||||||
rather than the LXC Python bindings, as is usual with ``lxc``.
|
than the LXC Python bindings, as is usual with ``lxc``.
|
||||||
|
|
||||||
The ``lxc-attach`` command must be available on the host machine.
|
The ``lxc-attach`` command must be available on the host machine.
|
||||||
|
|
||||||
|
@ -580,6 +580,20 @@ The ``lxc-attach`` command must be available on the host machine.
|
||||||
* ``ansible_host``: Name of LXC container (default: inventory hostname).
|
* ``ansible_host``: Name of LXC container (default: inventory hostname).
|
||||||
|
|
||||||
|
|
||||||
|
.. _method-lxd:
|
||||||
|
|
||||||
|
LXD
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Connect to modern LXD containers, like `lxd
|
||||||
|
<https://docs.ansible.com/ansible/2.6/plugins/connection/lxd.html>`_ except
|
||||||
|
connection delegation is supported. The ``lxc`` command must be available on
|
||||||
|
the host machine.
|
||||||
|
|
||||||
|
* ``ansible_python_interpreter``
|
||||||
|
* ``ansible_host``: Name of LXC container (default: inventory hostname).
|
||||||
|
|
||||||
|
|
||||||
.. _machinectl:
|
.. _machinectl:
|
||||||
|
|
||||||
Machinectl
|
Machinectl
|
||||||
|
@ -602,21 +616,23 @@ Setns
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
The ``setns`` method connects to Linux containers via `setns(2)
|
The ``setns`` method connects to Linux containers via `setns(2)
|
||||||
<https://linux.die.net/man/2/setns>`_. Unlike :ref:`method-docker` and
|
<https://linux.die.net/man/2/setns>`_. Unlike :ref:`method-docker`,
|
||||||
:ref:`method-lxc` the namespace transition is handled internally, ensuring
|
:ref:`method-lxc`, and :ref:`method-lxd` the namespace transition is handled
|
||||||
optimal throughput to the child. This is necessary for :ref:`machinectl` where
|
internally, ensuring optimal throughput to the child. This is necessary for
|
||||||
only PTY channels are supported.
|
:ref:`machinectl` where only PTY channels are supported.
|
||||||
|
|
||||||
A utility program must be installed to discover the PID of the container's root
|
A utility program must be installed to discover the PID of the container's root
|
||||||
process.
|
process.
|
||||||
|
|
||||||
* ``mitogen_kind``: one of ``docker``, ``lxc`` or ``machinectl``.
|
* ``mitogen_kind``: one of ``docker``, ``lxc``, ``lxd`` or ``machinectl``.
|
||||||
* ``ansible_host``: Name of container as it is known to the corresponding tool
|
* ``ansible_host``: Name of container as it is known to the corresponding tool
|
||||||
(default: inventory hostname).
|
(default: inventory hostname).
|
||||||
* ``ansible_user``: Name of user within the container to execute as.
|
* ``ansible_user``: Name of user within the container to execute as.
|
||||||
* ``mitogen_docker_path``: path to Docker if not available on the system path.
|
* ``mitogen_docker_path``: path to Docker if not available on the system path.
|
||||||
* ``mitogen_lxc_info_path``: path to ``lxc-info`` command if not available as
|
* ``mitogen_lxc_path``: path to LXD's ``lxc`` command if not available as
|
||||||
``/usr/bin/lxc-info``.
|
``lxc-info``.
|
||||||
|
* ``mitogen_lxc_info_path``: path to LXC classic's ``lxc-info`` command if not
|
||||||
|
available as ``lxc-info``.
|
||||||
* ``mitogen_machinectl_path``: path to ``machinectl`` command if not available
|
* ``mitogen_machinectl_path``: path to ``machinectl`` command if not available
|
||||||
as ``/bin/machinectl``.
|
as ``/bin/machinectl``.
|
||||||
|
|
||||||
|
|
30
docs/api.rst
30
docs/api.rst
|
@ -590,8 +590,8 @@ Router Class
|
||||||
|
|
||||||
.. method:: lxc (container, lxc_attach_path=None, \**kwargs)
|
.. method:: lxc (container, lxc_attach_path=None, \**kwargs)
|
||||||
|
|
||||||
Construct a context on the local machine within an LXC container using
|
Construct a context on the local machine within an LXC classic
|
||||||
the ``lxc-attach`` program.
|
container using the ``lxc-attach`` program.
|
||||||
|
|
||||||
Accepts all parameters accepted by :py:meth:`local`, in addition to:
|
Accepts all parameters accepted by :py:meth:`local`, in addition to:
|
||||||
|
|
||||||
|
@ -602,6 +602,19 @@ Router Class
|
||||||
will be searched if given as a filename. Defaults to
|
will be searched if given as a filename. Defaults to
|
||||||
``lxc-attach``.
|
``lxc-attach``.
|
||||||
|
|
||||||
|
.. method:: lxc (container, lxc_attach_path=None, \**kwargs)
|
||||||
|
|
||||||
|
Construct a context on the local machine within a LXD container using
|
||||||
|
the ``lxc`` program.
|
||||||
|
|
||||||
|
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_path:
|
||||||
|
Filename or complete path to the ``lxc`` binary. ``PATH`` will be
|
||||||
|
searched if given as a filename. Defaults to ``lxc``.
|
||||||
|
|
||||||
.. method:: setns (container, kind, docker_path=None, lxc_info_path=None, machinectl_path=None, \**kwargs)
|
.. method:: setns (container, kind, docker_path=None, lxc_info_path=None, machinectl_path=None, \**kwargs)
|
||||||
|
|
||||||
Construct a context in the style of :meth:`local`, but change the
|
Construct a context in the style of :meth:`local`, but change the
|
||||||
|
@ -609,7 +622,8 @@ Router Class
|
||||||
executing Python.
|
executing Python.
|
||||||
|
|
||||||
The namespaces to use, and the active root file system are taken from
|
The namespaces to use, and the active root file system are taken from
|
||||||
the root PID of a running Docker, LXC, or systemd-nspawn container.
|
the root PID of a running Docker, LXC, LXD, or systemd-nspawn
|
||||||
|
container.
|
||||||
|
|
||||||
A program is required only to find the root PID, after which management
|
A program is required only to find the root PID, after which management
|
||||||
of the child Python interpreter is handled directly.
|
of the child Python interpreter is handled directly.
|
||||||
|
@ -617,14 +631,16 @@ Router Class
|
||||||
:param str container:
|
:param str container:
|
||||||
Container to connect to.
|
Container to connect to.
|
||||||
:param str kind:
|
:param str kind:
|
||||||
One of ``docker``, ``lxc`` or ``machinectl``.
|
One of ``docker``, ``lxc``, ``lxd`` or ``machinectl``.
|
||||||
:param str docker_path:
|
:param str docker_path:
|
||||||
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``.
|
||||||
|
:param str lxc_path:
|
||||||
|
Filename or complete path to the LXD ``lxc`` binary. ``PATH`` will
|
||||||
|
be searched if given as a filename. Defaults to ``lxc``.
|
||||||
:param str lxc_info_path:
|
:param str lxc_info_path:
|
||||||
Filename or complete path to the ``lxc-info`` binary. ``PATH``
|
Filename or complete path to the LXC ``lxc-info`` binary. ``PATH``
|
||||||
will be searched if given as a filename. Defaults to
|
will be searched if given as a filename. Defaults to ``lxc-info``.
|
||||||
``lxc-info``.
|
|
||||||
:param str machinectl_path:
|
:param str machinectl_path:
|
||||||
Filename or complete path to the ``machinectl`` binary. ``PATH``
|
Filename or complete path to the ``machinectl`` binary. ``PATH``
|
||||||
will be searched if given as a filename. Defaults to
|
will be searched if given as a filename. Defaults to
|
||||||
|
|
|
@ -614,6 +614,7 @@ class Importer(object):
|
||||||
'fork',
|
'fork',
|
||||||
'jail',
|
'jail',
|
||||||
'lxc',
|
'lxc',
|
||||||
|
'lxd',
|
||||||
'master',
|
'master',
|
||||||
'minify',
|
'minify',
|
||||||
'parent',
|
'parent',
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
# 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):
|
||||||
|
child_is_immediate_subprocess = False
|
||||||
|
create_child_args = {
|
||||||
|
# If lxc 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_path = 'lxc'
|
||||||
|
python_path = 'python'
|
||||||
|
|
||||||
|
def construct(self, container, lxc_path=None, **kwargs):
|
||||||
|
super(Stream, self).construct(**kwargs)
|
||||||
|
self.container = container
|
||||||
|
if lxc_path:
|
||||||
|
self.lxc_path = lxc_path
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
super(Stream, self).connect()
|
||||||
|
self.name = u'lxd.' + self.container
|
||||||
|
|
||||||
|
def get_boot_command(self):
|
||||||
|
bits = [
|
||||||
|
self.lxc_path,
|
||||||
|
'exec',
|
||||||
|
'--force-noninteractive',
|
||||||
|
self.container,
|
||||||
|
'--',
|
||||||
|
]
|
||||||
|
return bits + super(Stream, self).get_boot_command()
|
|
@ -1288,6 +1288,9 @@ class Router(mitogen.core.Router):
|
||||||
def lxc(self, **kwargs):
|
def lxc(self, **kwargs):
|
||||||
return self.connect(u'lxc', **kwargs)
|
return self.connect(u'lxc', **kwargs)
|
||||||
|
|
||||||
|
def lxd(self, **kwargs):
|
||||||
|
return self.connect(u'lxd', **kwargs)
|
||||||
|
|
||||||
def setns(self, **kwargs):
|
def setns(self, **kwargs):
|
||||||
return self.connect(u'setns', **kwargs)
|
return self.connect(u'setns', **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,16 @@ def get_lxc_pid(path, name):
|
||||||
raise Error("could not find PID from lxc-info output.\n%s", output)
|
raise Error("could not find PID from lxc-info output.\n%s", output)
|
||||||
|
|
||||||
|
|
||||||
|
def get_lxd_pid(path, name):
|
||||||
|
output = _run_command([path, 'info', name])
|
||||||
|
for line in output.splitlines():
|
||||||
|
bits = line.split()
|
||||||
|
if bits and bits[0] == 'Pid:':
|
||||||
|
return int(bits[1])
|
||||||
|
|
||||||
|
raise Error("could not find PID from lxc output.\n%s", output)
|
||||||
|
|
||||||
|
|
||||||
def get_machinectl_pid(path, name):
|
def get_machinectl_pid(path, name):
|
||||||
output = _run_command([path, 'status', name])
|
output = _run_command([path, 'status', name])
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
|
@ -110,18 +120,22 @@ class Stream(mitogen.parent.Stream):
|
||||||
container = None
|
container = None
|
||||||
username = None
|
username = None
|
||||||
kind = None
|
kind = None
|
||||||
|
python_path = 'python'
|
||||||
docker_path = 'docker'
|
docker_path = 'docker'
|
||||||
|
lxc_path = 'lxc'
|
||||||
lxc_info_path = 'lxc-info'
|
lxc_info_path = 'lxc-info'
|
||||||
machinectl_path = 'machinectl'
|
machinectl_path = 'machinectl'
|
||||||
|
|
||||||
GET_LEADER_BY_KIND = {
|
GET_LEADER_BY_KIND = {
|
||||||
'docker': ('docker_path', get_docker_pid),
|
'docker': ('docker_path', get_docker_pid),
|
||||||
'lxc': ('lxc_info_path', get_lxc_pid),
|
'lxc': ('lxc_info_path', get_lxc_pid),
|
||||||
|
'lxd': ('lxc_path', get_lxd_pid),
|
||||||
'machinectl': ('machinectl_path', get_machinectl_pid),
|
'machinectl': ('machinectl_path', get_machinectl_pid),
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self, container, kind, username=None, docker_path=None,
|
def construct(self, container, kind, username=None, docker_path=None,
|
||||||
lxc_info_path=None, machinectl_path=None, **kwargs):
|
lxc_path=None, lxc_info_path=None, machinectl_path=None,
|
||||||
|
**kwargs):
|
||||||
super(Stream, self).construct(**kwargs)
|
super(Stream, self).construct(**kwargs)
|
||||||
if kind not in self.GET_LEADER_BY_KIND:
|
if kind not in self.GET_LEADER_BY_KIND:
|
||||||
raise Error('unsupported container kind: %r', kind)
|
raise Error('unsupported container kind: %r', kind)
|
||||||
|
@ -132,6 +146,8 @@ class Stream(mitogen.parent.Stream):
|
||||||
self.username = username
|
self.username = username
|
||||||
if docker_path:
|
if docker_path:
|
||||||
self.docker_path = docker_path
|
self.docker_path = docker_path
|
||||||
|
if lxc_path:
|
||||||
|
self.lxc_path = lxc_path
|
||||||
if lxc_info_path:
|
if lxc_info_path:
|
||||||
self.lxc_info_path = lxc_info_path
|
self.lxc_info_path = lxc_info_path
|
||||||
if machinectl_path:
|
if machinectl_path:
|
||||||
|
|
Loading…
Reference in New Issue