From 8a341cdbb922a492140fe81d2a0bfc62e20c2cdc Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Fri, 8 Dec 2017 11:54:54 -0700 Subject: [PATCH] add docker proxy minion --- .pylintrc | 1 + salt/executors/docker.py | 31 +++++++++++++++++ salt/loader.py | 4 ++- salt/minion.py | 9 +++-- salt/modules/dockermod.py | 57 +++++++++++++++++++++++++++++++ salt/proxy/docker.py | 72 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 salt/executors/docker.py create mode 100644 salt/proxy/docker.py diff --git a/.pylintrc b/.pylintrc index 390a82c9985..ea2705cb998 100644 --- a/.pylintrc +++ b/.pylintrc @@ -170,6 +170,7 @@ additional-builtins=__opts__, __proxy__, __serializers__, __reg__, + __executors__, __events__ # List of strings which can identify a callback function by name. A callback diff --git a/salt/executors/docker.py b/salt/executors/docker.py new file mode 100644 index 00000000000..283e65f953c --- /dev/null +++ b/salt/executors/docker.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +''' +Docker executor module + +.. versionadded: Fluorine + +Used with the docker proxy minion. +''' +from __future__ import absolute_import, unicode_literals + + +DOCKER_MOD_MAP = { + 'state.sls': 'docker.sls', + 'state.apply': 'docker.apply', + 'state.highstate': 'docker.highstate', +} + + +def execute(opts, data, func, args, kwargs): + ''' + Directly calls the given function with arguments + ''' + if data['fun'] == 'saltutil.find_job': + return __executors__['direct_call.execute'](opts, data, func, args, kwargs) + if data['fun'] in DOCKER_MOD_MAP: + return __executors__['direct_call.execute'](opts, data, __salt__[DOCKER_MOD_MAP[data['fun']]], [opts['proxy']['name']] + args, kwargs) + return __salt__['docker.call'](opts['proxy']['name'], data['fun'], *args, **kwargs) + + +def allow_missing_funcs(): + return True diff --git a/salt/loader.py b/salt/loader.py index 89596487f96..1a0d90f2a2f 100644 --- a/salt/loader.py +++ b/salt/loader.py @@ -971,12 +971,14 @@ def executors(opts, functions=None, context=None, proxy=None): ''' Returns the executor modules ''' - return LazyLoader( + executors = LazyLoader( _module_dirs(opts, 'executors', 'executor'), opts, tag='executor', pack={'__salt__': functions, '__context__': context or {}, '__proxy__': proxy or {}}, ) + executors.pack['__executors__'] = executors + return executors def cache(opts, serial): diff --git a/salt/minion.py b/salt/minion.py index 1fba16456c6..3eb0d98ccfa 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1589,8 +1589,9 @@ class Minion(MinionBase): data['arg'], data) minion_instance.functions.pack['__context__']['retcode'] = 0 - - executors = data.get('module_executors') or opts.get('module_executors', ['direct_call']) + executors = data.get('module_executors') or \ + getattr(minion_instance, 'module_executors', []) or \ + opts.get('module_executors', ['direct_call']) if isinstance(executors, six.string_types): executors = [executors] elif not isinstance(executors, list) or not executors: @@ -3597,6 +3598,7 @@ class ProxyMinion(Minion): self._running = False raise SaltSystemExit(code=-1, msg=errmsg) + self.module_executors = self.proxy.get('{0}.module_executors'.format(fq_proxyname), lambda: [])() proxy_init_fn = self.proxy[fq_proxyname + '.init'] proxy_init_fn(self.opts) @@ -3747,6 +3749,9 @@ class ProxyMinion(Minion): minion_instance.proxy.reload_modules() fq_proxyname = opts['proxy']['proxytype'] + + minion_instance.module_executors = minion_instance.proxy.get('{0}.module_executors'.format(fq_proxyname), lambda: [])() + proxy_init_fn = minion_instance.proxy[fq_proxyname + '.init'] proxy_init_fn(opts) if not hasattr(minion_instance, 'serial'): diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py index 58464c67df7..e77e40bc48a 100644 --- a/salt/modules/dockermod.py +++ b/salt/modules/dockermod.py @@ -257,6 +257,7 @@ __func_alias__ = { 'signal_': 'signal', 'start_': 'start', 'tag_': 'tag', + 'apply_': 'apply' } # Minimum supported versions @@ -271,6 +272,13 @@ NOTSET = object() __virtualname__ = 'docker' __virtual_aliases__ = ('dockerng', 'moby') +__proxyenabled__ = ['docker'] +__outputter__ = { + 'sls': 'highstate', + 'apply': 'highstate', + 'highstate': 'highstate', +} + def __virtual__(): ''' @@ -6586,6 +6594,9 @@ def _compile_state(sls_opts, mods=None): ''' st_ = HighState(sls_opts) + if not mods: + return st_.compile_low_chunks() + high_data, errors = st_.render_highstate({sls_opts['saltenv']: mods}) high_data, ext_errors = st_.state.reconcile_extend(high_data) errors += ext_errors @@ -6692,6 +6703,27 @@ def call(name, function, *args, **kwargs): run_all(name, subprocess.list2cmdline(rm_thin_argv)) +def apply_(name, mods=None, **kwargs): + ''' + .. versionadded:: Flourine + + Apply states! This function will call highstate or state.sls based on the + arguments passed in, ``apply`` is intended to be the main gateway for + all state executions. + + CLI Example: + + .. code-block:: bash + + salt 'docker' docker.apply web01 + salt 'docker' docker.apply web01 test + salt 'docker' docker.apply web01 test,pkgs + ''' + if mods: + return sls(name, mods, **kwargs) + return highstate(name, **kwargs) + + def sls(name, mods=None, **kwargs): ''' Apply the states defined by the specified SLS modules to the running @@ -6809,6 +6841,31 @@ def sls(name, mods=None, **kwargs): return ret +def highstate(name, saltenv='base', **kwargs): + ''' + Apply a highstate to the running container + + .. versionadded:: Flourine + + The container does not need to have Salt installed, but Python is required. + + name + Container name or ID + + saltenv : base + Specify the environment from which to retrieve the SLS indicated by the + `mods` parameter. + + CLI Example: + + .. code-block:: bash + + salt myminion docker.highstate compassionate_mirzakhani + + ''' + return sls(name, saltenv='base', **kwargs) + + def sls_build(repository, tag='latest', base='opensuse/python', diff --git a/salt/proxy/docker.py b/salt/proxy/docker.py new file mode 100644 index 00000000000..593785bb585 --- /dev/null +++ b/salt/proxy/docker.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +''' +Docker Proxy Minion + +.. versionadded: Fluorine + +:depends: docker + +This proxy minion is just a shim to the docker executor, which will use the +:py:func:`docker.call ` for everything except +state runs. + + +To configure the proxy minion: + +.. code-block:: yaml + + proxy: + proxytype: docker + name: festive_leakey + +It is also possible to just name the proxy minion the same name as the +container, and use grains to configure the proxy minion: + +.. code-block:: yaml + + proxy: + proxytype: docker + name: {{grains['id']}} + +name + + Name of the docker container +''' +from __future__ import absolute_import, unicode_literals + +__proxyenabled__ = ['docker'] +__virtualname__ = 'docker' + + +def __virtual__(): + if __opts__.get('proxy', {}).get('proxytype') != __virtualname__: + return False, 'Proxytype does not match: {0}'.format(__virtualname__) + return True + + +def module_executors(): + ''' + List of module executors to use for this Proxy Minion + ''' + return ['docker', ] + + +def init(opts): + ''' + Always initialize + ''' + __context__['initialized'] = True + + +def initialized(): + ''' + This should always be initialized + ''' + return __context__.get('initialized', False) + + +def shutdown(opts): + ''' + Nothing needs to be done to shutdown + ''' + __context__['initialized'] = False