test_client.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. # encoding: utf-8
  2. # Import Python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. import logging
  5. import os
  6. import time
  7. # Import Salt libs
  8. import salt.config
  9. import salt.netapi
  10. from salt.exceptions import EauthAuthenticationError
  11. from tests.support.case import SSHCase
  12. from tests.support.helpers import (
  13. SaveRequestsPostHandler,
  14. Webserver,
  15. requires_sshd_server,
  16. )
  17. from tests.support.mock import patch
  18. # Import Salt Testing libs
  19. from tests.support.paths import TMP, TMP_CONF_DIR
  20. from tests.support.runtests import RUNTIME_VARS
  21. from tests.support.unit import TestCase, skipIf
  22. log = logging.getLogger(__name__)
  23. class NetapiClientTest(TestCase):
  24. eauth_creds = {
  25. "username": "saltdev_auto",
  26. "password": "saltdev",
  27. "eauth": "auto",
  28. }
  29. def setUp(self):
  30. """
  31. Set up a NetapiClient instance
  32. """
  33. opts = salt.config.client_config(
  34. os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master")
  35. )
  36. self.netapi = salt.netapi.NetapiClient(opts)
  37. def tearDown(self):
  38. del self.netapi
  39. @skipIf(True, "SLOWTEST skip")
  40. def test_local(self):
  41. low = {"client": "local", "tgt": "*", "fun": "test.ping", "timeout": 300}
  42. low.update(self.eauth_creds)
  43. ret = self.netapi.run(low)
  44. # If --proxy is set, it will cause an extra minion_id to be in the
  45. # response. Since there's not a great way to know if the test
  46. # runner's proxy minion is running, and we're not testing proxy
  47. # minions here anyway, just remove it from the response.
  48. ret.pop("proxytest", None)
  49. self.assertEqual(ret, {"minion": True, "sub_minion": True})
  50. @skipIf(True, "SLOWTEST skip")
  51. def test_local_batch(self):
  52. low = {"client": "local_batch", "tgt": "*", "fun": "test.ping", "timeout": 300}
  53. low.update(self.eauth_creds)
  54. ret = self.netapi.run(low)
  55. rets = []
  56. for _ret in ret:
  57. rets.append(_ret)
  58. self.assertIn({"sub_minion": True}, rets)
  59. self.assertIn({"minion": True}, rets)
  60. def test_local_async(self):
  61. low = {"client": "local_async", "tgt": "*", "fun": "test.ping"}
  62. low.update(self.eauth_creds)
  63. ret = self.netapi.run(low)
  64. # Remove all the volatile values before doing the compare.
  65. self.assertIn("jid", ret)
  66. ret.pop("jid", None)
  67. ret["minions"] = sorted(ret["minions"])
  68. try:
  69. # If --proxy is set, it will cause an extra minion_id to be in the
  70. # response. Since there's not a great way to know if the test
  71. # runner's proxy minion is running, and we're not testing proxy
  72. # minions here anyway, just remove it from the response.
  73. ret["minions"].remove("proxytest")
  74. except ValueError:
  75. pass
  76. self.assertEqual(ret, {"minions": sorted(["minion", "sub_minion"])})
  77. def test_local_unauthenticated(self):
  78. low = {"client": "local", "tgt": "*", "fun": "test.ping"}
  79. with self.assertRaises(EauthAuthenticationError) as excinfo:
  80. ret = self.netapi.run(low)
  81. @skipIf(True, "SLOWTEST skip")
  82. def test_wheel(self):
  83. low = {"client": "wheel", "fun": "key.list_all"}
  84. low.update(self.eauth_creds)
  85. ret = self.netapi.run(low)
  86. # Remove all the volatile values before doing the compare.
  87. self.assertIn("tag", ret)
  88. ret.pop("tag")
  89. data = ret.get("data", {})
  90. self.assertIn("jid", data)
  91. data.pop("jid", None)
  92. self.assertIn("tag", data)
  93. data.pop("tag", None)
  94. ret.pop("_stamp", None)
  95. data.pop("_stamp", None)
  96. self.maxDiff = None
  97. self.assertTrue(
  98. set(["master.pem", "master.pub"]).issubset(
  99. set(ret["data"]["return"]["local"])
  100. )
  101. )
  102. @skipIf(True, "SLOWTEST skip")
  103. def test_wheel_async(self):
  104. # Give this test a little breathing room
  105. time.sleep(3)
  106. low = {"client": "wheel_async", "fun": "key.list_all"}
  107. low.update(self.eauth_creds)
  108. ret = self.netapi.run(low)
  109. self.assertIn("jid", ret)
  110. self.assertIn("tag", ret)
  111. def test_wheel_unauthenticated(self):
  112. low = {"client": "wheel", "tgt": "*", "fun": "test.ping"}
  113. with self.assertRaises(EauthAuthenticationError) as excinfo:
  114. ret = self.netapi.run(low)
  115. @skipIf(True, "This is not testing anything. Skipping for now.")
  116. def test_runner(self):
  117. # TODO: fix race condition in init of event-- right now the event class
  118. # will finish init even if the underlying zmq socket hasn't connected yet
  119. # this is problematic for the runnerclient's master_call method if the
  120. # runner is quick
  121. # low = {'client': 'runner', 'fun': 'cache.grains'}
  122. low = {"client": "runner", "fun": "test.sleep", "arg": [2]}
  123. low.update(self.eauth_creds)
  124. ret = self.netapi.run(low)
  125. @skipIf(True, "This is not testing anything. Skipping for now.")
  126. def test_runner_async(self):
  127. low = {"client": "runner", "fun": "cache.grains"}
  128. low.update(self.eauth_creds)
  129. ret = self.netapi.run(low)
  130. def test_runner_unauthenticated(self):
  131. low = {"client": "runner", "tgt": "*", "fun": "test.ping"}
  132. with self.assertRaises(EauthAuthenticationError) as excinfo:
  133. ret = self.netapi.run(low)
  134. @requires_sshd_server
  135. class NetapiSSHClientTest(SSHCase):
  136. eauth_creds = {
  137. "username": "saltdev_auto",
  138. "password": "saltdev",
  139. "eauth": "auto",
  140. }
  141. def setUp(self):
  142. """
  143. Set up a NetapiClient instance
  144. """
  145. opts = salt.config.client_config(os.path.join(TMP_CONF_DIR, "master"))
  146. self.netapi = salt.netapi.NetapiClient(opts)
  147. self.priv_file = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "key_test")
  148. self.rosters = os.path.join(RUNTIME_VARS.TMP_CONF_DIR)
  149. # Initialize salt-ssh
  150. self.run_function("test.ping")
  151. def tearDown(self):
  152. del self.netapi
  153. @classmethod
  154. def setUpClass(cls):
  155. cls.post_webserver = Webserver(handler=SaveRequestsPostHandler)
  156. cls.post_webserver.start()
  157. cls.post_web_root = cls.post_webserver.web_root
  158. cls.post_web_handler = cls.post_webserver.handler
  159. @classmethod
  160. def tearDownClass(cls):
  161. cls.post_webserver.stop()
  162. del cls.post_webserver
  163. @skipIf(True, "SLOWTEST skip")
  164. def test_ssh(self):
  165. low = {
  166. "client": "ssh",
  167. "tgt": "localhost",
  168. "fun": "test.ping",
  169. "ignore_host_keys": True,
  170. "roster_file": "roster",
  171. "rosters": [self.rosters],
  172. "ssh_priv": self.priv_file,
  173. }
  174. low.update(self.eauth_creds)
  175. ret = self.netapi.run(low)
  176. self.assertIn("localhost", ret)
  177. self.assertIn("return", ret["localhost"])
  178. self.assertEqual(ret["localhost"]["return"], True)
  179. self.assertEqual(ret["localhost"]["id"], "localhost")
  180. self.assertEqual(ret["localhost"]["fun"], "test.ping")
  181. @skipIf(True, "SLOWTEST skip")
  182. def test_ssh_unauthenticated(self):
  183. low = {"client": "ssh", "tgt": "localhost", "fun": "test.ping"}
  184. with self.assertRaises(EauthAuthenticationError) as excinfo:
  185. ret = self.netapi.run(low)
  186. @skipIf(True, "SLOWTEST skip")
  187. def test_ssh_unauthenticated_raw_shell_curl(self):
  188. fun = "-o ProxyCommand curl {0}".format(self.post_web_root)
  189. low = {"client": "ssh", "tgt": "localhost", "fun": fun, "raw_shell": True}
  190. ret = None
  191. with self.assertRaises(EauthAuthenticationError) as excinfo:
  192. ret = self.netapi.run(low)
  193. self.assertEqual(self.post_web_handler.received_requests, [])
  194. self.assertEqual(ret, None)
  195. @skipIf(True, "SLOWTEST skip")
  196. def test_ssh_unauthenticated_raw_shell_touch(self):
  197. badfile = os.path.join(TMP, "badfile.txt")
  198. fun = "-o ProxyCommand touch {0}".format(badfile)
  199. low = {"client": "ssh", "tgt": "localhost", "fun": fun, "raw_shell": True}
  200. ret = None
  201. with self.assertRaises(EauthAuthenticationError) as excinfo:
  202. ret = self.netapi.run(low)
  203. self.assertEqual(ret, None)
  204. self.assertFalse(os.path.exists("badfile.txt"))
  205. @skipIf(True, "SLOWTEST skip")
  206. def test_ssh_authenticated_raw_shell_disabled(self):
  207. badfile = os.path.join(TMP, "badfile.txt")
  208. fun = "-o ProxyCommand touch {0}".format(badfile)
  209. low = {"client": "ssh", "tgt": "localhost", "fun": fun, "raw_shell": True}
  210. low.update(self.eauth_creds)
  211. ret = None
  212. with patch.dict(self.netapi.opts, {"netapi_allow_raw_shell": False}):
  213. with self.assertRaises(EauthAuthenticationError) as excinfo:
  214. ret = self.netapi.run(low)
  215. self.assertEqual(ret, None)
  216. self.assertFalse(os.path.exists("badfile.txt"))