conftest.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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 pytestsalt.utils import SaltDaemonScriptBase, start_daemon, get_unused_localhost_port
  15. # Import Pepper libraries
  16. import pepper
  17. import pepper.script
  18. DEFAULT_MASTER_ID = 'pytest-salt-master'
  19. DEFAULT_MINION_ID = 'pytest-salt-minion'
  20. log = logging.getLogger(__name__)
  21. class SaltApi(SaltDaemonScriptBase):
  22. '''
  23. Class which runs the salt-api daemon
  24. '''
  25. def get_script_args(self):
  26. return ['-l', 'quiet']
  27. def get_check_events(self):
  28. if sys.platform.startswith('win'):
  29. return super(SaltApi, self).get_check_events()
  30. return set(['salt/{0}/{1}/start'.format(self.config['__role'], self.config['id'])])
  31. def get_check_ports(self):
  32. return [self.config['rest_cherrypy']['port']]
  33. @pytest.fixture(scope='session')
  34. def salt_api_port():
  35. '''
  36. Returns an unused localhost port for the api port
  37. '''
  38. return get_unused_localhost_port()
  39. @pytest.fixture(scope='session')
  40. def pepperconfig(salt_api_port):
  41. config = textwrap.dedent('''
  42. [main]
  43. SALTAPI_URL=http://localhost:{0}/
  44. SALTAPI_USER=pepper
  45. SALTAPI_PASS=pepper
  46. SALTAPI_EAUTH=sharedsecret
  47. [pepper]
  48. SALTAPI_URL=http://localhost:{0}/
  49. SALTAPI_USER=pepper
  50. SALTAPI_PASS=pepper
  51. SALTAPI_EAUTH=sharedsecret
  52. [baduser]
  53. SALTAPI_URL=http://localhost:{0}/
  54. SALTAPI_USER=saltdev
  55. SALTAPI_PASS=saltdev
  56. SALTAPI_EAUTH=pam
  57. [badapi]
  58. SALTAPI_URL=git://localhost:{0}/
  59. [noapi]
  60. SALTAPI_USER=pepper
  61. SALTAPI_PASS=pepper
  62. SALTAPI_EAUTH=sharedsecret
  63. [noopts]
  64. SALTAPI_URL=http://localhost:{0}/
  65. SALTAPI_EAUTH=kerberos
  66. '''.format(salt_api_port))
  67. with open('tests/.pepperrc', 'w') as pepper_file:
  68. print(config, file=pepper_file)
  69. yield
  70. os.remove('tests/.pepperrc')
  71. @pytest.fixture
  72. def pepper_client(session_salt_api, salt_api_port):
  73. client = pepper.Pepper('http://localhost:{0}'.format(salt_api_port))
  74. client.login('pepper', 'pepper', 'sharedsecret')
  75. return client
  76. @pytest.fixture
  77. def tokfile():
  78. tokdir = tempfile.mkdtemp()
  79. yield os.path.join(tokdir, 'peppertok.json')
  80. shutil.rmtree(tokdir)
  81. @pytest.fixture
  82. def output_file():
  83. '''
  84. Returns the path to the salt master configuration file
  85. '''
  86. out_dir = tempfile.mkdtemp()
  87. yield os.path.join(out_dir, 'output')
  88. shutil.rmtree(out_dir)
  89. @pytest.fixture
  90. def pepper_cli(session_salt_api, salt_api_port, output_file, session_sshd_server):
  91. '''
  92. Wrapper to invoke Pepper with common params and inside an empty env
  93. '''
  94. def_args = [
  95. '--out=json',
  96. '--output-file={0}'.format(output_file),
  97. '-c', 'tests/.pepperrc',
  98. ]
  99. def _run_pepper_cli(*args, **kwargs):
  100. sys.argv = ['pepper', '-p', kwargs.pop('profile', 'main')] + def_args + list(args)
  101. exitcode = pepper.script.Pepper()()
  102. try:
  103. with open(output_file, 'r') as result:
  104. try:
  105. return yaml.load(result)
  106. except yaml.parser.ParserError:
  107. result.seek(0)
  108. return [yaml.load('{0}}}'.format(ret).strip('"')) for ret in result.read().split('}"\n') if ret]
  109. except Exception as exc:
  110. log.info('ExitCode %s: %s', exitcode, exc)
  111. return exitcode
  112. return _run_pepper_cli
  113. @pytest.fixture(scope='session')
  114. def session_master_config_overrides(salt_api_port):
  115. return {
  116. 'rest_cherrypy': {
  117. 'port': salt_api_port,
  118. 'disable_ssl': True,
  119. },
  120. 'external_auth': {
  121. 'sharedsecret': {
  122. 'pepper': [
  123. '.*',
  124. '@jobs',
  125. '@wheel',
  126. '@runner',
  127. ],
  128. },
  129. },
  130. 'sharedsecret': 'pepper',
  131. 'token_expire': 94670856,
  132. 'ignore_host_keys': True,
  133. 'ssh_wipe': True,
  134. }
  135. @pytest.fixture(scope='session')
  136. def session_api_log_prefix(master_id):
  137. return 'salt-api/{0}'.format(master_id)
  138. @pytest.fixture(scope='session')
  139. def cli_api_script_name():
  140. '''
  141. Return the CLI script basename
  142. '''
  143. return 'salt-api'
  144. @pytest.yield_fixture(scope='session')
  145. def session_salt_api_before_start():
  146. '''
  147. This fixture should be overridden if you need to do
  148. some preparation and clean up work before starting
  149. the salt-api and after ending it.
  150. '''
  151. # Prep routines go here
  152. # Start the salt-api
  153. yield
  154. # Clean routines go here
  155. @pytest.yield_fixture(scope='session')
  156. def session_salt_api_after_start(session_salt_api):
  157. '''
  158. This fixture should be overridden if you need to do
  159. some preparation and clean up work after starting
  160. the salt-api and before ending it.
  161. '''
  162. # Prep routines go here
  163. # Resume test execution
  164. yield
  165. # Clean routines go here
  166. @pytest.fixture(scope='session')
  167. def _salt_fail_hard(request, salt_fail_hard):
  168. '''
  169. Return the salt fail hard value
  170. '''
  171. fail_hard = request.config.getoption('salt_fail_hard')
  172. if fail_hard is not None:
  173. # We were passed --salt-fail-hard as a CLI option
  174. return fail_hard
  175. # The salt fail hard was not passed as a CLI option
  176. fail_hard = request.config.getini('salt_fail_hard')
  177. if fail_hard != []:
  178. # We were passed salt_fail_hard as a INI option
  179. return fail_hard
  180. return salt_fail_hard
  181. @pytest.fixture(scope='session')
  182. def master_id(salt_master_id_counter):
  183. '''
  184. Returns the master id
  185. '''
  186. return DEFAULT_MASTER_ID + '-{0}'.format(salt_master_id_counter())
  187. @pytest.fixture(scope='session')
  188. def minion_id(salt_minion_id_counter):
  189. '''
  190. Returns the minion id
  191. '''
  192. return DEFAULT_MINION_ID + '-{0}'.format(salt_minion_id_counter())
  193. @pytest.fixture(scope='session')
  194. def session_salt_api(request,
  195. session_salt_minion,
  196. session_master_id,
  197. session_master_config,
  198. session_salt_api_before_start, # pylint: disable=unused-argument
  199. session_api_log_prefix,
  200. cli_api_script_name,
  201. log_server,
  202. _cli_bin_dir,
  203. session_conf_dir):
  204. '''
  205. Returns a running salt-api
  206. '''
  207. return start_daemon(request,
  208. daemon_name='salt-api',
  209. daemon_id=session_master_id,
  210. daemon_log_prefix=session_api_log_prefix,
  211. daemon_cli_script_name=cli_api_script_name,
  212. daemon_config=session_master_config,
  213. daemon_config_dir=session_conf_dir,
  214. daemon_class=SaltApi,
  215. bin_dir_path=_cli_bin_dir,
  216. start_timeout=30)
  217. @pytest.fixture(scope='session')
  218. def session_sshd_config_lines(session_sshd_port):
  219. '''
  220. Return a list of lines which will make the sshd_config file
  221. '''
  222. return [
  223. 'Port {0}'.format(session_sshd_port),
  224. 'ListenAddress 127.0.0.1',
  225. 'Protocol 2',
  226. 'UsePrivilegeSeparation yes',
  227. '# Turn strict modes off so that we can operate in /tmp',
  228. 'StrictModes no',
  229. '# Logging',
  230. 'SyslogFacility AUTH',
  231. 'LogLevel INFO',
  232. '# Authentication:',
  233. 'LoginGraceTime 120',
  234. 'PermitRootLogin without-password',
  235. 'StrictModes yes',
  236. 'PubkeyAuthentication yes',
  237. '#AuthorizedKeysFile %h/.ssh/authorized_keys',
  238. '#AuthorizedKeysFile key_test.pub',
  239. '# Don\'t read the user\'s ~/.rhosts and ~/.shosts files',
  240. 'IgnoreRhosts yes',
  241. '# similar for protocol version 2',
  242. 'HostbasedAuthentication no',
  243. '#IgnoreUserKnownHosts yes',
  244. '# To enable empty passwords, change to yes (NOT RECOMMENDED)',
  245. 'PermitEmptyPasswords no',
  246. '# Change to yes to enable challenge-response passwords (beware issues with',
  247. '# some PAM modules and threads)',
  248. 'ChallengeResponseAuthentication no',
  249. '# Change to no to disable tunnelled clear text passwords',
  250. 'PasswordAuthentication no',
  251. 'X11Forwarding no',
  252. 'X11DisplayOffset 10',
  253. 'PrintMotd no',
  254. 'PrintLastLog yes',
  255. 'TCPKeepAlive yes',
  256. '#UseLogin no',
  257. 'AcceptEnv LANG LC_*',
  258. 'Subsystem sftp /usr/lib/openssh/sftp-server',
  259. '#UsePAM yes',
  260. ]