diff options
author | Jeff Lane <jeffrey.lane@canonical.com> | 2016-10-20 18:01:12 -0400 |
---|---|---|
committer | Jeff Lane <jeffrey.lane@canonical.com> | 2016-10-20 18:01:12 -0400 |
commit | 01e7136418d3d64ea06265b340e33161197f7305 (patch) | |
tree | 14109f56f4b60d3c7c99d5aed55a05a409d7b19d /bin | |
parent | 5c5b246ca2d57393c877f7bfd71325969f3439fc (diff) |
bin/virtualization: change how URLs are constructed. Add URL validation testing. Imporve debug output. Now handles both older and newer cloud image naming schemas LP: #1635345
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/virtualization | 123 |
1 files changed, 92 insertions, 31 deletions
diff --git a/bin/virtualization b/bin/virtualization index fe59656..2b0fe68 100755 --- a/bin/virtualization +++ b/bin/virtualization @@ -8,6 +8,7 @@ Copyright (C) 2013, 2014 Canonical Ltd. Authors Jeff Marcom <jeff.marcom@canonical.com> Daniel Manrique <roadmr@ubuntu.com> + Jeff Lane <jeff@ubuntu.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, @@ -30,6 +31,7 @@ import os import re import logging import lsb_release +import requests import shlex import signal from subprocess import ( @@ -214,49 +216,104 @@ class KVMTest(object): # Gives us the stuff needed to build the URL to download the image return self.download_image(image_path) - def construct_cloud_filename(self): + def construct_cloud_url(self, image_url=None): """ Build a URL for official Ubuntu images hosted either at cloud-images.ubuntu.com or on a maas server hosting a mirror of cloud-images.ubuntu.com """ - if self.qemu_config['cloudimg_type'] == CLOUD_IMAGE_TYPE_TAR: - cloud_iso = "%s-server-cloudimg-%s.tar.gz" % ( - self.release, self.qemu_config['cloudimg_arch']) - elif self.qemu_config['cloudimg_type'] == CLOUD_IMAGE_TYPE_DISK: - cloud_iso = "%s-server-cloudimg-%s-disk1.img" % ( - self.release, self.qemu_config['cloudimg_arch']) - else: - logging.error("Unknown cloud image type") - sys.exit(1) - return cloud_iso - - def download_image(self, image_url=None): - """ - Downloads Cloud image for same release as host machine - """ + def _construct_filename(alt_pattern=None): + if self.qemu_config['cloudimg_type'] == CLOUD_IMAGE_TYPE_TAR: + cloud_iso = "%s-server-cloudimg-%s.tar.gz" % ( + self.release, self.qemu_config['cloudimg_arch']) + elif alt_pattern is "modern": + # LP 1635345 - yakkety and beyond have a new naming scheme + cloud_iso = "%s-server-cloudimg-%s.img" % ( + self.release, self.qemu_config['cloudimg_arch']) + elif self.qemu_config['cloudimg_type'] == CLOUD_IMAGE_TYPE_DISK: + cloud_iso = "%s-server-cloudimg-%s-disk1.img" % ( + self.release, self.qemu_config['cloudimg_arch']) + else: + logging.error("Unknown cloud image type") + sys.exit(1) + + return cloud_iso + + def _construct_url(initial_url, cloud_iso): + return "/".join((initial_url, cloud_iso)) + + def _test_cloud_url(url): + # test our URL to make sure it's reachable + ret = requests.head(url) + if ret.status_code is not 200: + return False + else: + return True + if image_url is None: # If we have not specified a URL to get our images from, default # to ubuntu.com - cloud_url = "http://cloud-images.ubuntu.com" - cloud_iso = self.construct_cloud_filename() - full_url = "/".join(( - cloud_url, self.release, "current", cloud_iso)) + cloud_iso = _construct_filename() + initial_url = "/".join(("http://cloud-images.ubuntu.com", + self.release, "current")) + full_url = _construct_url(initial_url, cloud_iso) + # Test our URL and rebuild with alternate name + if not _test_cloud_url(full_url): + logging.warn("Cloud Image URL not valid: %s" % full_url) + logging.warn(" * This means we could not reach the remote file. " + "We'll now try with a different filename schema.") + cloud_iso = _construct_filename("modern") + full_url = _construct_url(initial_url, cloud_iso) + # retest one more time then exit if it still fails + if not _test_cloud_url(full_url): + logging.error("Cloud URL is not valid: %s" % + full_url) + logging.error(" * It appears that there is a problem " + "finding the expected file. Check the URL " + "noted above.") + sys.exit(1) + else: return full_url + else: return full_url else: url = urlparse(image_url) - if url.path.endswith('/') or url.path == '': - # If we have a relative URL (MAAS server mirror) - cloud_url = image_url - cloud_iso = self.construct_cloud_filename() - full_url = "/".join(( - cloud_url, cloud_iso)) + if url.path.endswith('/') or url.path == '' or not url.path.endswith(".img"): + # If we have a relative URL (local copies of official images) + # http://192.168.0.1/ or http://192.168.0.1/images/ + cloud_iso = _construct_filename() + full_url = _construct_url(image_url.rstrip("/"), cloud_iso) + if not _test_cloud_url(full_url): + logging.warn("Cloud Image URL not valid: %s" % full_url) + logging.warn(" * This means we could not reach the remote file. " + "We'll now try with a different filename schema.") + cloud_iso = _construct_filename("modern") + full_url = _construct_url(image_url.rstrip("/"), cloud_iso) + if not _test_cloud_url(full_url): + logging.error("Cloud URL is not valid: %s" % + full_url) + logging.error(" * It appears that there is a problem " + "finding the expected file. Check the " + "URL noted above.") + sys.exit(1) + else: return full_url + else: return full_url else: # Assume anything else is an absolute URL to a remote server - cloud_iso = url.path.split('/')[-1] - cloud_url = "{}://{}".format(url.scheme, url.netloc) - full_url = image_url - logging.debug("Downloading {}, from {}".format(cloud_iso, cloud_url)) + if not _test_cloud_url(image_url): + logging.error("Cloud Image URL invalid: %s" % image_url) + logging.error(" * Check the URL and ensure it is correct") + sys.exit(1) + else: return image_url + def download_image(self, image_url=None): + """ + Downloads Cloud image for same release as host machine + """ + if image_url is None: + full_url = self.construct_cloud_url() + else: + full_url = self.construct_cloud_url(image_url) + logging.debug("Acquiring cloud image from: {}".format(full_url)) + # Attempt download try: resp = urllib.request.urlretrieve(full_url, cloud_iso) @@ -394,7 +451,7 @@ final_message: CERTIFICATION BOOT COMPLETE # Download cloud image self.image = self.download_image() else: - logging.debug('Cloud image location specified: %s.' % + logging.debug('Cloud image location specified: %s' % self.image) self.image = self.url_to_path(self.image) @@ -506,6 +563,10 @@ def main(): logging.basicConfig(level=args.log_level) except AttributeError: pass # avoids exception when trying to run without specifying 'kvm' + + # silence normal output from requests module + logging.getLogger("requests").setLevel(logging.WARNING) + # to check if not len(sys.argv) > 1 if len(vars(args)) == 0: |