test_matcher.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import
  3. import time
  4. import pytest
  5. import salt.utils.files
  6. import salt.utils.yaml
  7. from tests.support.case import ShellCase
  8. from tests.support.helpers import dedent
  9. from tests.support.mixins import ShellCaseCommonTestsMixin
  10. from tests.support.unit import skipIf
  11. def minion_in_returns(minion, lines):
  12. return bool([True for line in lines if line == "{0}:".format(minion)])
  13. @pytest.mark.windows_whitelisted
  14. @pytest.mark.usefixtures("salt_sub_minion")
  15. class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
  16. """
  17. Test salt matchers
  18. """
  19. _call_binary_ = "salt"
  20. @pytest.mark.slow_test(seconds=60) # Test takes >30 and <=60 seconds
  21. def test_list(self):
  22. """
  23. test salt -L matcher
  24. """
  25. data = self.run_salt("-L minion test.ping")
  26. data = "\n".join(data)
  27. self.assertIn("minion", data)
  28. self.assertNotIn("sub_minion", data)
  29. data = self.run_salt("-L minion,sub_minion test.ping")
  30. data = "\n".join(data)
  31. self.assertIn("minion", data)
  32. self.assertIn("sub_minion", data)
  33. # compound matcher tests: 12
  34. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  35. def test_compound_min_with_grain(self):
  36. """
  37. test salt compound matcher
  38. """
  39. data = self.run_salt('-C "min* and G@test_grain:cheese" test.ping')
  40. assert minion_in_returns("minion", data) is True
  41. assert minion_in_returns("sub_minion", data) is False
  42. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  43. def test_compound_and_not_grain(self):
  44. data = self.run_salt('-C "min* and not G@test_grain:foo" test.ping')
  45. assert minion_in_returns("minion", data) is True
  46. assert minion_in_returns("sub_minion", data) is False
  47. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  48. def test_compound_not_grain(self):
  49. data = self.run_salt('-C "min* not G@test_grain:foo" test.ping')
  50. assert minion_in_returns("minion", data) is True
  51. assert minion_in_returns("sub_minion", data) is False
  52. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  53. def test_compound_pcre_grain_and_grain(self):
  54. match = "P@test_grain:^cheese$ and * and G@test_grain:cheese"
  55. data = self.run_salt('-t 1 -C "{0}" test.ping'.format(match))
  56. assert minion_in_returns("minion", data) is True
  57. assert minion_in_returns("sub_minion", data) is False
  58. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  59. def test_compound_list_and_pcre_minion(self):
  60. match = "L@sub_minion and E@.*"
  61. data = self.run_salt('-t 1 -C "{0}" test.ping'.format(match))
  62. assert minion_in_returns("sub_minion", data) is True
  63. assert minion_in_returns("minion", data) is False
  64. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  65. def test_compound_not_sub_minion(self):
  66. data = self.run_salt('-C "not sub_minion" test.ping')
  67. assert minion_in_returns("minion", data) is True
  68. assert minion_in_returns("sub_minion", data) is False
  69. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  70. def test_compound_all_and_not_grains(self):
  71. data = self.run_salt('-C "* and ( not G@test_grain:cheese )" test.ping')
  72. assert minion_in_returns("minion", data) is False
  73. assert minion_in_returns("sub_minion", data) is True
  74. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  75. def test_compound_grain_regex(self):
  76. data = self.run_salt('-C "G%@planets%merc*" test.ping')
  77. assert minion_in_returns("minion", data) is True
  78. assert minion_in_returns("sub_minion", data) is False
  79. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  80. def test_compound_pcre_grain_regex(self):
  81. data = self.run_salt('-C "P%@planets%^(mercury|saturn)$" test.ping')
  82. assert minion_in_returns("minion", data) is True
  83. assert minion_in_returns("sub_minion", data) is True
  84. @skipIf(True, "This test is unreliable. Need to investigate why more deeply.")
  85. @pytest.mark.flaky(max_runs=4)
  86. def test_compound_pillar(self):
  87. data = self.run_salt("-C 'I%@companions%three%sarah*' test.ping")
  88. assert minion_in_returns("minion", data) is True
  89. assert minion_in_returns("sub_minion", data) is True
  90. @skipIf(True, "This test is unreliable. Need to investigate why more deeply.")
  91. @pytest.mark.flaky(max_runs=4)
  92. def test_coumpound_pillar_pcre(self):
  93. data = self.run_salt("-C 'J%@knights%^(Lancelot|Galahad)$' test.ping")
  94. self.assertTrue(minion_in_returns("minion", data))
  95. self.assertTrue(minion_in_returns("sub_minion", data))
  96. def test_compound_nodegroup(self):
  97. data = self.run_salt('-C "N@multiline_nodegroup" test.ping')
  98. self.assertTrue(minion_in_returns("minion", data))
  99. self.assertTrue(minion_in_returns("sub_minion", data))
  100. data = self.run_salt('-C "N@multiline_nodegroup not sub_minion" test.ping')
  101. self.assertTrue(minion_in_returns("minion", data))
  102. self.assertFalse(minion_in_returns("sub_minion", data))
  103. data = self.run_salt(
  104. '-C "N@multiline_nodegroup not @fakenodegroup not sub_minion" test.ping'
  105. )
  106. self.assertTrue(minion_in_returns("minion", data))
  107. self.assertFalse(minion_in_returns("sub_minion", data))
  108. @pytest.mark.slow_test(seconds=120) # Test takes >60 and <=120 seconds
  109. def test_nodegroup(self):
  110. """
  111. test salt nodegroup matcher
  112. """
  113. data = self.run_salt("-N min test.ping")
  114. self.assertTrue(minion_in_returns("minion", data))
  115. self.assertFalse(minion_in_returns("sub_minion", data))
  116. time.sleep(2)
  117. data = self.run_salt("-N sub_min test.ping")
  118. self.assertFalse(minion_in_returns("minion", data))
  119. self.assertTrue(minion_in_returns("sub_minion", data))
  120. time.sleep(2)
  121. data = self.run_salt("-N mins test.ping")
  122. self.assertTrue(minion_in_returns("minion", data))
  123. self.assertTrue(minion_in_returns("sub_minion", data))
  124. time.sleep(2)
  125. data = self.run_salt("-N unknown_nodegroup test.ping")
  126. self.assertFalse(minion_in_returns("minion", data))
  127. self.assertFalse(minion_in_returns("sub_minion", data))
  128. time.sleep(2)
  129. data = self.run_salt("-N redundant_minions test.ping")
  130. self.assertTrue(minion_in_returns("minion", data))
  131. self.assertTrue(minion_in_returns("sub_minion", data))
  132. time.sleep(2)
  133. data = "\n".join(self.run_salt("-N nodegroup_loop_a test.ping"))
  134. self.assertIn("No minions matched", data)
  135. time.sleep(2)
  136. data = self.run_salt("-N multiline_nodegroup test.ping")
  137. self.assertTrue(minion_in_returns("minion", data))
  138. self.assertTrue(minion_in_returns("sub_minion", data))
  139. @pytest.mark.slow_test(seconds=120) # Test takes >60 and <=120 seconds
  140. def test_nodegroup_list(self):
  141. data = self.run_salt("-N list_group test.ping")
  142. self.assertTrue(minion_in_returns("minion", data))
  143. self.assertTrue(minion_in_returns("sub_minion", data))
  144. data = self.run_salt("-N list_group2 test.ping")
  145. self.assertTrue(minion_in_returns("minion", data))
  146. self.assertTrue(minion_in_returns("sub_minion", data))
  147. data = self.run_salt("-N one_list_group test.ping")
  148. self.assertTrue(minion_in_returns("minion", data))
  149. self.assertFalse(minion_in_returns("sub_minion", data))
  150. data = self.run_salt("-N one_minion_list test.ping")
  151. self.assertTrue(minion_in_returns("minion", data))
  152. self.assertFalse(minion_in_returns("sub_minion", data))
  153. @pytest.mark.slow_test(seconds=60) # Test takes >30 and <=60 seconds
  154. def test_glob(self):
  155. """
  156. test salt glob matcher
  157. """
  158. data = self.run_salt("minion test.ping")
  159. data = "\n".join(data)
  160. self.assertIn("minion", data)
  161. self.assertNotIn("sub_minion", data)
  162. data = self.run_salt('"*" test.ping')
  163. data = "\n".join(data)
  164. self.assertIn("minion", data)
  165. self.assertIn("sub_minion", data)
  166. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  167. def test_regex(self):
  168. """
  169. test salt regex matcher
  170. """
  171. data = self.run_salt('-E "^minion$" test.ping')
  172. data = "\n".join(data)
  173. self.assertIn("minion", data)
  174. self.assertNotIn("sub_minion", data)
  175. data = self.run_salt('-E ".*" test.ping')
  176. data = "\n".join(data)
  177. self.assertIn("minion", data)
  178. self.assertIn("sub_minion", data)
  179. @pytest.mark.slow_test(seconds=240) # Test takes >120 and <=240 seconds
  180. def test_grain(self):
  181. """
  182. test salt grain matcher
  183. """
  184. # Sync grains
  185. self.run_salt('-t1 "*" saltutil.sync_grains')
  186. # First-level grain (string value)
  187. data = self.run_salt('-t 1 -G "test_grain:cheese" test.ping')
  188. data = "\n".join(data)
  189. self.assertIn("minion", data)
  190. self.assertNotIn("sub_minion", data)
  191. data = self.run_salt('-G "test_grain:spam" test.ping')
  192. data = "\n".join(data)
  193. self.assertIn("sub_minion", data)
  194. self.assertNotIn("minion", data.replace("sub_minion", "stub"))
  195. # Custom grain
  196. data = self.run_salt('-t 1 -G "match:maker" test.ping')
  197. data = "\n".join(data)
  198. self.assertIn("minion", data)
  199. self.assertIn("sub_minion", data)
  200. # First-level grain (list member)
  201. data = self.run_salt('-t 1 -G "planets:earth" test.ping')
  202. data = "\n".join(data)
  203. self.assertIn("minion", data)
  204. self.assertNotIn("sub_minion", data)
  205. data = self.run_salt('-G "planets:saturn" test.ping')
  206. data = "\n".join(data)
  207. self.assertIn("sub_minion", data)
  208. self.assertNotIn("minion", data.replace("sub_minion", "stub"))
  209. data = self.run_salt('-G "planets:pluto" test.ping')
  210. expect = None
  211. if self.master_opts["transport"] in ("zeromq", "tcp"):
  212. expect = (
  213. "No minions matched the target. "
  214. "No command was sent, no jid was "
  215. "assigned."
  216. )
  217. self.assertEqual("".join(data), expect)
  218. # Nested grain (string value)
  219. data = self.run_salt('-t 1 -G "level1:level2:foo" test.ping')
  220. data = "\n".join(data)
  221. self.assertIn("minion", data)
  222. self.assertNotIn("sub_minion", data)
  223. data = self.run_salt('-G "level1:level2:bar" test.ping')
  224. data = "\n".join(data)
  225. self.assertIn("sub_minion", data)
  226. self.assertNotIn("minion", data.replace("sub_minion", "stub"))
  227. # Nested grain (list member)
  228. data = self.run_salt('-t 1 -G "companions:one:ian" test.ping')
  229. data = "\n".join(data)
  230. self.assertIn("minion", data)
  231. self.assertNotIn("sub_minion", data)
  232. data = self.run_salt('-G "companions:two:jamie" test.ping')
  233. data = "\n".join(data)
  234. self.assertIn("sub_minion", data)
  235. self.assertNotIn("minion", data.replace("sub_minion", "stub"))
  236. # Test for issue: https://github.com/saltstack/salt/issues/19651
  237. data = self.run_salt('-G "companions:*:susan" test.ping')
  238. data = "\n".join(data)
  239. self.assertIn("minion:", data)
  240. self.assertNotIn("sub_minion", data)
  241. # Test to ensure wildcard at end works correctly
  242. data = self.run_salt('-G "companions:one:*" test.ping')
  243. data = "\n".join(data)
  244. self.assertIn("minion:", data)
  245. self.assertNotIn("sub_minion", data)
  246. # Test to ensure multiple wildcards works correctly
  247. data = self.run_salt('-G "companions:*:*" test.ping')
  248. data = "\n".join(data)
  249. self.assertIn("minion:", data)
  250. self.assertIn("sub_minion", data)
  251. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  252. def test_regrain(self):
  253. """
  254. test salt grain matcher
  255. """
  256. data = self.run_salt('-t 1 --grain-pcre "test_grain:^cheese$" test.ping')
  257. data = "\n".join(data)
  258. self.assertIn("minion", data)
  259. self.assertNotIn("sub_minion", data)
  260. data = self.run_salt('--grain-pcre "test_grain:.*am$" test.ping')
  261. data = "\n".join(data)
  262. self.assertIn("sub_minion", data)
  263. self.assertNotIn("minion", data.replace("sub_minion", "stub"))
  264. @pytest.mark.slow_test(seconds=120) # Test takes >60 and <=120 seconds
  265. def test_pillar(self):
  266. """
  267. test pillar matcher
  268. """
  269. # First-level pillar (string value)
  270. data = self.run_salt('-I "monty:python" test.ping')
  271. data = "\n".join(data)
  272. self.assertIn("minion", data)
  273. self.assertIn("sub_minion", data)
  274. # First-level pillar (string value, only in sub_minion)
  275. data = self.run_salt('-I "sub:sub_minion" test.ping')
  276. data = "\n".join(data)
  277. self.assertIn("sub_minion", data)
  278. self.assertNotIn("minion", data.replace("sub_minion", "stub"))
  279. # First-level pillar (list member)
  280. data = self.run_salt('-I "knights:Bedevere" test.ping')
  281. data = "\n".join(data)
  282. self.assertIn("minion", data)
  283. self.assertIn("sub_minion", data)
  284. # Nested pillar (string value)
  285. data = self.run_salt('-I "level1:level2:foo" test.ping')
  286. data = "\n".join(data)
  287. self.assertIn("minion", data)
  288. self.assertIn("sub_minion", data)
  289. # Nested pillar (list member)
  290. data = self.run_salt('-I "companions:three:sarah jane" test.ping')
  291. data = "\n".join(data)
  292. self.assertIn("minion", data)
  293. self.assertIn("sub_minion", data)
  294. @pytest.mark.slow_test(seconds=60) # Test takes >30 and <=60 seconds
  295. def test_repillar(self):
  296. """
  297. test salt pillar PCRE matcher
  298. """
  299. data = self.run_salt('-J "monty:^(python|hall)$" test.ping')
  300. data = "\n".join(data)
  301. self.assertIn("minion", data)
  302. self.assertIn("sub_minion", data)
  303. data = self.run_salt('--pillar-pcre "knights:^(Robin|Lancelot)$" test.ping')
  304. data = "\n".join(data)
  305. self.assertIn("sub_minion", data)
  306. self.assertIn("minion", data.replace("sub_minion", "stub"))
  307. @pytest.mark.slow_test(seconds=60) # Test takes >30 and <=60 seconds
  308. def test_ipcidr(self):
  309. subnets_data = self.run_salt('--out yaml "*" network.subnets')
  310. yaml_data = salt.utils.yaml.safe_load("\n".join(subnets_data))
  311. # We're just after the first defined subnet from 'minion'
  312. subnet = yaml_data["minion"][0]
  313. data = self.run_salt("-S {0} test.ping".format(subnet))
  314. data = "\n".join(data)
  315. self.assertIn("minion", data)
  316. self.assertIn("sub_minion", data)
  317. @pytest.mark.slow_test(seconds=30) # Test takes >10 and <=30 seconds
  318. def test_static(self):
  319. """
  320. test salt static call
  321. """
  322. data = self.run_salt("minion test.ping --static")
  323. data = "\n".join(data)
  324. self.assertIn("minion", data)
  325. @pytest.mark.slow_test(seconds=60) # Test takes >30 and <=60 seconds
  326. def test_salt_documentation(self):
  327. """
  328. Test to see if we're supporting --doc
  329. """
  330. expect_to_find = "test.ping:"
  331. stdout, stderr = self.run_salt('-d "*" test', catch_stderr=True)
  332. error_msg = dedent(
  333. """
  334. Failed to find \'{expected}\' in output
  335. {sep}
  336. --- STDOUT -----
  337. {stdout}
  338. {sep}
  339. --- STDERR -----
  340. {stderr}
  341. {sep}
  342. """.format(
  343. sep="-" * 80,
  344. expected=expect_to_find,
  345. stdout="\n".join(stdout).strip(),
  346. stderr="\n".join(stderr).strip(),
  347. )
  348. )
  349. self.assertIn(expect_to_find, stdout, msg=error_msg)
  350. @pytest.mark.slow_test(seconds=5) # Test takes >1 and <=5 seconds
  351. def test_salt_documentation_too_many_arguments(self):
  352. """
  353. Test to see if passing additional arguments shows an error
  354. """
  355. data = self.run_salt(
  356. '-d minion salt ldap.search "filter=ou=People"', catch_stderr=True
  357. )
  358. self.assertIn(
  359. "You can only get documentation for one method at one time",
  360. "\n".join(data[1]),
  361. )