conftest.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import, unicode_literals, print_function
  3. # Import python libraries
  4. import logging
  5. import os.path
  6. import shutil
  7. import sys
  8. import tempfile
  9. import textwrap
  10. # Import Salt Libraries
  11. import salt.utils.yaml as yaml
  12. # Import pytest libraries
  13. import pytest
  14. from pytestskipmarkers.utils import ports
  15. from saltfactories.utils import random_string, running_username
  16. # Import Pepper libraries
  17. import pepper
  18. import pepper.script
  19. log = logging.getLogger(__name__)
  20. @pytest.fixture(scope='session')
  21. def sshd_config_dir(salt_factories):
  22. config_dir = salt_factories.get_root_dir_for_daemon("sshd")
  23. yield config_dir
  24. shutil.rmtree(str(config_dir), ignore_errors=True)
  25. @pytest.fixture(scope='session')
  26. def session_sshd_server(salt_factories, sshd_config_dir, session_master):
  27. sshd_config_dict = {
  28. "Protocol": "2",
  29. # Turn strict modes off so that we can operate in /tmp
  30. "StrictModes": "no",
  31. # Logging
  32. "SyslogFacility": "AUTH",
  33. "LogLevel": "INFO",
  34. # Authentication:
  35. "LoginGraceTime": "120",
  36. "PermitRootLogin": "without-password",
  37. "PubkeyAuthentication": "yes",
  38. # Don't read the user's ~/.rhosts and ~/.shosts files
  39. "IgnoreRhosts": "yes",
  40. "HostbasedAuthentication": "no",
  41. # To enable empty passwords, change to yes (NOT RECOMMENDED)
  42. "PermitEmptyPasswords": "no",
  43. # Change to yes to enable challenge-response passwords (beware issues with
  44. # some PAM modules and threads)
  45. "ChallengeResponseAuthentication": "no",
  46. # Change to no to disable tunnelled clear text passwords
  47. "PasswordAuthentication": "no",
  48. "X11Forwarding": "no",
  49. "X11DisplayOffset": "10",
  50. "PrintMotd": "no",
  51. "PrintLastLog": "yes",
  52. "TCPKeepAlive": "yes",
  53. "AcceptEnv": "LANG LC_*",
  54. "UsePAM": "yes",
  55. }
  56. factory = salt_factories.get_sshd_daemon(
  57. sshd_config_dict=sshd_config_dict,
  58. config_dir=sshd_config_dir,
  59. )
  60. with factory.started():
  61. yield factory
  62. @pytest.fixture(scope='session')
  63. def session_ssh_roster_config(session_sshd_server, session_master):
  64. roster_contents = """
  65. localhost:
  66. host: 127.0.0.1
  67. port: {}
  68. user: {}
  69. priv: {}
  70. mine_functions:
  71. test.arg: ['itworked']
  72. """.format(
  73. session_sshd_server.listen_port,
  74. running_username(),
  75. session_sshd_server.client_key
  76. )
  77. with pytest.helpers.temp_file(
  78. "roster", roster_contents, session_master.config_dir
  79. ) as roster_file:
  80. yield roster_file
  81. @pytest.fixture(scope='session')
  82. def salt_api_port():
  83. '''
  84. Returns an unused localhost port for the api port
  85. '''
  86. return ports.get_unused_localhost_port()
  87. @pytest.fixture(scope='session')
  88. def pepperconfig(salt_api_port):
  89. config = textwrap.dedent('''
  90. [main]
  91. SALTAPI_URL=http://localhost:{0}/
  92. SALTAPI_USER=pepper
  93. SALTAPI_PASS=pepper
  94. SALTAPI_EAUTH=sharedsecret
  95. [pepper]
  96. SALTAPI_URL=http://localhost:{0}/
  97. SALTAPI_USER=pepper
  98. SALTAPI_PASS=pepper
  99. SALTAPI_EAUTH=sharedsecret
  100. [baduser]
  101. SALTAPI_URL=http://localhost:{0}/
  102. SALTAPI_USER=saltdev
  103. SALTAPI_PASS=saltdev
  104. SALTAPI_EAUTH=pam
  105. [badapi]
  106. SALTAPI_URL=git://localhost:{0}/
  107. [noapi]
  108. SALTAPI_USER=pepper
  109. SALTAPI_PASS=pepper
  110. SALTAPI_EAUTH=sharedsecret
  111. [noopts]
  112. SALTAPI_URL=http://localhost:{0}/
  113. '''.format(salt_api_port))
  114. with open('tests/.pepperrc', 'w') as pepper_file:
  115. print(config, file=pepper_file)
  116. yield
  117. os.remove('tests/.pepperrc')
  118. @pytest.fixture
  119. def pepper_client(session_salt_api, salt_api_port):
  120. client = pepper.Pepper('http://localhost:{0}'.format(salt_api_port))
  121. client.login('pepper', 'pepper', 'sharedsecret')
  122. return client
  123. @pytest.fixture
  124. def tokfile():
  125. tokdir = tempfile.mkdtemp()
  126. yield os.path.join(tokdir, 'peppertok.json')
  127. shutil.rmtree(tokdir)
  128. @pytest.fixture
  129. def output_file():
  130. '''
  131. Returns the path to the salt master configuration file
  132. '''
  133. out_dir = tempfile.mkdtemp()
  134. yield os.path.join(out_dir, 'output')
  135. shutil.rmtree(out_dir)
  136. @pytest.fixture(params=['/run', '/login'])
  137. def pepper_cli(request, session_salt_api, salt_api_port, output_file, session_sshd_server):
  138. '''
  139. Wrapper to invoke Pepper with common params and inside an empty env
  140. '''
  141. if request.config.getoption('--salt-api-backend') == 'rest_tornado' and request.param == '/run':
  142. pytest.xfail("rest_tornado does not support /run endpoint until next release")
  143. def_args = [
  144. '--out=json',
  145. '--output-file={0}'.format(output_file),
  146. '-c', 'tests/.pepperrc',
  147. ]
  148. if request.param == '/run':
  149. def_args = ['--run-uri'] + def_args
  150. def _run_pepper_cli(*args, **kwargs):
  151. sys.argv = ['pepper', '-p', kwargs.pop('profile', 'main')] + def_args + list(args)
  152. exitcode = pepper.script.Pepper()()
  153. try:
  154. with open(output_file, 'r') as result:
  155. try:
  156. return yaml.load(result)
  157. except yaml.parser.ParserError:
  158. result.seek(0)
  159. return [yaml.load('{0}}}'.format(ret).strip('"')) for ret in result.read().split('}"\n') if ret]
  160. except Exception as exc:
  161. log.error('ExitCode %s: %s', exitcode, exc)
  162. return exitcode
  163. return _run_pepper_cli
  164. @pytest.fixture(scope='session')
  165. def session_master_factory(request, salt_factories, session_master_config_overrides):
  166. return salt_factories.salt_master_daemon(
  167. random_string("master-"),
  168. overrides=session_master_config_overrides
  169. )
  170. @pytest.fixture(scope='session')
  171. def session_master(session_master_factory):
  172. with session_master_factory.started():
  173. yield session_master_factory
  174. @pytest.fixture(scope='session')
  175. def session_master_config_overrides(request, salt_api_port, salt_api_backend):
  176. return {
  177. salt_api_backend: {
  178. 'port': salt_api_port,
  179. 'disable_ssl': True,
  180. },
  181. 'external_auth': {
  182. 'sharedsecret': {
  183. 'pepper': [
  184. '.*',
  185. '@jobs',
  186. '@wheel',
  187. '@runner',
  188. ],
  189. },
  190. },
  191. 'sharedsecret': 'pepper',
  192. 'token_expire': 94670856,
  193. 'ignore_host_keys': True,
  194. 'ssh_wipe': True,
  195. }
  196. @pytest.fixture(scope='session')
  197. def session_minion_factory(session_master_factory):
  198. """Return a factory for a randomly named minion connected to master."""
  199. minion_factory = session_master_factory.salt_minion_daemon(random_string("minion-"))
  200. minion_factory.after_terminate(
  201. pytest.helpers.remove_stale_minion_key, session_master_factory, minion_factory.id
  202. )
  203. return minion_factory
  204. @pytest.fixture(scope='session')
  205. def session_minion(session_master, session_minion_factory): # noqa
  206. assert session_master.is_running()
  207. with session_minion_factory.started():
  208. yield session_minion_factory
  209. @pytest.fixture(scope='session')
  210. def session_minion_id(session_minion):
  211. return session_minion.id
  212. @pytest.fixture(scope='session')
  213. def salt_api_backend(request):
  214. '''
  215. Return the salt-api backend (cherrypy or tornado)
  216. '''
  217. backend = request.config.getoption('--salt-api-backend')
  218. if backend is not None:
  219. return backend
  220. backend = request.config.getini('salt_api_backend')
  221. if backend is not None:
  222. return backend
  223. return 'rest_cherrypy'
  224. @pytest.fixture(scope='session')
  225. def session_salt_api_factory(session_master_factory):
  226. return session_master_factory.salt_api_daemon()
  227. @pytest.fixture(scope='session')
  228. def session_salt_api(session_master, session_salt_api_factory):
  229. assert session_master.is_running()
  230. with session_salt_api_factory.started():
  231. yield session_salt_api_factory
  232. def pytest_addoption(parser):
  233. parser.addoption(
  234. '--salt-api-backend',
  235. action='store',
  236. default='rest_cherrypy',
  237. help='which backend to use for salt-api, must be one of rest_cherrypy or rest_tornado',
  238. )