test_matcher.py 15 KB

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