12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418 |
- """
- :codeauthor: Pedro Algarvio (pedro@algarvio.me)
- :codeauthor: Alexandru Bleotu (alexandru.bleotu@morganstanley.com)
- tests.unit.pillar_test
- ~~~~~~~~~~~~~~~~~~~~~~
- """
- import logging
- import os
- import shutil
- import tempfile
- import textwrap
- import salt.config
- import salt.exceptions
- import salt.fileclient
- import salt.utils.stringutils
- from salt.utils.files import fopen
- from tests.support.helpers import with_tempdir
- from tests.support.mock import MagicMock, patch
- from tests.support.runtests import RUNTIME_VARS
- from tests.support.unit import TestCase
- log = logging.getLogger(__name__)
- class MockFileclient:
- def __init__(self, cache_file=None, get_state=None, list_states=None):
- if cache_file is not None:
- self.cache_file = lambda *x, **y: cache_file
- if get_state is not None:
- self.get_state = lambda sls, env: get_state[sls]
- if list_states is not None:
- self.list_states = lambda *x, **y: list_states
- # pylint: disable=unused-argument,no-method-argument,method-hidden
- def cache_file(*args, **kwargs):
- raise NotImplementedError()
- def get_state(*args, **kwargs):
- raise NotImplementedError()
- def list_states(*args, **kwargs):
- raise NotImplementedError()
- # pylint: enable=unused-argument,no-method-argument,method-hidden
- 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 = {
- "optimization_order": [0, 1, 2],
- "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["saltenv"], "dev")
- self.assertEqual(pillar.opts["pillarenv"], "dev")
- def test_ext_pillar_no_extra_minion_data_val_dict(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {"dev": [], "base": []},
- "file_roots": {"dev": [], "base": []},
- "extension_modules": "",
- "pillarenv_from_saltenv": True,
- }
- mock_ext_pillar_func = MagicMock()
- with patch(
- "salt.loader.pillars",
- MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
- ):
- pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev")
- # ext pillar function doesn't have the extra_minion_data arg
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=[])),
- ):
- pillar._external_pillar_data(
- "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
- )
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", arg="foo"
- )
- # ext pillar function has the extra_minion_data arg
- mock_ext_pillar_func.reset_mock()
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
- ):
- pillar._external_pillar_data(
- "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
- )
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", arg="foo"
- )
- def test_ext_pillar_no_extra_minion_data_val_list(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {"dev": [], "base": []},
- "file_roots": {"dev": [], "base": []},
- "extension_modules": "",
- "pillarenv_from_saltenv": True,
- }
- mock_ext_pillar_func = MagicMock()
- with patch(
- "salt.loader.pillars",
- MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
- ):
- pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev")
- # ext pillar function doesn't have the extra_minion_data arg
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=[])),
- ):
- pillar._external_pillar_data("fake_pillar", ["foo"], "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "foo"
- )
- # ext pillar function has the extra_minion_data arg
- mock_ext_pillar_func.reset_mock()
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
- ):
- pillar._external_pillar_data("fake_pillar", ["foo"], "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "foo"
- )
- def test_ext_pillar_no_extra_minion_data_val_elem(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {"dev": [], "base": []},
- "file_roots": {"dev": [], "base": []},
- "extension_modules": "",
- "pillarenv_from_saltenv": True,
- }
- mock_ext_pillar_func = MagicMock()
- with patch(
- "salt.loader.pillars",
- MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
- ):
- pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev")
- # ext pillar function doesn't have the extra_minion_data arg
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=[])),
- ):
- pillar._external_pillar_data("fake_pillar", "fake_val", "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "fake_val"
- )
- # ext pillar function has the extra_minion_data arg
- mock_ext_pillar_func.reset_mock()
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
- ):
- pillar._external_pillar_data("fake_pillar", "fake_val", "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "fake_val"
- )
- def test_ext_pillar_with_extra_minion_data_val_dict(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {"dev": [], "base": []},
- "file_roots": {"dev": [], "base": []},
- "extension_modules": "",
- "pillarenv_from_saltenv": True,
- }
- mock_ext_pillar_func = MagicMock()
- with patch(
- "salt.loader.pillars",
- MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
- ):
- pillar = salt.pillar.Pillar(
- opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}
- )
- # ext pillar function doesn't have the extra_minion_data arg
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=[])),
- ):
- pillar._external_pillar_data(
- "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
- )
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", arg="foo"
- )
- # ext pillar function has the extra_minion_data arg
- mock_ext_pillar_func.reset_mock()
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
- ):
- pillar._external_pillar_data(
- "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
- )
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion",
- "fake_pillar",
- arg="foo",
- extra_minion_data={"fake_key": "foo"},
- )
- def test_ext_pillar_with_extra_minion_data_val_list(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {"dev": [], "base": []},
- "file_roots": {"dev": [], "base": []},
- "extension_modules": "",
- "pillarenv_from_saltenv": True,
- }
- mock_ext_pillar_func = MagicMock()
- with patch(
- "salt.loader.pillars",
- MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
- ):
- pillar = salt.pillar.Pillar(
- opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}
- )
- # ext pillar function doesn't have the extra_minion_data arg
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=[])),
- ):
- pillar._external_pillar_data("fake_pillar", ["bar"], "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "bar"
- )
- # ext pillar function has the extra_minion_data arg
- mock_ext_pillar_func.reset_mock()
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
- ):
- pillar._external_pillar_data("fake_pillar", ["bar"], "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "bar", extra_minion_data={"fake_key": "foo"}
- )
- def test_ext_pillar_with_extra_minion_data_val_elem(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {"dev": [], "base": []},
- "file_roots": {"dev": [], "base": []},
- "extension_modules": "",
- "pillarenv_from_saltenv": True,
- }
- mock_ext_pillar_func = MagicMock()
- with patch(
- "salt.loader.pillars",
- MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
- ):
- pillar = salt.pillar.Pillar(
- opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}
- )
- # ext pillar function doesn't have the extra_minion_data arg
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=[])),
- ):
- pillar._external_pillar_data("fake_pillar", "bar", "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "bar"
- )
- # ext pillar function has the extra_minion_data arg
- mock_ext_pillar_func.reset_mock()
- with patch(
- "salt.utils.args.get_function_argspec",
- MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
- ):
- pillar._external_pillar_data("fake_pillar", "bar", "fake_ext_pillar")
- mock_ext_pillar_func.assert_called_once_with(
- "mocked-minion", "fake_pillar", "bar", extra_minion_data={"fake_key": "foo"}
- )
- def test_ext_pillar_first(self):
- """
- test when using ext_pillar and ext_pillar_first
- """
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "yaml",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": [],
- "extension_modules": "",
- "saltenv": "base",
- "file_roots": [],
- "ext_pillar_first": True,
- }
- grains = {
- "os": "Ubuntu",
- "os_family": "Debian",
- "oscodename": "raring",
- "osfullname": "Ubuntu",
- "osrelease": "13.04",
- "kernel": "Linux",
- }
- tempdir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
- try:
- sls_files = self._setup_test_topfile_sls_pillar_match(tempdir,)
- fc_mock = MockFileclient(
- cache_file=sls_files["top"]["dest"],
- list_states=["top", "ssh", "ssh.minion", "generic", "generic.minion"],
- get_state=sls_files,
- )
- with patch.object(
- salt.fileclient, "get_file_client", MagicMock(return_value=fc_mock)
- ), patch(
- "salt.pillar.Pillar.ext_pillar",
- MagicMock(
- return_value=(
- {"id": "minion", "phase": "alpha", "role": "database"},
- [],
- )
- ),
- ):
- pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
- self.assertEqual(pillar.compile_pillar()["generic"]["key1"], "value1")
- finally:
- shutil.rmtree(tempdir, ignore_errors=True)
- def test_dynamic_pillarenv(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {
- "__env__": ["/srv/pillar/__env__"],
- "base": ["/srv/pillar/base"],
- },
- "file_roots": {"base": ["/srv/salt/base"], "dev": ["/svr/salt/dev"]},
- "extension_modules": "",
- }
- pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "base", pillarenv="dev")
- self.assertEqual(
- pillar.opts["pillar_roots"],
- {"base": ["/srv/pillar/base"], "dev": ["/srv/pillar/__env__"]},
- )
- def test_ignored_dynamic_pillarenv(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "json",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": {
- "__env__": ["/srv/pillar/__env__"],
- "base": ["/srv/pillar/base"],
- },
- "file_roots": {"base": ["/srv/salt/base"], "dev": ["/svr/salt/dev"]},
- "extension_modules": "",
- }
- pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "base", pillarenv="base")
- self.assertEqual(pillar.opts["pillar_roots"], {"base": ["/srv/pillar/base"]})
- @patch("salt.fileclient.Client.list_states")
- def test_malformed_pillar_sls(self, mock_list_states):
- with patch("salt.pillar.compile_template") as compile_template:
- opts = {
- "optimization_order": [0, 1, 2],
- "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",
- }
- mock_list_states.return_value = ["foo", "blah"]
- 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": "bar"}, [])
- )
- # 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": "bar"}, [])
- )
- # 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_includes_override_sls(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "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",
- }
- with patch("salt.pillar.compile_template") as compile_template, patch.object(
- salt.pillar.Pillar,
- "_Pillar__gather_avail",
- MagicMock(return_value={"base": ["blah", "foo"]}),
- ):
- # Test with option set to True
- opts["pillar_includes_override_sls"] = True
- 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",
- }
- )
- compile_template.side_effect = [
- {"foo": "bar", "include": ["blah"]},
- {"foo": "bar2"},
- ]
- self.assertEqual(
- pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar2"}, [])
- )
- # Test with option set to False
- opts["pillar_includes_override_sls"] = False
- 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",
- }
- )
- compile_template.side_effect = [
- {"foo": "bar", "include": ["blah"]},
- {"foo": "bar2"},
- ]
- self.assertEqual(
- pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar"}, [])
- )
- def test_topfile_order(self):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "yaml",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": [],
- "extension_modules": "",
- "saltenv": "base",
- "file_roots": [],
- }
- grains = {
- "os": "Ubuntu",
- "os_family": "Debian",
- "oscodename": "raring",
- "osfullname": "Ubuntu",
- "osrelease": "13.04",
- "kernel": "Linux",
- }
- def _run_test(nodegroup_order, glob_order, expected):
- tempdir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
- try:
- sls_files = self._setup_test_topfile_sls(
- tempdir, nodegroup_order, glob_order
- )
- fc_mock = MockFileclient(
- cache_file=sls_files["top"]["dest"],
- list_states=[
- "top",
- "ssh",
- "ssh.minion",
- "generic",
- "generic.minion",
- ],
- get_state=sls_files,
- )
- with patch.object(
- salt.fileclient, "get_file_client", MagicMock(return_value=fc_mock)
- ):
- pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
- # Make sure that confirm_top.confirm_top returns True
- pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
- self.assertEqual(pillar.compile_pillar()["ssh"], expected)
- finally:
- shutil.rmtree(tempdir, ignore_errors=True)
- # test case where glob match happens second and therefore takes
- # precedence over nodegroup match.
- _run_test(nodegroup_order=1, glob_order=2, expected="bar")
- # test case where nodegroup match happens second and therefore takes
- # precedence over glob match.
- _run_test(nodegroup_order=2, glob_order=1, expected="foo")
- def _setup_test_topfile_sls_pillar_match(self, tempdir):
- # Write a simple topfile and two pillar state files
- top_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- s = """
- base:
- 'phase:alpha':
- - match: pillar
- - generic
- """
- top_file.write(salt.utils.stringutils.to_bytes(s))
- top_file.flush()
- generic_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- generic_file.write(
- b"""
- generic:
- key1: value1
- """
- )
- generic_file.flush()
- return {
- "top": {"path": "", "dest": top_file.name},
- "generic": {"path": "", "dest": generic_file.name},
- }
- def _setup_test_topfile_sls(self, tempdir, nodegroup_order, glob_order):
- # Write a simple topfile and two pillar state files
- top_file = tempfile.NamedTemporaryFile(dir=tempdir, 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
- )
- top_file.write(salt.utils.stringutils.to_bytes(s))
- top_file.flush()
- ssh_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- ssh_file.write(
- b"""
- ssh:
- foo
- """
- )
- ssh_file.flush()
- ssh_minion_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- ssh_minion_file.write(
- b"""
- ssh:
- bar
- """
- )
- ssh_minion_file.flush()
- generic_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- generic_file.write(
- b"""
- generic:
- key1:
- - value1
- - value2
- key2:
- sub_key1: []
- """
- )
- generic_file.flush()
- generic_minion_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- generic_minion_file.write(
- b"""
- generic:
- key1:
- - value3
- key2:
- sub_key2: []
- """
- )
- generic_minion_file.flush()
- return {
- "top": {"path": "", "dest": top_file.name},
- "ssh": {"path": "", "dest": ssh_file.name},
- "ssh.minion": {"path": "", "dest": ssh_minion_file.name},
- "generic": {"path": "", "dest": generic_file.name},
- "generic.minion": {"path": "", "dest": generic_minion_file.name},
- }
- @with_tempdir()
- def test_include(self, tempdir):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "yaml",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "",
- "pillar_roots": [],
- "extension_modules": "",
- "saltenv": "base",
- "file_roots": [],
- }
- grains = {
- "os": "Ubuntu",
- "os_family": "Debian",
- "oscodename": "raring",
- "osfullname": "Ubuntu",
- "osrelease": "13.04",
- "kernel": "Linux",
- }
- sls_files = self._setup_test_include_sls(tempdir)
- fc_mock = MockFileclient(
- cache_file=sls_files["top"]["dest"],
- get_state=sls_files,
- list_states=[
- "top",
- "test.init",
- "test.sub1",
- "test.sub2",
- "test.sub_wildcard_1",
- "test.sub_with_init_dot",
- "test.sub.with.slashes",
- ],
- )
- with patch.object(
- salt.fileclient, "get_file_client", MagicMock(return_value=fc_mock)
- ):
- pillar = salt.pillar.Pillar(opts, grains, "minion", "base")
- # Make sure that confirm_top.confirm_top returns True
- pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
- compiled_pillar = pillar.compile_pillar()
- self.assertEqual(compiled_pillar["foo_wildcard"], "bar_wildcard")
- self.assertEqual(compiled_pillar["foo1"], "bar1")
- self.assertEqual(compiled_pillar["foo2"], "bar2")
- self.assertEqual(compiled_pillar["sub_with_slashes"], "sub_slashes_worked")
- self.assertEqual(
- compiled_pillar["sub_init_dot"], "sub_with_init_dot_worked"
- )
- def _setup_test_include_sls(self, tempdir):
- top_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- top_file.write(
- b"""
- base:
- '*':
- - order: 1
- - test.sub2
- minion:
- - order: 2
- - test
- """
- )
- top_file.flush()
- init_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- init_sls.write(
- b"""
- include:
- - test.sub1
- - test.sub_wildcard*
- - .test.sub_with_init_dot
- - test/sub/with/slashes
- """
- )
- init_sls.flush()
- sub1_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- sub1_sls.write(
- b"""
- foo1:
- bar1
- """
- )
- sub1_sls.flush()
- sub2_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- sub2_sls.write(
- b"""
- foo2:
- bar2
- """
- )
- sub2_sls.flush()
- sub_wildcard_1_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- sub_wildcard_1_sls.write(
- b"""
- foo_wildcard:
- bar_wildcard
- """
- )
- sub_wildcard_1_sls.flush()
- sub_with_init_dot_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- sub_with_init_dot_sls.write(
- b"""
- sub_init_dot:
- sub_with_init_dot_worked
- """
- )
- sub_with_init_dot_sls.flush()
- sub_with_slashes_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
- sub_with_slashes_sls.write(
- b"""
- sub_with_slashes:
- sub_slashes_worked
- """
- )
- sub_with_slashes_sls.flush()
- return {
- "top": {"path": "", "dest": top_file.name},
- "test": {"path": "", "dest": init_sls.name},
- "test.sub1": {"path": "", "dest": sub1_sls.name},
- "test.sub2": {"path": "", "dest": sub2_sls.name},
- "test.sub_wildcard_1": {"path": "", "dest": sub_wildcard_1_sls.name},
- "test.sub_with_init_dot": {"path": "", "dest": sub_with_init_dot_sls.name},
- "test.sub.with.slashes": {"path": "", "dest": sub_with_slashes_sls.name},
- }
- @with_tempdir()
- def test_relative_include(self, tempdir):
- join = os.path.join
- with fopen(join(tempdir, "top.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- base:
- '*':
- - includer
- - simple_includer
- - includes.with.more.depth
- """
- ),
- file=f,
- )
- includer_dir = join(tempdir, "includer")
- os.makedirs(includer_dir)
- with fopen(join(includer_dir, "init.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- include:
- - .this
- - includer.that
- """
- ),
- file=f,
- )
- with fopen(join(includer_dir, "this.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- this:
- is all good
- """
- ),
- file=f,
- )
- with fopen(join(includer_dir, "that.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- that:
- is also all good
- """
- ),
- file=f,
- )
- with fopen(join(tempdir, "simple_includer.sls"), "w") as simpleincluder:
- print(
- textwrap.dedent(
- """
- include:
- - .simple
- - super_simple
- """
- ),
- file=simpleincluder,
- )
- with fopen(join(tempdir, "simple.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- simple:
- simon
- """
- ),
- file=f,
- )
- with fopen(join(tempdir, "super_simple.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- super simple:
- a caveman
- """
- ),
- file=f,
- )
- depth_dir = join(tempdir, "includes", "with", "more")
- os.makedirs(depth_dir)
- with fopen(join(depth_dir, "depth.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- include:
- - .ramble
- - includes.with.more.doors
- mordor:
- has dark depths
- """
- ),
- file=f,
- )
- with fopen(join(depth_dir, "ramble.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- found:
- my precious
- """
- ),
- file=f,
- )
- with fopen(join(depth_dir, "doors.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- mojo:
- bad risin'
- """
- ),
- file=f,
- )
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "yaml",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "top.sls",
- "pillar_roots": {"base": [tempdir]},
- "extension_modules": "",
- "saltenv": "base",
- "file_roots": [],
- "file_ignore_regex": None,
- "file_ignore_glob": None,
- }
- grains = {
- "os": "Ubuntu",
- "os_family": "Debian",
- "oscodename": "raring",
- "osfullname": "Ubuntu",
- "osrelease": "13.04",
- "kernel": "Linux",
- }
- pillar = salt.pillar.Pillar(opts, grains, "minion", "base")
- # Make sure that confirm_top.confirm_top returns True
- pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
- # Act
- compiled_pillar = pillar.compile_pillar()
- # Assert
- self.assertEqual(compiled_pillar["this"], "is all good")
- self.assertEqual(compiled_pillar["that"], "is also all good")
- self.assertEqual(compiled_pillar["simple"], "simon")
- self.assertEqual(compiled_pillar["super simple"], "a caveman")
- self.assertEqual(compiled_pillar["mordor"], "has dark depths")
- self.assertEqual(compiled_pillar["found"], "my precious")
- self.assertEqual(compiled_pillar["mojo"], "bad risin'")
- @with_tempdir()
- def test_missing_include(self, tempdir):
- opts = {
- "optimization_order": [0, 1, 2],
- "renderer": "yaml",
- "renderer_blacklist": [],
- "renderer_whitelist": [],
- "state_top": "top.sls",
- "pillar_roots": {"base": [tempdir]},
- "extension_modules": "",
- "saltenv": "base",
- "file_roots": [],
- "file_ignore_regex": None,
- "file_ignore_glob": None,
- }
- grains = {
- "os": "Ubuntu",
- "os_family": "Debian",
- "oscodename": "raring",
- "osfullname": "Ubuntu",
- "osrelease": "13.04",
- "kernel": "Linux",
- }
- join = os.path.join
- with fopen(join(tempdir, "top.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- base:
- '*':
- - simple_include
- """
- ),
- file=f,
- )
- include_dir = join(tempdir, "simple_include")
- os.makedirs(include_dir)
- with fopen(join(include_dir, "init.sls"), "w") as f:
- print(
- textwrap.dedent(
- """
- include:
- - simple_include.missing_include
- simple_include: is ok
- """
- ),
- file=f,
- )
- pillar = salt.pillar.Pillar(opts, grains, "minion", "base")
- # Make sure that confirm_top.confirm_top returns True
- pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
- # Act
- compiled_pillar = pillar.compile_pillar()
- # Assert
- self.assertEqual(compiled_pillar["simple_include"], "is ok")
- self.assertTrue("_errors" in compiled_pillar)
- self.assertTrue(
- "simple_include.missing_include" in compiled_pillar["_errors"][0]
- )
- @patch("salt.transport.client.ReqChannel.factory", MagicMock())
- class RemotePillarTestCase(TestCase):
- """
- Tests for instantiating a RemotePillar in salt.pillar
- """
- def setUp(self):
- self.grains = {}
- def tearDown(self):
- for attr in ("grains",):
- try:
- delattr(self, attr)
- except AttributeError:
- continue
- def test_get_opts_in_pillar_override_call(self):
- mock_get_extra_minion_data = MagicMock(return_value={})
- with patch(
- "salt.pillar.RemotePillarMixin.get_ext_pillar_extra_minion_data",
- mock_get_extra_minion_data,
- ):
- salt.pillar.RemotePillar({}, self.grains, "mocked-minion", "dev")
- mock_get_extra_minion_data.assert_called_once_with({"saltenv": "dev"})
- def test_multiple_keys_in_opts_added_to_pillar(self):
- opts = {
- "renderer": "json",
- "path_to_add": "fake_data",
- "path_to_add2": {"fake_data2": ["fake_data3", "fake_data4"]},
- "pass_to_ext_pillars": ["path_to_add", "path_to_add2"],
- }
- pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
- self.assertEqual(
- pillar.extra_minion_data,
- {
- "path_to_add": "fake_data",
- "path_to_add2": {"fake_data2": ["fake_data3", "fake_data4"]},
- },
- )
- def test_subkey_in_opts_added_to_pillar(self):
- opts = {
- "renderer": "json",
- "path_to_add": "fake_data",
- "path_to_add2": {
- "fake_data5": "fake_data6",
- "fake_data2": ["fake_data3", "fake_data4"],
- },
- "pass_to_ext_pillars": ["path_to_add2:fake_data5"],
- }
- pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
- self.assertEqual(
- pillar.extra_minion_data, {"path_to_add2": {"fake_data5": "fake_data6"}}
- )
- def test_non_existent_leaf_opt_in_add_to_pillar(self):
- opts = {
- "renderer": "json",
- "path_to_add": "fake_data",
- "path_to_add2": {
- "fake_data5": "fake_data6",
- "fake_data2": ["fake_data3", "fake_data4"],
- },
- "pass_to_ext_pillars": ["path_to_add2:fake_data_non_exist"],
- }
- pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
- self.assertEqual(pillar.pillar_override, {})
- def test_non_existent_intermediate_opt_in_add_to_pillar(self):
- opts = {
- "renderer": "json",
- "path_to_add": "fake_data",
- "path_to_add2": {
- "fake_data5": "fake_data6",
- "fake_data2": ["fake_data3", "fake_data4"],
- },
- "pass_to_ext_pillars": ["path_to_add_no_exist"],
- }
- pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
- self.assertEqual(pillar.pillar_override, {})
- def test_malformed_add_to_pillar(self):
- opts = {
- "renderer": "json",
- "path_to_add": "fake_data",
- "path_to_add2": {
- "fake_data5": "fake_data6",
- "fake_data2": ["fake_data3", "fake_data4"],
- },
- "pass_to_ext_pillars": MagicMock(),
- }
- with self.assertRaises(salt.exceptions.SaltClientError) as excinfo:
- salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
- self.assertEqual(
- excinfo.exception.strerror, "'pass_to_ext_pillars' config is malformed."
- )
- def test_pillar_send_extra_minion_data_from_config(self):
- opts = {
- "renderer": "json",
- "pillarenv": "fake_pillar_env",
- "path_to_add": "fake_data",
- "path_to_add2": {
- "fake_data5": "fake_data6",
- "fake_data2": ["fake_data3", "fake_data4"],
- },
- "pass_to_ext_pillars": ["path_to_add"],
- }
- mock_channel = MagicMock(
- crypted_transfer_decode_dictentry=MagicMock(return_value={})
- )
- with patch(
- "salt.transport.client.ReqChannel.factory",
- MagicMock(return_value=mock_channel),
- ):
- pillar = salt.pillar.RemotePillar(
- opts, self.grains, "mocked_minion", "fake_env"
- )
- ret = pillar.compile_pillar()
- self.assertEqual(pillar.channel, mock_channel)
- mock_channel.crypted_transfer_decode_dictentry.assert_called_once_with(
- {
- "cmd": "_pillar",
- "ver": "2",
- "id": "mocked_minion",
- "grains": {},
- "saltenv": "fake_env",
- "pillarenv": "fake_pillar_env",
- "pillar_override": {},
- "extra_minion_data": {"path_to_add": "fake_data"},
- },
- dictkey="pillar",
- )
- def test_pillar_file_client_master_remote(self):
- """
- Test condition where local file_client and use_master_when_local option
- returns a remote file client.
- """
- mocked_minion = MagicMock()
- opts = {
- "file_client": "local",
- "use_master_when_local": True,
- "pillar_cache": None,
- }
- pillar = salt.pillar.get_pillar(opts, self.grains, mocked_minion)
- self.assertEqual(type(pillar), salt.pillar.RemotePillar)
- self.assertNotEqual(type(pillar), salt.pillar.PillarCache)
- @patch("salt.transport.client.AsyncReqChannel.factory", MagicMock())
- class AsyncRemotePillarTestCase(TestCase):
- """
- Tests for instantiating a AsyncRemotePillar in salt.pillar
- """
- def setUp(self):
- self.grains = {}
- def tearDown(self):
- for attr in ("grains",):
- try:
- delattr(self, attr)
- except AttributeError:
- continue
- def test_get_opts_in_pillar_override_call(self):
- mock_get_extra_minion_data = MagicMock(return_value={})
- with patch(
- "salt.pillar.RemotePillarMixin.get_ext_pillar_extra_minion_data",
- mock_get_extra_minion_data,
- ):
- salt.pillar.RemotePillar({}, self.grains, "mocked-minion", "dev")
- mock_get_extra_minion_data.assert_called_once_with({"saltenv": "dev"})
- def test_pillar_send_extra_minion_data_from_config(self):
- opts = {
- "renderer": "json",
- "pillarenv": "fake_pillar_env",
- "path_to_add": "fake_data",
- "path_to_add2": {
- "fake_data5": "fake_data6",
- "fake_data2": ["fake_data3", "fake_data4"],
- },
- "pass_to_ext_pillars": ["path_to_add"],
- }
- mock_channel = MagicMock(
- crypted_transfer_decode_dictentry=MagicMock(return_value={})
- )
- with patch(
- "salt.transport.client.AsyncReqChannel.factory",
- MagicMock(return_value=mock_channel),
- ):
- pillar = salt.pillar.RemotePillar(
- opts, self.grains, "mocked_minion", "fake_env"
- )
- ret = pillar.compile_pillar()
- mock_channel.crypted_transfer_decode_dictentry.assert_called_once_with(
- {
- "cmd": "_pillar",
- "ver": "2",
- "id": "mocked_minion",
- "grains": {},
- "saltenv": "fake_env",
- "pillarenv": "fake_pillar_env",
- "pillar_override": {},
- "extra_minion_data": {"path_to_add": "fake_data"},
- },
- dictkey="pillar",
- )
- @patch("salt.transport.client.ReqChannel.factory", MagicMock())
- class PillarCacheTestCase(TestCase):
- """
- Tests for instantiating a PillarCache in salt.pillar
- """
- def setUp(self):
- self.grains = {}
- @classmethod
- def setUpClass(cls):
- cls.mock_master_default_opts = salt.config.DEFAULT_MASTER_OPTS.copy()
- cls.mock_master_default_opts["cachedir"] = tempfile.mkdtemp(
- dir=RUNTIME_VARS.TMP
- )
- def tearDown(self):
- for attr in ("grains",):
- try:
- delattr(self, attr)
- except AttributeError:
- continue
- def test_compile_pillar_disk_cache(self):
- self.mock_master_default_opts.update(
- {"pillar_cache_backend": "disk", "pillar_cache_ttl": 3600}
- )
- pillar = salt.pillar.PillarCache(
- self.mock_master_default_opts,
- self.grains,
- "mocked_minion",
- "fake_env",
- pillarenv="base",
- )
- with patch("salt.utils.cache.CacheDisk._write", MagicMock()):
- with patch(
- "salt.pillar.PillarCache.fetch_pillar",
- side_effect=[{"foo": "bar"}, {"foo": "baz"}],
- ):
- # Run once for pillarenv base
- ret = pillar.compile_pillar()
- expected_cache = {"mocked_minion": {"base": {"foo": "bar"}}}
- self.assertEqual(pillar.cache._dict, expected_cache)
- # Run a second time for pillarenv base
- ret = pillar.compile_pillar()
- expected_cache = {"mocked_minion": {"base": {"foo": "bar"}}}
- self.assertEqual(pillar.cache._dict, expected_cache)
- # Change the pillarenv
- pillar.pillarenv = "dev"
- # Run once for pillarenv dev
- ret = pillar.compile_pillar()
- expected_cache = {
- "mocked_minion": {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
- }
- self.assertEqual(pillar.cache._dict, expected_cache)
- # Run a second time for pillarenv dev
- ret = pillar.compile_pillar()
- expected_cache = {
- "mocked_minion": {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
- }
- self.assertEqual(pillar.cache._dict, expected_cache)
- def test_compile_pillar_memory_cache(self):
- self.mock_master_default_opts.update(
- {"pillar_cache_backend": "memory", "pillar_cache_ttl": 3600}
- )
- pillar = salt.pillar.PillarCache(
- self.mock_master_default_opts,
- self.grains,
- "mocked_minion",
- "fake_env",
- pillarenv="base",
- )
- with patch(
- "salt.pillar.PillarCache.fetch_pillar",
- side_effect=[{"foo": "bar"}, {"foo": "baz"}],
- ):
- # Run once for pillarenv base
- ret = pillar.compile_pillar()
- expected_cache = {"base": {"foo": "bar"}}
- self.assertIn("mocked_minion", pillar.cache)
- self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
- # Run a second time for pillarenv base
- ret = pillar.compile_pillar()
- expected_cache = {"base": {"foo": "bar"}}
- self.assertIn("mocked_minion", pillar.cache)
- self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
- # Change the pillarenv
- pillar.pillarenv = "dev"
- # Run once for pillarenv dev
- ret = pillar.compile_pillar()
- expected_cache = {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
- self.assertIn("mocked_minion", pillar.cache)
- self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
- # Run a second time for pillarenv dev
- ret = pillar.compile_pillar()
- expected_cache = {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
- self.assertIn("mocked_minion", pillar.cache)
- self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
|