From 01019a31f8f429d2abc31e38a160d8e1a9e6c821 Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Thu, 4 Feb 2021 09:58:08 -0600 Subject: Add a kvm test using uvtool Changes made based upon merge proposal comments --- bin/virtualization.py | 142 ++++++++++++++++++++++++++++++++++++++++++ units/virtualization/jobs.pxu | 8 +-- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/bin/virtualization.py b/bin/virtualization.py index 10b827b..939a8a6 100755 --- a/bin/virtualization.py +++ b/bin/virtualization.py @@ -531,6 +531,123 @@ class RunCommand(object): self.returncode = proc.returncode +class UVTKVMTest(object): + + def __init__(self, image=None): + self.image = image + self.release = lsb_release.get_distro_information()["CODENAME"] + self.arch = check_output(['dpkg', '--print-architecture'], + universal_newlines=True).strip() + self.name = tempfile.mktemp()[5:] + + def run_command(self, cmd): + task = RunCommand(cmd) + if task.returncode != 0: + logging.error('Command {} returnd a code of {}'.format( + task.cmd, task.returncode)) + logging.error(' STDOUT: {}'.format(task.stdout)) + logging.error(' STDERR: {}'.format(task.stderr)) + return False + else: + logging.debug('Command {}:'.format(task.cmd)) + if task.stdout != '': + logging.debug(' STDOUT: {}'.format(task.stdout)) + elif task.stderr != '': + logging.debug(' STDERR: {}'.format(task.stderr)) + else: + logging.debug(' Command returned no output') + return True + + def get_image_or_source(self): + """ + An image can be specifed in a filesytem path and used directly in + uvt-create with the backing-image option or a url can be + specifed and used in uvt-simpletreams to generate an image. + """ + url = urlparse(self.image) + + if url.scheme == 'file': + logging.debug("Cloud image exists locally at %s" % url.path) + self.image = url.path + else: + cmd = ("uvt-simplestreams-libvirt sync release={} " + "arch={}".format(self.release, self.arch)) + + if url.scheme == 'http': + # Path specified to use -source option + logging.debug("Using --source option for uvt-simpletreams") + cmd = cmd + " --source {} ".format(self.image) + + logging.debug("uvt-simplestreams-libvirt sync") + if not self.run_command(cmd): + return False + return True + + def cleanup(self): + """ + A combination of virsh destroy/undefine is used instead of + uvt-kvm destroy. When using uvt-kvm destroy the following bug + is seen: + https://bugs.launchpad.net/ubuntu/+source/uvtool/+bug/1452095 + """ + # Destroy vm + logging.debug("Destroy VM") + if not self.run_command('virsh destroy {}'.format(self.name)): + return False + + # Virsh undefine + logging.debug("Undefine VM") + if not self.run_command('virsh undefine {}'.format(self.name)): + return False + + # Purge/Remove simplestreams image + if not self.run_command("uvt-simplestreams-libvirt purge"): + return False + return True + + def start(self): + # Generate ssh key if needed + home_dir = os.environ['HOME'] + ssh_key_file = "{}/.ssh/id_rsa".format(home_dir) + + if not os.path.exists(ssh_key_file): + self.run_command("mkdir -p {}/.ssh".format(home_dir)) + + cmd = ('ssh-keygen -f {} -t rsa -N \'\''.format(ssh_key_file)) + if not self.run_command(cmd): + return False + + # Create vm + logging.debug("Creating VM") + cmd = ('uvt-kvm create {} arch={}'.format(self.name, self.arch)) + + if self.image.find(".img") > 0: + cmd = cmd + " --backing-image-file {} ".format(self.image) + + if not self.run_command(cmd): + return False + + logging.debug("Wait for VM to complete creation") + if not self.run_command('uvt-kvm wait {}'.format(self.name)): + return False + + logging.debug("List newly created vm") + cmd = ("uvt-kvm list") + if not self.run_command(cmd): + return False + + logging.debug("Verify VM was created with ssh") + if not self.run_command('uvt-kvm ssh {}'.format(self.name)): + return False + + logging.debug("Verify VM was created with ssh and run a command") + if not self.run_command('uvt-kvm ssh {} \"lsb_release -a \"' + .format(self.name)): + return False + + return True + + class LXDTest(object): def __init__(self, template=None, rootfs=None): @@ -696,6 +813,24 @@ class LXDTest(object): return True +def test_uvtkvm(args): + logging.debug("Executing UVT KVM Test") + + image = args.image or os.environ['UVT_IMAGE_OR_SOURCE'] + + uvt_test = UVTKVMTest(image) + uvt_test.get_image_or_source() + result = uvt_test.start() + uvt_test.cleanup() + + if result: + print("PASS: VM was succssfully started and checked") + sys.exit(0) + else: + print("FAIL: VM was not started and/or checked") + sys.exit(1) + + def test_lxd(args): logging.debug("Executing LXD Test") @@ -770,6 +905,8 @@ def main(): # Main cli options kvm_test_parser = subparsers.add_parser( 'kvm', help=("Run kvm virtualization test")) + uvt_kvm_test_parser = subparsers.add_parser( + 'uvt', help=("Run uvt kvm virtualization test")) lxd_test_parser = subparsers.add_parser( 'lxd', help=("Run the LXD validation test")) parser.add_argument('--debug', dest='log_level', @@ -786,6 +923,11 @@ def main(): help="Location for debugging output log. Defaults to %(default)s.") kvm_test_parser.set_defaults(func=test_kvm) + # Sub test options + uvt_kvm_test_parser.add_argument( + '-i', '--image', type=str) + uvt_kvm_test_parser.set_defaults(func=test_uvtkvm) + lxd_test_parser.add_argument( '--template', type=str, default=None) lxd_test_parser.add_argument( diff --git a/units/virtualization/jobs.pxu b/units/virtualization/jobs.pxu index 9471031..2b6fd99 100644 --- a/units/virtualization/jobs.pxu +++ b/units/virtualization/jobs.pxu @@ -2,13 +2,13 @@ plugin: shell category_id: com.canonical.plainbox::virtualization id: virtualization/kvm_check_vm user: root -environ: KVM_TIMEOUT KVM_IMAGE http_proxy https_proxy +environ: UVT_IMAGE_OR_SOURCE http_proxy https_proxy estimated_duration: 300.0 requires: - package.name == 'qemu-system' - package.name == 'qemu-utils' + package.name == 'uvtool' + package.name == 'uvtool-libvirt' virtualization.kvm == 'supported' -command: virtualization.py --debug kvm --log-file="$PLAINBOX_SESSION_SHARE"/virt_debug +command: virtualization.py --debug uvt _description: Verifies that a KVM guest can be created and booted using an Ubuntu Server cloud image. -- cgit v1.2.3