test_gitfs.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: Erik Johnson <erik@saltstack.com>
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import errno
  8. import os
  9. import shutil
  10. import tempfile
  11. import textwrap
  12. import tornado.ioloop
  13. import logging
  14. import stat
  15. try:
  16. import pwd # pylint: disable=unused-import
  17. except ImportError:
  18. pass
  19. # Import Salt Testing Libs
  20. from tests.support.runtime import RUNTIME_VARS
  21. from tests.support.mixins import LoaderModuleMockMixin
  22. from tests.support.unit import TestCase, skipIf
  23. from tests.support.mock import patch
  24. from tests.support.helpers import patched_environ
  25. # Import salt libs
  26. import salt.fileserver.gitfs as gitfs
  27. import salt.utils.files
  28. import salt.utils.platform
  29. import salt.utils.win_functions
  30. import salt.utils.yaml
  31. import salt.ext.six
  32. import salt.utils.gitfs
  33. from salt.utils.gitfs import (
  34. GITPYTHON_VERSION,
  35. GITPYTHON_MINVER,
  36. PYGIT2_VERSION,
  37. PYGIT2_MINVER,
  38. LIBGIT2_VERSION,
  39. LIBGIT2_MINVER
  40. )
  41. try:
  42. import git
  43. # We still need to use GitPython here for temp repo setup, so we do need to
  44. # actually import it. But we don't need import pygit2 in this module, we
  45. # can just use the LooseVersion instances imported along with
  46. # salt.utils.gitfs to check if we have a compatible version.
  47. HAS_GITPYTHON = GITPYTHON_VERSION >= GITPYTHON_MINVER
  48. except (ImportError, AttributeError):
  49. HAS_GITPYTHON = False
  50. try:
  51. HAS_PYGIT2 = PYGIT2_VERSION >= PYGIT2_MINVER \
  52. and LIBGIT2_VERSION >= LIBGIT2_MINVER
  53. except AttributeError:
  54. HAS_PYGIT2 = False
  55. log = logging.getLogger(__name__)
  56. UNICODE_FILENAME = 'питон.txt'
  57. UNICODE_DIRNAME = UNICODE_ENVNAME = 'соль'
  58. TAG_NAME = 'mytag'
  59. def _rmtree_error(func, path, excinfo):
  60. os.chmod(path, stat.S_IWRITE)
  61. func(path)
  62. def _clear_instance_map():
  63. try:
  64. del salt.utils.gitfs.GitFS.instance_map[tornado.ioloop.IOLoop.current()]
  65. except KeyError:
  66. pass
  67. @skipIf(not HAS_GITPYTHON, 'GitPython >= {0} required'.format(GITPYTHON_MINVER))
  68. class GitfsConfigTestCase(TestCase, LoaderModuleMockMixin):
  69. def setup_loader_modules(self):
  70. opts = {
  71. 'sock_dir': self.tmp_sock_dir,
  72. 'gitfs_remotes': ['file://' + self.tmp_repo_dir],
  73. 'gitfs_root': '',
  74. 'fileserver_backend': ['gitfs'],
  75. 'gitfs_base': 'master',
  76. 'fileserver_events': True,
  77. 'transport': 'zeromq',
  78. 'gitfs_mountpoint': '',
  79. 'gitfs_saltenv': [],
  80. 'gitfs_env_whitelist': [],
  81. 'gitfs_env_blacklist': [],
  82. 'gitfs_saltenv_whitelist': [],
  83. 'gitfs_saltenv_blacklist': [],
  84. 'gitfs_user': '',
  85. 'gitfs_password': '',
  86. 'gitfs_insecure_auth': False,
  87. 'gitfs_privkey': '',
  88. 'gitfs_pubkey': '',
  89. 'gitfs_passphrase': '',
  90. 'gitfs_refspecs': [
  91. '+refs/heads/*:refs/remotes/origin/*',
  92. '+refs/tags/*:refs/tags/*'
  93. ],
  94. 'gitfs_ssl_verify': True,
  95. 'gitfs_disable_saltenv_mapping': False,
  96. 'gitfs_ref_types': ['branch', 'tag', 'sha'],
  97. 'gitfs_update_interval': 60,
  98. '__role': 'master',
  99. }
  100. opts['cachedir'] = self.tmp_cachedir
  101. opts['sock_dir'] = self.tmp_sock_dir
  102. return {
  103. gitfs: {
  104. '__opts__': opts,
  105. }
  106. }
  107. @classmethod
  108. def setUpClass(cls):
  109. # Clear the instance map so that we make sure to create a new instance
  110. # for this test class.
  111. _clear_instance_map()
  112. cls.tmp_repo_dir = os.path.join(RUNTIME_VARS.TMP, 'gitfs_root')
  113. if salt.utils.platform.is_windows():
  114. cls.tmp_repo_dir = cls.tmp_repo_dir.replace('\\', '/')
  115. cls.tmp_cachedir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  116. cls.tmp_sock_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  117. @classmethod
  118. def tearDownClass(cls):
  119. '''
  120. Remove the temporary git repository and gitfs cache directory to ensure
  121. a clean environment for the other test class(es).
  122. '''
  123. for path in (cls.tmp_cachedir, cls.tmp_sock_dir):
  124. try:
  125. shutil.rmtree(path, onerror=_rmtree_error)
  126. except OSError as exc:
  127. if exc.errno == errno.EACCES:
  128. log.error("Access error removeing file %s", path)
  129. continue
  130. if exc.errno != errno.EEXIST:
  131. raise
  132. def test_per_saltenv_config(self):
  133. tmp_file_uri = 'file://'
  134. if salt.utils.platform.is_windows():
  135. tmp_file_uri += '/'
  136. opts_override = textwrap.dedent('''
  137. gitfs_root: salt
  138. gitfs_saltenv:
  139. - baz:
  140. # when loaded, the "salt://" prefix will be removed
  141. - mountpoint: salt://baz_mountpoint
  142. - ref: baz_branch
  143. - root: baz_root
  144. gitfs_remotes:
  145. - {0}tmp/repo1:
  146. - saltenv:
  147. - foo:
  148. - ref: foo_branch
  149. - root: foo_root
  150. - {0}tmp/repo2:
  151. - mountpoint: repo2
  152. - saltenv:
  153. - baz:
  154. - mountpoint: abc
  155. '''.format(tmp_file_uri))
  156. with patch.dict(gitfs.__opts__, salt.utils.yaml.safe_load(opts_override)):
  157. git_fs = salt.utils.gitfs.GitFS(
  158. gitfs.__opts__,
  159. gitfs.__opts__['gitfs_remotes'],
  160. per_remote_overrides=gitfs.PER_REMOTE_OVERRIDES,
  161. per_remote_only=gitfs.PER_REMOTE_ONLY)
  162. # repo1 (branch: foo)
  163. # The mountpoint should take the default (from gitfs_mountpoint), while
  164. # ref and root should take the per-saltenv params.
  165. self.assertEqual(git_fs.remotes[0].mountpoint('foo'), '')
  166. self.assertEqual(git_fs.remotes[0].ref('foo'), 'foo_branch')
  167. self.assertEqual(git_fs.remotes[0].root('foo'), 'foo_root')
  168. # repo1 (branch: bar)
  169. # The 'bar' branch does not have a per-saltenv configuration set, so
  170. # each of the below values should fall back to global values.
  171. self.assertEqual(git_fs.remotes[0].mountpoint('bar'), '')
  172. self.assertEqual(git_fs.remotes[0].ref('bar'), 'bar')
  173. self.assertEqual(git_fs.remotes[0].root('bar'), 'salt')
  174. # repo1 (branch: baz)
  175. # The 'baz' branch does not have a per-saltenv configuration set, but
  176. # it is defined in the gitfs_saltenv parameter, so the values
  177. # from that parameter should be returned.
  178. self.assertEqual(git_fs.remotes[0].mountpoint('baz'), 'baz_mountpoint')
  179. self.assertEqual(git_fs.remotes[0].ref('baz'), 'baz_branch')
  180. self.assertEqual(git_fs.remotes[0].root('baz'), 'baz_root')
  181. # repo2 (branch: foo)
  182. # The mountpoint should take the per-remote mountpoint value of
  183. # 'repo2', while ref and root should fall back to global values.
  184. self.assertEqual(git_fs.remotes[1].mountpoint('foo'), 'repo2')
  185. self.assertEqual(git_fs.remotes[1].ref('foo'), 'foo')
  186. self.assertEqual(git_fs.remotes[1].root('foo'), 'salt')
  187. # repo2 (branch: bar)
  188. # The 'bar' branch does not have a per-saltenv configuration set, so
  189. # the mountpoint should take the per-remote mountpoint value of
  190. # 'repo2', while ref and root should fall back to global values.
  191. self.assertEqual(git_fs.remotes[1].mountpoint('bar'), 'repo2')
  192. self.assertEqual(git_fs.remotes[1].ref('bar'), 'bar')
  193. self.assertEqual(git_fs.remotes[1].root('bar'), 'salt')
  194. # repo2 (branch: baz)
  195. # The 'baz' branch has the mountpoint configured as a per-saltenv
  196. # parameter. The other two should take the values defined in
  197. # gitfs_saltenv.
  198. self.assertEqual(git_fs.remotes[1].mountpoint('baz'), 'abc')
  199. self.assertEqual(git_fs.remotes[1].ref('baz'), 'baz_branch')
  200. self.assertEqual(git_fs.remotes[1].root('baz'), 'baz_root')
  201. LOAD = {'saltenv': 'base'}
  202. class GitFSTestFuncs(object):
  203. '''
  204. These are where the tests go, so that they can be run using both GitPython
  205. and pygit2.
  206. NOTE: The gitfs.update() has to happen AFTER the setUp is called. This is
  207. because running it inside the setUp will spawn a new singleton, which means
  208. that tests which need to mock the __opts__ will be too late; the setUp will
  209. have created a new singleton that will bypass our mocking. To ensure that
  210. our tests are reliable and correct, we want to make sure that each test
  211. uses a new gitfs object, allowing different manipulations of the opts to be
  212. tested.
  213. Therefore, keep the following in mind:
  214. 1. Each test needs to call gitfs.update() *after* any patching, and
  215. *before* calling the function being tested.
  216. 2. Do *NOT* move the gitfs.update() into the setUp.
  217. '''
  218. def test_file_list(self):
  219. gitfs.update()
  220. ret = gitfs.file_list(LOAD)
  221. self.assertIn('testfile', ret)
  222. self.assertIn(UNICODE_FILENAME, ret)
  223. # This function does not use os.sep, the Salt fileserver uses the
  224. # forward slash, hence it being explicitly used to join here.
  225. self.assertIn('/'.join((UNICODE_DIRNAME, 'foo.txt')), ret)
  226. def test_dir_list(self):
  227. gitfs.update()
  228. ret = gitfs.dir_list(LOAD)
  229. self.assertIn('grail', ret)
  230. self.assertIn(UNICODE_DIRNAME, ret)
  231. def test_envs(self):
  232. gitfs.update()
  233. ret = gitfs.envs(ignore_cache=True)
  234. self.assertIn('base', ret)
  235. self.assertIn(UNICODE_ENVNAME, ret)
  236. self.assertIn(TAG_NAME, ret)
  237. def test_ref_types_global(self):
  238. '''
  239. Test the global gitfs_ref_types config option
  240. '''
  241. with patch.dict(gitfs.__opts__, {'gitfs_ref_types': ['branch']}):
  242. gitfs.update()
  243. ret = gitfs.envs(ignore_cache=True)
  244. # Since we are restricting to branches only, the tag should not
  245. # appear in the envs list.
  246. self.assertIn('base', ret)
  247. self.assertIn(UNICODE_ENVNAME, ret)
  248. self.assertNotIn(TAG_NAME, ret)
  249. def test_ref_types_per_remote(self):
  250. '''
  251. Test the per_remote ref_types config option, using a different
  252. ref_types setting than the global test.
  253. '''
  254. remotes = [{'file://' + self.tmp_repo_dir: [{'ref_types': ['tag']}]}]
  255. with patch.dict(gitfs.__opts__, {'gitfs_remotes': remotes}):
  256. gitfs.update()
  257. ret = gitfs.envs(ignore_cache=True)
  258. # Since we are restricting to tags only, the tag should appear in
  259. # the envs list, but the branches should not.
  260. self.assertNotIn('base', ret)
  261. self.assertNotIn(UNICODE_ENVNAME, ret)
  262. self.assertIn(TAG_NAME, ret)
  263. def test_disable_saltenv_mapping_global_with_mapping_defined_globally(self):
  264. '''
  265. Test the global gitfs_disable_saltenv_mapping config option, combined
  266. with the per-saltenv mapping being defined in the global gitfs_saltenv
  267. option.
  268. '''
  269. opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
  270. gitfs_disable_saltenv_mapping: True
  271. gitfs_saltenv:
  272. - foo:
  273. - ref: somebranch
  274. '''))
  275. with patch.dict(gitfs.__opts__, opts):
  276. gitfs.update()
  277. ret = gitfs.envs(ignore_cache=True)
  278. # Since we are restricting to tags only, the tag should appear in
  279. # the envs list, but the branches should not.
  280. self.assertEqual(ret, ['base', 'foo'])
  281. def test_disable_saltenv_mapping_global_with_mapping_defined_per_remote(self):
  282. '''
  283. Test the global gitfs_disable_saltenv_mapping config option, combined
  284. with the per-saltenv mapping being defined in the remote itself via the
  285. "saltenv" per-remote option.
  286. '''
  287. opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
  288. gitfs_disable_saltenv_mapping: True
  289. gitfs_remotes:
  290. - {0}:
  291. - saltenv:
  292. - bar:
  293. - ref: somebranch
  294. '''.format(self.tmp_repo_dir)))
  295. with patch.dict(gitfs.__opts__, opts):
  296. gitfs.update()
  297. ret = gitfs.envs(ignore_cache=True)
  298. # Since we are restricting to tags only, the tag should appear in
  299. # the envs list, but the branches should not.
  300. self.assertEqual(ret, ['bar', 'base'])
  301. def test_disable_saltenv_mapping_per_remote_with_mapping_defined_globally(self):
  302. '''
  303. Test the per-remote disable_saltenv_mapping config option, combined
  304. with the per-saltenv mapping being defined in the global gitfs_saltenv
  305. option.
  306. '''
  307. opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
  308. gitfs_remotes:
  309. - {0}:
  310. - disable_saltenv_mapping: True
  311. gitfs_saltenv:
  312. - hello:
  313. - ref: somebranch
  314. '''.format(self.tmp_repo_dir)))
  315. with patch.dict(gitfs.__opts__, opts):
  316. gitfs.update()
  317. ret = gitfs.envs(ignore_cache=True)
  318. # Since we are restricting to tags only, the tag should appear in
  319. # the envs list, but the branches should not.
  320. self.assertEqual(ret, ['base', 'hello'])
  321. def test_disable_saltenv_mapping_per_remote_with_mapping_defined_per_remote(self):
  322. '''
  323. Test the per-remote disable_saltenv_mapping config option, combined
  324. with the per-saltenv mapping being defined in the remote itself via the
  325. "saltenv" per-remote option.
  326. '''
  327. opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
  328. gitfs_remotes:
  329. - {0}:
  330. - disable_saltenv_mapping: True
  331. - saltenv:
  332. - world:
  333. - ref: somebranch
  334. '''.format(self.tmp_repo_dir)))
  335. with patch.dict(gitfs.__opts__, opts):
  336. gitfs.update()
  337. ret = gitfs.envs(ignore_cache=True)
  338. # Since we are restricting to tags only, the tag should appear in
  339. # the envs list, but the branches should not.
  340. self.assertEqual(ret, ['base', 'world'])
  341. class GitFSTestBase(object):
  342. @classmethod
  343. def setUpClass(cls):
  344. cls.tmp_repo_dir = os.path.join(RUNTIME_VARS.TMP, 'gitfs_root')
  345. if salt.utils.platform.is_windows():
  346. cls.tmp_repo_dir = cls.tmp_repo_dir.replace('\\', '/')
  347. cls.tmp_cachedir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  348. cls.tmp_sock_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  349. try:
  350. shutil.rmtree(cls.tmp_repo_dir)
  351. except OSError as exc:
  352. if exc.errno == errno.EACCES:
  353. log.error("Access error removing file %s", cls.tmp_repo_dir)
  354. elif exc.errno != errno.ENOENT:
  355. raise
  356. shutil.copytree(
  357. salt.ext.six.text_type(RUNTIME_VARS.BASE_FILES),
  358. salt.ext.six.text_type(cls.tmp_repo_dir + '/')
  359. )
  360. repo = git.Repo.init(cls.tmp_repo_dir)
  361. try:
  362. if salt.utils.platform.is_windows():
  363. username = salt.utils.win_functions.get_current_user()
  364. else:
  365. username = pwd.getpwuid(os.geteuid()).pw_name
  366. except AttributeError:
  367. log.error(
  368. 'Unable to get effective username, falling back to \'root\'.'
  369. )
  370. username = str('root')
  371. with patched_environ(USERNAME=username):
  372. repo.index.add([x for x in os.listdir(cls.tmp_repo_dir)
  373. if x != '.git'])
  374. repo.index.commit('Test')
  375. # Add another branch with unicode characters in the name
  376. repo.create_head(UNICODE_ENVNAME, 'HEAD')
  377. # Add a tag
  378. repo.create_tag(TAG_NAME, 'HEAD')
  379. # Older GitPython versions do not have a close method.
  380. if hasattr(repo, 'close'):
  381. repo.close()
  382. @classmethod
  383. def tearDownClass(cls):
  384. '''
  385. Remove the temporary git repository and gitfs cache directory to ensure
  386. a clean environment for the other test class(es).
  387. '''
  388. for path in (cls.tmp_cachedir, cls.tmp_sock_dir, cls.tmp_repo_dir):
  389. try:
  390. salt.utils.files.rm_rf(path)
  391. except OSError as exc:
  392. if exc.errno == errno.EACCES:
  393. log.error("Access error removeing file %s", path)
  394. elif exc.errno != errno.EEXIST:
  395. raise
  396. def setUp(self):
  397. '''
  398. We don't want to check in another .git dir into GH because that just
  399. gets messy. Instead, we'll create a temporary repo on the fly for the
  400. tests to examine.
  401. Also ensure we A) don't re-use the singleton, and B) that the cachedirs
  402. are cleared. This keeps these performance enhancements from affecting
  403. the results of subsequent tests.
  404. '''
  405. if not gitfs.__virtual__():
  406. self.skipTest("GitFS could not be loaded. Skipping GitFS tests!")
  407. _clear_instance_map()
  408. for subdir in ('gitfs', 'file_lists'):
  409. try:
  410. salt.utils.files.rm_rf(os.path.join(self.tmp_cachedir, subdir))
  411. except OSError as exc:
  412. if exc.errno == errno.EACCES:
  413. log.warning("Access error removeing file %s", os.path.join(self.tmp_cachedir, subdir))
  414. continue
  415. if exc.errno != errno.ENOENT:
  416. raise
  417. if salt.ext.six.PY3 and salt.utils.platform.is_windows():
  418. self.setUpClass()
  419. self.setup_loader_modules()
  420. @skipIf(not HAS_GITPYTHON, 'GitPython >= {0} required'.format(GITPYTHON_MINVER))
  421. class GitPythonTest(GitFSTestBase, GitFSTestFuncs, TestCase, LoaderModuleMockMixin):
  422. def setup_loader_modules(self):
  423. opts = {
  424. 'sock_dir': self.tmp_sock_dir,
  425. 'gitfs_remotes': ['file://' + self.tmp_repo_dir],
  426. 'gitfs_root': '',
  427. 'fileserver_backend': ['gitfs'],
  428. 'gitfs_base': 'master',
  429. 'fileserver_events': True,
  430. 'transport': 'zeromq',
  431. 'gitfs_mountpoint': '',
  432. 'gitfs_saltenv': [],
  433. 'gitfs_env_whitelist': [],
  434. 'gitfs_env_blacklist': [],
  435. 'gitfs_saltenv_whitelist': [],
  436. 'gitfs_saltenv_blacklist': [],
  437. 'gitfs_user': '',
  438. 'gitfs_password': '',
  439. 'gitfs_insecure_auth': False,
  440. 'gitfs_privkey': '',
  441. 'gitfs_pubkey': '',
  442. 'gitfs_passphrase': '',
  443. 'gitfs_refspecs': [
  444. '+refs/heads/*:refs/remotes/origin/*',
  445. '+refs/tags/*:refs/tags/*'
  446. ],
  447. 'gitfs_ssl_verify': True,
  448. 'gitfs_disable_saltenv_mapping': False,
  449. 'gitfs_ref_types': ['branch', 'tag', 'sha'],
  450. 'gitfs_update_interval': 60,
  451. '__role': 'master',
  452. }
  453. opts['cachedir'] = self.tmp_cachedir
  454. opts['sock_dir'] = self.tmp_sock_dir
  455. opts['gitfs_provider'] = 'gitpython'
  456. return {
  457. gitfs: {
  458. '__opts__': opts,
  459. }
  460. }
  461. @skipIf(not HAS_GITPYTHON, 'GitPython >= {0} required for temp repo setup'.format(GITPYTHON_MINVER))
  462. @skipIf(not HAS_PYGIT2, 'pygit2 >= {0} and libgit2 >= {1} required'.format(PYGIT2_MINVER, LIBGIT2_MINVER))
  463. @skipIf(salt.utils.platform.is_windows(), 'Skip Pygit2 on windows, due to pygit2 access error on windows')
  464. class Pygit2Test(GitFSTestBase, GitFSTestFuncs, TestCase, LoaderModuleMockMixin):
  465. def setup_loader_modules(self):
  466. opts = {
  467. 'sock_dir': self.tmp_sock_dir,
  468. 'gitfs_remotes': ['file://' + self.tmp_repo_dir],
  469. 'gitfs_root': '',
  470. 'fileserver_backend': ['gitfs'],
  471. 'gitfs_base': 'master',
  472. 'fileserver_events': True,
  473. 'transport': 'zeromq',
  474. 'gitfs_mountpoint': '',
  475. 'gitfs_saltenv': [],
  476. 'gitfs_env_whitelist': [],
  477. 'gitfs_env_blacklist': [],
  478. 'gitfs_saltenv_whitelist': [],
  479. 'gitfs_saltenv_blacklist': [],
  480. 'gitfs_user': '',
  481. 'gitfs_password': '',
  482. 'gitfs_insecure_auth': False,
  483. 'gitfs_privkey': '',
  484. 'gitfs_pubkey': '',
  485. 'gitfs_passphrase': '',
  486. 'gitfs_refspecs': [
  487. '+refs/heads/*:refs/remotes/origin/*',
  488. '+refs/tags/*:refs/tags/*'
  489. ],
  490. 'gitfs_ssl_verify': True,
  491. 'gitfs_disable_saltenv_mapping': False,
  492. 'gitfs_ref_types': ['branch', 'tag', 'sha'],
  493. 'gitfs_update_interval': 60,
  494. '__role': 'master',
  495. }
  496. opts['cachedir'] = self.tmp_cachedir
  497. opts['sock_dir'] = self.tmp_sock_dir
  498. opts['gitfs_provider'] = 'pygit2'
  499. return {
  500. gitfs: {
  501. '__opts__': opts,
  502. }
  503. }