gitfs.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Base classes for gitfs/git_pillar integration tests
  4. '''
  5. # Import python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import copy
  8. import errno
  9. import logging
  10. import os
  11. import psutil
  12. import shutil
  13. import signal
  14. import tempfile
  15. import textwrap
  16. import time
  17. # Import Salt libs
  18. import salt.utils.files
  19. import salt.utils.path
  20. import salt.utils.yaml
  21. from salt.fileserver import gitfs
  22. from salt.pillar import git_pillar
  23. from salt.ext.six.moves import range # pylint: disable=redefined-builtin
  24. # Import Salt Testing libs
  25. from tests.support.case import ModuleCase
  26. from tests.support.mixins import LoaderModuleMockMixin, SaltReturnAssertsMixin
  27. from tests.support.paths import TMP
  28. from tests.support.helpers import (
  29. get_unused_localhost_port,
  30. requires_system_grains,
  31. )
  32. from tests.support.mock import patch
  33. log = logging.getLogger(__name__)
  34. USERNAME = 'gitpillaruser'
  35. PASSWORD = 'saltrules'
  36. _OPTS = {
  37. '__role': 'minion',
  38. 'environment': None,
  39. 'pillarenv': None,
  40. 'hash_type': 'sha256',
  41. 'file_roots': {},
  42. 'state_top': 'top.sls',
  43. 'state_top_saltenv': None,
  44. 'renderer': 'yaml_jinja',
  45. 'renderer_whitelist': [],
  46. 'renderer_blacklist': [],
  47. 'pillar_merge_lists': False,
  48. 'git_pillar_base': 'master',
  49. 'git_pillar_branch': 'master',
  50. 'git_pillar_env': '',
  51. 'git_pillar_root': '',
  52. 'git_pillar_ssl_verify': True,
  53. 'git_pillar_global_lock': True,
  54. 'git_pillar_user': '',
  55. 'git_pillar_password': '',
  56. 'git_pillar_insecure_auth': False,
  57. 'git_pillar_privkey': '',
  58. 'git_pillar_pubkey': '',
  59. 'git_pillar_passphrase': '',
  60. 'git_pillar_refspecs': [
  61. '+refs/heads/*:refs/remotes/origin/*',
  62. '+refs/tags/*:refs/tags/*',
  63. ],
  64. 'git_pillar_includes': True,
  65. }
  66. PROC_TIMEOUT = 10
  67. class ProcessManager(object):
  68. '''
  69. Functions used both to set up self-contained SSH/HTTP servers for testing
  70. '''
  71. wait = 10
  72. def find_proc(self, name=None, search=None):
  73. def _search(proc):
  74. return any([search in x for x in proc.cmdline()])
  75. if name is None and search is None:
  76. raise ValueError('one of name or search is required')
  77. for proc in psutil.process_iter():
  78. if name is not None:
  79. try:
  80. if search is None:
  81. if name in proc.name():
  82. return proc
  83. elif name in proc.name() and _search(proc):
  84. return proc
  85. except psutil.NoSuchProcess:
  86. # Whichever process we are interrogating is no longer alive.
  87. # Skip it and keep searching.
  88. continue
  89. else:
  90. if _search(proc):
  91. return proc
  92. return None
  93. def wait_proc(self, name=None, search=None, timeout=PROC_TIMEOUT):
  94. for idx in range(1, self.wait + 1):
  95. proc = self.find_proc(name=name, search=search)
  96. if proc is not None:
  97. return proc
  98. else:
  99. if idx != self.wait:
  100. log.debug(
  101. 'Waiting for %s process (%d of %d)',
  102. name, idx, self.wait
  103. )
  104. time.sleep(1)
  105. else:
  106. log.debug(
  107. 'Failed fo find %s process after %d seconds',
  108. name, self.wait
  109. )
  110. raise Exception(
  111. 'Unable to find {0} process running from temp config file {1} '
  112. 'using psutil'.format(name, search)
  113. )
  114. class SSHDMixin(ModuleCase, ProcessManager, SaltReturnAssertsMixin):
  115. '''
  116. Functions to stand up an SSHD server to serve up git repos for tests.
  117. '''
  118. sshd_proc = None
  119. @classmethod
  120. def prep_server(cls):
  121. cls.sshd_config_dir = tempfile.mkdtemp(dir=TMP)
  122. cls.sshd_config = os.path.join(cls.sshd_config_dir, 'sshd_config')
  123. cls.sshd_port = get_unused_localhost_port()
  124. cls.url = 'ssh://{username}@127.0.0.1:{port}/~/repo.git'.format(
  125. username=cls.username,
  126. port=cls.sshd_port)
  127. cls.url_extra_repo = 'ssh://{username}@127.0.0.1:{port}/~/extra_repo.git'.format(
  128. username=cls.username,
  129. port=cls.sshd_port)
  130. home = '/root/.ssh'
  131. cls.ext_opts = {
  132. 'url': cls.url,
  133. 'url_extra_repo': cls.url_extra_repo,
  134. 'privkey_nopass': os.path.join(home, cls.id_rsa_nopass),
  135. 'pubkey_nopass': os.path.join(home, cls.id_rsa_nopass + '.pub'),
  136. 'privkey_withpass': os.path.join(home, cls.id_rsa_withpass),
  137. 'pubkey_withpass': os.path.join(home, cls.id_rsa_withpass + '.pub'),
  138. 'passphrase': cls.passphrase}
  139. def spawn_server(self):
  140. ret = self.run_function(
  141. 'state.apply',
  142. mods='git_pillar.ssh',
  143. pillar={'git_pillar': {'git_ssh': self.git_ssh,
  144. 'id_rsa_nopass': self.id_rsa_nopass,
  145. 'id_rsa_withpass': self.id_rsa_withpass,
  146. 'sshd_bin': self.sshd_bin,
  147. 'sshd_port': self.sshd_port,
  148. 'sshd_config_dir': self.sshd_config_dir,
  149. 'master_user': self.master_opts['user'],
  150. 'user': self.username}}
  151. )
  152. try:
  153. self.sshd_proc = self.wait_proc(name='sshd',
  154. search=self.sshd_config)
  155. finally:
  156. # Do the assert after we check for the PID so that we can track
  157. # it regardless of whether or not something else in the SLS
  158. # failed (but the SSH server still started).
  159. self.assertSaltTrueReturn(ret)
  160. class WebserverMixin(ModuleCase, ProcessManager, SaltReturnAssertsMixin):
  161. '''
  162. Functions to stand up an nginx + uWSGI + git-http-backend webserver to
  163. serve up git repos for tests.
  164. '''
  165. nginx_proc = uwsgi_proc = None
  166. @classmethod
  167. def prep_server(cls):
  168. '''
  169. Set up all the webserver paths. Designed to be run once in a
  170. setUpClass function.
  171. '''
  172. cls.root_dir = tempfile.mkdtemp(dir=TMP)
  173. cls.config_dir = os.path.join(cls.root_dir, 'config')
  174. cls.nginx_conf = os.path.join(cls.config_dir, 'nginx.conf')
  175. cls.uwsgi_conf = os.path.join(cls.config_dir, 'uwsgi.yml')
  176. cls.git_dir = os.path.join(cls.root_dir, 'git')
  177. cls.repo_dir = os.path.join(cls.git_dir, 'repos')
  178. cls.venv_dir = os.path.join(cls.root_dir, 'venv')
  179. cls.uwsgi_bin = os.path.join(cls.venv_dir, 'bin', 'uwsgi')
  180. cls.nginx_port = cls.uwsgi_port = get_unused_localhost_port()
  181. while cls.uwsgi_port == cls.nginx_port:
  182. # Ensure we don't hit a corner case in which two sucessive calls to
  183. # get_unused_localhost_port() return identical port numbers.
  184. cls.uwsgi_port = get_unused_localhost_port()
  185. cls.url = 'http://127.0.0.1:{port}/repo.git'.format(port=cls.nginx_port)
  186. cls.url_extra_repo = 'http://127.0.0.1:{port}/extra_repo.git'.format(port=cls.nginx_port)
  187. cls.ext_opts = {'url': cls.url, 'url_extra_repo': cls.url_extra_repo}
  188. # Add auth params if present (if so this will trigger the spawned
  189. # server to turn on HTTP basic auth).
  190. for credential_param in ('user', 'password'):
  191. if hasattr(cls, credential_param):
  192. cls.ext_opts[credential_param] = getattr(cls, credential_param)
  193. @requires_system_grains
  194. def spawn_server(self, grains):
  195. auth_enabled = hasattr(self, 'username') and hasattr(self, 'password')
  196. pillar = {'git_pillar': {'config_dir': self.config_dir,
  197. 'git_dir': self.git_dir,
  198. 'venv_dir': self.venv_dir,
  199. 'root_dir': self.root_dir,
  200. 'nginx_port': self.nginx_port,
  201. 'uwsgi_port': self.uwsgi_port,
  202. 'auth_enabled': auth_enabled}}
  203. # Different libexec dir for git backend on Debian-based systems
  204. git_core = '/usr/libexec/git-core' \
  205. if grains['os_family'] in ('RedHat') \
  206. else '/usr/lib/git-core'
  207. pillar['git_pillar']['git-http-backend'] = os.path.join(
  208. git_core,
  209. 'git-http-backend')
  210. ret = self.run_function(
  211. 'state.apply',
  212. mods='git_pillar.http',
  213. pillar=pillar)
  214. if not os.path.exists(pillar['git_pillar']['git-http-backend']):
  215. self.fail(
  216. '{0} not found. Either git is not installed, or the test '
  217. 'class needs to be updated.'.format(
  218. pillar['git_pillar']['git-http-backend']
  219. )
  220. )
  221. try:
  222. self.nginx_proc = self.wait_proc(name='nginx',
  223. search=self.nginx_conf)
  224. self.uwsgi_proc = self.wait_proc(name='uwsgi',
  225. search=self.uwsgi_conf)
  226. finally:
  227. # Do the assert after we check for the PID so that we can track
  228. # it regardless of whether or not something else in the SLS
  229. # failed (but the webserver still started).
  230. self.assertSaltTrueReturn(ret)
  231. class GitTestBase(ModuleCase):
  232. '''
  233. Base class for all gitfs/git_pillar tests. Must be subclassed and paired
  234. with either SSHDMixin or WebserverMixin to provide the server.
  235. '''
  236. case = port = bare_repo = base_extra_repo = admin_repo = admin_extra_repo = None
  237. maxDiff = None
  238. git_opts = '-c user.name="Foo Bar" -c user.email=foo@bar.com'
  239. ext_opts = {}
  240. # We need to temporarily skip pygit2 tests on EL7 until the EPEL packager
  241. # updates pygit2 to bring it up-to-date with libgit2.
  242. @requires_system_grains
  243. def is_el7(self, grains):
  244. return grains['os_family'] == 'RedHat' and grains['osmajorrelease'] == 7
  245. # Cent OS 6 has too old a version of git to handle the make_repo code, as
  246. # it lacks the -c option for git itself.
  247. @requires_system_grains
  248. def is_pre_el7(self, grains):
  249. return grains['os_family'] == 'RedHat' and grains['osmajorrelease'] < 7
  250. @classmethod
  251. def setUpClass(cls):
  252. cls.prep_server()
  253. def setUp(self):
  254. # Make the test class available to the tearDownClass so we can clean up
  255. # after ourselves. This (and the gated block below) prevent us from
  256. # needing to spend the extra time creating an ssh server and user and
  257. # then tear them down separately for each test.
  258. self.update_class(self)
  259. if self.is_pre_el7(): # pylint: disable=E1120
  260. self.skipTest(
  261. 'RHEL < 7 has too old a version of git to run these tests')
  262. @classmethod
  263. def update_class(cls, case):
  264. '''
  265. Make the test class available to the tearDownClass. Note that this
  266. cannot be defined in a parent class and inherited, as this will cause
  267. the parent class to be modified.
  268. '''
  269. if getattr(cls, 'case') is None:
  270. setattr(cls, 'case', case)
  271. def make_repo(self, root_dir, user='root'):
  272. raise NotImplementedError()
  273. class GitFSTestBase(GitTestBase, LoaderModuleMockMixin):
  274. '''
  275. Base class for all gitfs tests
  276. '''
  277. @requires_system_grains
  278. def setup_loader_modules(self, grains): # pylint: disable=W0221
  279. return {
  280. gitfs: {
  281. '__opts__': copy.copy(_OPTS),
  282. '__grains__': grains,
  283. }
  284. }
  285. def make_repo(self, root_dir, user='root'):
  286. raise NotImplementedError()
  287. class GitPillarTestBase(GitTestBase, LoaderModuleMockMixin):
  288. '''
  289. Base class for all git_pillar tests
  290. '''
  291. @requires_system_grains
  292. def setup_loader_modules(self, grains): # pylint: disable=W0221
  293. return {
  294. git_pillar: {
  295. '__opts__': copy.copy(_OPTS),
  296. '__grains__': grains,
  297. }
  298. }
  299. def get_pillar(self, ext_pillar_conf):
  300. '''
  301. Run git_pillar with the specified configuration
  302. '''
  303. cachedir = tempfile.mkdtemp(dir=TMP)
  304. self.addCleanup(shutil.rmtree, cachedir, ignore_errors=True)
  305. ext_pillar_opts = {'optimization_order': [0, 1, 2]}
  306. ext_pillar_opts.update(
  307. salt.utils.yaml.safe_load(
  308. ext_pillar_conf.format(
  309. cachedir=cachedir,
  310. extmods=os.path.join(cachedir, 'extmods'),
  311. **self.ext_opts
  312. )
  313. )
  314. )
  315. with patch.dict(git_pillar.__opts__, ext_pillar_opts):
  316. return git_pillar.ext_pillar(
  317. 'minion',
  318. {},
  319. *ext_pillar_opts['ext_pillar'][0]['git']
  320. )
  321. def make_repo(self, root_dir, user='root'):
  322. self.bare_repo = os.path.join(root_dir, 'repo.git')
  323. self.admin_repo = os.path.join(root_dir, 'admin')
  324. for dirname in (self.bare_repo, self.admin_repo):
  325. shutil.rmtree(dirname, ignore_errors=True)
  326. # Create bare repo
  327. self.run_function(
  328. 'git.init',
  329. [self.bare_repo],
  330. user=user,
  331. bare=True)
  332. # Clone bare repo
  333. self.run_function(
  334. 'git.clone',
  335. [self.admin_repo],
  336. url=self.bare_repo,
  337. user=user)
  338. def _push(branch, message):
  339. self.run_function(
  340. 'git.add',
  341. [self.admin_repo, '.'],
  342. user=user)
  343. self.run_function(
  344. 'git.commit',
  345. [self.admin_repo, message],
  346. user=user,
  347. git_opts=self.git_opts,
  348. )
  349. self.run_function(
  350. 'git.push',
  351. [self.admin_repo],
  352. remote='origin',
  353. ref=branch,
  354. user=user,
  355. )
  356. with salt.utils.files.fopen(
  357. os.path.join(self.admin_repo, 'top.sls'), 'w') as fp_:
  358. fp_.write(textwrap.dedent('''\
  359. base:
  360. '*':
  361. - foo
  362. '''))
  363. with salt.utils.files.fopen(
  364. os.path.join(self.admin_repo, 'foo.sls'), 'w') as fp_:
  365. fp_.write(textwrap.dedent('''\
  366. branch: master
  367. mylist:
  368. - master
  369. mydict:
  370. master: True
  371. nested_list:
  372. - master
  373. nested_dict:
  374. master: True
  375. '''))
  376. # Add another file to be referenced using git_pillar_includes
  377. with salt.utils.files.fopen(
  378. os.path.join(self.admin_repo, 'bar.sls'), 'w') as fp_:
  379. fp_.write('included_pillar: True\n')
  380. # Add another file in subdir
  381. os.mkdir(os.path.join(self.admin_repo, 'subdir'))
  382. with salt.utils.files.fopen(
  383. os.path.join(self.admin_repo, 'subdir', 'bar.sls'), 'w') as fp_:
  384. fp_.write('from_subdir: True\n')
  385. _push('master', 'initial commit')
  386. # Do the same with different values for "dev" branch
  387. self.run_function(
  388. 'git.checkout',
  389. [self.admin_repo],
  390. user=user,
  391. opts='-b dev')
  392. # The bar.sls shouldn't be in any branch but master
  393. self.run_function(
  394. 'git.rm',
  395. [self.admin_repo, 'bar.sls'],
  396. user=user)
  397. with salt.utils.files.fopen(
  398. os.path.join(self.admin_repo, 'top.sls'), 'w') as fp_:
  399. fp_.write(textwrap.dedent('''\
  400. dev:
  401. '*':
  402. - foo
  403. '''))
  404. with salt.utils.files.fopen(
  405. os.path.join(self.admin_repo, 'foo.sls'), 'w') as fp_:
  406. fp_.write(textwrap.dedent('''\
  407. branch: dev
  408. mylist:
  409. - dev
  410. mydict:
  411. dev: True
  412. nested_list:
  413. - dev
  414. nested_dict:
  415. dev: True
  416. '''))
  417. _push('dev', 'add dev branch')
  418. # Create just a top file in a separate repo, to be mapped to the base
  419. # env and referenced using git_pillar_includes
  420. self.run_function(
  421. 'git.checkout',
  422. [self.admin_repo],
  423. user=user,
  424. opts='-b top_only')
  425. # The top.sls should be the only file in this branch
  426. self.run_function(
  427. 'git.rm',
  428. [self.admin_repo, 'foo.sls', os.path.join('subdir', 'bar.sls')],
  429. user=user)
  430. with salt.utils.files.fopen(
  431. os.path.join(self.admin_repo, 'top.sls'), 'w') as fp_:
  432. fp_.write(textwrap.dedent('''\
  433. base:
  434. '*':
  435. - bar
  436. '''))
  437. _push('top_only', 'add top_only branch')
  438. # Create just another top file in a separate repo, to be mapped to the base
  439. # env and including mounted.bar
  440. self.run_function(
  441. 'git.checkout',
  442. [self.admin_repo],
  443. user=user,
  444. opts='-b top_mounted')
  445. # The top.sls should be the only file in this branch
  446. with salt.utils.files.fopen(
  447. os.path.join(self.admin_repo, 'top.sls'), 'w') as fp_:
  448. fp_.write(textwrap.dedent('''\
  449. base:
  450. '*':
  451. - mounted.bar
  452. '''))
  453. _push('top_mounted', 'add top_mounted branch')
  454. def make_extra_repo(self, root_dir, user='root'):
  455. self.bare_extra_repo = os.path.join(root_dir, 'extra_repo.git')
  456. self.admin_extra_repo = os.path.join(root_dir, 'admin_extra')
  457. for dirname in (self.bare_extra_repo, self.admin_extra_repo):
  458. shutil.rmtree(dirname, ignore_errors=True)
  459. # Create bare extra repo
  460. self.run_function(
  461. 'git.init',
  462. [self.bare_extra_repo],
  463. user=user,
  464. bare=True)
  465. # Clone bare repo
  466. self.run_function(
  467. 'git.clone',
  468. [self.admin_extra_repo],
  469. url=self.bare_extra_repo,
  470. user=user)
  471. def _push(branch, message):
  472. self.run_function(
  473. 'git.add',
  474. [self.admin_extra_repo, '.'],
  475. user=user)
  476. self.run_function(
  477. 'git.commit',
  478. [self.admin_extra_repo, message],
  479. user=user,
  480. git_opts=self.git_opts,
  481. )
  482. self.run_function(
  483. 'git.push',
  484. [self.admin_extra_repo],
  485. remote='origin',
  486. ref=branch,
  487. user=user,
  488. )
  489. with salt.utils.files.fopen(
  490. os.path.join(self.admin_extra_repo, 'top.sls'), 'w') as fp_:
  491. fp_.write(textwrap.dedent('''\
  492. "{{saltenv}}":
  493. '*':
  494. - motd
  495. - nowhere.foo
  496. '''))
  497. with salt.utils.files.fopen(
  498. os.path.join(self.admin_extra_repo, 'motd.sls'), 'w') as fp_:
  499. fp_.write(textwrap.dedent('''\
  500. motd: The force will be with you. Always.
  501. '''))
  502. _push('master', 'initial commit')
  503. class GitPillarSSHTestBase(GitPillarTestBase, SSHDMixin):
  504. '''
  505. Base class for GitPython and Pygit2 SSH tests
  506. '''
  507. id_rsa_nopass = id_rsa_withpass = None
  508. git_ssh = '/tmp/git_ssh'
  509. @classmethod
  510. def tearDownClass(cls):
  511. if cls.case is None:
  512. return
  513. if cls.case.sshd_proc is not None:
  514. cls.case.sshd_proc.send_signal(signal.SIGTERM)
  515. cls.case.run_state('user.absent', name=cls.username, purge=True)
  516. for dirname in (cls.sshd_config_dir, cls.case.admin_repo,
  517. cls.case.bare_repo):
  518. if dirname is not None:
  519. shutil.rmtree(dirname, ignore_errors=True)
  520. ssh_dir = os.path.expanduser('~/.ssh')
  521. for filename in (cls.id_rsa_nopass,
  522. cls.id_rsa_nopass + '.pub',
  523. cls.id_rsa_withpass,
  524. cls.id_rsa_withpass + '.pub',
  525. cls.git_ssh):
  526. try:
  527. os.remove(os.path.join(ssh_dir, filename))
  528. except OSError as exc:
  529. if exc.errno != errno.ENOENT:
  530. raise
  531. def setUp(self):
  532. '''
  533. Create the SSH server and user, and create the git repo
  534. '''
  535. super(GitPillarSSHTestBase, self).setUp()
  536. self.sshd_proc = self.find_proc(name='sshd',
  537. search=self.sshd_config)
  538. self.sshd_bin = salt.utils.path.which('sshd')
  539. if self.sshd_proc is None:
  540. self.spawn_server()
  541. known_hosts_ret = self.run_function(
  542. 'ssh.set_known_host',
  543. user=self.master_opts['user'],
  544. hostname='127.0.0.1',
  545. port=self.sshd_port,
  546. enc='ssh-rsa',
  547. fingerprint='fd:6f:7f:5d:06:6b:f2:06:0d:26:93:9e:5a:b5:19:46',
  548. hash_known_hosts=False,
  549. fingerprint_hash_type='md5',
  550. )
  551. if 'error' in known_hosts_ret:
  552. raise Exception(
  553. 'Failed to add key to {0} user\'s known_hosts '
  554. 'file: {1}'.format(
  555. self.master_opts['user'],
  556. known_hosts_ret['error']
  557. )
  558. )
  559. root_dir = os.path.expanduser('~{0}'.format(self.username))
  560. if root_dir.startswith('~'):
  561. self.fail(
  562. 'Unable to resolve homedir for user \'{0}\''.format(
  563. self.username
  564. )
  565. )
  566. self.make_repo(root_dir, user=self.username)
  567. self.make_extra_repo(root_dir, user=self.username)
  568. def get_pillar(self, ext_pillar_conf):
  569. '''
  570. Wrap the parent class' get_pillar() func in logic that temporarily
  571. changes the GIT_SSH to use our custom script, ensuring that the
  572. passphraselsess key is used to auth without needing to modify the root
  573. user's ssh config file.
  574. '''
  575. def cleanup_environ(environ):
  576. os.environ.clear()
  577. os.environ.update(environ)
  578. self.addCleanup(cleanup_environ, os.environ.copy())
  579. os.environ['GIT_SSH'] = self.git_ssh
  580. return super(GitPillarSSHTestBase, self).get_pillar(ext_pillar_conf)
  581. class GitPillarHTTPTestBase(GitPillarTestBase, WebserverMixin):
  582. '''
  583. Base class for GitPython and Pygit2 HTTP tests
  584. '''
  585. @classmethod
  586. def tearDownClass(cls):
  587. for proc in (cls.case.nginx_proc, cls.case.uwsgi_proc):
  588. if proc is not None:
  589. try:
  590. proc.send_signal(signal.SIGQUIT)
  591. except psutil.NoSuchProcess:
  592. pass
  593. shutil.rmtree(cls.root_dir, ignore_errors=True)
  594. def setUp(self):
  595. '''
  596. Create and start the webserver, and create the git repo
  597. '''
  598. super(GitPillarHTTPTestBase, self).setUp()
  599. self.nginx_proc = self.find_proc(name='nginx',
  600. search=self.nginx_conf)
  601. self.uwsgi_proc = self.find_proc(name='uwsgi',
  602. search=self.uwsgi_conf)
  603. if self.nginx_proc is None and self.uwsgi_proc is None:
  604. self.spawn_server() # pylint: disable=E1120
  605. self.make_repo(self.repo_dir)
  606. self.make_extra_repo(self.repo_dir)