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!
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

159 行
5.7KB

  1. import subprocess
  2. from .zfs import *
  3. import random
  4. import shutil
  5. import json
  6. from tabulate import tabulate
  7. import os
  8. import jailconf
  9. import shlex
  10. def jail_run_v2(path, command, env, mounts):
  11. name = os.path.split(path)[-1]
  12. if os.path.exists('/etc/jail.conf'):
  13. conf = jailconf.load('/etc/jail.conf')
  14. else:
  15. conf = jailconf.JailConf()
  16. conf[name] = blk = jailconf.JailBlock()
  17. blk['path'] = path
  18. env = [ 'export ' + k + '=' + shlex.quote(v) \
  19. for (k, v) in env.items() ]
  20. command = ' && '.join(env + [ command ])
  21. # blk['exec.start'] = command
  22. prestart = [ 'cp /etc/resolv.conf ' +
  23. shlex.quote(os.path.join(path, 'etc/resolv.conf')) ]
  24. poststop = []
  25. if mounts:
  26. for (from_, on) in mounts:
  27. if not from_.startswith('/'):
  28. from_, _ = zfs_find(from_, focker_type='volume')
  29. from_ = zfs_mountpoint(from_)
  30. prestart.append('mount -t nullfs ' + shlex.quote(from_) +
  31. ' ' + shlex.quote(os.path.join(path, on.strip('/'))))
  32. poststop += [ 'umount -f ' +
  33. os.path.join(path, on.strip('/')) \
  34. for (_, on) in reversed(mounts) ]
  35. if prestart:
  36. blk['exec.prestart'] = shlex.quote(' && '.join(prestart))
  37. if poststop:
  38. blk['exec.poststop'] = shlex.quote(' && '.join(poststop))
  39. blk['persist'] = True
  40. blk['interface'] = 'lo1'
  41. blk['ip4.addr'] = '127.0.1.0'
  42. blk['mount.devfs'] = True
  43. blk['exec.clean'] = True
  44. conf.write('/etc/jail.conf')
  45. # command = '/bin/sh -c ' + shlex.quote(command)
  46. subprocess.check_output([ 'jail', '-c', name ])
  47. subprocess.run([ 'jexec', name, '/bin/sh', '-c', command ])
  48. subprocess.check_output([ 'jail', '-r', name ])
  49. def get_jid(path):
  50. data = json.loads(subprocess.check_output(['jls', '--libxo=json']))
  51. lst = data['jail-information']['jail']
  52. lst = list(filter(lambda a: a['path'] == path, lst))
  53. if len(lst) == 0:
  54. raise ValueError('JID not found for path: ' + path)
  55. if len(lst) > 1:
  56. raise ValueError('Ambiguous JID for path: ' + path)
  57. return str(lst[0]['jid'])
  58. def do_mounts(path, mounts):
  59. print('mounts:', mounts)
  60. for (source, target) in mounts:
  61. if source.startswith('/'):
  62. name = source
  63. else:
  64. name, _ = zfs_find(source, focker_type='volume')
  65. name = zfs_mountpoint(name)
  66. while target.startswith('/'):
  67. target = target[1:]
  68. subprocess.check_output(['mount', '-t', 'nullfs', name, os.path.join(path, target)])
  69. def undo_mounts(path, mounts):
  70. for (_, target) in reversed(mounts):
  71. while target.startswith('/'):
  72. target = target[1:]
  73. subprocess.check_output(['umount', '-f', os.path.join(path, target)])
  74. def jail_run(path, command, mounts=[]):
  75. command = ['jail', '-c', 'host.hostname=' + os.path.split(path)[1], 'persist=1', 'mount.devfs=1', 'interface=lo1', 'ip4.addr=127.0.1.0', 'path=' + path, 'command', '/bin/sh', '-c', command]
  76. print('Running:', ' '.join(command))
  77. try:
  78. do_mounts(path, mounts)
  79. shutil.copyfile('/etc/resolv.conf', os.path.join(path, 'etc/resolv.conf'))
  80. res = subprocess.run(command)
  81. finally:
  82. try:
  83. subprocess.run(['jail', '-r', get_jid(path)])
  84. except ValueError:
  85. pass
  86. subprocess.run(['umount', '-f', os.path.join(path, 'dev')])
  87. undo_mounts(path, mounts)
  88. if res.returncode != 0:
  89. # subprocess.run(['umount', os.path.join(path, 'dev')])
  90. raise RuntimeError('Command failed')
  91. def jail_remove(path):
  92. print('Removing jail:', path)
  93. # subprocess.
  94. def command_jail_run(args):
  95. base, _ = zfs_snapshot_by_tag_or_sha256(args.image)
  96. # root = '/'.join(base.split('/')[:-1])
  97. for _ in range(10**6):
  98. sha256 = bytes([ random.randint(0, 255) for _ in range(32) ]).hex()
  99. name = sha256[:7]
  100. name = base.split('/')[0] + '/focker/jails/' + name
  101. if not zfs_exists(name):
  102. break
  103. zfs_run(['zfs', 'clone', '-o', 'focker:sha256=' + sha256, base, name])
  104. try:
  105. mounts = list(map(lambda a: a.split(':'), args.mounts))
  106. jail_run(zfs_mountpoint(name), args.command, mounts)
  107. # subprocess.check_output(['jail', '-c', 'interface=lo1', 'ip4.addr=127.0.1.0', 'path=' + zfs_mountpoint(name), 'command', command])
  108. finally:
  109. # subprocess.run(['umount', zfs_mountpoint(name) + '/dev'])
  110. zfs_run(['zfs', 'destroy', '-f', name])
  111. # raise
  112. def command_jail_list(args):
  113. lst = zfs_list(fields=['focker:sha256,focker:tags,mountpoint'], focker_type='jail')
  114. jails = subprocess.check_output(['jls', '--libxo=json'])
  115. jails = json.loads(jails)['jail-information']['jail']
  116. jails = { j['path']: j for j in jails }
  117. lst = list(map(lambda a: [ a[1],
  118. a[0] if args.full_sha256 else a[0][:7],
  119. a[2],
  120. jails[a[2]]['jid'] if a[2] in jails else '-' ], lst))
  121. print(tabulate(lst, headers=['Tags', 'SHA256', 'mountpoint', 'JID']))
  122. def command_jail_tag(args):
  123. name, _ = zfs_find(args.reference, focker_type='jail')
  124. zfs_untag(args.tags, focker_type='jail')
  125. zfs_tag(name, args.tags)
  126. def command_jail_untag(args):
  127. zfs_untag(args.tags, focker_type='jail')
  128. def command_jail_prune(args):
  129. jails = subprocess.check_output(['jls', '--libxo=json'])
  130. jails = json.loads(jails)['jail-information']['jail']
  131. used = set()
  132. for j in jails:
  133. used.add(j['path'])
  134. lst = zfs_list(fields=['focker:sha256,focker:tags,mountpoint,name'], focker_type='jail')
  135. for j in lst:
  136. if j[1] == '-' and j[2] not in used:
  137. jail_remove(j[3])