diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-03-21 09:57:36 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-03-21 14:05:34 +0200 |
commit | 6f3a666cecc9972985ce31f151528dc5749c112f (patch) | |
tree | 4059e3786e119156d15db772f466f7b57f477233 | |
parent | aebe12f5b1edbbf221ea06dc0b41c58ad1f3c118 (diff) | |
download | vmdb2-6f3a666cecc9972985ce31f151528dc5749c112f.tar.gz |
Change: make step runners check the values for the step at init
28 files changed, 443 insertions, 215 deletions
diff --git a/vmdb/__init__.py b/vmdb/__init__.py index 0b9ddc1..5308c5a 100644 --- a/vmdb/__init__.py +++ b/vmdb/__init__.py @@ -25,6 +25,8 @@ from .step_list import ( NoMatchingRunner, NotString, StepError, + StepKeyMissing, + StepKeyWrongValueType, ) from .runcmd import ( runcmd, diff --git a/vmdb/app.py b/vmdb/app.py index cf6fc39..4668bc3 100644 --- a/vmdb/app.py +++ b/vmdb/app.py @@ -102,9 +102,10 @@ class Vmdb2(cliapp.Application): if hasattr(runner, name) ] + values = runner.get_values(step) for method in methods: logging.info('Calling %s', method) - method(step, self.settings, state) + method(values, self.settings, state) except KeyError as e: vmdb.error('Key error: %s' % str(e)) vmdb.error(repr(e)) diff --git a/vmdb/plugins/ansible_plugin.py b/vmdb/plugins/ansible_plugin.py index edce52f..a223735 100644 --- a/vmdb/plugins/ansible_plugin.py +++ b/vmdb/plugins/ansible_plugin.py @@ -33,12 +33,15 @@ class AnsiblePlugin(cliapp.Plugin): class AnsibleStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['ansible', 'playbook'] - - def run(self, step, settings, state): - tag = step['ansible'] - playbook = step['playbook'] + def get_key_spec(self): + return { + 'ansible': str, + 'playbook': str, + } + + def run(self, values, settings, state): + tag = values['ansible'] + playbook = values['playbook'] mount_point = state.tags.get_builder_mount_point(tag) rootfs_tarball = settings['rootfs-tarball'] @@ -59,7 +62,7 @@ class AnsibleStepRunner(vmdb.StepRunnerInterface): playbook], env=env) - def teardown(self, step, settings, state): + def teardown(self, values, settings, state): if hasattr(state, 'ansible_inventory'): vmdb.progress('Removing {}'.format(state.ansible_inventory)) os.remove(state.ansible_inventory) diff --git a/vmdb/plugins/apt_plugin.py b/vmdb/plugins/apt_plugin.py index 7356369..4ebaf38 100644 --- a/vmdb/plugins/apt_plugin.py +++ b/vmdb/plugins/apt_plugin.py @@ -32,18 +32,24 @@ class AptPlugin(cliapp.Plugin): class AptStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['apt', 'packages'] - - def run(self, step, settings, state): - operation = step['apt'] + def get_key_spec(self): + return { + 'apt': str, + 'packages': [], + 'tag': '', + 'fs-tag': '', + 'clean': True, + } + + def run(self, values, settings, state): + operation = values['apt'] if operation != 'install': raise Exception('"apt" must always have value "install"') - packages = step['packages'] - tag = step.get('tag') + packages = values['packages'] + tag = values.get('tag') or None if tag is None: - tag = step['fs-tag'] + tag = values['fs-tag'] mount_point = state.tags.get_builder_mount_point(tag) if not self.got_eatmydata(state): @@ -51,7 +57,7 @@ class AptStepRunner(vmdb.StepRunnerInterface): state.got_eatmydata = True self.install_packages(mount_point, ['eatmydata'], packages) - if step.get('clean', True): + if values['clean']: self.clean_cache(mount_point) def got_eatmydata(self, state): diff --git a/vmdb/plugins/cache_rootfs_plugin.py b/vmdb/plugins/cache_rootfs_plugin.py index c114945..eb4f75a 100644 --- a/vmdb/plugins/cache_rootfs_plugin.py +++ b/vmdb/plugins/cache_rootfs_plugin.py @@ -37,14 +37,17 @@ class CacheRootFSPlugin(cliapp.Plugin): class MakeCacheStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['cache-rootfs'] - - def run(self, step, settings, state): - fs_tag = step['cache-rootfs'] + def get_key_spec(self): + return { + 'cache-rootfs': str, + 'options': '--one-file-system', + } + + def run(self, values, settings, state): + fs_tag = values['cache-rootfs'] rootdir = state.tags.get_builder_mount_point(fs_tag) tar_path = settings['rootfs-tarball'] - opts = step.get('options', '--one-file-system').split() + opts = values['options'].split() if not tar_path: raise Exception('--rootfs-tarball MUST be set') dirs = self._find_cacheable_mount_points(state.tags, rootdir) diff --git a/vmdb/plugins/chroot_plugin.py b/vmdb/plugins/chroot_plugin.py index 4eb5847..bded609 100644 --- a/vmdb/plugins/chroot_plugin.py +++ b/vmdb/plugins/chroot_plugin.py @@ -32,12 +32,15 @@ class ChrootPlugin(cliapp.Plugin): class ChrootStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['chroot', 'shell'] - - def run(self, step, settings, state): - fs_tag = step['chroot'] - shell = step['shell'] + def get_key_spec(self): + return { + 'chroot': str, + 'shell': str, + } + + def run(self, values, settings, state): + fs_tag = values['chroot'] + shell = values['shell'] mount_point = state.tags.get_builder_mount_point(fs_tag) vmdb.runcmd_chroot(mount_point, ['sh', '-ec', shell]) diff --git a/vmdb/plugins/copy_file_plugin.py b/vmdb/plugins/copy_file_plugin.py index 7683d7e..b82497b 100644 --- a/vmdb/plugins/copy_file_plugin.py +++ b/vmdb/plugins/copy_file_plugin.py @@ -28,16 +28,22 @@ class CopyFilePlugin(cliapp.Plugin): class CopyFileStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['copy-file', 'src'] - - def run(self, step, settings, state): + def get_key_spec(self): + return { + 'copy-file': str, + 'src': str, + 'perm': 0o644, + 'uid': 0, + 'gid': 0, + } + + def run(self, values, settings, state): root = state.tags.get_builder_from_target_mount_point('/') - newfile = step['copy-file'] - src = step['src'] - perm = step.get('perm', 0o644) - uid = step.get('uid', 0) - gid = step.get('gid', 0) + newfile = values['copy-file'] + src = values['src'] + perm = values['perm'] + uid = values['uid'] + gid = values['gid'] filename = '/'.join([root,newfile]) diff --git a/vmdb/plugins/create_dir_plugin.py b/vmdb/plugins/create_dir_plugin.py index c48b662..77fc72a 100644 --- a/vmdb/plugins/create_dir_plugin.py +++ b/vmdb/plugins/create_dir_plugin.py @@ -28,18 +28,25 @@ class CreateDirPlugin(cliapp.Plugin): class CreateDirStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['create-dir'] - - def run(self, step, settings, state): + def get_key_spec(self): + return { + 'create-dir': str, + 'perm': 0o755, + 'uid': 0, + 'gid': 0, + } + + def run(self, values, settings, state): root = state.tags.get_builder_from_target_mount_point('/') - newdir = step['create-dir'] + newdir = values['create-dir'] path = '/'.join([root, newdir]) - perm = step.get('perm', 0o755) - uid = step.get('uid', 0) - gid = step.get('gid', 0) + perm = values['perm'] + uid = values['uid'] + gid = values['gid'] - logging.info('Creating directory %s, uid %d, gid %d, perms %o' % (path, uid, gid, perm)) + logging.info( + 'Creating directory %s, uid %d, gid %d, perms %o' % ( + path, uid, gid, perm)) os.makedirs(path, perm) os.chown(path, uid, gid) diff --git a/vmdb/plugins/create_file_plugin.py b/vmdb/plugins/create_file_plugin.py index d6f9d7a..6d5621c 100644 --- a/vmdb/plugins/create_file_plugin.py +++ b/vmdb/plugins/create_file_plugin.py @@ -29,20 +29,29 @@ class CreateFilePlugin(cliapp.Plugin): class CreateFileStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['create-file', 'contents'] - - def run(self, step, settings, state): + def get_key_spec(self): + return { + 'create-file': str, + 'contents': str, + 'perm': 0o644, + 'uid': 0, + 'gid': 0, + } + + def run(self, values, settings, state): root = state.tags.get_builder_from_target_mount_point('/') - newfile = step['create-file'] - contents = step['contents'] - perm = step.get('perm', 0o644) - uid = step.get('uid', 0) - gid = step.get('gid', 0) + newfile = values['create-file'] + contents = values['contents'] + perm = values['perm'] + uid = values['uid'] + gid = values['gid'] + + filename = '/'.join([root, newfile]) - filename = '/'.join([root,newfile]) + logging.info( + 'Creating file %s, uid %d, gid %d, perms %o' % ( + filename, uid, gid, perm)) - logging.info('Creating file %s, uid %d, gid %d, perms %o' % (filename, uid, gid, perm)) fd = open(filename, 'w') fd.write(contents) fd.close diff --git a/vmdb/plugins/debootstrap_plugin.py b/vmdb/plugins/debootstrap_plugin.py index cf2fb43..f2f284b 100644 --- a/vmdb/plugins/debootstrap_plugin.py +++ b/vmdb/plugins/debootstrap_plugin.py @@ -30,24 +30,41 @@ class DebootstrapPlugin(cliapp.Plugin): class DebootstrapStepRunner(vmdb.StepRunnerInterface): + def get_key_spec(self): + return { + 'debootstrap': str, + 'target': str, + 'mirror': str, + 'keyring': '', + 'variant': '-', + } + def get_required_keys(self): return ['debootstrap', 'target', 'mirror'] - def run(self, step, settings, state): - suite = step['debootstrap'] - tag = step['target'] + def run(self, values, settings, state): + suite = values['debootstrap'] + tag = values['target'] target = state.tags.get_builder_mount_point(tag) - mirror = step['mirror'] - keyring = step.get('keyring', None) - variant = step.get('variant', '-') + mirror = values['mirror'] + keyring = values['keyring'] or None + variant = values['variant'] + if not (suite and tag and target and mirror): raise Exception('missing arg for debootstrap step') if keyring: - vmdb.runcmd(['debootstrap', '--keyring', keyring, '--variant', variant, suite, target, mirror]) + vmdb.runcmd([ + 'debootstrap', + '--keyring', keyring, + '--variant', variant, + suite, target, mirror]) else: - vmdb.runcmd(['debootstrap', '--variant', variant, suite, target, mirror]) + vmdb.runcmd([ + 'debootstrap', + '--variant', variant, + suite, target, mirror]) - def run_even_if_skipped(self, step, settings, state): - tag = step['target'] + def run_even_if_skipped(self, values, settings, state): + tag = values['target'] target = state.tags.get_builder_mount_point(tag) vmdb.runcmd_chroot(target, ['apt-get', 'update']) diff --git a/vmdb/plugins/echo_plugin.py b/vmdb/plugins/echo_plugin.py index c09a387..d7748d7 100644 --- a/vmdb/plugins/echo_plugin.py +++ b/vmdb/plugins/echo_plugin.py @@ -32,15 +32,18 @@ class EchoPlugin(cliapp.Plugin): class EchoStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['echo'] - - def run(self, step, settings, state): - text = step['echo'] + def get_key_spec(self): + return { + 'echo': str, + 'teardown': '', + } + + def run(self, values, settings, state): + text = values['echo'] vmdb.progress('{}'.format(text)) - def teardown(self, step, settings, state): - if 'teardown' in step: - text = step['teardown'] + def teardown(self, values, settings, state): + text = values['teardown'] + if text: vmdb.progress('{}'.format(text)) logging.info('%s', text) diff --git a/vmdb/plugins/error_plugin.py b/vmdb/plugins/error_plugin.py index e40e1ec..7c5ce8c 100644 --- a/vmdb/plugins/error_plugin.py +++ b/vmdb/plugins/error_plugin.py @@ -30,16 +30,22 @@ class ErrorPlugin(cliapp.Plugin): class ErrorStepRunner(vmdb.StepRunnerInterface): + def get_key_spec(self): + return { + 'error': str, + 'teardown': str, + } + def get_required_keys(self): return ['error', 'teardown'] - def run(self, step, settings, state): + def run(self, values, settings, state): # We use vmdb.progress here to get output to go to stdout, # instead of stderr. We want that for tests. - vmdb.progress('{}'.format(step['error'])) + vmdb.progress('{}'.format(values['error'])) raise vmdb.StepError('an error occurred') - def teardown(self, step, settings, state): + def teardown(self, values, settings, state): # We use vmdb.progress here to get output to go to stdout, # instead of stderr. We want that for tests. - vmdb.progress('{}'.format(step['teardown'])) + vmdb.progress('{}'.format(values['teardown'])) diff --git a/vmdb/plugins/fstab_plugin.py b/vmdb/plugins/fstab_plugin.py index e0bd29d..508ef07 100644 --- a/vmdb/plugins/fstab_plugin.py +++ b/vmdb/plugins/fstab_plugin.py @@ -30,11 +30,13 @@ class FstabPlugin(cliapp.Plugin): class FstabStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['fstab'] + def get_key_spec(self): + return { + 'fstab': str, + } - def run(self, step, setting, state): - tag = step['fstab'] + def run(self, values, setting, state): + tag = values['fstab'] chroot = state.tags.get_builder_mount_point(tag) filesystems = [] diff --git a/vmdb/plugins/grub_plugin.py b/vmdb/plugins/grub_plugin.py index 937fffc..e38ca27 100644 --- a/vmdb/plugins/grub_plugin.py +++ b/vmdb/plugins/grub_plugin.py @@ -86,53 +86,63 @@ class GrubPlugin(cliapp.Plugin): class GrubStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['grub', 'tag'] - - def run(self, step, settings, state): + def get_key_spec(self): + return { + 'grub': str, + 'tag': str, + 'root-fs': '', + 'efi': '', + 'efi-part': '', + 'console': '', + 'tag': '', + 'image-dev': '', + } + + def run(self, values, settings, state): state.grub_mounts = [] - flavor = step['grub'] + flavor = values['grub'] if flavor == 'uefi': - self.install_uefi(step, settings, state) + self.install_uefi(values, settings, state) elif flavor == 'bios': - self.install_bios(step, settings, state) + self.install_bios(values, settings, state) else: raise Exception('Unknown GRUB flavor {}'.format(flavor)) - def install_uefi(self, step, settings, state): - if not 'efi' in step and 'efi-part' not in step: - raise Exception('"efi" or "efi-part" required in UEFI GRUB installtion') + def install_uefi(self, values, settings, state): + efi = values['efi'] or None + efi_part = values['efi-part'] or None + if efi is None and efi_part is None: + raise Exception( + '"efi" or "efi-part" required in UEFI GRUB installation') vmdb.progress('Installing GRUB for UEFI') grub_package = 'grub-efi-amd64' grub_target = 'x86_64-efi' - self.install_grub(step, settings, state, grub_package, grub_target) + self.install_grub(values, settings, state, grub_package, grub_target) - def install_bios(self, step, settings, state): + def install_bios(self, values, settings, state): vmdb.progress('Installing GRUB for BIOS') grub_package = 'grub-pc' grub_target = 'i386-pc' - self.install_grub(step, settings, state, grub_package, grub_target) + self.install_grub(values, settings, state, grub_package, grub_target) - def install_grub(self, step, settings, state, grub_package, grub_target): - console = step.get('console', None) + def install_grub(self, values, settings, state, grub_package, grub_target): + console = values['console'] or None - tag = step.get('tag') - if tag is None: - tag = step['root-fs'] + tag = values['tag'] or values['root-fs'] or None root_dev = state.tags.get_dev(tag) chroot = state.tags.get_builder_mount_point(tag) - image_dev = step.get('image-dev') + image_dev = values['image-dev'] or None if image_dev is None: image_dev = self.get_image_loop_device(root_dev) - if 'efi' in step: - efi = step['efi'] - efi_dev = state.tags.get_dev(efi) - elif 'efi-part' in step: - efi = step['efi-part'] + efi = values['efi'] or None + efi_part = values['efi-part'] or None + if efi is not None: efi_dev = state.tags.get_dev(efi) + elif efi_part is not None: + efi_dev = state.tags.get_dev(efi_part) else: efi_dev = None @@ -181,7 +191,7 @@ class GrubStepRunner(vmdb.StepRunnerInterface): # self.unmount(state) - def teardown(self, step, settings, state): + def teardown(self, values, settings, state): self.unmount(state) def unmount(self, state): diff --git a/vmdb/plugins/kpartx_plugin.py b/vmdb/plugins/kpartx_plugin.py index dca61bb..5d320ea 100644 --- a/vmdb/plugins/kpartx_plugin.py +++ b/vmdb/plugins/kpartx_plugin.py @@ -33,11 +33,13 @@ class KpartxPlugin(cliapp.Plugin): class KpartxStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['kpartx'] + def get_key_spec(self): + return { + 'kpartx': str, + } - def run(self, step, settings, state): - device = step['kpartx'] + def run(self, values, settings, state): + device = values['kpartx'] tags = state.tags.get_tags() devs = self.kpartx(device) for tag, dev in zip(tags, devs): @@ -52,6 +54,6 @@ class KpartxStepRunner(vmdb.StepRunnerInterface): name = words[2] yield '/dev/mapper/{}'.format(name) - def teardown(self, step, settings, state): - device = step['kpartx'] + def teardown(self, values, settings, state): + device = values['kpartx'] vmdb.runcmd(['kpartx', '-dsv', device]) diff --git a/vmdb/plugins/luks_plugin.py b/vmdb/plugins/luks_plugin.py index c95d07f..9ea066c 100644 --- a/vmdb/plugins/luks_plugin.py +++ b/vmdb/plugins/luks_plugin.py @@ -34,12 +34,17 @@ class LuksPlugin(cliapp.Plugin): class CryptsetupStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['cryptsetup'] - - def run(self, step, settings, state): - underlying = step['cryptsetup'] - crypt_name = step['tag'] + def get_key_spec(self): + return { + 'cryptsetup': str, + 'tag': str, + 'key-file': '', + 'key-cmd': '', + } + + def run(self, values, settings, state): + underlying = values['cryptsetup'] + crypt_name = values['tag'] if not isinstance(underlying, str): raise vmdb.NotString('cryptsetup', underlying) @@ -47,8 +52,8 @@ class CryptsetupStepRunner(vmdb.StepRunnerInterface): raise vmdb.NotString('cryptsetup: tag', crypt_name) state.tmp_key_file = None - key_file = step.get('key-file') - key_cmd = step.get('key-cmd') + key_file = values['key-file'] or None + key_cmd = values['key-cmd'] or None if key_file is None and key_cmd is None: raise Exception( 'cryptsetup step MUST define one of key-file or key-cmd') @@ -80,12 +85,12 @@ class CryptsetupStepRunner(vmdb.StepRunnerInterface): state.tags.append(crypt_name) state.tags.set_dev(crypt_name, crypt_dev) - def teardown(self, step, settings, state): + def teardown(self, values, settings, state): x = state.tmp_key_file if x is not None and os.path.exists(x): os.remove(x) - crypt_name = step['tag'] + crypt_name = values['tag'] crypt_dev = '/dev/mapper/{}'.format(crypt_name) vmdb.runcmd(['cryptsetup', 'close', crypt_dev]) diff --git a/vmdb/plugins/lvcreate_plugin.py b/vmdb/plugins/lvcreate_plugin.py index c8a83b8..4b135bc 100644 --- a/vmdb/plugins/lvcreate_plugin.py +++ b/vmdb/plugins/lvcreate_plugin.py @@ -32,13 +32,17 @@ class LvcreatePlugin(cliapp.Plugin): class LvcreateStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['lvcreate'] - - def run(self, step, settings, state): - vgname = step['lvcreate'] - lvname = step['name'] - size = step['size'] + def get_key_spec(self): + return { + 'lvcreate': str, + 'name': str, + 'size': str, + } + + def run(self, values, settings, state): + vgname = values['lvcreate'] + lvname = values['name'] + size = values['size'] vmdb.runcmd(['lvcreate', '--name', lvname, '--size', size, vgname]) diff --git a/vmdb/plugins/mkfs_plugin.py b/vmdb/plugins/mkfs_plugin.py index 49ca86b..967493f 100644 --- a/vmdb/plugins/mkfs_plugin.py +++ b/vmdb/plugins/mkfs_plugin.py @@ -30,12 +30,16 @@ class MkfsPlugin(cliapp.Plugin): class MkfsStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['mkfs', 'partition'] + def get_key_spec(self): + return { + 'mkfs': str, + 'partition': str, + 'label': '', + } - def run(self, step, settings, state): - fstype = step['mkfs'] - tag = step['partition'] + def run(self, values, settings, state): + fstype = values['mkfs'] + tag = values['partition'] device = state.tags.get_dev(tag) if not isinstance(fstype, str): @@ -46,14 +50,15 @@ class MkfsStepRunner(vmdb.StepRunnerInterface): raise vmdb.NotString('mkfs: device (for tag)', device) cmd = ['/sbin/mkfs', '-t', fstype] - if 'label' in step: + label = values['label'] or None + if label: if fstype == 'vfat': cmd.append('-n') elif fstype == 'f2fs': cmd.append('-l') else: cmd.append('-L') - cmd.append(step['label']) + cmd.append(label) cmd.append(device) vmdb.runcmd(cmd) diff --git a/vmdb/plugins/mkimg_plugin.py b/vmdb/plugins/mkimg_plugin.py index f68f7c3..15467e1 100644 --- a/vmdb/plugins/mkimg_plugin.py +++ b/vmdb/plugins/mkimg_plugin.py @@ -34,12 +34,15 @@ class MkimgPlugin(cliapp.Plugin): class MkimgStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['mkimg'] - - def run(self, step, settings, state): - filename = step['mkimg'] - size = step['size'] + def get_key_spec(self): + return { + 'mkimg': str, + 'size': str, + } + + def run(self, values, settings, state): + filename = values['mkimg'] + size = values['size'] if not isinstance(filename, str): raise vmdb.NotString('mkimg', filename) diff --git a/vmdb/plugins/mklabel_plugin.py b/vmdb/plugins/mklabel_plugin.py index 39e8c8d..5b5fd5a 100644 --- a/vmdb/plugins/mklabel_plugin.py +++ b/vmdb/plugins/mklabel_plugin.py @@ -33,10 +33,13 @@ class MklabelPlugin(cliapp.Plugin): class MklabelStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['mklabel', 'device'] - - def run(self, step, settings, state): - label_type = step['mklabel'] - device = step['device'] + def get_key_spec(self): + return { + 'mklabel': str, + 'device': str, + } + + def run(self, values, settings, state): + label_type = values['mklabel'] + device = values['device'] vmdb.runcmd(['parted', '-s', device, 'mklabel', label_type]) diff --git a/vmdb/plugins/mkpart_plugin.py b/vmdb/plugins/mkpart_plugin.py index 45c4148..6b37d8c 100644 --- a/vmdb/plugins/mkpart_plugin.py +++ b/vmdb/plugins/mkpart_plugin.py @@ -33,18 +33,24 @@ class MkpartPlugin(cliapp.Plugin): class MkpartStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['mkpart', 'device', 'start', 'end'] - - def run(self, step, settings, state): - part_type = step['mkpart'] - device = step['device'] - start = step['start'] - end = step['end'] - tag = step.get('tag') or step.get('part-tag') - if tag is None: - tag = step['part-tag'] - fs_type = step.get('fs-type', 'ext2') + def get_key_spec(self): + return { + 'mkpart': str, + 'device': str, + 'start': str, + 'end': str, + 'tag': '', + 'part-tag': '', + 'fs-type': 'ext2', + } + + def run(self, values, settings, state): + part_type = values['mkpart'] + device = values['device'] + start = values['start'] + end = values['end'] + tag = values['tag'] or values['part-tag'] or None + fs_type = values['fs-type'] orig = self.list_partitions(device) vmdb.runcmd(['parted', '-s', device, 'mkpart', part_type, fs_type, start, end]) diff --git a/vmdb/plugins/mount_plugin.py b/vmdb/plugins/mount_plugin.py index f3c736e..fc5ffeb 100644 --- a/vmdb/plugins/mount_plugin.py +++ b/vmdb/plugins/mount_plugin.py @@ -34,19 +34,23 @@ class MountPlugin(cliapp.Plugin): class MountStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['mount'] + def get_key_spec(self): + return { + 'mount': str, + 'dirname': '', + 'mount-on': '', + } - def run(self, step, settings, state): - self.mount_rootfs(step, settings, state) + def run(self, values, settings, state): + self.mount_rootfs(values, settings, state) - def teardown(self, step, settings, state): - self.unmount_rootfs(step, settings, state) + def teardown(self, values, settings, state): + self.unmount_rootfs(values, settings, state) - def mount_rootfs(self, step, settings, state): - tag = step['mount'] - dirname = step.get('dirname') - mount_on = step.get('mount-on') + def mount_rootfs(self, values, settings, state): + tag = values['mount'] + dirname = values['dirname'] or None + mount_on = values['mount-on'] or None device = state.tags.get_dev(tag) @@ -72,8 +76,8 @@ class MountStepRunner(vmdb.StepRunnerInterface): return mount_point - def unmount_rootfs(self, step, settings, state): - tag = step['mount'] + def unmount_rootfs(self, values, settings, state): + tag = values['mount'] mount_point = state.tags.get_builder_mount_point(tag) if mount_point is None: return @@ -83,5 +87,5 @@ class MountStepRunner(vmdb.StepRunnerInterface): except vmdb.NotMounted as e: logging.warning(str(e)) - if not step.get('mount-on'): + if not values['mount-on']: os.rmdir(mount_point) diff --git a/vmdb/plugins/qemudebootstrap_plugin.py b/vmdb/plugins/qemudebootstrap_plugin.py index 75755ac..a195d29 100644 --- a/vmdb/plugins/qemudebootstrap_plugin.py +++ b/vmdb/plugins/qemudebootstrap_plugin.py @@ -30,18 +30,26 @@ class QemuDebootstrapPlugin(cliapp.Plugin): class QemuDebootstrapStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['qemu-debootstrap', 'target', 'mirror', 'arch'] + def get_key_spec(self): + return { + 'debootstrap': str, + 'target': str, + 'mirror': str, + 'arch': str, + 'keyring': '', + 'variant': '-', + 'components': ['main'], + } - def run(self, step, settings, state): - suite = step['qemu-debootstrap'] - tag = step['target'] + def run(self, values, settings, state): + suite = values['qemu-debootstrap'] + tag = values['target'] target = state.tags.get_builder_mount_point(tag) - mirror = step['mirror'] - keyring = step.get('keyring', None) - variant = step.get('variant', '-') - arch = step['arch'] - components = step.get('components', ['main']) + mirror = values['mirror'] + keyring = values['keyring'] or None + variant = values['variant'] + arch = values['arch'] + components = values['compontents'] if not (suite and tag and target and mirror and arch): raise Exception('missing arg for qemu-debootstrap step') if keyring: @@ -63,7 +71,7 @@ class QemuDebootstrapStepRunner(vmdb.StepRunnerInterface): mirror]) vmdb.runcmd_chroot(target, ['apt-get', 'update']) - def run_even_if_skipped(self, step, settings, state): - tag = step['target'] + def run_even_if_skipped(self, values, settings, state): + tag = values['target'] target = state.tags.get_builder_mount_point(tag) vmdb.runcmd_chroot(target, ['apt-get', 'update']) diff --git a/vmdb/plugins/unpack_rootfs_plugin.py b/vmdb/plugins/unpack_rootfs_plugin.py index 8e6aada..9143143 100644 --- a/vmdb/plugins/unpack_rootfs_plugin.py +++ b/vmdb/plugins/unpack_rootfs_plugin.py @@ -32,11 +32,13 @@ class UnpackRootFSPlugin(cliapp.Plugin): class UnpackCacheStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['unpack-rootfs'] + def get_key_spec(self): + return { + 'unpack-rootfs': str, + } - def run(self, step, settings, state): - fs_tag = step['unpack-rootfs'] + def run(self, values, settings, state): + fs_tag = values['unpack-rootfs'] rootdir = state.tags.get_builder_mount_point(fs_tag) tar_path = settings['rootfs-tarball'] if not tar_path: diff --git a/vmdb/plugins/vgcreate_plugin.py b/vmdb/plugins/vgcreate_plugin.py index 2816265..d6b3c45 100644 --- a/vmdb/plugins/vgcreate_plugin.py +++ b/vmdb/plugins/vgcreate_plugin.py @@ -32,26 +32,29 @@ class VgcreatePlugin(cliapp.Plugin): class VgcreateStepRunner(vmdb.StepRunnerInterface): - def get_required_keys(self): - return ['vgcreate', 'physical'] + def get_key_spec(self): + return { + 'vgcreate': str, + 'physical': [], + } - def run(self, step, settings, state): - vgname = self.get_vg(step) - physical = self.get_pv(step, state) + def run(self, values, settings, state): + vgname = self.get_vg(values) + physical = self.get_pv(values, state) for phys in physical: vmdb.runcmd(['pvcreate', '-ff', '--yes', phys]) vmdb.runcmd(['vgcreate', vgname] + physical) - def teardown(self, step, settings, state): - vgname = self.get_vg(step) + def teardown(self, values, settings, state): + vgname = self.get_vg(values) vmdb.runcmd(['vgchange', '-an', vgname]) - def get_vg(self, step): - return step['vgcreate'] + def get_vg(self, values): + return values['vgcreate'] - def get_pv(self, step, state): + def get_pv(self, values, state): return [ state.tags.get_dev(tag) - for tag in step['physical'] + for tag in values['physical'] ] diff --git a/vmdb/plugins/virtuals_plugin.py b/vmdb/plugins/virtuals_plugin.py index 10ae586..71176f8 100644 --- a/vmdb/plugins/virtuals_plugin.py +++ b/vmdb/plugins/virtuals_plugin.py @@ -43,15 +43,17 @@ class VirtualFilesystemMountStepRunner(vmdb.StepRunnerInterface): ['none', '/sys', 'sysfs'], ] - def get_required_keys(self): - return ['mount-virtual-filesystems'] + def get_key_spec(self): + return { + 'mount-virtual-filesystems': str, + } - def run(self, step, settings, state): - fstag = step['mount-virtual-filesystems'] + def run(self, values, settings, state): + fstag = values['mount-virtual-filesystems'] mount_point = state.tags.get_builder_mount_point(fstag) self.mount_virtuals(mount_point, state) - def teardown(self, step, settings, state): + def teardown(self, values, settings, state): self.unmount_virtuals(state) def mount_virtuals(self, rootfs, state): diff --git a/vmdb/step_list.py b/vmdb/step_list.py index 468cf35..16bdb5f 100644 --- a/vmdb/step_list.py +++ b/vmdb/step_list.py @@ -24,9 +24,40 @@ import cliapp class StepRunnerInterface: # pragma: no cover - def get_required_keys(self): + def get_key_spec(self): raise NotImplementedError() + def get_values(self, step): + keyspec = self.get_key_spec() + values = {} + + # Get keys from step or defaults from spec. + for key, specvalue in keyspec.items(): + if specvalue.__class__ == type: + if key not in step: + raise StepKeyMissing(key) + values[key] = step[key] + else: + values[key] = step.get(key, specvalue) + + # Check types of values. + for key, specvalue in keyspec.items(): + if specvalue.__class__ == type: + wanted = specvalue + else: + wanted = specvalue.__class__ + if not isinstance(values[key], wanted): + raise StepKeyWrongValueType(key, wanted, values[key]) + + return values + + def get_required_keys(self): + return [ + key + for key, value in self.get_key_spec().items() + if value.__class__ == type + ] + def run(self, step_spec, settings, state): raise NotImplementedError() @@ -72,6 +103,7 @@ class StepRunnerList: for runner in self._runners: required = set(runner.get_required_keys()) if actual.intersection(required) == required: + runner.get_values(step_spec) return runner raise NoMatchingRunner(actual) @@ -83,6 +115,20 @@ class StepError(cliapp.AppException): super().__init__(msg) +class StepKeyMissing(StepError): + + def __init__(self, key): + super().__init__('Step is missing key {}'.format(key)) + + +class StepKeyWrongValueType(StepError): + + def __init__(self, key, wanted, actual): + super().__init__( + 'Step key {} has value {!r}, expected {!r}'.format( + key, wanted, actual)) + + class NoMatchingRunner(StepError): def __init__(self, keys): diff --git a/vmdb/step_list_tests.py b/vmdb/step_list_tests.py index 4d052d7..13836a5 100644 --- a/vmdb/step_list_tests.py +++ b/vmdb/step_list_tests.py @@ -35,23 +35,80 @@ class StepRunnerListTests(unittest.TestCase): def test_finds_correct_runner(self): steps = vmdb.StepRunnerList() - runner = DummyStepRunner() + keyspec = { + 'foo': str, + 'bar': str, + } + runner = DummyStepRunner(keyspec=keyspec) steps.add(runner) - found = steps.find({'foo': None, 'bar': None}) + found = steps.find({'foo': 'foo', 'bar': 'bar'}) self.assertEqual(runner, found) def test_raises_error_if_runner_not_found(self): steps = vmdb.StepRunnerList() - runner = DummyStepRunner() + keyspec = { + 'foo': str, + 'bar': str, + } + runner = DummyStepRunner(keyspec=keyspec) steps.add(runner) with self.assertRaises(vmdb.NoMatchingRunner): - steps.find({'foo': None}) + steps.find({'foo': 'foo'}) + + def test_raises_error_if_wrong_step_key_values(self): + steps = vmdb.StepRunnerList() + keyspec = { + 'foo': str, + } + runner = DummyStepRunner(keyspec=keyspec) + steps.add(runner) + with self.assertRaises(vmdb.StepKeyWrongValueType): + steps.find({'foo': 42}) class DummyStepRunner(vmdb.StepRunnerInterface): + def __init__(self, keyspec=None): + self.keyspec = keyspec + + def get_key_spec(self): + return self.keyspec + def run(self, *args): pass - def get_required_keys(self): - return ['foo', 'bar'] + +class StepRunnerGetKeyValuesTests(unittest.TestCase): + + def test_returns_values_from_step_for_mandatory_keys(self): + keyspec = {'foo': str} + runner = DummyStepRunner(keyspec=keyspec) + self.assertEqual(runner.get_values({'foo': 'bar'}), {'foo': 'bar'}) + + def test_raises_error_for_missing_mandatory_key(self): + keyspec = {'foo': str} + runner = DummyStepRunner(keyspec=keyspec) + with self.assertRaises(vmdb.StepKeyMissing): + runner.get_values({}) + + def test_raises_error_for_wrong_type_of_value_for_mandatory_key(self): + keyspec = {'foo': str} + runner = DummyStepRunner(keyspec=keyspec) + with self.assertRaises(vmdb.StepKeyWrongValueType): + runner.get_values({'foo': 42}) + + def test_returns_default_value_for_missing_optional_key(self): + keyspec = {'foo': 'bar'} + runner = DummyStepRunner(keyspec=keyspec) + self.assertEqual(runner.get_values({}), {'foo': 'bar'}) + + def test_returns_actual_value_for_optional_key(self): + keyspec = {'foo': 'bar'} + runner = DummyStepRunner(keyspec=keyspec) + self.assertEqual(runner.get_values({'foo': 'yo'}), {'foo': 'yo'}) + + def test_raises_error_for_wrong_type_of_value_for_optional_key(self): + keyspec = {'foo': 'bar'} + runner = DummyStepRunner(keyspec=keyspec) + with self.assertRaises(vmdb.StepKeyWrongValueType): + runner.get_values({'foo': 42}) |