test_matcher.py 15 KB

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