diff --git a/roles/copr/backend/files/provision/libvirt-delete b/roles/copr/backend/files/provision/libvirt-delete new file mode 100755 index 0000000000..e6699b498c --- /dev/null +++ b/roles/copr/backend/files/provision/libvirt-delete @@ -0,0 +1,73 @@ +#! /usr/bin/python3 + +""" +Delete the given Resalloc-related LibVirt domain (and the related resources) +""" + +# pylint: disable=broad-except + +import argparse +import logging +import time + +import libvirt + +def repeat(call, args): + """ Repeat the given function call, with args """ + attempts = 3 + for attempt in range(1, attempts+1): + try: + return call(*args) + except Exception: + seconds = 10 + if attempt < attempts: + logging.exception("Failed repeatable call, sleep %ss", + seconds) + time.sleep(seconds) + continue + raise + +def _get_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("--connection", required=True) + parser.add_argument("domainname") + return parser + +def _delete_domain(domain): + try: + domain.destroy() + logging.info("Domain %s destroyed", domain.name()) + except Exception: + logging.exception("can't destroy %s", domain.name()) + + domain.undefine() + logging.info("Domain %s undefined", domain.name()) + +def _delete_volume(pool, volume_name): + volume = pool.storageVolLookupByName(volume_name) + volume.delete() + + +def _main(): + logging.basicConfig(level=logging.INFO) + args = _get_parser().parse_args() + conn = repeat(libvirt.open, (args.connection,)) + try: + domain = repeat(conn.lookupByName, (args.domainname,)) + repeat(_delete_domain, (domain,)) + logging.info("domain %s removed", args.domainname) + except Exception: + logging.exception("domain can't be removed") + + pool = repeat(conn.storagePoolLookupByName, ("images",)) + for volume_name in repeat(pool.listVolumes, ()): + if not volume_name.startswith(args.domainname): + continue + try: + repeat(_delete_volume, (pool, volume_name,)) + logging.info("volume %s removed", volume_name) + except Exception: + logging.exception("volume %s can not be removed", volume_name) + +if __name__ == "__main__": + _main() diff --git a/roles/copr/backend/files/provision/libvirt-list b/roles/copr/backend/files/provision/libvirt-list new file mode 100755 index 0000000000..510144d897 --- /dev/null +++ b/roles/copr/backend/files/provision/libvirt-list @@ -0,0 +1,52 @@ +#! /usr/bin/python3 + +""" +List all the Resalloc Pool-related LibVirt domains that are either (a) still +defined/running, or (b) have some resource (e.g. storage) still available in the +LibVirt hypervisor. +""" + +import argparse +import sys + +import libvirt + +def _get_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("--connection", required=True) + parser.add_argument("--pool", required=True) + return parser + +def _main(): + args = _get_parser().parse_args() + + try: + conn = libvirt.openReadOnly(args.connection) + except libvirt.libvirtError: + print('Failed to open connection to the hypervisor') + sys.exit(1) + + # Gather the list of all domains here + vm_names = set() + + # List all the volumes in the 'images' pool that seem to be related to given + # Pool name + pool = conn.storagePoolLookupByName("images") + for volume in pool.listVolumes(): + if volume.startswith(args.pool): + vm_names.add(volume.rsplit("_", 1)[0]) + + # List all domains that are related to given Pool (just to be 100% sure, but + # this shouldn't add any new items to the vm_names set actually). + for domain in conn.listAllDomains(): + name = domain.name() + if name.startswith(args.pool): + vm_names.add(name) + + # Print them out, so upper level tooling can work with the list. See: + # roles/copr/backend/files/provision/libvirt-list + for name in vm_names: + print(name) + +if __name__ == "__main__": + _main() diff --git a/roles/copr/backend/templates/resalloc/vm-delete.j2 b/roles/copr/backend/templates/resalloc/vm-delete.j2 index 55c5e9228f..b78aa0bc33 100755 --- a/roles/copr/backend/templates/resalloc/vm-delete.j2 +++ b/roles/copr/backend/templates/resalloc/vm-delete.j2 @@ -66,14 +66,4 @@ copr_p09_01*) esac # The rest of this script is LibVirt only! - -repeat() -{ - for _ in a b c; do - "$@" && break - sleep 15 - done -} - -repeat virsh -c "$conn" destroy "$RESALLOC_NAME" -repeat virsh -c "$conn" undefine "$RESALLOC_NAME" --remove-all-storage --nvram +{{ provision_directory }}/libvirt-delete --connection "$conn" "$RESALLOC_NAME"