test_pillar.py 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. """
  2. :codeauthor: Pedro Algarvio (pedro@algarvio.me)
  3. :codeauthor: Alexandru Bleotu (alexandru.bleotu@morganstanley.com)
  4. tests.unit.pillar_test
  5. ~~~~~~~~~~~~~~~~~~~~~~
  6. """
  7. import logging
  8. import os
  9. import shutil
  10. import tempfile
  11. import textwrap
  12. import salt.config
  13. import salt.exceptions
  14. import salt.fileclient
  15. import salt.utils.stringutils
  16. from salt.utils.files import fopen
  17. from tests.support.helpers import with_tempdir
  18. from tests.support.mock import MagicMock, patch
  19. from tests.support.runtests import RUNTIME_VARS
  20. from tests.support.unit import TestCase
  21. log = logging.getLogger(__name__)
  22. class MockFileclient:
  23. def __init__(self, cache_file=None, get_state=None, list_states=None):
  24. if cache_file is not None:
  25. self.cache_file = lambda *x, **y: cache_file
  26. if get_state is not None:
  27. self.get_state = lambda sls, env: get_state[sls]
  28. if list_states is not None:
  29. self.list_states = lambda *x, **y: list_states
  30. # pylint: disable=unused-argument,no-method-argument,method-hidden
  31. def cache_file(*args, **kwargs):
  32. raise NotImplementedError()
  33. def get_state(*args, **kwargs):
  34. raise NotImplementedError()
  35. def list_states(*args, **kwargs):
  36. raise NotImplementedError()
  37. # pylint: enable=unused-argument,no-method-argument,method-hidden
  38. class PillarTestCase(TestCase):
  39. def tearDown(self):
  40. for attrname in (
  41. "generic_file",
  42. "generic_minion_file",
  43. "ssh_file",
  44. "ssh_minion_file",
  45. "top_file",
  46. ):
  47. try:
  48. delattr(self, attrname)
  49. except AttributeError:
  50. continue
  51. def test_pillarenv_from_saltenv(self):
  52. with patch("salt.pillar.compile_template") as compile_template:
  53. opts = {
  54. "optimization_order": [0, 1, 2],
  55. "renderer": "json",
  56. "renderer_blacklist": [],
  57. "renderer_whitelist": [],
  58. "state_top": "",
  59. "pillar_roots": {"dev": [], "base": []},
  60. "file_roots": {"dev": [], "base": []},
  61. "extension_modules": "",
  62. "pillarenv_from_saltenv": True,
  63. }
  64. grains = {
  65. "os": "Ubuntu",
  66. }
  67. pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "dev")
  68. self.assertEqual(pillar.opts["saltenv"], "dev")
  69. self.assertEqual(pillar.opts["pillarenv"], "dev")
  70. def test_ext_pillar_no_extra_minion_data_val_dict(self):
  71. opts = {
  72. "optimization_order": [0, 1, 2],
  73. "renderer": "json",
  74. "renderer_blacklist": [],
  75. "renderer_whitelist": [],
  76. "state_top": "",
  77. "pillar_roots": {"dev": [], "base": []},
  78. "file_roots": {"dev": [], "base": []},
  79. "extension_modules": "",
  80. "pillarenv_from_saltenv": True,
  81. }
  82. mock_ext_pillar_func = MagicMock()
  83. with patch(
  84. "salt.loader.pillars",
  85. MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
  86. ):
  87. pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev")
  88. # ext pillar function doesn't have the extra_minion_data arg
  89. with patch(
  90. "salt.utils.args.get_function_argspec",
  91. MagicMock(return_value=MagicMock(args=[])),
  92. ):
  93. pillar._external_pillar_data(
  94. "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
  95. )
  96. mock_ext_pillar_func.assert_called_once_with(
  97. "mocked-minion", "fake_pillar", arg="foo"
  98. )
  99. # ext pillar function has the extra_minion_data arg
  100. mock_ext_pillar_func.reset_mock()
  101. with patch(
  102. "salt.utils.args.get_function_argspec",
  103. MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
  104. ):
  105. pillar._external_pillar_data(
  106. "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
  107. )
  108. mock_ext_pillar_func.assert_called_once_with(
  109. "mocked-minion", "fake_pillar", arg="foo"
  110. )
  111. def test_ext_pillar_no_extra_minion_data_val_list(self):
  112. opts = {
  113. "optimization_order": [0, 1, 2],
  114. "renderer": "json",
  115. "renderer_blacklist": [],
  116. "renderer_whitelist": [],
  117. "state_top": "",
  118. "pillar_roots": {"dev": [], "base": []},
  119. "file_roots": {"dev": [], "base": []},
  120. "extension_modules": "",
  121. "pillarenv_from_saltenv": True,
  122. }
  123. mock_ext_pillar_func = MagicMock()
  124. with patch(
  125. "salt.loader.pillars",
  126. MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
  127. ):
  128. pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev")
  129. # ext pillar function doesn't have the extra_minion_data arg
  130. with patch(
  131. "salt.utils.args.get_function_argspec",
  132. MagicMock(return_value=MagicMock(args=[])),
  133. ):
  134. pillar._external_pillar_data("fake_pillar", ["foo"], "fake_ext_pillar")
  135. mock_ext_pillar_func.assert_called_once_with(
  136. "mocked-minion", "fake_pillar", "foo"
  137. )
  138. # ext pillar function has the extra_minion_data arg
  139. mock_ext_pillar_func.reset_mock()
  140. with patch(
  141. "salt.utils.args.get_function_argspec",
  142. MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
  143. ):
  144. pillar._external_pillar_data("fake_pillar", ["foo"], "fake_ext_pillar")
  145. mock_ext_pillar_func.assert_called_once_with(
  146. "mocked-minion", "fake_pillar", "foo"
  147. )
  148. def test_ext_pillar_no_extra_minion_data_val_elem(self):
  149. opts = {
  150. "optimization_order": [0, 1, 2],
  151. "renderer": "json",
  152. "renderer_blacklist": [],
  153. "renderer_whitelist": [],
  154. "state_top": "",
  155. "pillar_roots": {"dev": [], "base": []},
  156. "file_roots": {"dev": [], "base": []},
  157. "extension_modules": "",
  158. "pillarenv_from_saltenv": True,
  159. }
  160. mock_ext_pillar_func = MagicMock()
  161. with patch(
  162. "salt.loader.pillars",
  163. MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
  164. ):
  165. pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "dev")
  166. # ext pillar function doesn't have the extra_minion_data arg
  167. with patch(
  168. "salt.utils.args.get_function_argspec",
  169. MagicMock(return_value=MagicMock(args=[])),
  170. ):
  171. pillar._external_pillar_data("fake_pillar", "fake_val", "fake_ext_pillar")
  172. mock_ext_pillar_func.assert_called_once_with(
  173. "mocked-minion", "fake_pillar", "fake_val"
  174. )
  175. # ext pillar function has the extra_minion_data arg
  176. mock_ext_pillar_func.reset_mock()
  177. with patch(
  178. "salt.utils.args.get_function_argspec",
  179. MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
  180. ):
  181. pillar._external_pillar_data("fake_pillar", "fake_val", "fake_ext_pillar")
  182. mock_ext_pillar_func.assert_called_once_with(
  183. "mocked-minion", "fake_pillar", "fake_val"
  184. )
  185. def test_ext_pillar_with_extra_minion_data_val_dict(self):
  186. opts = {
  187. "optimization_order": [0, 1, 2],
  188. "renderer": "json",
  189. "renderer_blacklist": [],
  190. "renderer_whitelist": [],
  191. "state_top": "",
  192. "pillar_roots": {"dev": [], "base": []},
  193. "file_roots": {"dev": [], "base": []},
  194. "extension_modules": "",
  195. "pillarenv_from_saltenv": True,
  196. }
  197. mock_ext_pillar_func = MagicMock()
  198. with patch(
  199. "salt.loader.pillars",
  200. MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
  201. ):
  202. pillar = salt.pillar.Pillar(
  203. opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}
  204. )
  205. # ext pillar function doesn't have the extra_minion_data arg
  206. with patch(
  207. "salt.utils.args.get_function_argspec",
  208. MagicMock(return_value=MagicMock(args=[])),
  209. ):
  210. pillar._external_pillar_data(
  211. "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
  212. )
  213. mock_ext_pillar_func.assert_called_once_with(
  214. "mocked-minion", "fake_pillar", arg="foo"
  215. )
  216. # ext pillar function has the extra_minion_data arg
  217. mock_ext_pillar_func.reset_mock()
  218. with patch(
  219. "salt.utils.args.get_function_argspec",
  220. MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
  221. ):
  222. pillar._external_pillar_data(
  223. "fake_pillar", {"arg": "foo"}, "fake_ext_pillar"
  224. )
  225. mock_ext_pillar_func.assert_called_once_with(
  226. "mocked-minion",
  227. "fake_pillar",
  228. arg="foo",
  229. extra_minion_data={"fake_key": "foo"},
  230. )
  231. def test_ext_pillar_with_extra_minion_data_val_list(self):
  232. opts = {
  233. "optimization_order": [0, 1, 2],
  234. "renderer": "json",
  235. "renderer_blacklist": [],
  236. "renderer_whitelist": [],
  237. "state_top": "",
  238. "pillar_roots": {"dev": [], "base": []},
  239. "file_roots": {"dev": [], "base": []},
  240. "extension_modules": "",
  241. "pillarenv_from_saltenv": True,
  242. }
  243. mock_ext_pillar_func = MagicMock()
  244. with patch(
  245. "salt.loader.pillars",
  246. MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
  247. ):
  248. pillar = salt.pillar.Pillar(
  249. opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}
  250. )
  251. # ext pillar function doesn't have the extra_minion_data arg
  252. with patch(
  253. "salt.utils.args.get_function_argspec",
  254. MagicMock(return_value=MagicMock(args=[])),
  255. ):
  256. pillar._external_pillar_data("fake_pillar", ["bar"], "fake_ext_pillar")
  257. mock_ext_pillar_func.assert_called_once_with(
  258. "mocked-minion", "fake_pillar", "bar"
  259. )
  260. # ext pillar function has the extra_minion_data arg
  261. mock_ext_pillar_func.reset_mock()
  262. with patch(
  263. "salt.utils.args.get_function_argspec",
  264. MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
  265. ):
  266. pillar._external_pillar_data("fake_pillar", ["bar"], "fake_ext_pillar")
  267. mock_ext_pillar_func.assert_called_once_with(
  268. "mocked-minion", "fake_pillar", "bar", extra_minion_data={"fake_key": "foo"}
  269. )
  270. def test_ext_pillar_with_extra_minion_data_val_elem(self):
  271. opts = {
  272. "optimization_order": [0, 1, 2],
  273. "renderer": "json",
  274. "renderer_blacklist": [],
  275. "renderer_whitelist": [],
  276. "state_top": "",
  277. "pillar_roots": {"dev": [], "base": []},
  278. "file_roots": {"dev": [], "base": []},
  279. "extension_modules": "",
  280. "pillarenv_from_saltenv": True,
  281. }
  282. mock_ext_pillar_func = MagicMock()
  283. with patch(
  284. "salt.loader.pillars",
  285. MagicMock(return_value={"fake_ext_pillar": mock_ext_pillar_func}),
  286. ):
  287. pillar = salt.pillar.Pillar(
  288. opts, {}, "mocked-minion", "dev", extra_minion_data={"fake_key": "foo"}
  289. )
  290. # ext pillar function doesn't have the extra_minion_data arg
  291. with patch(
  292. "salt.utils.args.get_function_argspec",
  293. MagicMock(return_value=MagicMock(args=[])),
  294. ):
  295. pillar._external_pillar_data("fake_pillar", "bar", "fake_ext_pillar")
  296. mock_ext_pillar_func.assert_called_once_with(
  297. "mocked-minion", "fake_pillar", "bar"
  298. )
  299. # ext pillar function has the extra_minion_data arg
  300. mock_ext_pillar_func.reset_mock()
  301. with patch(
  302. "salt.utils.args.get_function_argspec",
  303. MagicMock(return_value=MagicMock(args=["extra_minion_data"])),
  304. ):
  305. pillar._external_pillar_data("fake_pillar", "bar", "fake_ext_pillar")
  306. mock_ext_pillar_func.assert_called_once_with(
  307. "mocked-minion", "fake_pillar", "bar", extra_minion_data={"fake_key": "foo"}
  308. )
  309. def test_ext_pillar_first(self):
  310. """
  311. test when using ext_pillar and ext_pillar_first
  312. """
  313. opts = {
  314. "optimization_order": [0, 1, 2],
  315. "renderer": "yaml",
  316. "renderer_blacklist": [],
  317. "renderer_whitelist": [],
  318. "state_top": "",
  319. "pillar_roots": [],
  320. "extension_modules": "",
  321. "saltenv": "base",
  322. "file_roots": [],
  323. "ext_pillar_first": True,
  324. }
  325. grains = {
  326. "os": "Ubuntu",
  327. "os_family": "Debian",
  328. "oscodename": "raring",
  329. "osfullname": "Ubuntu",
  330. "osrelease": "13.04",
  331. "kernel": "Linux",
  332. }
  333. tempdir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  334. try:
  335. sls_files = self._setup_test_topfile_sls_pillar_match(tempdir,)
  336. fc_mock = MockFileclient(
  337. cache_file=sls_files["top"]["dest"],
  338. list_states=["top", "ssh", "ssh.minion", "generic", "generic.minion"],
  339. get_state=sls_files,
  340. )
  341. with patch.object(
  342. salt.fileclient, "get_file_client", MagicMock(return_value=fc_mock)
  343. ), patch(
  344. "salt.pillar.Pillar.ext_pillar",
  345. MagicMock(
  346. return_value=(
  347. {"id": "minion", "phase": "alpha", "role": "database"},
  348. [],
  349. )
  350. ),
  351. ):
  352. pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
  353. self.assertEqual(pillar.compile_pillar()["generic"]["key1"], "value1")
  354. finally:
  355. shutil.rmtree(tempdir, ignore_errors=True)
  356. def test_dynamic_pillarenv(self):
  357. opts = {
  358. "optimization_order": [0, 1, 2],
  359. "renderer": "json",
  360. "renderer_blacklist": [],
  361. "renderer_whitelist": [],
  362. "state_top": "",
  363. "pillar_roots": {
  364. "__env__": ["/srv/pillar/__env__"],
  365. "base": ["/srv/pillar/base"],
  366. },
  367. "file_roots": {"base": ["/srv/salt/base"], "dev": ["/svr/salt/dev"]},
  368. "extension_modules": "",
  369. }
  370. pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "base", pillarenv="dev")
  371. self.assertEqual(
  372. pillar.opts["pillar_roots"],
  373. {"base": ["/srv/pillar/base"], "dev": ["/srv/pillar/__env__"]},
  374. )
  375. def test_ignored_dynamic_pillarenv(self):
  376. opts = {
  377. "optimization_order": [0, 1, 2],
  378. "renderer": "json",
  379. "renderer_blacklist": [],
  380. "renderer_whitelist": [],
  381. "state_top": "",
  382. "pillar_roots": {
  383. "__env__": ["/srv/pillar/__env__"],
  384. "base": ["/srv/pillar/base"],
  385. },
  386. "file_roots": {"base": ["/srv/salt/base"], "dev": ["/svr/salt/dev"]},
  387. "extension_modules": "",
  388. }
  389. pillar = salt.pillar.Pillar(opts, {}, "mocked-minion", "base", pillarenv="base")
  390. self.assertEqual(pillar.opts["pillar_roots"], {"base": ["/srv/pillar/base"]})
  391. @patch("salt.fileclient.Client.list_states")
  392. def test_malformed_pillar_sls(self, mock_list_states):
  393. with patch("salt.pillar.compile_template") as compile_template:
  394. opts = {
  395. "optimization_order": [0, 1, 2],
  396. "renderer": "json",
  397. "renderer_blacklist": [],
  398. "renderer_whitelist": [],
  399. "state_top": "",
  400. "pillar_roots": [],
  401. "file_roots": [],
  402. "extension_modules": "",
  403. }
  404. grains = {
  405. "os": "Ubuntu",
  406. "os_family": "Debian",
  407. "oscodename": "raring",
  408. "osfullname": "Ubuntu",
  409. "osrelease": "13.04",
  410. "kernel": "Linux",
  411. }
  412. mock_list_states.return_value = ["foo", "blah"]
  413. pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
  414. # Mock getting the proper template files
  415. pillar.client.get_state = MagicMock(
  416. return_value={
  417. "dest": "/path/to/pillar/files/foo.sls",
  418. "source": "salt://foo.sls",
  419. }
  420. )
  421. # Template compilation returned a string
  422. compile_template.return_value = "BAHHH"
  423. self.assertEqual(
  424. pillar.render_pillar({"base": ["foo.sls"]}),
  425. ({}, ["SLS 'foo.sls' does not render to a dictionary"]),
  426. )
  427. # Template compilation returned a list
  428. compile_template.return_value = ["BAHHH"]
  429. self.assertEqual(
  430. pillar.render_pillar({"base": ["foo.sls"]}),
  431. ({}, ["SLS 'foo.sls' does not render to a dictionary"]),
  432. )
  433. # Template compilation returned a dictionary, which is what's expected
  434. compile_template.return_value = {"foo": "bar"}
  435. self.assertEqual(
  436. pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar"}, [])
  437. )
  438. # Test improper includes
  439. compile_template.side_effect = [
  440. {"foo": "bar", "include": "blah"},
  441. {"foo2": "bar2"},
  442. ]
  443. self.assertEqual(
  444. pillar.render_pillar({"base": ["foo.sls"]}),
  445. (
  446. {"foo": "bar", "include": "blah"},
  447. ["Include Declaration in SLS 'foo.sls' is not formed as a list"],
  448. ),
  449. )
  450. # Test includes as a list, which is what's expected
  451. compile_template.side_effect = [
  452. {"foo": "bar", "include": ["blah"]},
  453. {"foo2": "bar2"},
  454. ]
  455. self.assertEqual(
  456. pillar.render_pillar({"base": ["foo.sls"]}),
  457. ({"foo": "bar", "foo2": "bar2"}, []),
  458. )
  459. # Test includes as a list overriding data
  460. compile_template.side_effect = [
  461. {"foo": "bar", "include": ["blah"]},
  462. {"foo": "bar2"},
  463. ]
  464. self.assertEqual(
  465. pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar"}, [])
  466. )
  467. # Test includes using empty key directive
  468. compile_template.side_effect = [
  469. {"foo": "bar", "include": [{"blah": {"key": ""}}]},
  470. {"foo": "bar2"},
  471. ]
  472. self.assertEqual(
  473. pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar"}, [])
  474. )
  475. # Test includes using simple non-nested key
  476. compile_template.side_effect = [
  477. {"foo": "bar", "include": [{"blah": {"key": "nested"}}]},
  478. {"foo": "bar2"},
  479. ]
  480. self.assertEqual(
  481. pillar.render_pillar({"base": ["foo.sls"]}),
  482. ({"foo": "bar", "nested": {"foo": "bar2"}}, []),
  483. )
  484. # Test includes using nested key
  485. compile_template.side_effect = [
  486. {"foo": "bar", "include": [{"blah": {"key": "nested:level"}}]},
  487. {"foo": "bar2"},
  488. ]
  489. self.assertEqual(
  490. pillar.render_pillar({"base": ["foo.sls"]}),
  491. ({"foo": "bar", "nested": {"level": {"foo": "bar2"}}}, []),
  492. )
  493. def test_includes_override_sls(self):
  494. opts = {
  495. "optimization_order": [0, 1, 2],
  496. "renderer": "json",
  497. "renderer_blacklist": [],
  498. "renderer_whitelist": [],
  499. "state_top": "",
  500. "pillar_roots": {},
  501. "file_roots": {},
  502. "extension_modules": "",
  503. }
  504. grains = {
  505. "os": "Ubuntu",
  506. "os_family": "Debian",
  507. "oscodename": "raring",
  508. "osfullname": "Ubuntu",
  509. "osrelease": "13.04",
  510. "kernel": "Linux",
  511. }
  512. with patch("salt.pillar.compile_template") as compile_template, patch.object(
  513. salt.pillar.Pillar,
  514. "_Pillar__gather_avail",
  515. MagicMock(return_value={"base": ["blah", "foo"]}),
  516. ):
  517. # Test with option set to True
  518. opts["pillar_includes_override_sls"] = True
  519. pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
  520. # Mock getting the proper template files
  521. pillar.client.get_state = MagicMock(
  522. return_value={
  523. "dest": "/path/to/pillar/files/foo.sls",
  524. "source": "salt://foo.sls",
  525. }
  526. )
  527. compile_template.side_effect = [
  528. {"foo": "bar", "include": ["blah"]},
  529. {"foo": "bar2"},
  530. ]
  531. self.assertEqual(
  532. pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar2"}, [])
  533. )
  534. # Test with option set to False
  535. opts["pillar_includes_override_sls"] = False
  536. pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
  537. # Mock getting the proper template files
  538. pillar.client.get_state = MagicMock(
  539. return_value={
  540. "dest": "/path/to/pillar/files/foo.sls",
  541. "source": "salt://foo.sls",
  542. }
  543. )
  544. compile_template.side_effect = [
  545. {"foo": "bar", "include": ["blah"]},
  546. {"foo": "bar2"},
  547. ]
  548. self.assertEqual(
  549. pillar.render_pillar({"base": ["foo.sls"]}), ({"foo": "bar"}, [])
  550. )
  551. def test_topfile_order(self):
  552. opts = {
  553. "optimization_order": [0, 1, 2],
  554. "renderer": "yaml",
  555. "renderer_blacklist": [],
  556. "renderer_whitelist": [],
  557. "state_top": "",
  558. "pillar_roots": [],
  559. "extension_modules": "",
  560. "saltenv": "base",
  561. "file_roots": [],
  562. }
  563. grains = {
  564. "os": "Ubuntu",
  565. "os_family": "Debian",
  566. "oscodename": "raring",
  567. "osfullname": "Ubuntu",
  568. "osrelease": "13.04",
  569. "kernel": "Linux",
  570. }
  571. def _run_test(nodegroup_order, glob_order, expected):
  572. tempdir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  573. try:
  574. sls_files = self._setup_test_topfile_sls(
  575. tempdir, nodegroup_order, glob_order
  576. )
  577. fc_mock = MockFileclient(
  578. cache_file=sls_files["top"]["dest"],
  579. list_states=[
  580. "top",
  581. "ssh",
  582. "ssh.minion",
  583. "generic",
  584. "generic.minion",
  585. ],
  586. get_state=sls_files,
  587. )
  588. with patch.object(
  589. salt.fileclient, "get_file_client", MagicMock(return_value=fc_mock)
  590. ):
  591. pillar = salt.pillar.Pillar(opts, grains, "mocked-minion", "base")
  592. # Make sure that confirm_top.confirm_top returns True
  593. pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
  594. self.assertEqual(pillar.compile_pillar()["ssh"], expected)
  595. finally:
  596. shutil.rmtree(tempdir, ignore_errors=True)
  597. # test case where glob match happens second and therefore takes
  598. # precedence over nodegroup match.
  599. _run_test(nodegroup_order=1, glob_order=2, expected="bar")
  600. # test case where nodegroup match happens second and therefore takes
  601. # precedence over glob match.
  602. _run_test(nodegroup_order=2, glob_order=1, expected="foo")
  603. def _setup_test_topfile_sls_pillar_match(self, tempdir):
  604. # Write a simple topfile and two pillar state files
  605. top_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  606. s = """
  607. base:
  608. 'phase:alpha':
  609. - match: pillar
  610. - generic
  611. """
  612. top_file.write(salt.utils.stringutils.to_bytes(s))
  613. top_file.flush()
  614. generic_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  615. generic_file.write(
  616. b"""
  617. generic:
  618. key1: value1
  619. """
  620. )
  621. generic_file.flush()
  622. return {
  623. "top": {"path": "", "dest": top_file.name},
  624. "generic": {"path": "", "dest": generic_file.name},
  625. }
  626. def _setup_test_topfile_sls(self, tempdir, nodegroup_order, glob_order):
  627. # Write a simple topfile and two pillar state files
  628. top_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  629. s = """
  630. base:
  631. group:
  632. - match: nodegroup
  633. - order: {nodegroup_order}
  634. - ssh
  635. - generic
  636. '*':
  637. - generic
  638. minion:
  639. - order: {glob_order}
  640. - ssh.minion
  641. - generic.minion
  642. """.format(
  643. nodegroup_order=nodegroup_order, glob_order=glob_order
  644. )
  645. top_file.write(salt.utils.stringutils.to_bytes(s))
  646. top_file.flush()
  647. ssh_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  648. ssh_file.write(
  649. b"""
  650. ssh:
  651. foo
  652. """
  653. )
  654. ssh_file.flush()
  655. ssh_minion_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  656. ssh_minion_file.write(
  657. b"""
  658. ssh:
  659. bar
  660. """
  661. )
  662. ssh_minion_file.flush()
  663. generic_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  664. generic_file.write(
  665. b"""
  666. generic:
  667. key1:
  668. - value1
  669. - value2
  670. key2:
  671. sub_key1: []
  672. """
  673. )
  674. generic_file.flush()
  675. generic_minion_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  676. generic_minion_file.write(
  677. b"""
  678. generic:
  679. key1:
  680. - value3
  681. key2:
  682. sub_key2: []
  683. """
  684. )
  685. generic_minion_file.flush()
  686. return {
  687. "top": {"path": "", "dest": top_file.name},
  688. "ssh": {"path": "", "dest": ssh_file.name},
  689. "ssh.minion": {"path": "", "dest": ssh_minion_file.name},
  690. "generic": {"path": "", "dest": generic_file.name},
  691. "generic.minion": {"path": "", "dest": generic_minion_file.name},
  692. }
  693. @with_tempdir()
  694. def test_include(self, tempdir):
  695. opts = {
  696. "optimization_order": [0, 1, 2],
  697. "renderer": "yaml",
  698. "renderer_blacklist": [],
  699. "renderer_whitelist": [],
  700. "state_top": "",
  701. "pillar_roots": [],
  702. "extension_modules": "",
  703. "saltenv": "base",
  704. "file_roots": [],
  705. }
  706. grains = {
  707. "os": "Ubuntu",
  708. "os_family": "Debian",
  709. "oscodename": "raring",
  710. "osfullname": "Ubuntu",
  711. "osrelease": "13.04",
  712. "kernel": "Linux",
  713. }
  714. sls_files = self._setup_test_include_sls(tempdir)
  715. fc_mock = MockFileclient(
  716. cache_file=sls_files["top"]["dest"],
  717. get_state=sls_files,
  718. list_states=[
  719. "top",
  720. "test.init",
  721. "test.sub1",
  722. "test.sub2",
  723. "test.sub_wildcard_1",
  724. "test.sub_with_init_dot",
  725. "test.sub.with.slashes",
  726. ],
  727. )
  728. with patch.object(
  729. salt.fileclient, "get_file_client", MagicMock(return_value=fc_mock)
  730. ):
  731. pillar = salt.pillar.Pillar(opts, grains, "minion", "base")
  732. # Make sure that confirm_top.confirm_top returns True
  733. pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
  734. compiled_pillar = pillar.compile_pillar()
  735. self.assertEqual(compiled_pillar["foo_wildcard"], "bar_wildcard")
  736. self.assertEqual(compiled_pillar["foo1"], "bar1")
  737. self.assertEqual(compiled_pillar["foo2"], "bar2")
  738. self.assertEqual(compiled_pillar["sub_with_slashes"], "sub_slashes_worked")
  739. self.assertEqual(
  740. compiled_pillar["sub_init_dot"], "sub_with_init_dot_worked"
  741. )
  742. def _setup_test_include_sls(self, tempdir):
  743. top_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  744. top_file.write(
  745. b"""
  746. base:
  747. '*':
  748. - order: 1
  749. - test.sub2
  750. minion:
  751. - order: 2
  752. - test
  753. """
  754. )
  755. top_file.flush()
  756. init_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  757. init_sls.write(
  758. b"""
  759. include:
  760. - test.sub1
  761. - test.sub_wildcard*
  762. - .test.sub_with_init_dot
  763. - test/sub/with/slashes
  764. """
  765. )
  766. init_sls.flush()
  767. sub1_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  768. sub1_sls.write(
  769. b"""
  770. foo1:
  771. bar1
  772. """
  773. )
  774. sub1_sls.flush()
  775. sub2_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  776. sub2_sls.write(
  777. b"""
  778. foo2:
  779. bar2
  780. """
  781. )
  782. sub2_sls.flush()
  783. sub_wildcard_1_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  784. sub_wildcard_1_sls.write(
  785. b"""
  786. foo_wildcard:
  787. bar_wildcard
  788. """
  789. )
  790. sub_wildcard_1_sls.flush()
  791. sub_with_init_dot_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  792. sub_with_init_dot_sls.write(
  793. b"""
  794. sub_init_dot:
  795. sub_with_init_dot_worked
  796. """
  797. )
  798. sub_with_init_dot_sls.flush()
  799. sub_with_slashes_sls = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)
  800. sub_with_slashes_sls.write(
  801. b"""
  802. sub_with_slashes:
  803. sub_slashes_worked
  804. """
  805. )
  806. sub_with_slashes_sls.flush()
  807. return {
  808. "top": {"path": "", "dest": top_file.name},
  809. "test": {"path": "", "dest": init_sls.name},
  810. "test.sub1": {"path": "", "dest": sub1_sls.name},
  811. "test.sub2": {"path": "", "dest": sub2_sls.name},
  812. "test.sub_wildcard_1": {"path": "", "dest": sub_wildcard_1_sls.name},
  813. "test.sub_with_init_dot": {"path": "", "dest": sub_with_init_dot_sls.name},
  814. "test.sub.with.slashes": {"path": "", "dest": sub_with_slashes_sls.name},
  815. }
  816. @with_tempdir()
  817. def test_relative_include(self, tempdir):
  818. join = os.path.join
  819. with fopen(join(tempdir, "top.sls"), "w") as f:
  820. print(
  821. textwrap.dedent(
  822. """
  823. base:
  824. '*':
  825. - includer
  826. - simple_includer
  827. - includes.with.more.depth
  828. """
  829. ),
  830. file=f,
  831. )
  832. includer_dir = join(tempdir, "includer")
  833. os.makedirs(includer_dir)
  834. with fopen(join(includer_dir, "init.sls"), "w") as f:
  835. print(
  836. textwrap.dedent(
  837. """
  838. include:
  839. - .this
  840. - includer.that
  841. """
  842. ),
  843. file=f,
  844. )
  845. with fopen(join(includer_dir, "this.sls"), "w") as f:
  846. print(
  847. textwrap.dedent(
  848. """
  849. this:
  850. is all good
  851. """
  852. ),
  853. file=f,
  854. )
  855. with fopen(join(includer_dir, "that.sls"), "w") as f:
  856. print(
  857. textwrap.dedent(
  858. """
  859. that:
  860. is also all good
  861. """
  862. ),
  863. file=f,
  864. )
  865. with fopen(join(tempdir, "simple_includer.sls"), "w") as simpleincluder:
  866. print(
  867. textwrap.dedent(
  868. """
  869. include:
  870. - .simple
  871. - super_simple
  872. """
  873. ),
  874. file=simpleincluder,
  875. )
  876. with fopen(join(tempdir, "simple.sls"), "w") as f:
  877. print(
  878. textwrap.dedent(
  879. """
  880. simple:
  881. simon
  882. """
  883. ),
  884. file=f,
  885. )
  886. with fopen(join(tempdir, "super_simple.sls"), "w") as f:
  887. print(
  888. textwrap.dedent(
  889. """
  890. super simple:
  891. a caveman
  892. """
  893. ),
  894. file=f,
  895. )
  896. depth_dir = join(tempdir, "includes", "with", "more")
  897. os.makedirs(depth_dir)
  898. with fopen(join(depth_dir, "depth.sls"), "w") as f:
  899. print(
  900. textwrap.dedent(
  901. """
  902. include:
  903. - .ramble
  904. - includes.with.more.doors
  905. mordor:
  906. has dark depths
  907. """
  908. ),
  909. file=f,
  910. )
  911. with fopen(join(depth_dir, "ramble.sls"), "w") as f:
  912. print(
  913. textwrap.dedent(
  914. """
  915. found:
  916. my precious
  917. """
  918. ),
  919. file=f,
  920. )
  921. with fopen(join(depth_dir, "doors.sls"), "w") as f:
  922. print(
  923. textwrap.dedent(
  924. """
  925. mojo:
  926. bad risin'
  927. """
  928. ),
  929. file=f,
  930. )
  931. opts = {
  932. "optimization_order": [0, 1, 2],
  933. "renderer": "yaml",
  934. "renderer_blacklist": [],
  935. "renderer_whitelist": [],
  936. "state_top": "top.sls",
  937. "pillar_roots": {"base": [tempdir]},
  938. "extension_modules": "",
  939. "saltenv": "base",
  940. "file_roots": [],
  941. "file_ignore_regex": None,
  942. "file_ignore_glob": None,
  943. }
  944. grains = {
  945. "os": "Ubuntu",
  946. "os_family": "Debian",
  947. "oscodename": "raring",
  948. "osfullname": "Ubuntu",
  949. "osrelease": "13.04",
  950. "kernel": "Linux",
  951. }
  952. pillar = salt.pillar.Pillar(opts, grains, "minion", "base")
  953. # Make sure that confirm_top.confirm_top returns True
  954. pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
  955. # Act
  956. compiled_pillar = pillar.compile_pillar()
  957. # Assert
  958. self.assertEqual(compiled_pillar["this"], "is all good")
  959. self.assertEqual(compiled_pillar["that"], "is also all good")
  960. self.assertEqual(compiled_pillar["simple"], "simon")
  961. self.assertEqual(compiled_pillar["super simple"], "a caveman")
  962. self.assertEqual(compiled_pillar["mordor"], "has dark depths")
  963. self.assertEqual(compiled_pillar["found"], "my precious")
  964. self.assertEqual(compiled_pillar["mojo"], "bad risin'")
  965. @with_tempdir()
  966. def test_missing_include(self, tempdir):
  967. opts = {
  968. "optimization_order": [0, 1, 2],
  969. "renderer": "yaml",
  970. "renderer_blacklist": [],
  971. "renderer_whitelist": [],
  972. "state_top": "top.sls",
  973. "pillar_roots": {"base": [tempdir]},
  974. "extension_modules": "",
  975. "saltenv": "base",
  976. "file_roots": [],
  977. "file_ignore_regex": None,
  978. "file_ignore_glob": None,
  979. }
  980. grains = {
  981. "os": "Ubuntu",
  982. "os_family": "Debian",
  983. "oscodename": "raring",
  984. "osfullname": "Ubuntu",
  985. "osrelease": "13.04",
  986. "kernel": "Linux",
  987. }
  988. join = os.path.join
  989. with fopen(join(tempdir, "top.sls"), "w") as f:
  990. print(
  991. textwrap.dedent(
  992. """
  993. base:
  994. '*':
  995. - simple_include
  996. """
  997. ),
  998. file=f,
  999. )
  1000. include_dir = join(tempdir, "simple_include")
  1001. os.makedirs(include_dir)
  1002. with fopen(join(include_dir, "init.sls"), "w") as f:
  1003. print(
  1004. textwrap.dedent(
  1005. """
  1006. include:
  1007. - simple_include.missing_include
  1008. simple_include: is ok
  1009. """
  1010. ),
  1011. file=f,
  1012. )
  1013. pillar = salt.pillar.Pillar(opts, grains, "minion", "base")
  1014. # Make sure that confirm_top.confirm_top returns True
  1015. pillar.matchers["confirm_top.confirm_top"] = lambda *x, **y: True
  1016. # Act
  1017. compiled_pillar = pillar.compile_pillar()
  1018. # Assert
  1019. self.assertEqual(compiled_pillar["simple_include"], "is ok")
  1020. self.assertTrue("_errors" in compiled_pillar)
  1021. self.assertTrue(
  1022. "simple_include.missing_include" in compiled_pillar["_errors"][0]
  1023. )
  1024. @patch("salt.transport.client.ReqChannel.factory", MagicMock())
  1025. class RemotePillarTestCase(TestCase):
  1026. """
  1027. Tests for instantiating a RemotePillar in salt.pillar
  1028. """
  1029. def setUp(self):
  1030. self.grains = {}
  1031. def tearDown(self):
  1032. for attr in ("grains",):
  1033. try:
  1034. delattr(self, attr)
  1035. except AttributeError:
  1036. continue
  1037. def test_get_opts_in_pillar_override_call(self):
  1038. mock_get_extra_minion_data = MagicMock(return_value={})
  1039. with patch(
  1040. "salt.pillar.RemotePillarMixin.get_ext_pillar_extra_minion_data",
  1041. mock_get_extra_minion_data,
  1042. ):
  1043. salt.pillar.RemotePillar({}, self.grains, "mocked-minion", "dev")
  1044. mock_get_extra_minion_data.assert_called_once_with({"saltenv": "dev"})
  1045. def test_multiple_keys_in_opts_added_to_pillar(self):
  1046. opts = {
  1047. "renderer": "json",
  1048. "path_to_add": "fake_data",
  1049. "path_to_add2": {"fake_data2": ["fake_data3", "fake_data4"]},
  1050. "pass_to_ext_pillars": ["path_to_add", "path_to_add2"],
  1051. }
  1052. pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
  1053. self.assertEqual(
  1054. pillar.extra_minion_data,
  1055. {
  1056. "path_to_add": "fake_data",
  1057. "path_to_add2": {"fake_data2": ["fake_data3", "fake_data4"]},
  1058. },
  1059. )
  1060. def test_subkey_in_opts_added_to_pillar(self):
  1061. opts = {
  1062. "renderer": "json",
  1063. "path_to_add": "fake_data",
  1064. "path_to_add2": {
  1065. "fake_data5": "fake_data6",
  1066. "fake_data2": ["fake_data3", "fake_data4"],
  1067. },
  1068. "pass_to_ext_pillars": ["path_to_add2:fake_data5"],
  1069. }
  1070. pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
  1071. self.assertEqual(
  1072. pillar.extra_minion_data, {"path_to_add2": {"fake_data5": "fake_data6"}}
  1073. )
  1074. def test_non_existent_leaf_opt_in_add_to_pillar(self):
  1075. opts = {
  1076. "renderer": "json",
  1077. "path_to_add": "fake_data",
  1078. "path_to_add2": {
  1079. "fake_data5": "fake_data6",
  1080. "fake_data2": ["fake_data3", "fake_data4"],
  1081. },
  1082. "pass_to_ext_pillars": ["path_to_add2:fake_data_non_exist"],
  1083. }
  1084. pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
  1085. self.assertEqual(pillar.pillar_override, {})
  1086. def test_non_existent_intermediate_opt_in_add_to_pillar(self):
  1087. opts = {
  1088. "renderer": "json",
  1089. "path_to_add": "fake_data",
  1090. "path_to_add2": {
  1091. "fake_data5": "fake_data6",
  1092. "fake_data2": ["fake_data3", "fake_data4"],
  1093. },
  1094. "pass_to_ext_pillars": ["path_to_add_no_exist"],
  1095. }
  1096. pillar = salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
  1097. self.assertEqual(pillar.pillar_override, {})
  1098. def test_malformed_add_to_pillar(self):
  1099. opts = {
  1100. "renderer": "json",
  1101. "path_to_add": "fake_data",
  1102. "path_to_add2": {
  1103. "fake_data5": "fake_data6",
  1104. "fake_data2": ["fake_data3", "fake_data4"],
  1105. },
  1106. "pass_to_ext_pillars": MagicMock(),
  1107. }
  1108. with self.assertRaises(salt.exceptions.SaltClientError) as excinfo:
  1109. salt.pillar.RemotePillar(opts, self.grains, "mocked-minion", "dev")
  1110. self.assertEqual(
  1111. excinfo.exception.strerror, "'pass_to_ext_pillars' config is malformed."
  1112. )
  1113. def test_pillar_send_extra_minion_data_from_config(self):
  1114. opts = {
  1115. "renderer": "json",
  1116. "pillarenv": "fake_pillar_env",
  1117. "path_to_add": "fake_data",
  1118. "path_to_add2": {
  1119. "fake_data5": "fake_data6",
  1120. "fake_data2": ["fake_data3", "fake_data4"],
  1121. },
  1122. "pass_to_ext_pillars": ["path_to_add"],
  1123. }
  1124. mock_channel = MagicMock(
  1125. crypted_transfer_decode_dictentry=MagicMock(return_value={})
  1126. )
  1127. with patch(
  1128. "salt.transport.client.ReqChannel.factory",
  1129. MagicMock(return_value=mock_channel),
  1130. ):
  1131. pillar = salt.pillar.RemotePillar(
  1132. opts, self.grains, "mocked_minion", "fake_env"
  1133. )
  1134. ret = pillar.compile_pillar()
  1135. self.assertEqual(pillar.channel, mock_channel)
  1136. mock_channel.crypted_transfer_decode_dictentry.assert_called_once_with(
  1137. {
  1138. "cmd": "_pillar",
  1139. "ver": "2",
  1140. "id": "mocked_minion",
  1141. "grains": {},
  1142. "saltenv": "fake_env",
  1143. "pillarenv": "fake_pillar_env",
  1144. "pillar_override": {},
  1145. "extra_minion_data": {"path_to_add": "fake_data"},
  1146. },
  1147. dictkey="pillar",
  1148. )
  1149. def test_pillar_file_client_master_remote(self):
  1150. """
  1151. Test condition where local file_client and use_master_when_local option
  1152. returns a remote file client.
  1153. """
  1154. mocked_minion = MagicMock()
  1155. opts = {
  1156. "file_client": "local",
  1157. "use_master_when_local": True,
  1158. "pillar_cache": None,
  1159. }
  1160. pillar = salt.pillar.get_pillar(opts, self.grains, mocked_minion)
  1161. self.assertEqual(type(pillar), salt.pillar.RemotePillar)
  1162. self.assertNotEqual(type(pillar), salt.pillar.PillarCache)
  1163. @patch("salt.transport.client.AsyncReqChannel.factory", MagicMock())
  1164. class AsyncRemotePillarTestCase(TestCase):
  1165. """
  1166. Tests for instantiating a AsyncRemotePillar in salt.pillar
  1167. """
  1168. def setUp(self):
  1169. self.grains = {}
  1170. def tearDown(self):
  1171. for attr in ("grains",):
  1172. try:
  1173. delattr(self, attr)
  1174. except AttributeError:
  1175. continue
  1176. def test_get_opts_in_pillar_override_call(self):
  1177. mock_get_extra_minion_data = MagicMock(return_value={})
  1178. with patch(
  1179. "salt.pillar.RemotePillarMixin.get_ext_pillar_extra_minion_data",
  1180. mock_get_extra_minion_data,
  1181. ):
  1182. salt.pillar.RemotePillar({}, self.grains, "mocked-minion", "dev")
  1183. mock_get_extra_minion_data.assert_called_once_with({"saltenv": "dev"})
  1184. def test_pillar_send_extra_minion_data_from_config(self):
  1185. opts = {
  1186. "renderer": "json",
  1187. "pillarenv": "fake_pillar_env",
  1188. "path_to_add": "fake_data",
  1189. "path_to_add2": {
  1190. "fake_data5": "fake_data6",
  1191. "fake_data2": ["fake_data3", "fake_data4"],
  1192. },
  1193. "pass_to_ext_pillars": ["path_to_add"],
  1194. }
  1195. mock_channel = MagicMock(
  1196. crypted_transfer_decode_dictentry=MagicMock(return_value={})
  1197. )
  1198. with patch(
  1199. "salt.transport.client.AsyncReqChannel.factory",
  1200. MagicMock(return_value=mock_channel),
  1201. ):
  1202. pillar = salt.pillar.RemotePillar(
  1203. opts, self.grains, "mocked_minion", "fake_env"
  1204. )
  1205. ret = pillar.compile_pillar()
  1206. mock_channel.crypted_transfer_decode_dictentry.assert_called_once_with(
  1207. {
  1208. "cmd": "_pillar",
  1209. "ver": "2",
  1210. "id": "mocked_minion",
  1211. "grains": {},
  1212. "saltenv": "fake_env",
  1213. "pillarenv": "fake_pillar_env",
  1214. "pillar_override": {},
  1215. "extra_minion_data": {"path_to_add": "fake_data"},
  1216. },
  1217. dictkey="pillar",
  1218. )
  1219. @patch("salt.transport.client.ReqChannel.factory", MagicMock())
  1220. class PillarCacheTestCase(TestCase):
  1221. """
  1222. Tests for instantiating a PillarCache in salt.pillar
  1223. """
  1224. def setUp(self):
  1225. self.grains = {}
  1226. @classmethod
  1227. def setUpClass(cls):
  1228. cls.mock_master_default_opts = salt.config.DEFAULT_MASTER_OPTS.copy()
  1229. cls.mock_master_default_opts["cachedir"] = tempfile.mkdtemp(
  1230. dir=RUNTIME_VARS.TMP
  1231. )
  1232. def tearDown(self):
  1233. for attr in ("grains",):
  1234. try:
  1235. delattr(self, attr)
  1236. except AttributeError:
  1237. continue
  1238. def test_compile_pillar_disk_cache(self):
  1239. self.mock_master_default_opts.update(
  1240. {"pillar_cache_backend": "disk", "pillar_cache_ttl": 3600}
  1241. )
  1242. pillar = salt.pillar.PillarCache(
  1243. self.mock_master_default_opts,
  1244. self.grains,
  1245. "mocked_minion",
  1246. "fake_env",
  1247. pillarenv="base",
  1248. )
  1249. with patch("salt.utils.cache.CacheDisk._write", MagicMock()):
  1250. with patch(
  1251. "salt.pillar.PillarCache.fetch_pillar",
  1252. side_effect=[{"foo": "bar"}, {"foo": "baz"}],
  1253. ):
  1254. # Run once for pillarenv base
  1255. ret = pillar.compile_pillar()
  1256. expected_cache = {"mocked_minion": {"base": {"foo": "bar"}}}
  1257. self.assertEqual(pillar.cache._dict, expected_cache)
  1258. # Run a second time for pillarenv base
  1259. ret = pillar.compile_pillar()
  1260. expected_cache = {"mocked_minion": {"base": {"foo": "bar"}}}
  1261. self.assertEqual(pillar.cache._dict, expected_cache)
  1262. # Change the pillarenv
  1263. pillar.pillarenv = "dev"
  1264. # Run once for pillarenv dev
  1265. ret = pillar.compile_pillar()
  1266. expected_cache = {
  1267. "mocked_minion": {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
  1268. }
  1269. self.assertEqual(pillar.cache._dict, expected_cache)
  1270. # Run a second time for pillarenv dev
  1271. ret = pillar.compile_pillar()
  1272. expected_cache = {
  1273. "mocked_minion": {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
  1274. }
  1275. self.assertEqual(pillar.cache._dict, expected_cache)
  1276. def test_compile_pillar_memory_cache(self):
  1277. self.mock_master_default_opts.update(
  1278. {"pillar_cache_backend": "memory", "pillar_cache_ttl": 3600}
  1279. )
  1280. pillar = salt.pillar.PillarCache(
  1281. self.mock_master_default_opts,
  1282. self.grains,
  1283. "mocked_minion",
  1284. "fake_env",
  1285. pillarenv="base",
  1286. )
  1287. with patch(
  1288. "salt.pillar.PillarCache.fetch_pillar",
  1289. side_effect=[{"foo": "bar"}, {"foo": "baz"}],
  1290. ):
  1291. # Run once for pillarenv base
  1292. ret = pillar.compile_pillar()
  1293. expected_cache = {"base": {"foo": "bar"}}
  1294. self.assertIn("mocked_minion", pillar.cache)
  1295. self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
  1296. # Run a second time for pillarenv base
  1297. ret = pillar.compile_pillar()
  1298. expected_cache = {"base": {"foo": "bar"}}
  1299. self.assertIn("mocked_minion", pillar.cache)
  1300. self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
  1301. # Change the pillarenv
  1302. pillar.pillarenv = "dev"
  1303. # Run once for pillarenv dev
  1304. ret = pillar.compile_pillar()
  1305. expected_cache = {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
  1306. self.assertIn("mocked_minion", pillar.cache)
  1307. self.assertEqual(pillar.cache["mocked_minion"], expected_cache)
  1308. # Run a second time for pillarenv dev
  1309. ret = pillar.compile_pillar()
  1310. expected_cache = {"base": {"foo": "bar"}, "dev": {"foo": "baz"}}
  1311. self.assertIn("mocked_minion", pillar.cache)
  1312. self.assertEqual(pillar.cache["mocked_minion"], expected_cache)