test_matcher.py 14 KB

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