| @@ -9,12 +9,12 @@ jails: | |||||
| image: wordpress-5 | image: wordpress-5 | ||||
| mounts: | mounts: | ||||
| test-volume2: /mnt/volume2 | test-volume2: /mnt/volume2 | ||||
| test-volume: /mnt/volume1 | |||||
| test-volume2: /mnt/volume1 | |||||
| ip4.addr: 127.0.1.1 | ip4.addr: 127.0.1.1 | ||||
| volumes: | volumes: | ||||
| test-volume2: {} | test-volume2: {} | ||||
| test-volume: {} | |||||
| test-volume2: {} | |||||
| commands: | commands: | ||||
| backup: | backup: | ||||
| @@ -27,6 +27,9 @@ from .jail import command_jail_create, \ | |||||
| command_jail_tag, \ | command_jail_tag, \ | ||||
| command_jail_untag, \ | command_jail_untag, \ | ||||
| command_jail_prune | command_jail_prune | ||||
| from .compose import \ | |||||
| command_compose_build, \ | |||||
| command_compose_run | |||||
| class ListForwarderFunctor(object): | class ListForwarderFunctor(object): | ||||
| @@ -63,7 +66,7 @@ def create_parser(): | |||||
| # image | # image | ||||
| subparsers = ListForwarder([ subparsers_top.add_parser(cmd).add_subparsers(dest='L2_command') \ | subparsers = ListForwarder([ subparsers_top.add_parser(cmd).add_subparsers(dest='L2_command') \ | ||||
| for cmd in ['image', 'i'] ]) | |||||
| for cmd in ['image', 'img', 'im', 'i'] ]) | |||||
| subparsers.required = True | subparsers.required = True | ||||
| parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['build', 'b']]) | parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['build', 'b']]) | ||||
| parser.set_defaults(func=command_image_build) | parser.set_defaults(func=command_image_build) | ||||
| @@ -148,7 +151,7 @@ def create_parser(): | |||||
| # volume | # volume | ||||
| subparsers = ListForwarder([ subparsers_top.add_parser(cmd).add_subparsers(dest='L2_command') \ | subparsers = ListForwarder([ subparsers_top.add_parser(cmd).add_subparsers(dest='L2_command') \ | ||||
| for cmd in ['volume', 'v'] ]) | |||||
| for cmd in ['volume', 'vol', 'v'] ]) | |||||
| subparsers.required = True | subparsers.required = True | ||||
| parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['create', 'c']]) | parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['create', 'c']]) | ||||
| parser.set_defaults(func=command_volume_create) | parser.set_defaults(func=command_volume_create) | ||||
| @@ -170,6 +173,19 @@ def create_parser(): | |||||
| parser.set_defaults(func=command_volume_untag) | parser.set_defaults(func=command_volume_untag) | ||||
| parser.add_argument('tags', type=str, nargs='+') | parser.add_argument('tags', type=str, nargs='+') | ||||
| # compose | |||||
| subparsers = ListForwarder([ subparsers_top.add_parser(cmd).add_subparsers(dest='L2_command') \ | |||||
| for cmd in ['compose', 'comp', 'c'] ]) | |||||
| subparsers.required = True | |||||
| parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['build', 'b']]) | |||||
| parser.set_defaults(func=command_compose_build) | |||||
| parser.add_argument('filename', type=str) | |||||
| parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['run', 'r']]) | |||||
| parser.set_defaults(func=command_compose_run) | |||||
| parser.add_argument('filename', type=str) | |||||
| parser.add_argument('command', type=str) | |||||
| return parser_top | return parser_top | ||||
| @@ -1,4 +1,14 @@ | |||||
| import random | import random | ||||
| from .zfs import zfs_exists | |||||
| def random_sha256_hexdigest(): | def random_sha256_hexdigest(): | ||||
| return bytes([ random.randint(0, 255) for _ in range(32) ]).hex() | return bytes([ random.randint(0, 255) for _ in range(32) ]).hex() | ||||
| def find_prefix(head, tail): | |||||
| for pre in range(7, len(tail)): | |||||
| name = head + tail[:pre] | |||||
| if not zfs_exists(name): | |||||
| break | |||||
| return name | |||||
| @@ -4,7 +4,7 @@ import io | |||||
| import os | import os | ||||
| class AmbiguousReference(ValueError): | |||||
| class AmbiguousValueError(ValueError): | |||||
| def __init__(self, msg): | def __init__(self, msg): | ||||
| super().__init__(msg) | super().__init__(msg) | ||||
| @@ -34,24 +34,31 @@ def zfs_snapshot_by_tag_or_sha256(s, focker_type='image'): | |||||
| if len(lst) == 0: | if len(lst) == 0: | ||||
| raise ValueError('Reference not found: ' + s) | raise ValueError('Reference not found: ' + s) | ||||
| if len(lst) > 1: | if len(lst) > 1: | ||||
| raise AmbiguousReference('Ambiguous reference: ' + s) | |||||
| raise AmbiguousValueError('Ambiguous reference: ' + s) | |||||
| return (lst[0][3], lst[0][0]) | return (lst[0][3], lst[0][0]) | ||||
| def zfs_find(reference, focker_type='image', zfs_type='filesystem'): | def zfs_find(reference, focker_type='image', zfs_type='filesystem'): | ||||
| poolname = zfs_poolname() | poolname = zfs_poolname() | ||||
| lst = zfs_parse_output(['zfs', 'list', '-o', 'focker:sha256,focker:tags,type,name', '-H', '-t', zfs_type, '-r', poolname + '/focker/' + focker_type + 's']) | lst = zfs_parse_output(['zfs', 'list', '-o', 'focker:sha256,focker:tags,type,name', '-H', '-t', zfs_type, '-r', poolname + '/focker/' + focker_type + 's']) | ||||
| def match(sha256, tags, type, name): | |||||
| if sha256.startswith(reference) or \ | |||||
| any(map(lambda a: a.startswith(reference), tags.split(' '))) or \ | |||||
| name.split('/')[-1].startswith(reference): | |||||
| def match(sha256, tags, type, name, exact=False): | |||||
| if exact: | |||||
| predicate = lambda a: (a == reference) | |||||
| else: | |||||
| predicate = lambda a: a.startswith(reference) | |||||
| if predicate(sha256) or \ | |||||
| any(map(predicate, tags.split(' '))) or \ | |||||
| predicate(name.split('/')[-1]): | |||||
| return True | return True | ||||
| return False | return False | ||||
| lst = list(filter(lambda a: match(*a), lst)) | lst = list(filter(lambda a: match(*a), lst)) | ||||
| exact_lst = list(filter(lambda a: match(*a, exact=True), lst)) | |||||
| if len(lst) == 0: | if len(lst) == 0: | ||||
| raise ValueError('Reference not found: ' + reference) | raise ValueError('Reference not found: ' + reference) | ||||
| if len(lst) > 1: | if len(lst) > 1: | ||||
| raise AmbiguousReference('Ambiguous reference: ' + reference) | |||||
| if len(exact_lst) == 1: | |||||
| return (exact_lst[0][3], exact_lst[0][0]) | |||||
| raise AmbiguousValueError('Ambiguous reference: ' + reference) | |||||
| return (lst[0][3], lst[0][0]) | return (lst[0][3], lst[0][0]) | ||||
| @@ -124,7 +131,7 @@ def zfs_snapshot_by_sha256(sha256, focker_type='image'): | |||||
| if len(lst) == 0: | if len(lst) == 0: | ||||
| raise ValueError('Snapshot with given sha256 does not exist: ' + sha256) | raise ValueError('Snapshot with given sha256 does not exist: ' + sha256) | ||||
| if len(lst) > 1: | if len(lst) > 1: | ||||
| raise AmbiguousReference('Ambiguous snapshot sha256: ' + sha256) | |||||
| raise AmbiguousValueError('Ambiguous snapshot sha256: ' + sha256) | |||||
| return lst[0][1] | return lst[0][1] | ||||
| @@ -163,7 +170,7 @@ def zfs_name(path): | |||||
| if len(lst) == 0: | if len(lst) == 0: | ||||
| raise ValueError('Not a ZFS path') | raise ValueError('Not a ZFS path') | ||||
| if len(lst) > 1: | if len(lst) > 1: | ||||
| raise AmbiguousReference('Ambiguous ZFS path') | |||||
| raise AmbiguousValueError('Ambiguous ZFS path') | |||||
| return lst[0][0] | return lst[0][0] | ||||