summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunar Borge <runar@borge.nu>2019-09-23 21:33:58 +0200
committerRunar Borge <runar@borge.nu>2019-09-23 21:33:58 +0200
commit3258d73399c8426c5c28711b93e87c4f6c8f89de (patch)
treee55c36e567e0a66ca25e0b8cbdf0e2fe3b32b039
parent1b3c234f214767df6e7208576fb9ab52e8ec9151 (diff)
downloadvyos-build-3258d73399c8426c5c28711b93e87c4f6c8f89de.tar.gz
vyos-build-3258d73399c8426c5c28711b93e87c4f6c8f89de.zip
Add script to check installation iso with qemu
This script installs a system on a emulated qemu host to verify that the iso produced is installable and boots. After the iso is booted from disk it also tries to execute the vyos-smoketest script to verify checks there.
-rwxr-xr-xscripts/check-qemu-install349
1 files changed, 349 insertions, 0 deletions
diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install
new file mode 100755
index 00000000..688aa556
--- /dev/null
+++ b/scripts/check-qemu-install
@@ -0,0 +1,349 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019, VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# File: check-qemu-install
+# Purpose:
+# This script installs a system on a emulated qemu host to verify
+# that the iso produced is installable and boots.
+# after the iso is booted from disk it also tries to execute the
+# vyos-smoketest script to verify checks there.
+#
+# For now it will not fail on failed smoketest but will fail on
+# install and boot errors.
+# Arguments:
+# iso iso image to install
+# [disk] disk filename to use, if none is provided it
+# is autogenerated
+# [--keep] Keep the disk image after completion
+# [--logfile] name of logfile to save, defaulting to stdout
+# [--silent] only print on errors
+# [--debug] print all communication with the device
+
+
+import pexpect
+import sys
+import os
+import time
+import argparse
+import subprocess
+import random
+import traceback
+import logging
+import re
+from io import BytesIO, StringIO
+from datetime import datetime
+
+EXCEPTION = 0
+now = datetime.now()
+
+
+parser = argparse.ArgumentParser(description='Install and start a test VyOS vm.')
+parser.add_argument('iso', help='ISO file to install')
+parser.add_argument('disk', help='name of disk image file',
+ nargs='?',
+ default='testinstall-{}-{}.img'.format(now.strftime('%Y%m%d-%H%M%S'),
+ "%04x" % random.randint(0,65535)))
+parser.add_argument('--keep', help='Do not remove disk-image after installation',
+ action='store_true',
+ default=False)
+parser.add_argument('--silent', help='Do not show output on stdout unless an error has occured',
+ action='store_true',
+ default=False)
+parser.add_argument('--debug', help='Send all debug output to stdout',
+ action='store_true',
+ default=False)
+parser.add_argument('--logfile', help='Log to file')
+
+args = parser.parse_args()
+
+class StreamToLogger(object):
+ """
+ Fake file-like stream object that redirects writes to a logger instance.
+ """
+ def __init__(self, logger, log_level=logging.INFO):
+ self.logger = logger
+ self.log_level = log_level
+ self.linebuf = b''
+ self.ansi_escape = re.compile(r'\x1B[@-_][0-?]*[ -/]*[@-~]')
+
+ def write(self, buf):
+ self.linebuf += buf
+ #print('.')
+ while b'\n' in self.linebuf:
+ f = self.linebuf.split(b'\n', 1)
+ if len(f) == 2:
+ self.logger.debug(self.ansi_escape.sub('', f[0].decode(errors="replace").rstrip()))
+ self.linebuf = f[1]
+ #print(f)
+
+
+ def flush(self):
+ pass
+
+
+# Setting up logger
+log = logging.getLogger()
+log.setLevel(logging.DEBUG)
+
+stl = StreamToLogger(log)
+formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+
+handler = logging.StreamHandler(sys.stdout)
+if args.silent:
+ handler.setLevel(logging.ERROR)
+elif args.debug:
+ handler.setLevel(logging.DEBUG)
+else:
+ handler.setLevel(logging.INFO)
+
+handler.setFormatter(formatter)
+log.addHandler(handler)
+
+
+if args.logfile:
+ filehandler = logging.FileHandler(args.logfile)
+ filehandler.setLevel(logging.DEBUG)
+ filehandler.setFormatter(formatter)
+ log.addHandler(filehandler)
+
+
+
+if args.silent:
+ output = BytesIO()
+else:
+ output = sys.stdout.buffer
+
+if not os.path.isfile(args.iso):
+ log.error("Unable to find iso image to install")
+ sys.exit(1)
+
+
+# Creating diskimage!!
+
+if not os.path.isfile(args.disk):
+ log.info("Creating Disk image {}".format(args.disk))
+ c = subprocess.check_output(["qemu-img", "create", args.disk, "2G"])
+ log.debug(c.decode())
+else:
+ log.info("Diskimage already exists, using the existing one")
+
+
+
+try:
+ #################################################
+ # Installing image to disk
+ #################################################
+ log.info("Installing system")
+
+ cmd = """qemu-system-x86_64 \
+ -name "TESTVM" \
+ -m 1G \
+ -nic user,model=virtio,mac=52:54:99:12:34:56,hostfwd=tcp::2299-:22 \
+ -machine accel=kvm \
+ -cpu host -smp 2 \
+ -vnc 0.0.0.0:99 \
+ -nographic \
+ -boot d -cdrom {CD} \
+ -drive format=raw,file={DISK}
+ """.format(CD=args.iso, DISK=args.disk)
+ log.debug("Executing command: {}".format(cmd))
+ c = pexpect.spawn(cmd, logfile=stl)
+
+ #################################################
+ # Logging into VyOS system
+ #################################################
+ try:
+ c.expect('Automatic boot in', timeout=10)
+ c.sendline('')
+ except pexpect.TIMEOUT:
+ log.warning("Did not find grub countdown window, ignoring")
+
+ log.info('Waiting for login prompt')
+ c.expect('[Ll]ogin:', timeout=120)
+ c.sendline('vyos')
+ c.expect('[Pp]assword:', timeout=10)
+ c.sendline('vyos')
+ c.expect(r'vyos@vyos:~\$')
+ log.info('Logged in!')
+
+
+ #################################################
+ # Installing into VyOS system
+ #################################################
+ log.info("Starting installer")
+ c.sendline('install image')
+ c.expect('\nWould you like to continue?.*:')
+ c.sendline('yes')
+ log.info("Partitioning disk")
+ c.expect('\nPartition.*:')
+ c.sendline('')
+ c.expect('\nInstall the image on.*:')
+ c.sendline('')
+ c.expect(r'\nContinue\?.*:')
+ c.sendline('Yes')
+ c.expect('\nHow big of a root partition should I create?.*:')
+ c.sendline('')
+ log.info('Disk partitioned, installing')
+ c.expect('\nWhat would you like to name this image?.*:')
+ c.sendline('')
+ log.info('Copying files')
+ c.expect('\nWhich one should I copy to.*:', timeout=300)
+ c.sendline('')
+ log.info('Files Copied!')
+ c.expect('\nEnter password for user.*:')
+ c.sendline('vyos')
+ c.expect('\nRetype password for user.*:')
+ c.sendline('vyos')
+ c.expect('\nWhich drive should GRUB modify the boot partition on.*:')
+ c.sendline('')
+ c.expect(r'\nvyos@vyos:~\$')
+ log.info('system installed, shutting down')
+
+ #################################################
+ # Powering down installer
+ #################################################
+ log.info("Shutting down installation system")
+ c.sendline('poweroff')
+ c.expect(r'\nAre you sure you want to poweroff this system.*\]')
+ c.sendline('Y')
+ for i in range(30):
+ log.info("Waiting for shutdown...")
+ if not c.isalive():
+ log.info("VM is shut down!")
+ break
+ time.sleep(10)
+ else:
+ log.error("VM Did not shut down after 300sec, killing")
+ c.close()
+
+
+ #################################################
+ # Booting installed system
+ #################################################
+ log.info("Booting installed system")
+
+ cmd = """qemu-system-x86_64 \
+ -name "TESTVM" \
+ -m 1G \
+ -nic user,model=virtio,mac=52:54:99:12:34:56,hostfwd=tcp::2299-:22
+ -machine accel=kvm \
+ -cpu host -smp 2 \
+ -vnc 0.0.0.0:99 \
+ -nographic \
+ -drive format=raw,file={DISK}
+ """.format(DISK=args.disk)
+
+ log.debug('Executing command: {}'.format(cmd))
+ c = pexpect.spawn(cmd, logfile=stl)
+
+ #################################################
+ # Logging into VyOS system
+ #################################################
+ try:
+ c.expect('The highlighted entry will be executed automatically in', timeout=10)
+ c.sendline('')
+ except pexpect.TIMEOUT:
+ log.warning("Did not find grub countdown window, ignoring")
+
+ log.info('Waiting for login prompt')
+ c.expect('[Ll]ogin:', timeout=120)
+ c.sendline('vyos')
+ c.expect('[Pp]assword:', timeout=10)
+ c.sendline('vyos')
+ c.expect(r'vyos@vyos:~\$')
+ log.info('Logged in!')
+
+
+
+ #################################################
+ # Executing test-suite
+ #################################################
+ log.info("Executing test-suite ")
+
+ def cr(child, command):
+ child.sendline(command)
+ i = child.expect(['\n +Invalid command:',
+ '\n +Set failed',
+ 'No such file or directory',
+ r'\n\S+@\S+[$#]'])
+
+ if i==0:
+ raise Exception('Invalid command detected')
+ elif i==1:
+ raise Exception('Set syntax failed :/')
+ elif i==2:
+ log.error("Did not find VyOS-smoketest, this should be an exception")
+ #raise Exception("WTF? did not find VyOS-smoketest, this should be an exception")
+ cr(c, '/usr/bin/vyos-smoketest')
+
+ log.info("Smoke test status")
+ #data = c.before.decode()
+
+ #################################################
+ # Powering off system
+ #################################################
+ log.info("Powering off system ")
+ c.sendline('poweroff')
+ c.expect(r'\nAre you sure you want to poweroff this system.*\]')
+ c.sendline('Y')
+ log.info("Shutting down virtual machine")
+ for i in range(30):
+ log.info("Waiting for shutdown...")
+ if not c.isalive():
+ log.info("VM is shut down!")
+ break
+ time.sleep(10)
+ else:
+ log.error("VM Did not shut down after 300sec")
+ raise Exception("VM Did not shut down after 300sec")
+ c.close()
+
+except pexpect.exceptions.TIMEOUT:
+ log.error("Timeout waiting for VyOS system")
+ log.error(traceback.format_exc())
+ EXCEPTION = 1
+
+except pexpect.exceptions.ExceptionPexpect:
+ log.error("Exeption while executing QEMU")
+ log.error("Is qemu working on this system?")
+ log.error(traceback.format_exc())
+ EXCEPTION = 1
+
+except Exception:
+ log.error("An unknown error occured when installing the VyOS system")
+ traceback.print_exc()
+ EXCEPTION = 1
+
+
+
+#################################################
+# Cleaning up
+#################################################
+log.info("Cleaning up")
+
+if not args.keep:
+ log.info("Removing disk file: {}".format(args.disk))
+ try:
+ os.remove(args.disk)
+ except Exception:
+ log.error("Exception while removing diskimage")
+ log.error(traceback.format_exc())
+ EXCEPTION = 1
+
+if EXCEPTION:
+ log.error("Hmm... System got an exception while processing")
+ log.error("The ISO is not considered usable")
+ sys.exit(1)