1
0

test_matcher.py 14 KB

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