IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
9.1KB

  1. from focker.compose import exec_hook, \
  2. exec_prebuild, \
  3. exec_postbuild, \
  4. build_volumes, \
  5. build_images, \
  6. setup_dependencies, \
  7. build_jails
  8. from tempfile import TemporaryDirectory
  9. import os
  10. import pytest
  11. import fcntl
  12. from focker.misc import focker_lock, \
  13. focker_unlock
  14. import inspect
  15. import ast
  16. import stat
  17. from focker.zfs import zfs_find, \
  18. zfs_mountpoint, \
  19. zfs_parse_output
  20. import subprocess
  21. import yaml
  22. import jailconf
  23. from focker.jail import backup_file
  24. def test_exec_hook_01():
  25. spec = [
  26. 'touch test-exec-hook-01',
  27. 'touch test-exec-hook-02'
  28. ]
  29. with TemporaryDirectory() as d:
  30. exec_hook(spec, d, 'test-exec-hook')
  31. assert os.path.exists(os.path.join(d, 'test-exec-hook-01'))
  32. assert os.path.exists(os.path.join(d, 'test-exec-hook-02'))
  33. assert not os.path.exists(d)
  34. def test_exec_hook_02():
  35. spec = 'touch test-exec-hook-01 && touch test-exec-hook-02'
  36. with TemporaryDirectory() as d:
  37. exec_hook(spec, d, 'test-exec-hook')
  38. assert os.path.exists(os.path.join(d, 'test-exec-hook-01'))
  39. assert os.path.exists(os.path.join(d, 'test-exec-hook-02'))
  40. assert not os.path.exists(d)
  41. def test_exec_hook_03a():
  42. spec = 1
  43. with TemporaryDirectory() as d:
  44. with pytest.raises(ValueError):
  45. exec_hook(spec, d, 'test-exec-hook')
  46. def test_exec_hook_03b():
  47. spec = [1]
  48. with TemporaryDirectory() as d:
  49. with pytest.raises(TypeError):
  50. exec_hook(spec, d, 'test-exec-hook')
  51. def test_exec_hook_04():
  52. spec = 'ls'
  53. with pytest.raises(FileNotFoundError):
  54. exec_hook(spec, '/non-existent-directory/wcj20fy103', 'test-exec-hook')
  55. def test_exec_hook_05():
  56. spec = 'ls'
  57. oldwd = os.getcwd()
  58. with TemporaryDirectory() as d:
  59. exec_hook(spec, d, 'test-exec-hook')
  60. assert os.getcwd() == oldwd
  61. def test_exec_hook_06():
  62. spec = '/non-existent-command/hf249h'
  63. with TemporaryDirectory() as d:
  64. with pytest.raises(RuntimeError):
  65. exec_hook(spec, d, 'test-exec-hook')
  66. def test_exec_hook_07():
  67. os.chdir('/')
  68. spec = 'flock --nonblock /var/lock/focker.lock -c ls'
  69. focker_lock()
  70. assert fcntl.flock(focker_lock.fd, fcntl.LOCK_EX | fcntl.LOCK_NB) != 0
  71. with TemporaryDirectory() as d:
  72. exec_hook(spec, d, 'test-exec-hook')
  73. assert fcntl.flock(focker_lock.fd, fcntl.LOCK_EX | fcntl.LOCK_NB) != 0
  74. focker_unlock()
  75. def _test_simple_forward(fun, fwd_fun_name='exec_hook'):
  76. src = inspect.getsource(fun)
  77. mod = ast.parse(src)
  78. assert isinstance(mod.body[0], ast.FunctionDef)
  79. assert isinstance(mod.body[0].body[0], ast.Return)
  80. assert isinstance(mod.body[0].body[0].value, ast.Call)
  81. assert mod.body[0].body[0].value.func.id == fwd_fun_name
  82. def test_exec_prebuild():
  83. _test_simple_forward(exec_prebuild)
  84. def test_exec_postbuild():
  85. _test_simple_forward(exec_postbuild)
  86. def test_build_volumes():
  87. subprocess.check_output(['focker', 'volume', 'remove', '--force', 'test-build-volumes'])
  88. err = False
  89. try:
  90. name, _ = zfs_find('test-build-volumes', focker_type='volume')
  91. except:
  92. err = True
  93. assert err
  94. spec = {
  95. 'test-build-volumes': {
  96. 'chown': '65534:65534',
  97. 'chmod': 0o123,
  98. 'zfs': {
  99. 'quota': '1G',
  100. 'readonly': 'on'
  101. }
  102. }
  103. }
  104. build_volumes(spec)
  105. name, _ = zfs_find('test-build-volumes', focker_type='volume')
  106. st = os.stat(zfs_mountpoint(name))
  107. assert st.st_uid == 65534
  108. assert st.st_gid == 65534
  109. assert ('%o' % st.st_mode)[-3:] == '123'
  110. zst = zfs_parse_output(['zfs', 'get', '-H', 'quota,readonly', name])
  111. assert zst[0][2] == '1G'
  112. assert zst[1][2] == 'on'
  113. subprocess.check_output(['zfs', 'destroy', '-r', '-f', name])
  114. def test_build_images():
  115. subprocess.check_output(['focker', 'image', 'remove', '--force', 'test-focker-bootstrap'])
  116. subprocess.check_output(['focker', 'bootstrap', '--dry-run', '--tags', 'test-focker-bootstrap'])
  117. subprocess.check_output(['focker', 'image', 'remove', '--force', 'test-build-images'])
  118. with TemporaryDirectory() as d:
  119. with open(os.path.join(d, 'Fockerfile'), 'w') as f:
  120. yaml.dump({
  121. 'base': 'test-focker-bootstrap',
  122. 'steps': [
  123. { 'copy': [
  124. [ '/bin/sh', '/bin/sh', { 'chmod': 0o777 } ],
  125. [ '/lib/libedit.so.7', '/lib/libedit.so.7' ],
  126. [ '/lib/libncursesw.so.8', '/lib/libncursesw.so.8' ],
  127. [ '/lib/libc.so.7', '/lib/libc.so.7' ],
  128. [ '/usr/bin/touch', '/usr/bin/touch', { 'chmod': 0o777 } ],
  129. [ '/libexec/ld-elf.so.1', '/libexec/ld-elf.so.1', { 'chmod': 0o555 } ]
  130. ] },
  131. { 'run': 'touch /test-build-images' }
  132. ]
  133. }, f)
  134. args = lambda: 0
  135. args.squeeze = False
  136. build_images({
  137. 'test-build-images': '.'
  138. }, d, args)
  139. focker_unlock()
  140. name, _ = zfs_find('test-build-images', focker_type='image')
  141. assert os.path.exists(os.path.join(zfs_mountpoint(name), 'test-build-images'))
  142. subprocess.check_output(['focker', 'image', 'remove', '--force', 'test-build-images'])
  143. subprocess.check_output(['focker', 'image', 'prune'])
  144. subprocess.check_output(['focker', 'image', 'remove', '--force', 'test-focker-bootstrap'])
  145. def test_setup_dependencies():
  146. backup_file('/etc/jail.conf')
  147. conf = jailconf.load('/etc/jail.conf')
  148. jail = jailconf.JailBlock()
  149. conf['test-setup-dependencies-A'] = jail
  150. conf['test-setup-dependencies-B'] = jail
  151. conf['test-setup-dependencies-C'] = jail
  152. conf.write('/etc/jail.conf')
  153. setup_dependencies({
  154. 'test-setup-dependencies-A': {},
  155. 'test-setup-dependencies-B': { 'depend': 'test-setup-dependencies-A' },
  156. 'test-setup-dependencies-C': { 'depend': [
  157. 'test-setup-dependencies-A',
  158. 'test-setup-dependencies-B'
  159. ] }
  160. }, {
  161. 'test-setup-dependencies-A': 'test-setup-dependencies-A',
  162. 'test-setup-dependencies-B': 'test-setup-dependencies-B',
  163. 'test-setup-dependencies-C': 'test-setup-dependencies-C'
  164. })
  165. conf = jailconf.load('/etc/jail.conf')
  166. assert 'depend' not in conf['test-setup-dependencies-A']
  167. assert conf['test-setup-dependencies-B']['depend'] == 'test-setup-dependencies-A'
  168. assert conf['test-setup-dependencies-C']['depend'] == [
  169. 'test-setup-dependencies-A',
  170. 'test-setup-dependencies-B'
  171. ]
  172. del conf['test-setup-dependencies-A']
  173. del conf['test-setup-dependencies-B']
  174. del conf['test-setup-dependencies-C']
  175. conf.write('/etc/jail.conf')
  176. def test_build_jails():
  177. backup_file('/etc/jail.conf')
  178. conf = jailconf.load('/etc/jail.conf')
  179. for k in list(conf.keys()):
  180. if conf[k]['host.hostname'].strip('\'"') in ['test-build-jails-A', 'test-build-jails-B']:
  181. del conf[k]
  182. conf.write('/etc/jail.conf')
  183. subprocess.check_output(['focker', 'jail', 'remove', '--force', 'test-build-jails-A'])
  184. subprocess.check_output(['focker', 'jail', 'remove', '--force', 'test-build-jails-B'])
  185. subprocess.check_output(['focker', 'image', 'remove', '--force', '-R', 'test-focker-bootstrap'])
  186. subprocess.check_output(['focker', 'bootstrap', '--dry-run', '-t', 'test-focker-bootstrap'])
  187. spec = {
  188. 'test-build-jails-A': {
  189. 'image': 'test-focker-bootstrap',
  190. 'exec.start': 'test-exec-start',
  191. 'exec.stop': 'test-exec-stop',
  192. 'ip4.addr': 'test-ip4-addr',
  193. 'interface': 'test-interface',
  194. 'host.hostname': 'test-build-jails-A'
  195. }
  196. }
  197. spec['test-build-jails-B'] = spec['test-build-jails-A'].copy()
  198. spec['test-build-jails-B']['host.hostname'] = 'test-build-jails-B'
  199. build_jails(spec)
  200. conf = jailconf.load('/etc/jail.conf')
  201. print(conf.values())
  202. blocks = list(filter(lambda a: a['host.hostname'].strip('"\'') in [ 'test-build-jails-A',
  203. 'test-build-jails-B' ], conf.values()))
  204. print(blocks)
  205. assert len(blocks) == 2
  206. assert blocks[0]['host.hostname'] != blocks[1]['host.hostname']
  207. for b in blocks:
  208. name, _ = zfs_find(b['host.hostname'].strip('\'"'), focker_type='jail')
  209. mountpoint = zfs_mountpoint(name)
  210. assert b['path'] == mountpoint
  211. assert b['exec.start'].strip('\'"') == 'test-exec-start'
  212. assert b['exec.stop'].strip('\'"') == 'test-exec-stop'
  213. assert b['ip4.addr'].strip('\'"') == 'test-ip4-addr'
  214. assert b['interface'].strip('\'"') == 'test-interface'
  215. subprocess.check_output(['focker', 'jail', 'remove', '--force', 'test-build-jails-A'])
  216. subprocess.check_output(['focker', 'jail', 'remove', '--force', 'test-build-jails-B'])
  217. subprocess.check_output(['focker', 'image', 'remove', '--force', 'test-focker-bootstrap'])
  218. conf.write('/etc/jail.conf')