Properly support pillarenv in docker.sls_build

This commit is contained in:
Erik Johnson 2017-12-15 10:47:07 -06:00
parent 76a7c0b593
commit 387378c4b6
No known key found for this signature in database
GPG key ID: 5E5583C437808F3F
6 changed files with 146 additions and 84 deletions

View file

@ -6466,26 +6466,6 @@ def _compile_state(mods=None, saltenv='base'):
return st_.state.compile_high_data(high_data)
def _gather_pillar(pillarenv, pillar_override, **grains):
'''
Gathers pillar with a custom set of grains, which should
be first retrieved from the container
'''
pillar = salt.pillar.get_pillar(
__opts__,
grains,
# Not sure if these two are correct
__opts__['id'],
__opts__['saltenv'],
pillar_override=pillar_override,
pillarenv=pillarenv
)
ret = pillar.compile_pillar()
if pillar_override and isinstance(pillar_override, dict):
ret.update(pillar_override)
return ret
def call(name, function, *args, **kwargs):
'''
Executes a Salt function inside a running container
@ -6574,7 +6554,7 @@ def call(name, function, *args, **kwargs):
run_all(name, subprocess.list2cmdline(rm_thin_argv))
def sls(name, mods=None, saltenv='base', **kwargs):
def sls(name, mods=None, **kwargs):
'''
Apply the states defined by the specified SLS modules to the running
container
@ -6594,6 +6574,24 @@ def sls(name, mods=None, saltenv='base', **kwargs):
Specify the environment from which to retrieve the SLS indicated by the
`mods` parameter.
pillarenv
Specify a Pillar environment to be used when applying states. This
can also be set in the minion config file using the
:conf_minion:`pillarenv` option. When neither the
:conf_minion:`pillarenv` minion config option nor this CLI argument is
used, all Pillar environments will be merged together.
.. versionadded:: Oxygen
pillar
Custom Pillar values, passed as a dictionary of key-value pairs
.. note::
Values passed this way will override Pillar values set via
``pillar_roots`` or an external Pillar source.
.. versionadded:: Oxygen
CLI Example:
.. code-block:: bash
@ -6603,13 +6601,30 @@ def sls(name, mods=None, saltenv='base', **kwargs):
'''
mods = [item.strip() for item in mods.split(',')] if mods else []
# Figure out the saltenv/pillarenv to use
pillar_override = kwargs.pop('pillar', None)
if 'saltenv' not in kwargs:
kwargs['saltenv'] = 'base'
sls_opts = __utils__['state.get_sls_opts'](__opts__, **kwargs)
# gather grains from the container
grains = call(name, 'grains.items')
# compile pillar with container grains
pillar = _gather_pillar(saltenv, {}, **grains)
pillar = salt.pillar.get_pillar(
__opts__,
grains,
__opts__['id'],
pillar_override=pillar_override,
pillarenv=sls_opts['pillarenv']).compile_pillar()
if pillar_override and isinstance(pillar_override, dict):
pillar.update(pillar_override)
trans_tar = _prepare_trans_tar(name, mods=mods, saltenv=saltenv, pillar=pillar)
trans_tar = _prepare_trans_tar(
name,
mods=mods,
saltenv=sls_opts['saltenv'],
pillar=pillar)
# where to put the salt trans tar
trans_dest_path = _generate_tmp_path()
@ -6659,7 +6674,6 @@ def sls_build(repository,
tag='latest',
base='opensuse/python',
mods=None,
saltenv='base',
dryrun=False,
**kwargs):
'''
@ -6699,6 +6713,24 @@ def sls_build(repository,
Specify the environment from which to retrieve the SLS indicated by the
`mods` parameter.
pillarenv
Specify a Pillar environment to be used when applying states. This
can also be set in the minion config file using the
:conf_minion:`pillarenv` option. When neither the
:conf_minion:`pillarenv` minion config option nor this CLI argument is
used, all Pillar environments will be merged together.
.. versionadded:: Oxygen
pillar
Custom Pillar values, passed as a dictionary of key-value pairs
.. note::
Values passed this way will override Pillar values set via
``pillar_roots`` or an external Pillar source.
.. versionadded:: Oxygen
dryrun: False
when set to True the container will not be commited at the end of
the build. The dryrun succeed also when the state contains errors.
@ -6742,7 +6774,7 @@ def sls_build(repository,
start_(id_)
# Now execute the state into the container
ret = sls(id_, mods, saltenv, **kwargs)
ret = sls(id_, mods, **kwargs)
# fail if the state was not successful
if not dryrun and not __utils__['state.check_result'](ret):
raise CommandExecutionError(ret)

View file

@ -36,6 +36,7 @@ import salt.utils.functools
import salt.utils.hashutils
import salt.utils.jid
import salt.utils.platform
import salt.utils.state
import salt.utils.url
import salt.utils.versions
from salt.exceptions import CommandExecutionError, SaltInvocationError
@ -420,36 +421,6 @@ def _check_queue(queue, kwargs):
return conflict
def _get_opts(**kwargs):
'''
Return a copy of the opts for use, optionally load a local config on top
'''
opts = copy.deepcopy(__opts__)
if 'localconfig' in kwargs:
return salt.config.minion_config(kwargs['localconfig'], defaults=opts)
if 'saltenv' in kwargs:
saltenv = kwargs['saltenv']
if saltenv is not None:
if not isinstance(saltenv, six.string_types):
saltenv = six.text_type(saltenv)
if opts['lock_saltenv'] and saltenv != opts['saltenv']:
raise CommandExecutionError(
'lock_saltenv is enabled, saltenv cannot be changed'
)
opts['saltenv'] = kwargs['saltenv']
if 'pillarenv' in kwargs or opts.get('pillarenv_from_saltenv', False):
pillarenv = kwargs.get('pillarenv') or kwargs.get('saltenv')
if pillarenv is not None and not isinstance(pillarenv, six.string_types):
opts['pillarenv'] = str(pillarenv)
else:
opts['pillarenv'] = pillarenv
return opts
def _get_initial_pillar(opts):
return __pillar__ if __opts__['__cli'] == 'salt-call' \
and opts['pillarenv'] == __opts__['pillarenv'] \
@ -521,7 +492,7 @@ def high(data, test=None, queue=False, **kwargs):
conflict = _check_queue(queue, kwargs)
if conflict is not None:
return conflict
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
@ -573,7 +544,7 @@ def template(tem, queue=False, **kwargs):
if conflict is not None:
return conflict
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
try:
st_ = salt.state.HighState(opts,
context=__context__,
@ -618,7 +589,7 @@ def template_str(tem, queue=False, **kwargs):
if conflict is not None:
return conflict
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
try:
st_ = salt.state.State(opts,
@ -1022,7 +993,7 @@ def highstate(test=None, queue=False, **kwargs):
return conflict
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
@ -1228,7 +1199,7 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
return disabled
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
@ -1376,7 +1347,7 @@ def top(topfn, test=None, queue=False, **kwargs):
if conflict is not None:
return conflict
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
pillar_override = kwargs.get('pillar')
@ -1455,7 +1426,7 @@ def show_highstate(queue=False, **kwargs):
'is specified.'
)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
try:
st_ = salt.state.HighState(opts,
pillar_override,
@ -1497,7 +1468,7 @@ def show_lowstate(queue=False, **kwargs):
assert False
return conflict
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
try:
st_ = salt.state.HighState(opts,
proxy=__proxy__,
@ -1605,7 +1576,7 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
if conflict is not None:
return conflict
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
# Since this is running a specific ID within a specific SLS file, fall back
@ -1716,7 +1687,7 @@ def show_low_sls(mods, test=None, queue=False, **kwargs):
if conflict is not None:
return conflict
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
# Since this is dealing with a specific SLS file (or files), fall back to
@ -1802,7 +1773,7 @@ def show_sls(mods, test=None, queue=False, **kwargs):
if conflict is not None:
return conflict
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
@ -1873,7 +1844,7 @@ def show_top(queue=False, **kwargs):
if conflict is not None:
return conflict
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
try:
st_ = salt.state.HighState(opts,
proxy=__proxy__,
@ -1925,7 +1896,7 @@ def single(fun, name, test=None, queue=False, **kwargs):
'__id__': name,
'name': name})
orig_test = __opts__.get('test', None)
opts = _get_opts(**kwargs)
opts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
opts['test'] = _get_test_value(test, **kwargs)
pillar_override = kwargs.get('pillar')
@ -2008,7 +1979,7 @@ def pkg(pkg_path,
salt '*' state.pkg /tmp/salt_state.tgz 760a9353810e36f6d81416366fc426dc md5
'''
# TODO - Add ability to download from salt master or other source
popts = _get_opts(**kwargs)
popts = salt.utils.state.get_sls_opts(__opts__, **kwargs)
if not os.path.isfile(pkg_path):
return {}
if not salt.utils.hashutils.get_hash(pkg_path, hash_type) == pkg_sum:

View file

@ -73,6 +73,8 @@ def present(name,
sls=None,
base='opensuse/python',
saltenv='base',
pillarenv=None,
pillar=None,
**kwargs):
'''
.. versionchanged:: Oxygen
@ -178,13 +180,34 @@ def present(name,
Base image with which to start :py:func:`docker.sls_build
<salt.modules.dockermod.sls_build>`
.. versionadded: 2017.7.0
.. versionadded:: 2017.7.0
saltenv
Environment from which to pull SLS files for :py:func:`docker.sls_build
<salt.modules.dockermod.sls_build>`
Specify the environment from which to retrieve the SLS indicated by the
`mods` parameter.
.. versionadded: 2017.7.0
.. versionadded:: 2017.7.0
.. versionchanged:: Oxygen
Now uses the effective saltenv if not explicitly passed. In earlier
versions, ``base`` was assumed as a default.
pillarenv
Specify a Pillar environment to be used when applying states. This
can also be set in the minion config file using the
:conf_minion:`pillarenv` option. When neither the
:conf_minion:`pillarenv` minion config option nor this CLI argument is
used, all Pillar environments will be merged together.
.. versionadded:: Oxygen
pillar
Custom Pillar values, passed as a dictionary of key-value pairs
.. note::
Values passed this way will override Pillar values set via
``pillar_roots`` or an external Pillar source.
.. versionadded:: Oxygen
'''
ret = {'name': name,
'changes': {},
@ -273,12 +296,15 @@ def present(name,
ret['changes'] = image_update
elif sls:
_locals = locals()
sls_build_kwargs = {k: _locals[k] for k in ('saltenv', 'pillarenv', 'pillar')
if _locals[k] is not None}
try:
image_update = __salt__['docker.sls_build'](repository=name,
tag=tag,
base=base,
mods=sls,
saltenv=saltenv)
**sls_build_kwargs)
except Exception as exc:
ret['comment'] = (
'Encountered error using SLS {0} for building {1}: {2}'

View file

@ -7,9 +7,11 @@ Utility functions for state functions
# Import Python Libs
from __future__ import absolute_import
import copy
# Import Salt libs
from salt.ext import six
from salt.exceptions import CommandExecutionError
import salt.state
_empty = object()
@ -215,3 +217,33 @@ def merge_subreturn(original_return, sub_return, subkey=None):
original_return['pchanges'][subkey] = sub_return['pchanges']
return original_return
def get_sls_opts(opts, **kwargs):
'''
Return a copy of the opts for use, optionally load a local config on top
'''
opts = copy.deepcopy(opts)
if 'localconfig' in kwargs:
return salt.config.minion_config(kwargs['localconfig'], defaults=opts)
if 'saltenv' in kwargs:
saltenv = kwargs['saltenv']
if saltenv is not None:
if not isinstance(saltenv, six.string_types):
saltenv = six.text_type(saltenv)
if opts['lock_saltenv'] and saltenv != opts['saltenv']:
raise CommandExecutionError(
'lock_saltenv is enabled, saltenv cannot be changed'
)
opts['saltenv'] = kwargs['saltenv']
if 'pillarenv' in kwargs or opts.get('pillarenv_from_saltenv', False):
pillarenv = kwargs.get('pillarenv') or kwargs.get('saltenv')
if pillarenv is not None and not isinstance(pillarenv, six.string_types):
opts['pillarenv'] = str(pillarenv)
else:
opts['pillarenv'] = pillarenv
return opts

View file

@ -565,7 +565,7 @@ class DockerTestCase(TestCase, LoaderModuleMockMixin):
cmd='sleep infinity',
image='opensuse/python', interactive=True, tty=True)
docker_start_mock.assert_called_once_with('ID')
docker_sls_mock.assert_called_once_with('ID', 'foo', 'base')
docker_sls_mock.assert_called_once_with('ID', 'foo')
docker_stop_mock.assert_called_once_with('ID')
docker_rm_mock.assert_called_once_with('ID')
docker_commit_mock.assert_called_once_with('ID', 'foo', tag='latest')
@ -619,7 +619,7 @@ class DockerTestCase(TestCase, LoaderModuleMockMixin):
cmd='sleep infinity',
image='opensuse/python', interactive=True, tty=True)
docker_start_mock.assert_called_once_with('ID')
docker_sls_mock.assert_called_once_with('ID', 'foo', 'base')
docker_sls_mock.assert_called_once_with('ID', 'foo')
docker_stop_mock.assert_called_once_with('ID')
docker_rm_mock.assert_called_once_with('ID')
self.assertEqual(

View file

@ -24,6 +24,7 @@ import salt.loader
import salt.utils.hashutils
import salt.utils.odict
import salt.utils.platform
import salt.utils.state
import salt.modules.state as state
from salt.exceptions import CommandExecutionError, SaltInvocationError
import salt.modules.config as config
@ -423,7 +424,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
self.assertFalse(state.high({"vim": {"pkg": ["installed"]}}))
mock = MagicMock(return_value={"test": True})
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
self.assertTrue(state.high({"vim": {"pkg": ["installed"]}}))
def test_template(self):
@ -539,7 +540,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(state.__opts__, {"test": "install"}):
mock = MagicMock(return_value={"test": ""})
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
mock = MagicMock(return_value=True)
with patch.object(salt.utils, 'test_mode', mock):
self.assertRaises(SaltInvocationError,
@ -643,7 +644,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
return_value={'test': True,
'saltenv': None}
)
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
mock = MagicMock(return_value=True)
with patch.object(salt.utils, 'test_mode', mock):
MockState.State.flag = True
@ -670,7 +671,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
return_value={'test': True,
'saltenv': None}
)
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
MockState.State.flag = True
MockState.HighState.flag = True
self.assertEqual(state.show_low_sls("foo"), 2)
@ -692,7 +693,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
return_value={'test': True,
'saltenv': None}
)
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
mock = MagicMock(return_value=True)
with patch.object(salt.utils, 'test_mode', mock):
self.assertRaises(SaltInvocationError,
@ -723,7 +724,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(state.__opts__, {"test": "A"}):
mock = MagicMock(return_value={'test': True})
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
mock = MagicMock(return_value=True)
with patch.object(salt.utils, 'test_mode', mock):
self.assertRaises(SaltInvocationError,
@ -764,7 +765,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(state.__opts__, {"test": "A"}):
mock = MagicMock(return_value={'test': True})
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
self.assertRaises(SaltInvocationError,
state.highstate,
"whitelist=sls1.sls",
@ -887,7 +888,7 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
with patch.dict(state.__opts__, {"test": None}):
mock = MagicMock(return_value={"test": "",
"saltenv": None})
with patch.object(state, '_get_opts', mock):
with patch.object(salt.utils.state, 'get_sls_opts', mock):
mock = MagicMock(return_value=True)
with patch.object(salt.utils,
'test_mode',