mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #46149 from rallytime/bp-46145
Back-port #46145 to oxygen.rc1
This commit is contained in:
commit
e6374bf68d
7 changed files with 78 additions and 35 deletions
|
@ -332,10 +332,9 @@ Given the above setup, the orchestration will be carried out as follows:
|
|||
3. Finally, the ``ceph`` SLS target will be executed on all minions which have
|
||||
a grain called ``role`` with a value of ``storage``.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Remember, salt-run is always executed on the master.
|
||||
Remember, salt-run is *always* executed on the master.
|
||||
|
||||
.. _orchestrate-runner-parsing-results-programatically:
|
||||
|
||||
|
@ -603,3 +602,32 @@ succeeded. In addition, ``salt.function`` jobs which failed because the
|
|||
:ref:`fail function <orchestrate-runner-fail-functions>` returned ``False``
|
||||
used to handle their failures in the same way ``salt.state`` jobs did, and this
|
||||
has likewise been corrected.
|
||||
|
||||
|
||||
Running States on the Master without a Minion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The orchestrate runner can be used to execute states on the master without
|
||||
using a minion. For example, assume that ``salt://foo.sls`` contains the
|
||||
following SLS:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
/etc/foo.conf:
|
||||
file.managed:
|
||||
- source: salt://files/foo.conf
|
||||
- mode: 0600
|
||||
|
||||
In this case, running ``salt-run state.orchestrate foo`` would be the
|
||||
equivalent of running a ``state.sls foo``, but it would execute on the master
|
||||
only, and would not require a minion daemon to be running on the master.
|
||||
|
||||
This is not technically orchestration, but it can be useful in certain use
|
||||
cases.
|
||||
|
||||
Limitations
|
||||
^^^^^^^^^^^
|
||||
|
||||
Only one SLS target can be run at a time using this method, while using
|
||||
:py:func:`state.sls <salt.modules.state.sls>` allows for multiple SLS files to
|
||||
be passed in a comma-separated list.
|
||||
|
|
|
@ -232,7 +232,7 @@ class Runner(RunnerClient):
|
|||
else:
|
||||
user = salt.utils.user.get_specific_user()
|
||||
|
||||
if low['fun'] == 'state.orchestrate':
|
||||
if low['fun'] in ('state.orchestrate', 'state.orch'):
|
||||
low['kwarg']['orchestration_jid'] = async_pub['jid']
|
||||
|
||||
# Run the runner!
|
||||
|
|
|
@ -82,19 +82,17 @@ def show_pillar(minion='*', **kwargs):
|
|||
pillar = runner.cmd('pillar.show_pillar', [])
|
||||
print(pillar)
|
||||
'''
|
||||
|
||||
pillarenv = None
|
||||
saltenv = 'base'
|
||||
pillarenv = __opts__['pillarenv'] if 'pillarenv' in __opts__ else None
|
||||
id_, grains, _ = salt.utils.minions.get_minion_data(minion, __opts__)
|
||||
if grains is None:
|
||||
grains = {'fqdn': minion}
|
||||
|
||||
for key in kwargs:
|
||||
if key == 'pillarenv':
|
||||
__opts__['pillarenv'] = kwargs[key]
|
||||
if key == 'saltenv':
|
||||
saltenv = kwargs[key]
|
||||
elif key == 'pillarenv':
|
||||
# pillarenv overridden on CLI
|
||||
pillarenv = kwargs[key]
|
||||
else:
|
||||
grains[key] = kwargs[key]
|
||||
|
|
|
@ -1245,7 +1245,7 @@ class State(object):
|
|||
'''
|
||||
err = []
|
||||
for chunk in chunks:
|
||||
err += self.verify_data(chunk)
|
||||
err.extend(self.verify_data(chunk))
|
||||
return err
|
||||
|
||||
def order_chunks(self, chunks):
|
||||
|
@ -2684,12 +2684,12 @@ class State(object):
|
|||
errors = []
|
||||
# If there is extension data reconcile it
|
||||
high, ext_errors = self.reconcile_extend(high)
|
||||
errors += ext_errors
|
||||
errors += self.verify_high(high)
|
||||
errors.extend(ext_errors)
|
||||
errors.extend(self.verify_high(high))
|
||||
if errors:
|
||||
return errors
|
||||
high, req_in_errors = self.requisite_in(high)
|
||||
errors += req_in_errors
|
||||
errors.extend(req_in_errors)
|
||||
high = self.apply_exclude(high)
|
||||
# Verify that the high data is structurally sound
|
||||
if errors:
|
||||
|
|
|
@ -67,9 +67,11 @@ class SaltCacheLoader(BaseLoader):
|
|||
else:
|
||||
self.searchpath = [os.path.join(opts['cachedir'], 'files', saltenv)]
|
||||
log.debug('Jinja search path: %s', self.searchpath)
|
||||
self._file_client = None
|
||||
self.cached = []
|
||||
self.pillar_rend = pillar_rend
|
||||
self._file_client = None
|
||||
# Instantiate the fileclient
|
||||
self.file_client()
|
||||
|
||||
def file_client(self):
|
||||
'''
|
||||
|
|
|
@ -11,7 +11,7 @@ import textwrap
|
|||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.paths import TMP
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import MagicMock, patch, mock_open
|
||||
from tests.support.mock import MagicMock, Mock, patch, mock_open
|
||||
|
||||
try:
|
||||
import pytest
|
||||
|
@ -19,6 +19,7 @@ except ImportError:
|
|||
pytest = None
|
||||
|
||||
# Import Salt libs
|
||||
from salt.ext import six
|
||||
import salt.config
|
||||
import salt.loader
|
||||
import salt.utils.files
|
||||
|
@ -28,7 +29,7 @@ import salt.modules.file as filemod
|
|||
import salt.modules.config as configmod
|
||||
import salt.modules.cmdmod as cmdmod
|
||||
from salt.exceptions import CommandExecutionError
|
||||
from salt.ext import six
|
||||
from salt.utils.jinja import SaltCacheLoader
|
||||
|
||||
SED_CONTENT = '''test
|
||||
some
|
||||
|
@ -754,12 +755,13 @@ class FileModuleTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'''
|
||||
contents = 'This is a {{ template }}.'
|
||||
defaults = {'template': 'templated file'}
|
||||
ret = filemod.apply_template_on_contents(
|
||||
contents,
|
||||
template='jinja',
|
||||
context={'opts': filemod.__opts__},
|
||||
defaults=defaults,
|
||||
saltenv='base')
|
||||
with patch.object(SaltCacheLoader, 'file_client', Mock()):
|
||||
ret = filemod.apply_template_on_contents(
|
||||
contents,
|
||||
template='jinja',
|
||||
context={'opts': filemod.__opts__},
|
||||
defaults=defaults,
|
||||
saltenv='base')
|
||||
self.assertEqual(ret, 'This is a templated file.')
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import tempfile
|
|||
# Import Salt Testing libs
|
||||
from tests.support.unit import skipIf, TestCase
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock
|
||||
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, Mock
|
||||
from tests.support.paths import TMP_CONF_DIR
|
||||
|
||||
# Import Salt libs
|
||||
|
@ -71,7 +71,7 @@ class MockFileClient(object):
|
|||
|
||||
class TestSaltCacheLoader(TestCase):
|
||||
def __init__(self, *args, **kws):
|
||||
TestCase.__init__(self, *args, **kws)
|
||||
super(TestSaltCacheLoader, self).__init__(*args, **kws)
|
||||
self.opts = {
|
||||
'cachedir': TEMPLATES_DIR,
|
||||
'file_roots': {
|
||||
|
@ -89,7 +89,7 @@ class TestSaltCacheLoader(TestCase):
|
|||
tmp = tempfile.gettempdir()
|
||||
opts = copy.deepcopy(self.opts)
|
||||
opts.update({'cachedir': tmp})
|
||||
loader = SaltCacheLoader(opts, saltenv='test')
|
||||
loader = self.get_loader(opts=opts, saltenv='test')
|
||||
assert loader.searchpath == [os.path.join(tmp, 'files', 'test')]
|
||||
|
||||
def test_mockclient(self):
|
||||
|
@ -97,8 +97,7 @@ class TestSaltCacheLoader(TestCase):
|
|||
A MockFileClient is used that records all file requests normally sent
|
||||
to the master.
|
||||
'''
|
||||
loader = SaltCacheLoader(self.opts, 'test')
|
||||
fc = MockFileClient(loader)
|
||||
loader = self.get_loader(opts=self.opts, saltenv='test')
|
||||
res = loader.get_source(None, 'hello_simple')
|
||||
assert len(res) == 3
|
||||
# res[0] on Windows is unicode and use os.linesep so it works cross OS
|
||||
|
@ -106,17 +105,28 @@ class TestSaltCacheLoader(TestCase):
|
|||
tmpl_dir = os.path.join(TEMPLATES_DIR, 'files', 'test', 'hello_simple')
|
||||
self.assertEqual(res[1], tmpl_dir)
|
||||
assert res[2](), 'Template up to date?'
|
||||
assert len(fc.requests)
|
||||
self.assertEqual(fc.requests[0]['path'], 'salt://hello_simple')
|
||||
assert len(loader._file_client.requests)
|
||||
self.assertEqual(loader._file_client.requests[0]['path'], 'salt://hello_simple')
|
||||
|
||||
def get_loader(self, opts=None, saltenv='base'):
|
||||
'''
|
||||
Now that we instantiate the client in the __init__, we need to mock it
|
||||
'''
|
||||
if opts is None:
|
||||
opts = self.opts
|
||||
with patch.object(SaltCacheLoader, 'file_client', Mock()):
|
||||
loader = SaltCacheLoader(opts, saltenv)
|
||||
# Create a mock file client and attach it to the loader
|
||||
MockFileClient(loader)
|
||||
return loader
|
||||
|
||||
def get_test_saltenv(self):
|
||||
'''
|
||||
Setup a simple jinja test environment
|
||||
'''
|
||||
loader = SaltCacheLoader(self.opts, 'test')
|
||||
fc = MockFileClient(loader)
|
||||
loader = self.get_loader(saltenv='test')
|
||||
jinja = Environment(loader=loader)
|
||||
return fc, jinja
|
||||
return loader._file_client, jinja
|
||||
|
||||
def test_import(self):
|
||||
'''
|
||||
|
@ -152,7 +162,7 @@ class TestSaltCacheLoader(TestCase):
|
|||
|
||||
class TestGetTemplate(TestCase):
|
||||
def __init__(self, *args, **kws):
|
||||
TestCase.__init__(self, *args, **kws)
|
||||
super(TestGetTemplate, self).__init__(*args, **kws)
|
||||
self.local_opts = {
|
||||
'cachedir': TEMPLATES_DIR,
|
||||
'file_client': 'local',
|
||||
|
@ -514,7 +524,7 @@ class TestJinjaDefaultOptions(TestCase):
|
|||
class TestCustomExtensions(TestCase):
|
||||
|
||||
def __init__(self, *args, **kws):
|
||||
TestCase.__init__(self, *args, **kws)
|
||||
super(TestCustomExtensions, self).__init__(*args, **kws)
|
||||
self.local_opts = {
|
||||
'cachedir': TEMPLATES_DIR,
|
||||
'file_client': 'local',
|
||||
|
@ -1202,7 +1212,8 @@ class TestDotNotationLookup(ModuleCase):
|
|||
'''
|
||||
tmpl_str = '''Hello, {{ salt['mocktest.ping']() }}.'''
|
||||
|
||||
ret = self.render(tmpl_str)
|
||||
with patch.object(SaltCacheLoader, 'file_client', Mock()):
|
||||
ret = self.render(tmpl_str)
|
||||
self.assertEqual(ret, 'Hello, True.')
|
||||
|
||||
def test_dotlookup(self):
|
||||
|
@ -1211,7 +1222,8 @@ class TestDotNotationLookup(ModuleCase):
|
|||
'''
|
||||
tmpl_str = '''Hello, {{ salt.mocktest.ping() }}.'''
|
||||
|
||||
ret = self.render(tmpl_str)
|
||||
with patch.object(SaltCacheLoader, 'file_client', Mock()):
|
||||
ret = self.render(tmpl_str)
|
||||
self.assertEqual(ret, 'Hello, True.')
|
||||
|
||||
def test_shadowed_dict_method(self):
|
||||
|
@ -1221,5 +1233,6 @@ class TestDotNotationLookup(ModuleCase):
|
|||
'''
|
||||
tmpl_str = '''Hello, {{ salt.mockgrains.get('id') }}.'''
|
||||
|
||||
ret = self.render(tmpl_str)
|
||||
with patch.object(SaltCacheLoader, 'file_client', Mock()):
|
||||
ret = self.render(tmpl_str)
|
||||
self.assertEqual(ret, 'Hello, jerry.')
|
||||
|
|
Loading…
Add table
Reference in a new issue