mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
00dbba5712
Use delete=True in NamedTemporaryFile command otherwise the handle to the file isn't released and the file can't be opened by the actual test.
314 lines
10 KiB
Python
314 lines
10 KiB
Python
# -*- coding: utf-8 -*-
|
|
'''
|
|
:codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)`
|
|
|
|
|
|
tests.unit.pillar_test
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
'''
|
|
|
|
# Import python libs
|
|
from __future__ import absolute_import
|
|
import tempfile
|
|
|
|
# Import Salt Testing libs
|
|
from tests.support.unit import skipIf, TestCase
|
|
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
|
|
from tests.support.paths import TMP
|
|
|
|
# Import salt libs
|
|
import salt.pillar
|
|
|
|
|
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
|
class PillarTestCase(TestCase):
|
|
|
|
def tearDown(self):
|
|
for attrname in ('generic_file', 'generic_minion_file', 'ssh_file', 'ssh_minion_file', 'top_file'):
|
|
try:
|
|
delattr(self, attrname)
|
|
except AttributeError:
|
|
continue
|
|
|
|
def test_pillarenv_from_saltenv(self):
|
|
with patch('salt.pillar.compile_template') as compile_template:
|
|
opts = {
|
|
'renderer': 'json',
|
|
'renderer_blacklist': [],
|
|
'renderer_whitelist': [],
|
|
'state_top': '',
|
|
'pillar_roots': ['dev', 'base'],
|
|
'file_roots': ['dev', 'base'],
|
|
'extension_modules': '',
|
|
'pillarenv_from_saltenv': True
|
|
}
|
|
grains = {
|
|
'os': 'Ubuntu',
|
|
}
|
|
pillar = salt.pillar.Pillar(opts, grains, 'mocked-minion', 'dev')
|
|
self.assertEqual(pillar.opts['environment'], 'dev')
|
|
self.assertEqual(pillar.opts['pillarenv'], 'dev')
|
|
|
|
def test_malformed_pillar_sls(self):
|
|
with patch('salt.pillar.compile_template') as compile_template:
|
|
opts = {
|
|
'renderer': 'json',
|
|
'renderer_blacklist': [],
|
|
'renderer_whitelist': [],
|
|
'state_top': '',
|
|
'pillar_roots': [],
|
|
'file_roots': [],
|
|
'extension_modules': ''
|
|
}
|
|
grains = {
|
|
'os': 'Ubuntu',
|
|
'os_family': 'Debian',
|
|
'oscodename': 'raring',
|
|
'osfullname': 'Ubuntu',
|
|
'osrelease': '13.04',
|
|
'kernel': 'Linux'
|
|
}
|
|
pillar = salt.pillar.Pillar(opts, grains, 'mocked-minion', 'base')
|
|
# Mock getting the proper template files
|
|
pillar.client.get_state = MagicMock(
|
|
return_value={
|
|
'dest': '/path/to/pillar/files/foo.sls',
|
|
'source': 'salt://foo.sls'
|
|
}
|
|
)
|
|
|
|
# Template compilation returned a string
|
|
compile_template.return_value = 'BAHHH'
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({}, ['SLS \'foo.sls\' does not render to a dictionary'])
|
|
)
|
|
|
|
# Template compilation returned a list
|
|
compile_template.return_value = ['BAHHH']
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({}, ['SLS \'foo.sls\' does not render to a dictionary'])
|
|
)
|
|
|
|
# Template compilation returned a dictionary, which is what's expected
|
|
compile_template.return_value = {'foo': 'bar'}
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar'}, [])
|
|
)
|
|
|
|
# Test improper includes
|
|
compile_template.side_effect = [
|
|
{'foo': 'bar', 'include': 'blah'},
|
|
{'foo2': 'bar2'}
|
|
]
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar', 'include': 'blah'},
|
|
["Include Declaration in SLS 'foo.sls' is not formed as a list"])
|
|
)
|
|
|
|
# Test includes as a list, which is what's expected
|
|
compile_template.side_effect = [
|
|
{'foo': 'bar', 'include': ['blah']},
|
|
{'foo2': 'bar2'}
|
|
]
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar', 'foo2': 'bar2'}, [])
|
|
)
|
|
|
|
# Test includes as a list overriding data
|
|
compile_template.side_effect = [
|
|
{'foo': 'bar', 'include': ['blah']},
|
|
{'foo': 'bar2'}
|
|
]
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar2'}, [])
|
|
)
|
|
|
|
# Test includes using empty key directive
|
|
compile_template.side_effect = [
|
|
{'foo': 'bar', 'include': [{'blah': {'key': ''}}]},
|
|
{'foo': 'bar2'}
|
|
]
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar2'}, [])
|
|
)
|
|
|
|
# Test includes using simple non-nested key
|
|
compile_template.side_effect = [
|
|
{'foo': 'bar', 'include': [{'blah': {'key': 'nested'}}]},
|
|
{'foo': 'bar2'}
|
|
]
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar', 'nested': {'foo': 'bar2'}}, [])
|
|
)
|
|
|
|
# Test includes using nested key
|
|
compile_template.side_effect = [
|
|
{'foo': 'bar', 'include': [{'blah': {'key': 'nested:level'}}]},
|
|
{'foo': 'bar2'}
|
|
]
|
|
self.assertEqual(
|
|
pillar.render_pillar({'base': ['foo.sls']}),
|
|
({'foo': 'bar', 'nested': {'level': {'foo': 'bar2'}}}, [])
|
|
)
|
|
|
|
def test_topfile_order(self):
|
|
with patch('salt.pillar.salt.fileclient.get_file_client', autospec=True) as get_file_client, \
|
|
patch('salt.pillar.salt.minion.Matcher') as Matcher: # autospec=True disabled due to py3 mock bug
|
|
opts = {
|
|
'renderer': 'yaml',
|
|
'renderer_blacklist': [],
|
|
'renderer_whitelist': [],
|
|
'state_top': '',
|
|
'pillar_roots': [],
|
|
'extension_modules': '',
|
|
'environment': 'base',
|
|
'file_roots': [],
|
|
}
|
|
grains = {
|
|
'os': 'Ubuntu',
|
|
'os_family': 'Debian',
|
|
'oscodename': 'raring',
|
|
'osfullname': 'Ubuntu',
|
|
'osrelease': '13.04',
|
|
'kernel': 'Linux'
|
|
}
|
|
# glob match takes precedence
|
|
self._setup_test_topfile_mocks(Matcher, get_file_client, 1, 2)
|
|
pillar = salt.pillar.Pillar(opts, grains, 'mocked-minion', 'base')
|
|
self.assertEqual(pillar.compile_pillar()['ssh'], 'bar')
|
|
# nodegroup match takes precedence
|
|
self._setup_test_topfile_mocks(Matcher, get_file_client, 2, 1)
|
|
pillar = salt.pillar.Pillar(opts, grains, 'mocked-minion', 'base')
|
|
self.assertEqual(pillar.compile_pillar()['ssh'], 'foo')
|
|
|
|
def _setup_test_topfile_mocks(self, Matcher, get_file_client,
|
|
nodegroup_order, glob_order):
|
|
# Write a simple topfile and two pillar state files
|
|
self.top_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
s = '''
|
|
base:
|
|
group:
|
|
- match: nodegroup
|
|
- order: {nodegroup_order}
|
|
- ssh
|
|
- generic
|
|
'*':
|
|
- generic
|
|
minion:
|
|
- order: {glob_order}
|
|
- ssh.minion
|
|
- generic.minion
|
|
'''.format(nodegroup_order=nodegroup_order, glob_order=glob_order)
|
|
self.top_file.write(salt.utils.to_bytes(s))
|
|
self.top_file.flush()
|
|
self.ssh_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
self.ssh_file.write(b'''
|
|
ssh:
|
|
foo
|
|
''')
|
|
self.ssh_file.flush()
|
|
self.ssh_minion_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
self.ssh_minion_file.write(b'''
|
|
ssh:
|
|
bar
|
|
''')
|
|
self.ssh_minion_file.flush()
|
|
self.generic_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
self.generic_file.write(b'''
|
|
generic:
|
|
key1:
|
|
- value1
|
|
- value2
|
|
key2:
|
|
sub_key1: []
|
|
''')
|
|
self.generic_file.flush()
|
|
self.generic_minion_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
self.generic_minion_file.write(b'''
|
|
generic:
|
|
key1:
|
|
- value3
|
|
key2:
|
|
sub_key2: []
|
|
''')
|
|
self.generic_minion_file.flush()
|
|
|
|
# Setup Matcher mock
|
|
matcher = Matcher.return_value
|
|
matcher.confirm_top.return_value = True
|
|
|
|
# Setup fileclient mock
|
|
client = get_file_client.return_value
|
|
client.cache_file.return_value = self.top_file.name
|
|
|
|
def get_state(sls, env):
|
|
return {
|
|
'ssh': {'path': '', 'dest': self.ssh_file.name},
|
|
'ssh.minion': {'path': '', 'dest': self.ssh_minion_file.name},
|
|
'generic': {'path': '', 'dest': self.generic_file.name},
|
|
'generic.minion': {'path': '', 'dest': self.generic_minion_file.name},
|
|
}[sls]
|
|
|
|
client.get_state.side_effect = get_state
|
|
|
|
def _setup_test_include_mocks(self, Matcher, get_file_client):
|
|
self.top_file = top_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
top_file.write(b'''
|
|
base:
|
|
'*':
|
|
- order: 1
|
|
- test.sub2
|
|
minion:
|
|
- order: 2
|
|
- test
|
|
''')
|
|
top_file.flush()
|
|
self.init_sls = init_sls = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
init_sls.write(b'''
|
|
include:
|
|
- test.sub1
|
|
- test.sub2
|
|
''')
|
|
init_sls.flush()
|
|
self.sub1_sls = sub1_sls = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
sub1_sls.write(b'''
|
|
p1:
|
|
- value1_1
|
|
- value1_2
|
|
''')
|
|
sub1_sls.flush()
|
|
self.sub2_sls = sub2_sls = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
|
|
sub2_sls.write(b'''
|
|
p1:
|
|
- value1_3
|
|
p2:
|
|
- value2_1
|
|
- value2_2
|
|
''')
|
|
sub2_sls.flush()
|
|
|
|
# Setup Matcher mock
|
|
matcher = Matcher.return_value
|
|
matcher.confirm_top.return_value = True
|
|
|
|
# Setup fileclient mock
|
|
client = get_file_client.return_value
|
|
client.cache_file.return_value = self.top_file.name
|
|
|
|
def get_state(sls, env):
|
|
return {
|
|
'test': {'path': '', 'dest': init_sls.name},
|
|
'test.sub1': {'path': '', 'dest': sub1_sls.name},
|
|
'test.sub2': {'path': '', 'dest': sub2_sls.name},
|
|
}[sls]
|
|
|
|
client.get_state.side_effect = get_state
|