diff --git a/ansible_mitogen/connection.py b/ansible_mitogen/connection.py index 1b6a2e9a..42fa2ef8 100644 --- a/ansible_mitogen/connection.py +++ b/ansible_mitogen/connection.py @@ -154,6 +154,20 @@ def _connect_ssh(spec): } } +def _connect_buildah(spec): + """ + Return ContextService arguments for a Buildah connection. + """ + return { + 'method': 'buildah', + 'kwargs': { + 'username': spec.remote_user(), + 'container': spec.remote_addr(), + 'python_path': spec.python_path(), + 'connect_timeout': spec.ansible_ssh_timeout() or spec.timeout(), + 'remote_name': get_remote_name(spec), + } + } def _connect_docker(spec): """ @@ -373,6 +387,7 @@ def _connect_mitogen_doas(spec): #: generating ContextService keyword arguments matching a connection #: specification. CONNECTION_METHOD = { + 'buildah': _connect_buildah, 'docker': _connect_docker, 'kubectl': _connect_kubectl, 'jail': _connect_jail, diff --git a/ansible_mitogen/plugins/connection/mitogen_buildah.py b/ansible_mitogen/plugins/connection/mitogen_buildah.py new file mode 100644 index 00000000..017214b2 --- /dev/null +++ b/ansible_mitogen/plugins/connection/mitogen_buildah.py @@ -0,0 +1,44 @@ +# Copyright 2019, 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. + +from __future__ import absolute_import +import os.path +import sys + +try: + import ansible_mitogen +except ImportError: + base_dir = os.path.dirname(__file__) + sys.path.insert(0, os.path.abspath(os.path.join(base_dir, '../../..'))) + del base_dir + +import ansible_mitogen.connection + + +class Connection(ansible_mitogen.connection.Connection): + transport = 'buildah' diff --git a/ansible_mitogen/strategy.py b/ansible_mitogen/strategy.py index b6b9aaf2..01dff285 100644 --- a/ansible_mitogen/strategy.py +++ b/ansible_mitogen/strategy.py @@ -139,8 +139,8 @@ def wrap_connection_loader__get(name, *args, **kwargs): While the strategy is active, rewrite connection_loader.get() calls for some transports into requests for a compatible Mitogen transport. """ - if name in ('docker', 'kubectl', 'jail', 'local', 'lxc', - 'lxd', 'machinectl', 'setns', 'ssh'): + if name in ('buildah', 'docker', 'kubectl', 'jail', 'local', + 'lxc', 'lxd', 'machinectl', 'setns', 'ssh'): name = 'mitogen_' + name return connection_loader__get(name, *args, **kwargs) diff --git a/ansible_mitogen/transport_config.py b/ansible_mitogen/transport_config.py index 27e368d4..aa4a16d0 100644 --- a/ansible_mitogen/transport_config.py +++ b/ansible_mitogen/transport_config.py @@ -240,6 +240,12 @@ class Spec(with_metaclass(abc.ABCMeta, object)): undesirable in some circumstances. """ + @abc.abstractmethod + def mitogen_buildah_path(self): + """ + The path to the "buildah" program for the 'buildah' transport. + """ + @abc.abstractmethod def mitogen_docker_path(self): """ @@ -424,6 +430,9 @@ class PlayContextSpec(Spec): def mitogen_mask_remote_name(self): return self._connection.get_task_var('mitogen_mask_remote_name') + def mitogen_buildah_path(self): + return self._connection.get_task_var('mitogen_buildah_path') + def mitogen_docker_path(self): return self._connection.get_task_var('mitogen_docker_path') @@ -647,6 +656,9 @@ class MitogenViaSpec(Spec): def mitogen_mask_remote_name(self): return self._host_vars.get('mitogen_mask_remote_name') + def mitogen_buildah_path(self): + return self._host_vars.get('mitogen_buildah_path') + def mitogen_docker_path(self): return self._host_vars.get('mitogen_docker_path') diff --git a/mitogen/buildah.py b/mitogen/buildah.py new file mode 100644 index 00000000..eec415f3 --- /dev/null +++ b/mitogen/buildah.py @@ -0,0 +1,73 @@ +# Copyright 2019, 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. + +# !mitogen: minify_safe + +import logging + +import mitogen.core +import mitogen.parent + + +LOG = logging.getLogger(__name__) + + +class Stream(mitogen.parent.Stream): + child_is_immediate_subprocess = False + + container = None + username = None + buildah_path = 'buildah' + + # TODO: better way of capturing errors such as "No such container." + create_child_args = { + 'merge_stdio': True + } + + def construct(self, container=None, + buildah_path=None, username=None, + **kwargs): + assert container or image + super(Stream, self).construct(**kwargs) + if container: + self.container = container + if buildah_path: + self.buildah_path = buildah_path + if username: + self.username = username + + def _get_name(self): + return u'buildah.' + self.container + + def get_boot_command(self): + args = [] + if self.username: + args += ['--user=' + self.username] + bits = [self.buildah_path, 'run'] + args + ['--', self.container] + + return bits + super(Stream, self).get_boot_command() diff --git a/mitogen/core.py b/mitogen/core.py index 0d88d7f0..ea83f961 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -1089,6 +1089,7 @@ class Importer(object): # The Mitogen package is handled specially, since the child context must # construct it manually during startup. MITOGEN_PKG_CONTENT = [ + 'buildah', 'compat', 'debug', 'doas', diff --git a/mitogen/parent.py b/mitogen/parent.py index 3d02bc43..113fdc2e 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -2163,6 +2163,9 @@ class Router(mitogen.core.Router): self._write_lock.release() return context + def buildah(self, **kwargs): + return self.connect(u'buildah', **kwargs) + def doas(self, **kwargs): return self.connect(u'doas', **kwargs)