From 655f2a49814da2d7e414d23129eb6c9fb4b0f7b3 Mon Sep 17 00:00:00 2001 From: Stanislaw Adaszewski Date: Thu, 23 Apr 2020 18:57:55 +0200 Subject: [PATCH] Working on image build --- .gitignore | 1 + focker.py | 69 ++++++++++++++------------------------------ build.py => image.py | 17 +++++++++-- run.py | 0 zfs.py | 39 +++++++++++++++++++++---- 5 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 .gitignore rename build.py => image.py (50%) create mode 100644 run.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/focker.py b/focker.py index 88f10e5..c6649f0 100644 --- a/focker.py +++ b/focker.py @@ -1,58 +1,31 @@ from argparse import ArgumentParser import yaml import os -from weir import zfs, process -from .build import build +# from weir import zfs, process +from .image import command_image_build +import sys +from .zfs import zfs_init -def clone(self, name, props={}, force=False): - url = zfs._urlsplit(self.name) - url_1 = zfs._urlsplit(name) - if url.netloc != url_1.netloc: - raise ValueError('Clone has to happen on the same host') - cmd = ['zfs', 'clone'] - for prop, value in props.items(): - cmd.append('-o') - cmd.append(prop + '=' + str(value)) - cmd.append(url.path) - cmd.append(url_1.path) - process.check_call(cmd, netloc=url.netloc) - -zfs.ZFSSnapshot.clone = clone - - -def command_build(args): - fname = os.path.join(args.focker_dir, 'Fockerfile.yml') - print('fname:', fname) - if not os.path.exists(fname): - raise ValueError('No Fockerfile.yml could be found in the specified directory') - with open(fname, 'r') as f: - spec = yaml.safe_load(f) - print('spec:', spec) - build(spec) - +def create_parser(): + parser_top = ArgumentParser() + subparsers_top = parser_top.add_subparsers() -def run(args): - pass + subparsers = subparsers_top.add_parser('image').add_subparsers() + parser = subparsers.add_parser('build') + parser.set_defaults(func=command_image_build) + parser.add_argument('focker_dir', type=str) + return parser_top -def create_parser(): - parser = ArgumentParser() - subparsers = parser.add_subparsers() - parser_build = subparsers.add_parser('build') - parser_build.set_defaults(func=command_build) - parser_build.add_argument('focker_dir', type=str) - parser_run = subparsers.add_parser('run') - parser_run.set_defaults(func=run) - parser_rm = subparsers.add_parser('rm') - parser_rmi = subparsers.add_parser('rmi') - parser_ps = subparsers.add_parser('ps') - parser_images = subparsers.add_parser('images') - return parser +def main(): + zfs_init() + parser = create_parser() + args = parser.parse_args() + if not hasattr(args, 'func'): + sys.exit('You must choose a mode') + args.func(args) -parser = create_parser() -args = parser.parse_args() -if not hasattr(args, 'func'): - raise ValueError('You must choose the mode') -args.func(args) +if __name__ == '__main__': + main() diff --git a/build.py b/image.py similarity index 50% rename from build.py rename to image.py index 6812e5d..66957fc 100644 --- a/build.py +++ b/image.py @@ -1,4 +1,6 @@ from .zfs import * +import os +import yaml def process_step(step, name): @@ -17,8 +19,19 @@ def process_steps(steps, name): def build(spec): if 'base' not in spec: raise ValueError('Missing base specification') - base = spec.base - base = zfs_snapshot_by_tag_or_name(base) + base = spec['base'] + base = zfs_snapshot_by_tag_or_sha256(base) root = '/'.join(base.split('/')[:-1]) print('base:', base, 'root:', root) + + +def command_image_build(args): + fname = os.path.join(args.focker_dir, 'Fockerfile') + print('fname:', fname) + if not os.path.exists(fname): + raise ValueError('No Fockerfile could be found in the specified directory') + with open(fname, 'r') as f: + spec = yaml.safe_load(f) + print('spec:', spec) + build(spec) diff --git a/run.py b/run.py new file mode 100644 index 0000000..e69de29 diff --git a/zfs.py b/zfs.py index f35576d..a7fe91d 100644 --- a/zfs.py +++ b/zfs.py @@ -1,10 +1,12 @@ import subprocess import csv import io +import os def zfs_run(command): - out = subprocess.check_output(command) + # print('Running:', command) + out = subprocess.check_output(command, stderr=subprocess.STDOUT) return out @@ -20,15 +22,42 @@ def zfs_get_type(name): return lst[0][1] -def zfs_snapshot_by_tag_or_name(s): - lst = zfs_parse_output(['zfs', 'list', '-o', 'name,focker:tags,type', '-H']) - lst = list(filter(lambda a: (a[0] == s or s in a[1].split(' ') and a[2] == 'snapshot'))) +def zfs_snapshot_by_tag_or_sha256(s): + lst = zfs_parse_output(['zfs', 'list', '-o', 'focker:sha256,focker:tags,type,name', '-H', '-t', 'snapshot']) + lst = list(filter(lambda a: (a[0] == s or s in a[1].split(' ')) and a[2] == 'snapshot', lst)) if len(lst) == 0: raise ValueError('Reference not found: ' + s) if len(lst) > 1: raise ValueError('Ambiguous reference: ' + s) - return lst[0][0] + return lst[0][3] def zfs_clone(name, target_name): zfs_run(['zfs', 'clone', name, target_name]) + + +def zfs_exists(name): + try: + zfs_run(['zfs', 'list', name]) + except subprocess.CalledProcessError as e: + return False + return True + + +def zfs_init(): + poolname = zfs_parse_output(['zfs', 'list', '-H', '/']) + if len(poolname) == 0: + raise ValueError('Not a ZFS root') + poolname = poolname[0][0].split('/')[0] + print('poolname:', poolname) + for path in ['/focker', '/focker/images', '/focker/volumes', '/focker/jails']: + if not os.path.exists(path): + os.mkdir(path) + if not zfs_exists(poolname + '/focker'): + zfs_run(['zfs', 'create', '-o', 'canmount=off', '-o', 'mountpoint=/focker', poolname + '/focker']) + if not zfs_exists(poolname + '/focker/images'): + zfs_run(['zfs', 'create', '-o', 'canmount=off', poolname + '/focker/images']) + if not zfs_exists(poolname + '/focker/volumes'): + zfs_run(['zfs', 'create', '-o', 'canmount=off', poolname + '/focker/volumes']) + if not zfs_exists(poolname + '/focker/volumes'): + zfs_run(['zfs', 'create', '-o', 'canmount=off', poolname + '/focker/jails'])