Merge pull request #376 from Yannig/kubectl

Kubernetes connection support for mitogen.
pull/381/head
dw 6 years ago committed by GitHub
commit 4356fdf027
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -125,6 +125,22 @@ def _connect_docker(spec):
} }
def _connect_kubectl(spec):
"""
Return ContextService arguments for a Kubernetes connection.
"""
return {
'method': 'kubectl',
'kwargs': {
'username': spec['remote_user'],
'pod': spec['remote_addr'],
#'container': spec['container'],
'python_path': spec['python_path'],
'connect_timeout': spec['ansible_ssh_timeout'] or spec['timeout'],
}
}
def _connect_jail(spec): def _connect_jail(spec):
""" """
Return ContextService arguments for a FreeBSD jail connection. Return ContextService arguments for a FreeBSD jail connection.
@ -187,6 +203,7 @@ def _connect_setns(spec):
'python_path': spec['python_path'], 'python_path': spec['python_path'],
'kind': spec['mitogen_kind'], 'kind': spec['mitogen_kind'],
'docker_path': spec['mitogen_docker_path'], 'docker_path': spec['mitogen_docker_path'],
'kubectl_path': spec['mitogen_kubectl_path'],
'lxc_info_path': spec['mitogen_lxc_info_path'], 'lxc_info_path': spec['mitogen_lxc_info_path'],
'machinectl_path': spec['mitogen_machinectl_path'], 'machinectl_path': spec['mitogen_machinectl_path'],
} }
@ -299,6 +316,7 @@ def _connect_mitogen_doas(spec):
#: specification. #: specification.
CONNECTION_METHOD = { CONNECTION_METHOD = {
'docker': _connect_docker, 'docker': _connect_docker,
'kubectl': _connect_kubectl,
'jail': _connect_jail, 'jail': _connect_jail,
'local': _connect_local, 'local': _connect_local,
'lxc': _connect_lxc, 'lxc': _connect_lxc,
@ -366,6 +384,8 @@ def config_from_play_context(transport, inventory_name, connection):
connection.get_task_var('mitogen_kind'), connection.get_task_var('mitogen_kind'),
'mitogen_docker_path': 'mitogen_docker_path':
connection.get_task_var('mitogen_docker_path'), connection.get_task_var('mitogen_docker_path'),
'mitogen_kubectl_path':
connection.get_task_var('mitogen_kubectl_path'),
'mitogen_lxc_info_path': 'mitogen_lxc_info_path':
connection.get_task_var('mitogen_lxc_info_path'), connection.get_task_var('mitogen_lxc_info_path'),
'mitogen_machinectl_path': 'mitogen_machinectl_path':
@ -398,6 +418,7 @@ def config_from_hostvars(transport, inventory_name, connection,
'mitogen_via': hostvars.get('mitogen_via'), 'mitogen_via': hostvars.get('mitogen_via'),
'mitogen_kind': hostvars.get('mitogen_kind'), 'mitogen_kind': hostvars.get('mitogen_kind'),
'mitogen_docker_path': hostvars.get('mitogen_docker_path'), 'mitogen_docker_path': hostvars.get('mitogen_docker_path'),
'mitogen_kubectl_path': hostvars.get('mitogen_kubectl_path'),
'mitogen_lxc_info_path': hostvars.get('mitogen_lxc_info_path'), 'mitogen_lxc_info_path': hostvars.get('mitogen_lxc_info_path'),
'mitogen_machinectl_path': hostvars.get('mitogen_machinctl_path'), 'mitogen_machinectl_path': hostvars.get('mitogen_machinctl_path'),
}) })

@ -0,0 +1,45 @@
# coding: utf-8
# Copyright 2018, Yannig Perré
#
# 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 = 'kubectl'

@ -59,7 +59,7 @@ def wrap_connection_loader__get(name, *args, **kwargs):
While the strategy is active, rewrite connection_loader.get() calls for While the strategy is active, rewrite connection_loader.get() calls for
some transports into requests for a compatible Mitogen transport. some transports into requests for a compatible Mitogen transport.
""" """
if name in ('docker', 'jail', 'local', 'lxc', if name in ('docker', 'kubectl', 'jail', 'local', 'lxc',
'lxd', 'machinectl', 'setns', 'ssh'): 'lxd', 'machinectl', 'setns', 'ssh'):
name = 'mitogen_' + name name = 'mitogen_' + name
return connection_loader__get(name, *args, **kwargs) return connection_loader__get(name, *args, **kwargs)

@ -717,6 +717,7 @@ class Importer(object):
'debug', 'debug',
'doas', 'doas',
'docker', 'docker',
'kubectl',
'fakessh', 'fakessh',
'fork', 'fork',
'jail', 'jail',

@ -0,0 +1,78 @@
# coding: utf-8
# Copyright 2018, Yannig Perré
#
# 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 = True
pod = None
container = None
username = None
kubectl_path = 'kubectl'
# TODO: better way of capturing errors such as "No such container."
create_child_args = {
'merge_stdio': True
}
def construct(self, pod = None, container=None,
kubectl_path=None, username=None,
**kwargs):
assert pod
super(Stream, self).construct(**kwargs)
if pod:
self.pod = pod
if container:
self.container = container
if kubectl_path:
self.kubectl_path = kubectl_path
if username:
self.username = username
def connect(self):
super(Stream, self).connect()
self.name = u'kubectl.' + (self.pod) + str(self.container)
def get_boot_command(self):
args = ['exec', '-it', self.pod]
if self.username:
args += ['--username=' + self.username]
if self.container:
args += ['--container=' + self.container]
bits = [self.kubectl_path]
return bits + args + [ "--" ] + super(Stream, self).get_boot_command()

@ -1596,6 +1596,9 @@ class Router(mitogen.core.Router):
def docker(self, **kwargs): def docker(self, **kwargs):
return self.connect(u'docker', **kwargs) return self.connect(u'docker', **kwargs)
def kubectl(self, **kwargs):
return self.connect(u'kubectl', **kwargs)
def fork(self, **kwargs): def fork(self, **kwargs):
return self.connect(u'fork', **kwargs) return self.connect(u'fork', **kwargs)

@ -0,0 +1,91 @@
---
- name: "Create pod"
tags: always
hosts: localhost
gather_facts: no
tasks:
- name: Create a test pod
k8s:
state: present
definition:
apiVersion: v1
kind: Pod
metadata:
name: test-pod-{{item}}
namespace: default
spec:
containers:
- name: python2
image: python:2
args: [ "sleep", "100000" ]
loop: "{{ range(10)|list }}"
- name: "Wait pod to be running"
debug: { msg: "pod is running" }
# status and availableReplicas might not be there. Using default value (d(default_value))
until: "pod_def.status.containerStatuses[0].ready"
# Waiting 100 s
retries: 50
delay: 2
vars:
pod_def: "{{lookup('k8s', kind='Pod', namespace='default', resource_name='test-pod-' ~ item)}}"
loop: "{{ range(10)|list }}"
- name: "Add pod to pods group"
add_host:
name: "test-pod-{{item}}"
groups: [ "pods" ]
ansible_connection: "kubectl"
changed_when: no
tags: "always"
loop: "{{ range(10)|list }}"
- name: "Test kubectl connection (default strategy)"
tags: default
hosts: pods
strategy: "linear"
gather_facts: no
tasks:
- name: "Simple shell with linear"
shell: ls /tmp
loop: [ 1, 2, 3, 4, 5 ]
- name: "Simple file with linear"
file:
path: "/etc"
state: directory
loop: [ 1, 2, 3, 4, 5 ]
- name: "Test kubectl connection (mitogen strategy)"
tags: mitogen
hosts: pods
strategy: "mitogen_linear"
gather_facts: no
tasks:
- name: "Simple shell with mitogen"
shell: ls /tmp
loop: [ 1, 2, 3, 4, 5 ]
- name: "Simple file with mitogen"
file:
path: "/etc"
state: directory
loop: [ 1, 2, 3, 4, 5 ]
register: _
- name: "Destroy pod"
tags: cleanup
hosts: localhost
gather_facts: no
tasks:
- name: Destroy pod
k8s:
state: absent
definition:
apiVersion: v1
kind: Pod
metadata:
name: test-pod-{{item}}
namespace: default
loop: "{{ range(10)|list }}"
Loading…
Cancel
Save