Hyper-V: refines the exceptions raised in the driver
The exceptions raised in the HyperVDriver are too generic. This commit addresses this issue. Partially Implements: blueprint add-os-win-library Change-Id: I05f1fa21540dad36bb4b04c8eebe8cc0b8585c1f
This commit is contained in:
		@@ -19,12 +19,12 @@ Module contains helper methods for dealing with block device information
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from nova import block_device
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.virt import configdrive
 | 
			
		||||
from nova.virt import driver
 | 
			
		||||
 | 
			
		||||
from hyperv.i18n import _
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.nova import volumeops
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -86,9 +86,8 @@ class BlockDeviceInfoManager(object):
 | 
			
		||||
            root_disk['type'] = self._TYPE_FOR_DISK_FORMAT.get(
 | 
			
		||||
                image_meta['disk_format'])
 | 
			
		||||
            if root_disk['type'] is None:
 | 
			
		||||
                msg = _("Hyper-V driver does not support image type "
 | 
			
		||||
                        "%s.") % image_meta['disk_format']
 | 
			
		||||
                raise vmutils.HyperVException(msg)
 | 
			
		||||
                raise exception.InvalidDiskFormat(
 | 
			
		||||
                    disk_format=image_meta['disk_format'])
 | 
			
		||||
            root_disk['path'] = None
 | 
			
		||||
            root_disk['connection_info'] = None
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +114,7 @@ class BlockDeviceInfoManager(object):
 | 
			
		||||
 | 
			
		||||
        msg = _("There are no more free slots on controller %s"
 | 
			
		||||
                ) % controller_type
 | 
			
		||||
        raise vmutils.HyperVException(msg)
 | 
			
		||||
        raise exception.Invalid(msg)
 | 
			
		||||
 | 
			
		||||
    def is_boot_from_volume(self, block_device_info):
 | 
			
		||||
        if block_device_info:
 | 
			
		||||
@@ -156,7 +155,7 @@ class BlockDeviceInfoManager(object):
 | 
			
		||||
                    "for generation %(vm_gen)s instances."
 | 
			
		||||
                    ) % {'disk_bus': disk_bus,
 | 
			
		||||
                         'vm_gen': vm_gen}
 | 
			
		||||
            raise vmutils.HyperVException(msg)
 | 
			
		||||
            raise exception.InvalidDiskInfo(reason=msg)
 | 
			
		||||
 | 
			
		||||
        device_type = bdm.get('device_type')
 | 
			
		||||
        if not device_type:
 | 
			
		||||
@@ -164,7 +163,7 @@ class BlockDeviceInfoManager(object):
 | 
			
		||||
        elif device_type != 'disk':
 | 
			
		||||
            msg = _("Hyper-V does not support disk type %s for ephemerals "
 | 
			
		||||
                    "or volumes.") % device_type
 | 
			
		||||
            raise vmutils.HyperVException(msg)
 | 
			
		||||
            raise exception.InvalidDiskInfo(reason=msg)
 | 
			
		||||
 | 
			
		||||
        (bdm['drive_addr'],
 | 
			
		||||
         bdm['ctrl_disk_addr']) = self._get_available_controller_slot(
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ A Hyper-V Nova Compute driver.
 | 
			
		||||
 | 
			
		||||
import platform
 | 
			
		||||
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.virt import driver
 | 
			
		||||
from oslo_log import log as logging
 | 
			
		||||
from oslo_utils import excutils
 | 
			
		||||
@@ -34,7 +35,6 @@ from hyperv.nova import rdpconsoleops
 | 
			
		||||
from hyperv.nova import serialconsoleops
 | 
			
		||||
from hyperv.nova import snapshotops
 | 
			
		||||
from hyperv.nova import vmops
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.nova import volumeops
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
@@ -69,12 +69,11 @@ class HyperVDriver(driver.ComputeDriver):
 | 
			
		||||
            # the version is of Windows is older than Windows Server 2012 R2.
 | 
			
		||||
            # Log an error, lettingusers know that this version is not
 | 
			
		||||
            # supported any longer.
 | 
			
		||||
            err_msg = _LE('You are running nova-compute on an unsupported '
 | 
			
		||||
            LOG.error(_LE('You are running nova-compute on an unsupported '
 | 
			
		||||
                          'version of Windows (older than Windows / Hyper-V '
 | 
			
		||||
                          'Server 2012). The support for this version of '
 | 
			
		||||
                          'Windows has been removed in Mitaka.')
 | 
			
		||||
            LOG.error(err_msg)
 | 
			
		||||
            raise vmutils.HyperVException(err_msg)
 | 
			
		||||
                          'Windows has been removed in Mitaka.'))
 | 
			
		||||
            raise exception.HypervisorTooOld(version='6.2')
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def need_legacy_block_device_info(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,6 @@ from hyperv.i18n import _, _LE, _LI
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import utilsfactory
 | 
			
		||||
from hyperv.nova import vmops
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
 | 
			
		||||
hyper_host_opts = [
 | 
			
		||||
    cfg.IntOpt('evacuate_task_state_timeout',
 | 
			
		||||
@@ -270,8 +269,8 @@ class HostOps(object):
 | 
			
		||||
            LOG.info(_LI('All vms have been migrated successfully.'
 | 
			
		||||
                         'Host is down for maintenance'))
 | 
			
		||||
            return 'on_maintenance'
 | 
			
		||||
        raise vmutils.HyperVException(
 | 
			
		||||
            _('Not all vms have been migrated: %s remaining instances.')
 | 
			
		||||
        raise exception.MigrationError(
 | 
			
		||||
            reason=_('Not all vms have been migrated: %s remaining instances.')
 | 
			
		||||
            % remaining_vms)
 | 
			
		||||
 | 
			
		||||
    def _set_service_state(self, host, binary, is_disabled):
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ Image caching and management.
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova import utils
 | 
			
		||||
from nova.virt import imagecache
 | 
			
		||||
from nova.virt import images
 | 
			
		||||
@@ -29,7 +30,6 @@ from oslo_utils import uuidutils
 | 
			
		||||
 | 
			
		||||
from hyperv.i18n import _
 | 
			
		||||
from hyperv.nova import utilsfactory
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
@@ -78,12 +78,8 @@ class ImageCache(imagecache.ImageCacheManager):
 | 
			
		||||
                    vhd_path, root_vhd_size))
 | 
			
		||||
 | 
			
		||||
        if root_vhd_internal_size < vhd_size:
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
                _("Cannot resize the image to a size smaller than the VHD "
 | 
			
		||||
                  "max. internal size: %(vhd_size)s. Requested disk size: "
 | 
			
		||||
                  "%(root_vhd_size)s") %
 | 
			
		||||
                {'vhd_size': vhd_size, 'root_vhd_size': root_vhd_size}
 | 
			
		||||
            )
 | 
			
		||||
            raise exception.FlavorDiskSmallerThanImage(
 | 
			
		||||
                flavor_size=root_vhd_size, image_size=vhd_size)
 | 
			
		||||
        if root_vhd_internal_size > vhd_size:
 | 
			
		||||
            path_parts = os.path.splitext(vhd_path)
 | 
			
		||||
            resized_vhd_path = '%s_%s%s' % (path_parts[0],
 | 
			
		||||
@@ -179,7 +175,7 @@ class ImageCache(imagecache.ImageCacheManager):
 | 
			
		||||
                        'Rescue image size: %(rescue_image_size)s. '
 | 
			
		||||
                        'Flavor disk size:%(flavor_disk_size)s. '
 | 
			
		||||
                        'Rescue image id %(rescue_image_id)s.')
 | 
			
		||||
            raise vmutils.HyperVException(err_msg %
 | 
			
		||||
            raise exception.FlavorDiskSmallerThanImage(err_msg %
 | 
			
		||||
                {'rescue_image_size': rescue_image_size,
 | 
			
		||||
                 'flavor_disk_size': flavor_disk_size,
 | 
			
		||||
                 'rescue_image_id': rescue_image_id})
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,6 @@ from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import imagecache
 | 
			
		||||
from hyperv.nova import utilsfactory
 | 
			
		||||
from hyperv.nova import vmops
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.nova import volumeops
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
@@ -114,22 +113,22 @@ class MigrationOps(object):
 | 
			
		||||
 | 
			
		||||
        if new_root_gb < curr_root_gb:
 | 
			
		||||
            raise exception.InstanceFaultRollback(
 | 
			
		||||
                vmutils.VHDResizeException(
 | 
			
		||||
                    _("Cannot resize the root disk to a smaller size. "
 | 
			
		||||
                      "Current size: %(curr_root_gb)s GB. Requested size: "
 | 
			
		||||
                      "%(new_root_gb)s GB") %
 | 
			
		||||
                    {'curr_root_gb': curr_root_gb,
 | 
			
		||||
                     'new_root_gb': new_root_gb}))
 | 
			
		||||
                exception.CannotResizeDisk(
 | 
			
		||||
                    reason=_("Cannot resize the root disk to a smaller size. "
 | 
			
		||||
                             "Current size: %(curr_root_gb)s GB. Requested "
 | 
			
		||||
                             "size: %(new_root_gb)s GB.") % {
 | 
			
		||||
                                 'curr_root_gb': curr_root_gb,
 | 
			
		||||
                                 'new_root_gb': new_root_gb}))
 | 
			
		||||
 | 
			
		||||
        if new_eph_gb < curr_eph_gb:
 | 
			
		||||
                raise exception.InstanceFaultRollback(
 | 
			
		||||
                    vmutils.VHDResizeException(
 | 
			
		||||
                        _("Cannot resize the ephemeral disk(s) to a smaller "
 | 
			
		||||
                          "size. Current total ephemeral size: "
 | 
			
		||||
                          "%(curr_eph_gb)s GB. Requested total size: "
 | 
			
		||||
                          "%(new_eph_gb)s GB") %
 | 
			
		||||
                        {'curr_eph_gb': curr_eph_gb,
 | 
			
		||||
                         'new_eph_gb': new_eph_gb}))
 | 
			
		||||
            raise exception.InstanceFaultRollback(
 | 
			
		||||
                exception.CannotResizeDisk(
 | 
			
		||||
                    reason=_("Cannot resize the ephemeral disk(s) to a smaller"
 | 
			
		||||
                             " size. Current total ephemeral size: "
 | 
			
		||||
                             "%(curr_eph_gb)s GB. Requested total size: "
 | 
			
		||||
                             "%(new_eph_gb)s GB") % {
 | 
			
		||||
                                 'curr_eph_gb': curr_eph_gb,
 | 
			
		||||
                                 'new_eph_gb': new_eph_gb}))
 | 
			
		||||
 | 
			
		||||
    def migrate_disk_and_power_off(self, context, instance, dest,
 | 
			
		||||
                                   flavor, network_info,
 | 
			
		||||
@@ -174,9 +173,8 @@ class MigrationOps(object):
 | 
			
		||||
                self._vmops.attach_config_drive(instance, configdrive_path,
 | 
			
		||||
                                                vm_gen)
 | 
			
		||||
            else:
 | 
			
		||||
                raise vmutils.HyperVException(
 | 
			
		||||
                    _("Config drive is required by instance: %s, "
 | 
			
		||||
                      "but it does not exist.") % instance.name)
 | 
			
		||||
                raise exception.ConfigDriveNotFound(
 | 
			
		||||
                    instance_uuid=instance.uuid)
 | 
			
		||||
 | 
			
		||||
    def finish_revert_migration(self, context, instance, network_info,
 | 
			
		||||
                                block_device_info=None, power_on=True):
 | 
			
		||||
@@ -186,7 +184,7 @@ class MigrationOps(object):
 | 
			
		||||
        self._revert_migration_files(instance_name)
 | 
			
		||||
 | 
			
		||||
        image_meta = self._imagecache.get_image_details(context, instance)
 | 
			
		||||
        vm_gen = self._vmops.get_image_vm_generation(image_meta)
 | 
			
		||||
        vm_gen = self._vmops.get_image_vm_generation(instance.uuid, image_meta)
 | 
			
		||||
 | 
			
		||||
        self._block_dev_manager.validate_and_update_bdi(
 | 
			
		||||
            instance, image_meta, vm_gen, block_device_info)
 | 
			
		||||
@@ -196,7 +194,7 @@ class MigrationOps(object):
 | 
			
		||||
            root_device['path'] = self._pathutils.lookup_root_vhd_path(
 | 
			
		||||
                instance_name)
 | 
			
		||||
            if not root_device['path']:
 | 
			
		||||
                raise vmutils.HyperVException(
 | 
			
		||||
                raise exception.DiskNotFound(
 | 
			
		||||
                    _("Cannot find boot VHD file for instance: %s")
 | 
			
		||||
                    % instance_name)
 | 
			
		||||
 | 
			
		||||
@@ -246,8 +244,12 @@ class MigrationOps(object):
 | 
			
		||||
    def _check_resize_vhd(self, vhd_path, vhd_info, new_size):
 | 
			
		||||
        curr_size = vhd_info['MaxInternalSize']
 | 
			
		||||
        if new_size < curr_size:
 | 
			
		||||
            raise vmutils.VHDResizeException(_("Cannot resize a VHD "
 | 
			
		||||
                                               "to a smaller size"))
 | 
			
		||||
            raise exception.CannotResizeDisk(
 | 
			
		||||
                reason=_("Cannot resize the root disk to a smaller size. "
 | 
			
		||||
                         "Current size: %(curr_root_gb)s GB. Requested "
 | 
			
		||||
                         "size: %(new_root_gb)s GB.") % {
 | 
			
		||||
                             'curr_root_gb': curr_size,
 | 
			
		||||
                             'new_root_gb': new_size})
 | 
			
		||||
        elif new_size > curr_size:
 | 
			
		||||
            self._resize_vhd(vhd_path, new_size)
 | 
			
		||||
 | 
			
		||||
@@ -286,7 +288,7 @@ class MigrationOps(object):
 | 
			
		||||
 | 
			
		||||
        instance_name = instance.name
 | 
			
		||||
 | 
			
		||||
        vm_gen = self._vmops.get_image_vm_generation(image_meta)
 | 
			
		||||
        vm_gen = self._vmops.get_image_vm_generation(instance.uuid, image_meta)
 | 
			
		||||
 | 
			
		||||
        self._block_dev_manager.validate_and_update_bdi(
 | 
			
		||||
            instance, image_meta, vm_gen, block_device_info)
 | 
			
		||||
@@ -296,9 +298,9 @@ class MigrationOps(object):
 | 
			
		||||
            root_device['path'] = self._pathutils.lookup_root_vhd_path(
 | 
			
		||||
                instance_name)
 | 
			
		||||
            if not root_device['path']:
 | 
			
		||||
                raise vmutils.HyperVException(_("Cannot find boot VHD "
 | 
			
		||||
                                                "file for instance: %s") %
 | 
			
		||||
                                              instance_name)
 | 
			
		||||
                raise exception.DiskNotFound(_("Cannot find boot VHD "
 | 
			
		||||
                                               "file for instance: %s") %
 | 
			
		||||
                                             instance_name)
 | 
			
		||||
 | 
			
		||||
            root_vhd_info = self._vhdutils.get_vhd_info(root_device['path'])
 | 
			
		||||
            src_base_disk_path = root_vhd_info.get("ParentPath")
 | 
			
		||||
@@ -332,9 +334,9 @@ class MigrationOps(object):
 | 
			
		||||
                instance_name, eph_name)
 | 
			
		||||
 | 
			
		||||
            if not eph['path'] and not resize_instance:
 | 
			
		||||
                raise vmutils.HyperVException(_("Cannot find ephemeral VHD "
 | 
			
		||||
                                                "file for instance: %s") %
 | 
			
		||||
                                              instance_name)
 | 
			
		||||
                raise exception.DiskNotFound(_("Cannot find ephemeral VHD "
 | 
			
		||||
                                               "file for instance: %s") %
 | 
			
		||||
                                             instance_name)
 | 
			
		||||
            if resize_instance and not eph['path'] and new_eph_gb:
 | 
			
		||||
                eph['format'] = (
 | 
			
		||||
                    self._vhdutils.get_best_supported_vhd_format())
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ import time
 | 
			
		||||
if sys.platform == 'win32':
 | 
			
		||||
    import wmi
 | 
			
		||||
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova import utils
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
from oslo_log import log as logging
 | 
			
		||||
@@ -166,7 +167,7 @@ class PathUtils(object):
 | 
			
		||||
            return path
 | 
			
		||||
        except WindowsError as ex:
 | 
			
		||||
            if ex.winerror == ERROR_INVALID_NAME:
 | 
			
		||||
                raise vmutils.HyperVException(_(
 | 
			
		||||
                raise exception.AdminRequired(_(
 | 
			
		||||
                    "Cannot access \"%(instances_path)s\", make sure the "
 | 
			
		||||
                    "path exists and that you have the proper permissions. "
 | 
			
		||||
                    "In particular Nova-Compute must not be executed with the "
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ from hyperv.nova import ioutils
 | 
			
		||||
from hyperv.nova import namedpipe
 | 
			
		||||
from hyperv.nova import serialproxy
 | 
			
		||||
from hyperv.nova import utilsfactory
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
@@ -139,7 +138,7 @@ class SerialConsoleHandler(object):
 | 
			
		||||
        if not serial_port_conns:
 | 
			
		||||
            err_msg = _("No suitable serial port pipe was found "
 | 
			
		||||
                        "for instance %(instance_name)s")
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
            raise exception.NovaException(
 | 
			
		||||
                err_msg % {'instance_name': self._instance_name})
 | 
			
		||||
 | 
			
		||||
        serial_port_mapping = {}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,14 +17,14 @@ import functools
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.i18n import _, _LI, _LE  # noqa
 | 
			
		||||
from nova.i18n import _LI, _LE  # noqa
 | 
			
		||||
from nova import utils
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
from oslo_log import log as logging
 | 
			
		||||
import six
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import serialconsolehandler
 | 
			
		||||
from hyperv.nova import utilsfactory
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
 | 
			
		||||
@@ -101,11 +101,8 @@ class SerialConsoleOps(object):
 | 
			
		||||
                        log += fp.read()
 | 
			
		||||
            return log
 | 
			
		||||
        except IOError as err:
 | 
			
		||||
            msg = (_("Could not get instance %(instance_name)s "
 | 
			
		||||
                     "console output. Error: %(err)s") %
 | 
			
		||||
                   {'instance_name': instance_name,
 | 
			
		||||
                    'err': err})
 | 
			
		||||
            raise vmutils.HyperVException(msg)
 | 
			
		||||
            raise exception.ConsoleLogOutputException(
 | 
			
		||||
                instance_id=instance_name, reason=six.text_type(err))
 | 
			
		||||
 | 
			
		||||
    def start_console_handlers(self):
 | 
			
		||||
        active_instances = self._vmutils.get_active_instances()
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,10 @@ from eventlet import patcher
 | 
			
		||||
import functools
 | 
			
		||||
import socket
 | 
			
		||||
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.i18n import _
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
 | 
			
		||||
threading = patcher.original('threading')
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +69,7 @@ class SerialProxy(threading.Thread):
 | 
			
		||||
                   {'addr': self._addr, 'port': self._port,
 | 
			
		||||
                    'instance_name': self._instance_name,
 | 
			
		||||
                    'error': err})
 | 
			
		||||
            raise vmutils.HyperVException(msg)
 | 
			
		||||
            raise exception.NovaException(msg)
 | 
			
		||||
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        self._stopped.set()
 | 
			
		||||
 
 | 
			
		||||
@@ -172,7 +172,7 @@ class VMOps(object):
 | 
			
		||||
        path = None
 | 
			
		||||
        if root_disk_info['type'] == constants.DISK:
 | 
			
		||||
            path = self._create_root_vhd(context, instance)
 | 
			
		||||
            self.check_vm_image_type(vm_gen, path)
 | 
			
		||||
            self.check_vm_image_type(instance.uuid, vm_gen, path)
 | 
			
		||||
        elif root_disk_info['type'] == constants.DVD:
 | 
			
		||||
            path = self._create_root_iso(context, instance)
 | 
			
		||||
        root_disk_info['path'] = path
 | 
			
		||||
@@ -249,12 +249,8 @@ class VMOps(object):
 | 
			
		||||
 | 
			
		||||
    def _is_resize_needed(self, vhd_path, old_size, new_size, instance):
 | 
			
		||||
        if new_size < old_size:
 | 
			
		||||
            error_msg = _("Cannot resize a VHD to a smaller size, the"
 | 
			
		||||
                          " original size is %(old_size)s, the"
 | 
			
		||||
                          " newer size is %(new_size)s"
 | 
			
		||||
                          ) % {'old_size': old_size,
 | 
			
		||||
                               'new_size': new_size}
 | 
			
		||||
            raise vmutils.VHDResizeException(error_msg)
 | 
			
		||||
            raise exception.FlavorDiskSmallerThanImage(
 | 
			
		||||
                flavor_size=new_size, image_size=old_size)
 | 
			
		||||
        elif new_size > old_size:
 | 
			
		||||
            LOG.debug("Resizing VHD %(vhd_path)s to new "
 | 
			
		||||
                      "size %(new_size)s" %
 | 
			
		||||
@@ -296,7 +292,7 @@ class VMOps(object):
 | 
			
		||||
        # Make sure we're starting with a clean slate.
 | 
			
		||||
        self._delete_disk_files(instance_name)
 | 
			
		||||
 | 
			
		||||
        vm_gen = self.get_image_vm_generation(image_meta)
 | 
			
		||||
        vm_gen = self.get_image_vm_generation(instance.uuid, image_meta)
 | 
			
		||||
 | 
			
		||||
        self._block_device_manager.validate_and_update_bdi(
 | 
			
		||||
            instance, image_meta, vm_gen, block_device_info)
 | 
			
		||||
@@ -322,12 +318,13 @@ class VMOps(object):
 | 
			
		||||
            with excutils.save_and_reraise_exception():
 | 
			
		||||
                self.destroy(instance)
 | 
			
		||||
 | 
			
		||||
    def _requires_certificate(self, image_meta):
 | 
			
		||||
    def _requires_certificate(self, instance_id, image_meta):
 | 
			
		||||
        os_type = image_meta.get('properties', {}).get('os_type', None)
 | 
			
		||||
        if not os_type:
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
                _('For secure boot, os_type must be specified in image '
 | 
			
		||||
                  'properties.'))
 | 
			
		||||
            reason = _('For secure boot, os_type must be specified in image '
 | 
			
		||||
                       'properties.')
 | 
			
		||||
            raise exception.InstanceUnacceptable(instance_id=instance_id,
 | 
			
		||||
                                                 reason=reason)
 | 
			
		||||
        elif os_type == 'windows':
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
@@ -349,7 +346,10 @@ class VMOps(object):
 | 
			
		||||
        else:
 | 
			
		||||
            requires_secure_boot = image_prop_secure_boot == constants.REQUIRED
 | 
			
		||||
        if vm_gen != constants.VM_GEN_2 and requires_secure_boot:
 | 
			
		||||
            raise vmutils.HyperVException(_('Secure boot requires gen 2 VM.'))
 | 
			
		||||
 | 
			
		||||
            reason = _('Secure boot requires generation 2 VM.')
 | 
			
		||||
            raise exception.InstanceUnacceptable(instance_id=instance.uuid,
 | 
			
		||||
                                                 reason=reason)
 | 
			
		||||
        return requires_secure_boot
 | 
			
		||||
 | 
			
		||||
    def create_instance(self, instance, network_info, root_device,
 | 
			
		||||
@@ -391,9 +391,10 @@ class VMOps(object):
 | 
			
		||||
                constants.FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY)
 | 
			
		||||
        if remote_fx_config:
 | 
			
		||||
            if vm_gen == constants.VM_GEN_2:
 | 
			
		||||
                raise vmutils.HyperVException(_("RemoteFX is not supported "
 | 
			
		||||
                                                "on generation 2 virtual "
 | 
			
		||||
                                                "machines."))
 | 
			
		||||
                reason = _("RemoteFX is not supported on generation 2 virtual "
 | 
			
		||||
                           "machines.")
 | 
			
		||||
                raise exception.InstanceUnacceptable(instance_id=instance.uuid,
 | 
			
		||||
                                                     reason=reason)
 | 
			
		||||
            else:
 | 
			
		||||
                self._configure_remotefx(instance, remote_fx_config)
 | 
			
		||||
 | 
			
		||||
@@ -452,36 +453,33 @@ class VMOps(object):
 | 
			
		||||
            self._vmutils.attach_ide_drive(instance_name, path, drive_addr,
 | 
			
		||||
                                           ctrl_disk_addr, drive_type)
 | 
			
		||||
 | 
			
		||||
    def get_image_vm_generation(self, image_meta):
 | 
			
		||||
    def get_image_vm_generation(self, instance_id, image_meta):
 | 
			
		||||
        image_props = image_meta['properties']
 | 
			
		||||
        default_vm_gen = self._hostutils.get_default_vm_generation()
 | 
			
		||||
        image_prop_vm = image_props.get(constants.IMAGE_PROP_VM_GEN,
 | 
			
		||||
                                        default_vm_gen)
 | 
			
		||||
        if image_prop_vm not in self._hostutils.get_supported_vm_types():
 | 
			
		||||
            LOG.error(_LE('Requested VM Generation %s is not supported on '
 | 
			
		||||
                         ' this OS.'), image_prop_vm)
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
                _('Requested VM Generation %s is not supported on this '
 | 
			
		||||
                  'OS.') % image_prop_vm)
 | 
			
		||||
            reason = _LE('Requested VM Generation %s is not supported on '
 | 
			
		||||
                         'this OS.') % image_prop_vm
 | 
			
		||||
            raise exception.InstanceUnacceptable(instance_id=instance_id,
 | 
			
		||||
                                                 reason=reason)
 | 
			
		||||
 | 
			
		||||
        return VM_GENERATIONS[image_prop_vm]
 | 
			
		||||
 | 
			
		||||
    def check_vm_image_type(self, vm_gen, root_vhd_path):
 | 
			
		||||
    def check_vm_image_type(self, instance_id, vm_gen, root_vhd_path):
 | 
			
		||||
        if (vm_gen != constants.VM_GEN_1 and root_vhd_path and
 | 
			
		||||
                self._vhdutils.get_vhd_format(
 | 
			
		||||
                    root_vhd_path) == constants.DISK_FORMAT_VHD):
 | 
			
		||||
            LOG.error(_LE('Requested VM Generation %s, but provided VHD '
 | 
			
		||||
                          'instead of VHDX.'), vm_gen)
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
                _('Requested VM Generation %s, but provided VHD instead of '
 | 
			
		||||
                  'VHDX.') % vm_gen)
 | 
			
		||||
            reason = _LE('Requested VM Generation %s is not supported on '
 | 
			
		||||
                         'this OS.') % vm_gen
 | 
			
		||||
            raise exception.InstanceUnacceptable(instance_id=instance_id,
 | 
			
		||||
                                                 reason=reason)
 | 
			
		||||
 | 
			
		||||
    def _create_config_drive(self, instance, injected_files, admin_password,
 | 
			
		||||
                             network_info, rescue=False):
 | 
			
		||||
        if CONF.config_drive_format != 'iso9660':
 | 
			
		||||
            raise vmutils.UnsupportedConfigDriveFormatException(
 | 
			
		||||
                _('Invalid config_drive_format "%s"') %
 | 
			
		||||
                CONF.config_drive_format)
 | 
			
		||||
            raise exception.ConfigDriveUnsupportedFormat(
 | 
			
		||||
                format=CONF.config_drive_format)
 | 
			
		||||
 | 
			
		||||
        LOG.info(_LI('Using config drive for instance'), instance=instance)
 | 
			
		||||
 | 
			
		||||
@@ -570,15 +568,17 @@ class VMOps(object):
 | 
			
		||||
 | 
			
		||||
    def _configure_remotefx(self, instance, config):
 | 
			
		||||
        if not CONF.hyperv.enable_remotefx:
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
                _("enable_remotefx configuration option needs to be set to "
 | 
			
		||||
                  "True in order to use RemoteFX"))
 | 
			
		||||
            reason = _("enable_remotefx configuration option needs to be set "
 | 
			
		||||
                       "to True in order to use RemoteFX")
 | 
			
		||||
            raise exception.InstanceUnacceptable(instance_id=instance.uuid,
 | 
			
		||||
                                                 reason=reason)
 | 
			
		||||
 | 
			
		||||
        if not self._hostutils.check_server_feature(
 | 
			
		||||
                        self._hostutils.FEATURE_RDS_VIRTUALIZATION):
 | 
			
		||||
                    raise vmutils.HyperVException(
 | 
			
		||||
                        _("The RDS-Virtualization feature must be installed "
 | 
			
		||||
                          "in order to use RemoteFX"))
 | 
			
		||||
            reason = _("The RDS-Virtualization feature must be installed in "
 | 
			
		||||
                       "order to use RemoteFX")
 | 
			
		||||
            raise exception.InstanceUnacceptable(instance_id=instance.uuid,
 | 
			
		||||
                                                 reason=reason)
 | 
			
		||||
 | 
			
		||||
        instance_name = instance.name
 | 
			
		||||
        LOG.debug('Configuring RemoteFX for instance: %s', instance_name)
 | 
			
		||||
@@ -837,9 +837,9 @@ class VMOps(object):
 | 
			
		||||
 | 
			
		||||
            if port_number not in [1, 2]:
 | 
			
		||||
                err_msg = _("Invalid serial port number: %(port_number)s. "
 | 
			
		||||
                            "Only COM 1 and COM 2 are available.")
 | 
			
		||||
                raise vmutils.HyperVException(
 | 
			
		||||
                    err_msg % {'port_number': port_number})
 | 
			
		||||
                            "Only COM 1 and COM 2 are available.") % dict(
 | 
			
		||||
                                port_number=port_number)
 | 
			
		||||
                raise exception.ImageSerialPortNumberInvalid(err_msg)
 | 
			
		||||
 | 
			
		||||
            existing_type = serial_ports.get(port_number)
 | 
			
		||||
            if (not existing_type or
 | 
			
		||||
@@ -854,24 +854,27 @@ class VMOps(object):
 | 
			
		||||
        rescue_vhd_path = self._create_root_vhd(
 | 
			
		||||
            context, instance, rescue_image_id=rescue_image_id)
 | 
			
		||||
 | 
			
		||||
        rescue_vm_gen = self.get_image_vm_generation(image_meta)
 | 
			
		||||
        rescue_vm_gen = self.get_image_vm_generation(instance.uuid, image_meta)
 | 
			
		||||
        vm_gen = self._vmutils.get_vm_gen(instance.name)
 | 
			
		||||
        if rescue_vm_gen != vm_gen:
 | 
			
		||||
            err_msg = _('The requested rescue image requires a different VM '
 | 
			
		||||
                        'generation than the actual rescued instance. '
 | 
			
		||||
                        'Rescue image VM generation: %(rescue_vm_gen)s. '
 | 
			
		||||
                        'Rescued instance VM generation: %(vm_gen)s.')
 | 
			
		||||
            raise vmutils.HyperVException(err_msg %
 | 
			
		||||
                {'rescue_vm_gen': rescue_vm_gen,
 | 
			
		||||
                 'vm_gen': vm_gen})
 | 
			
		||||
        self.check_vm_image_type(rescue_vm_gen, rescue_vhd_path)
 | 
			
		||||
                        'Rescued instance VM generation: %(vm_gen)s.') % dict(
 | 
			
		||||
                            rescue_vm_gen=rescue_vm_gen,
 | 
			
		||||
                            vm_gen=vm_gen)
 | 
			
		||||
            raise exception.ImageUnacceptable(reason=err_msg,
 | 
			
		||||
                                              image_id=rescue_image_id)
 | 
			
		||||
 | 
			
		||||
        self.check_vm_image_type(instance.uuid, rescue_vm_gen, rescue_vhd_path)
 | 
			
		||||
 | 
			
		||||
        root_vhd_path = self._pathutils.lookup_root_vhd_path(instance.name)
 | 
			
		||||
        if not root_vhd_path:
 | 
			
		||||
            err_msg = _('Instance root disk image could not be found. '
 | 
			
		||||
                        'Rescuing instances booted from volume is '
 | 
			
		||||
                        'not supported.')
 | 
			
		||||
            raise vmutils.HyperVException(err_msg)
 | 
			
		||||
            raise exception.InstanceNotRescuable(reason=err_msg,
 | 
			
		||||
                                                 instance_id=instance.uuid)
 | 
			
		||||
 | 
			
		||||
        controller_type = VM_GENERATIONS_CONTROLLER_TYPES[vm_gen]
 | 
			
		||||
 | 
			
		||||
@@ -904,9 +907,9 @@ class VMOps(object):
 | 
			
		||||
 | 
			
		||||
        if (instance.vm_state == vm_states.RESCUED and
 | 
			
		||||
                not (rescue_vhd_path and root_vhd_path)):
 | 
			
		||||
            err_msg = _('Missing instance root and/or rescue image. '
 | 
			
		||||
                        'The instance cannot be unrescued.')
 | 
			
		||||
            raise vmutils.HyperVException(err_msg)
 | 
			
		||||
            err_msg = _('Missing instance root and/or rescue image.')
 | 
			
		||||
            raise exception.InstanceNotRescuable(reason=err_msg,
 | 
			
		||||
                                                 instance_id=instance.uuid)
 | 
			
		||||
 | 
			
		||||
        vm_gen = self._vmutils.get_vm_gen(instance.name)
 | 
			
		||||
        controller_type = VM_GENERATIONS_CONTROLLER_TYPES[vm_gen]
 | 
			
		||||
 
 | 
			
		||||
@@ -177,7 +177,7 @@ class VolumeOps(object):
 | 
			
		||||
                         "Requested maximum IOPS: %(total_iops)s.") %
 | 
			
		||||
                       {'min_iops': min_iops,
 | 
			
		||||
                        'total_iops': total_iops})
 | 
			
		||||
            raise vmutils.HyperVException(err_msg)
 | 
			
		||||
            raise exception.Invalid(err_msg)
 | 
			
		||||
 | 
			
		||||
        unsupported_specs = [spec for spec in qos_specs if
 | 
			
		||||
                             spec not in self._SUPPORTED_QOS_SPECS]
 | 
			
		||||
@@ -224,11 +224,12 @@ class ISCSIVolumeDriver(object):
 | 
			
		||||
        auth_password = data.get('auth_password')
 | 
			
		||||
 | 
			
		||||
        if auth_method and auth_method.upper() != 'CHAP':
 | 
			
		||||
            raise vmutils.HyperVException(
 | 
			
		||||
                _("Cannot log in target %(target_iqn)s. Unsupported iSCSI "
 | 
			
		||||
                  "authentication method: %(auth_method)s.") %
 | 
			
		||||
                 {'target_iqn': target_iqn,
 | 
			
		||||
                  'auth_method': auth_method})
 | 
			
		||||
            LOG.error(_LE("Cannot log in target %(target_iqn)s. Unsupported "
 | 
			
		||||
                          "iSCSI authentication method: %(auth_method)s."),
 | 
			
		||||
                      {'target_iqn': target_iqn,
 | 
			
		||||
                       'auth_method': auth_method})
 | 
			
		||||
            raise exception.UnsupportedBDMVolumeAuthMethod(
 | 
			
		||||
                auth_method=auth_method)
 | 
			
		||||
 | 
			
		||||
        # Check if we already logged in
 | 
			
		||||
        if self._volutils.get_device_number_for_target(target_iqn, target_lun):
 | 
			
		||||
@@ -443,9 +444,12 @@ class SMBFSVolumeDriver(object):
 | 
			
		||||
                                       ctrller_path,
 | 
			
		||||
                                       slot)
 | 
			
		||||
        except vmutils.HyperVException as exn:
 | 
			
		||||
            LOG.exception(_LE('Attach volume failed: %s'), exn)
 | 
			
		||||
            raise vmutils.HyperVException(_('Unable to attach volume '
 | 
			
		||||
                                            'to instance %s') % instance_name)
 | 
			
		||||
            LOG.exception(_LE('Attach volume failed to %(instance_name)s: '
 | 
			
		||||
                              '%(exn)s'), {'instance_name': instance_name,
 | 
			
		||||
                                           'exn': exn})
 | 
			
		||||
            raise exception.VolumeAttachFailed(
 | 
			
		||||
                volume_id=connection_info['data']['volume_id'],
 | 
			
		||||
                reason=exn.message)
 | 
			
		||||
 | 
			
		||||
    def detach_volume(self, connection_info, instance_name):
 | 
			
		||||
        LOG.debug("Detaching volume: %(connection_info)s "
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,10 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import mock
 | 
			
		||||
from nova import exception
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import block_device_manager
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -106,7 +106,7 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                                           mock_get_avail_ctrl_slot,
 | 
			
		||||
                                           disk_format,
 | 
			
		||||
                                           vm_gen=constants.VM_GEN_1,
 | 
			
		||||
                                           exception=False,
 | 
			
		||||
                                           fail=False,
 | 
			
		||||
                                           boot_from_volume=False):
 | 
			
		||||
        image_meta = {'disk_format': disk_format}
 | 
			
		||||
        bdi = {'root_device': '/dev/sda',
 | 
			
		||||
@@ -116,8 +116,8 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
 | 
			
		||||
        mock_is_boot_from_vol.return_value = boot_from_volume
 | 
			
		||||
        mock_get_avail_ctrl_slot.return_value = (0, 0)
 | 
			
		||||
        if exception:
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        if fail:
 | 
			
		||||
            self.assertRaises(exception.InvalidDiskFormat,
 | 
			
		||||
                              self._bdman._check_and_update_root_device,
 | 
			
		||||
                              vm_gen, image_meta, bdi,
 | 
			
		||||
                              mock.sentinel.SLOT_MAP)
 | 
			
		||||
@@ -148,7 +148,7 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
 | 
			
		||||
    def test_check_and_update_root_device_exception(self):
 | 
			
		||||
        self._test_check_and_update_root_device(disk_format='fake_format',
 | 
			
		||||
                                                exception=True)
 | 
			
		||||
                                                fail=True)
 | 
			
		||||
 | 
			
		||||
    def test_check_and_update_root_device_gen1(self):
 | 
			
		||||
        self._test_check_and_update_root_device(disk_format='vhd')
 | 
			
		||||
@@ -172,15 +172,15 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    @mock.patch('nova.virt.configdrive.required_by', return_value=True)
 | 
			
		||||
    def _test_get_available_controller_slot(self, mock_config_drive_req,
 | 
			
		||||
                                            bus=constants.CTRL_TYPE_IDE,
 | 
			
		||||
                                            exception=False):
 | 
			
		||||
                                            fail=False):
 | 
			
		||||
 | 
			
		||||
        slot_map = self._bdman._initialize_controller_slot_counter(
 | 
			
		||||
            mock.sentinel.FAKE_VM, constants.VM_GEN_1)
 | 
			
		||||
 | 
			
		||||
        if exception:
 | 
			
		||||
        if fail:
 | 
			
		||||
            slot_map[constants.CTRL_TYPE_IDE][0] = 0
 | 
			
		||||
            slot_map[constants.CTRL_TYPE_IDE][1] = 0
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
            self.assertRaises(exception.Invalid,
 | 
			
		||||
                              self._bdman._get_available_controller_slot,
 | 
			
		||||
                              constants.CTRL_TYPE_IDE,
 | 
			
		||||
                              slot_map)
 | 
			
		||||
@@ -196,7 +196,7 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._test_get_available_controller_slot()
 | 
			
		||||
 | 
			
		||||
    def test_get_available_controller_slot_exception(self):
 | 
			
		||||
        self._test_get_available_controller_slot(exception=True)
 | 
			
		||||
        self._test_get_available_controller_slot(fail=True)
 | 
			
		||||
 | 
			
		||||
    def test_get_available_controller_slot_scsi_ctrl(self):
 | 
			
		||||
        self._test_get_available_controller_slot(bus=constants.CTRL_TYPE_SCSI)
 | 
			
		||||
@@ -265,13 +265,13 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    @mock.patch.object(block_device_manager.BlockDeviceInfoManager,
 | 
			
		||||
                       '_get_available_controller_slot')
 | 
			
		||||
    def _test_check_and_update_bdm(self, mock_get_ctrl_slot,
 | 
			
		||||
                                   bdm, exception=False,
 | 
			
		||||
                                   bdm, fail=False,
 | 
			
		||||
                                   vm_gen=constants.VM_GEN_1,
 | 
			
		||||
                                   slot_map=None):
 | 
			
		||||
        mock_get_ctrl_slot.return_value = ((mock.sentinel.DRIVE_ADDR,
 | 
			
		||||
                                            mock.sentinel.CTRL_DISK_ADDR))
 | 
			
		||||
        if exception:
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        if fail:
 | 
			
		||||
            self.assertRaises(exception.InvalidDiskInfo,
 | 
			
		||||
                              self._bdman._check_and_update_bdm,
 | 
			
		||||
                              slot_map, vm_gen, bdm)
 | 
			
		||||
        else:
 | 
			
		||||
@@ -297,14 +297,14 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        bdm = {'device_type': 'cdrom',
 | 
			
		||||
               'disk_bus': 'IDE'}
 | 
			
		||||
 | 
			
		||||
        self._test_check_and_update_bdm(bdm=bdm, exception=True,
 | 
			
		||||
        self._test_check_and_update_bdm(bdm=bdm, fail=True,
 | 
			
		||||
                                        slot_map=mock.sentinel.FAKE_SLOT_MAP)
 | 
			
		||||
 | 
			
		||||
    def test_check_and_update_bdm_exception_disk_bus(self):
 | 
			
		||||
        bdm = {'device_type': 'disk',
 | 
			
		||||
               'disk_bus': 'fake_bus'}
 | 
			
		||||
 | 
			
		||||
        self._test_check_and_update_bdm(bdm=bdm, exception=True,
 | 
			
		||||
        self._test_check_and_update_bdm(bdm=bdm, fail=True,
 | 
			
		||||
                                        slot_map=mock.sentinel.FAKE_SLOT_MAP)
 | 
			
		||||
 | 
			
		||||
    def test_sort_by_boot_order(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -20,10 +20,10 @@ Unit tests for the Hyper-V Driver.
 | 
			
		||||
import platform
 | 
			
		||||
 | 
			
		||||
import mock
 | 
			
		||||
from nova import exception
 | 
			
		||||
from nova.virt import driver as base_driver
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import driver
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +51,7 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    def test_check_minimum_windows_version(self, mock_check_min_win_version):
 | 
			
		||||
        mock_check_min_win_version.return_value = False
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.HypervisorTooOld,
 | 
			
		||||
                          self.driver._check_minimum_windows_version)
 | 
			
		||||
 | 
			
		||||
    def test_public_api_signatures(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,6 @@ import six
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import hostops
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
@@ -254,7 +253,7 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                host=mock.sentinel.HOST, mode=True)
 | 
			
		||||
            self.assertEqual('on_maintenance', result)
 | 
			
		||||
        else:
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
            self.assertRaises(exception.MigrationError,
 | 
			
		||||
                              self._hostops.host_maintenance_mode,
 | 
			
		||||
                              host=mock.sentinel.HOST,
 | 
			
		||||
                              mode=True)
 | 
			
		||||
 
 | 
			
		||||
@@ -20,10 +20,10 @@ from nova import exception
 | 
			
		||||
from nova import objects
 | 
			
		||||
from nova.tests.unit.objects import test_flavor
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
from oslo_utils import units
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
from hyperv.nova import imagecache
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests import fake_instance
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +36,7 @@ class ImageCacheTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    FAKE_BASE_DIR = 'fake/base/dir'
 | 
			
		||||
    FAKE_FORMAT = 'fake_format'
 | 
			
		||||
    FAKE_IMAGE_REF = 'fake_image_ref'
 | 
			
		||||
    FAKE_VHD_SIZE_GB = 1
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(ImageCacheTestCase, self).setUp()
 | 
			
		||||
@@ -47,6 +48,27 @@ class ImageCacheTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self.imagecache._pathutils = mock.MagicMock()
 | 
			
		||||
        self.imagecache._vhdutils = mock.MagicMock()
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(imagecache.ImageCache, '_get_root_vhd_size_gb')
 | 
			
		||||
    def test_resize_and_cache_vhd_smaller(self, mock_get_vhd_size_gb):
 | 
			
		||||
        self.imagecache._vhdutils.get_vhd_info.return_value = {
 | 
			
		||||
            'MaxInternalSize': (self.FAKE_VHD_SIZE_GB + 1) * units.Gi
 | 
			
		||||
        }
 | 
			
		||||
        mock_get_vhd_size_gb.return_value = self.FAKE_VHD_SIZE_GB
 | 
			
		||||
        mock_internal_vhd_size = (
 | 
			
		||||
            self.imagecache._vhdutils.get_internal_vhd_size_by_file_size)
 | 
			
		||||
        mock_internal_vhd_size.return_value = self.FAKE_VHD_SIZE_GB * units.Gi
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(exception.FlavorDiskSmallerThanImage,
 | 
			
		||||
                          self.imagecache._resize_and_cache_vhd,
 | 
			
		||||
                          mock.sentinel.instance,
 | 
			
		||||
                          mock.sentinel.vhd_path)
 | 
			
		||||
 | 
			
		||||
        self.imagecache._vhdutils.get_vhd_info.assert_called_once_with(
 | 
			
		||||
            mock.sentinel.vhd_path)
 | 
			
		||||
        mock_get_vhd_size_gb.assert_called_once_with(mock.sentinel.instance)
 | 
			
		||||
        mock_internal_vhd_size.assert_called_once_with(
 | 
			
		||||
            mock.sentinel.vhd_path, self.FAKE_VHD_SIZE_GB * units.Gi)
 | 
			
		||||
 | 
			
		||||
    def _test_get_root_vhd_size_gb(self, old_flavor=True):
 | 
			
		||||
        if old_flavor:
 | 
			
		||||
            mock_flavor = objects.Flavor(**test_flavor.fake_flavor)
 | 
			
		||||
@@ -145,7 +167,7 @@ class ImageCacheTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
         expected_vhd_path) = self._prepare_get_cached_image(
 | 
			
		||||
            rescue_image_id=fake_rescue_image_id,
 | 
			
		||||
            image_format=constants.DISK_FORMAT_VHD)
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.FlavorDiskSmallerThanImage,
 | 
			
		||||
                          self.imagecache.get_cached_image,
 | 
			
		||||
                          self.context, self.instance,
 | 
			
		||||
                          fake_rescue_image_id)
 | 
			
		||||
 
 | 
			
		||||
@@ -171,7 +171,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        instance.config_drive = 'True'
 | 
			
		||||
        self._migrationops._pathutils.lookup_configdrive_path.return_value = (
 | 
			
		||||
            None)
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.ConfigDriveNotFound,
 | 
			
		||||
                          self._migrationops._check_and_attach_config_drive,
 | 
			
		||||
                          instance,
 | 
			
		||||
                          mock.sentinel.FAKE_VM_GEN)
 | 
			
		||||
@@ -260,7 +260,8 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        image_meta = (
 | 
			
		||||
            self._migrationops._imagecache.get_image_details.return_value)
 | 
			
		||||
        get_image_vm_gen = self._migrationops._vmops.get_image_vm_generation
 | 
			
		||||
        get_image_vm_gen.assert_called_once_with(image_meta)
 | 
			
		||||
        get_image_vm_gen.assert_called_once_with(
 | 
			
		||||
            mock_instance.uuid, image_meta)
 | 
			
		||||
        self._migrationops._vmops.create_instance.assert_called_once_with(
 | 
			
		||||
            mock_instance, mock.sentinel.network_info, root_device,
 | 
			
		||||
            block_device_info, get_image_vm_gen.return_value,
 | 
			
		||||
@@ -294,7 +295,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._migrationops._pathutils.lookup_root_vhd_path.return_value = None
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(
 | 
			
		||||
            vmutils.HyperVException,
 | 
			
		||||
            exception.DiskNotFound,
 | 
			
		||||
            self._migrationops.finish_revert_migration, self.context,
 | 
			
		||||
            mock_instance, mock.sentinel.network_info, bdi, True)
 | 
			
		||||
 | 
			
		||||
@@ -345,7 +346,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        mock_resize_vhd.assert_called_once_with(mock.sentinel.vhd_path, 2)
 | 
			
		||||
 | 
			
		||||
    def test_check_resize_vhd_exception(self):
 | 
			
		||||
        self.assertRaises(vmutils.VHDResizeException,
 | 
			
		||||
        self.assertRaises(exception.CannotResizeDisk,
 | 
			
		||||
                          self._migrationops._check_resize_vhd,
 | 
			
		||||
                          mock.sentinel.vhd_path,
 | 
			
		||||
                          {'MaxInternalSize': 1}, 0)
 | 
			
		||||
@@ -436,7 +437,8 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._migrationops._vhdutils.get_vhd_info.assert_has_calls(
 | 
			
		||||
            expected_get_info)
 | 
			
		||||
        get_image_vm_gen = self._migrationops._vmops.get_image_vm_generation
 | 
			
		||||
        get_image_vm_gen.assert_called_once_with(mock.sentinel.image_meta)
 | 
			
		||||
        get_image_vm_gen.assert_called_once_with(mock_instance.uuid,
 | 
			
		||||
                                                 mock.sentinel.image_meta)
 | 
			
		||||
        self._migrationops._vmops.create_instance.assert_called_once_with(
 | 
			
		||||
            mock_instance, mock.sentinel.network_info, root_device,
 | 
			
		||||
            block_device_info, get_image_vm_gen.return_value,
 | 
			
		||||
@@ -473,7 +475,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        mock_instance = fake_instance.fake_instance_obj(self.context)
 | 
			
		||||
        self._migrationops._pathutils.lookup_root_vhd_path.return_value = None
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.DiskNotFound,
 | 
			
		||||
                          self._migrationops.finish_migration,
 | 
			
		||||
                          self.context, mock.sentinel.migration,
 | 
			
		||||
                          mock_instance, mock.sentinel.disk_info,
 | 
			
		||||
@@ -481,7 +483,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                          mock.sentinel.image_meta, True,
 | 
			
		||||
                          bdi, True)
 | 
			
		||||
 | 
			
		||||
    def _test_check_ephemeral_disks(self, exception, resize):
 | 
			
		||||
    def _test_check_ephemeral_disks(self, exc, resize):
 | 
			
		||||
        mock_ephemerals = [dict(), dict()]
 | 
			
		||||
        mock_instance = fake_instance.fake_instance_obj(self.context)
 | 
			
		||||
        mock_instance.ephemeral_gb = 2
 | 
			
		||||
@@ -496,8 +498,8 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        mock_get_vhd_format = mock_vhdutils.get_best_supported_vhd_format
 | 
			
		||||
        mock_get_vhd_format.return_value = mock.sentinel.VHD_FORMAT
 | 
			
		||||
 | 
			
		||||
        if exception:
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        if exc:
 | 
			
		||||
            self.assertRaises(exception.DiskNotFound,
 | 
			
		||||
                              self._migrationops._check_ephemeral_disks,
 | 
			
		||||
                              mock_instance, mock_ephemerals)
 | 
			
		||||
        else:
 | 
			
		||||
@@ -518,7 +520,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                mock_instance.name, mock_ephemerals[1])
 | 
			
		||||
 | 
			
		||||
    def test_check_ephemeral_disks_exception(self):
 | 
			
		||||
        self._test_check_ephemeral_disks(exception=True, resize=False)
 | 
			
		||||
        self._test_check_ephemeral_disks(exc=True, resize=False)
 | 
			
		||||
 | 
			
		||||
    def test_check_ephemeral_disks(self):
 | 
			
		||||
        self._test_check_ephemeral_disks(exception=False, resize=True)
 | 
			
		||||
        self._test_check_ephemeral_disks(exc=False, resize=True)
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import os
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
import mock
 | 
			
		||||
from nova import exception
 | 
			
		||||
from six.moves import builtins
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import constants
 | 
			
		||||
@@ -200,7 +201,7 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
            side_effect=WindowsError(pathutils.ERROR_INVALID_NAME))
 | 
			
		||||
        with mock.patch.object(builtins, 'WindowsError',
 | 
			
		||||
                               fake_windows_error, create=True):
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
            self.assertRaises(exception.AdminRequired,
 | 
			
		||||
                              self._pathutils._get_instances_sub_dir,
 | 
			
		||||
                              fake_dir_name)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ from hyperv.nova import namedpipe
 | 
			
		||||
from hyperv.nova import serialconsolehandler
 | 
			
		||||
from hyperv.nova import serialproxy
 | 
			
		||||
from hyperv.nova import utilsfactory
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -228,7 +227,7 @@ class SerialConsoleHandlerTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
 | 
			
		||||
    def test_get_vm_serial_port_mapping_exception(self):
 | 
			
		||||
        self._mock_get_port_connections([])
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.NovaException,
 | 
			
		||||
                          self._consolehandler._get_vm_serial_port_mapping)
 | 
			
		||||
 | 
			
		||||
    @mock.patch('nova.console.type.ConsoleSerial')
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,6 @@ from nova import exception
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import serialconsolehandler
 | 
			
		||||
from hyperv.nova import serialconsoleops
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -98,7 +97,7 @@ class SerialConsoleOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        fake_open.side_effect = IOError
 | 
			
		||||
        fake_path_exists.return_value = True
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.ConsoleLogOutputException,
 | 
			
		||||
                          self._serialops.get_console_output,
 | 
			
		||||
                          mock.sentinel.instance_name)
 | 
			
		||||
        fake_open.assert_called_once_with(mock.sentinel.log_path, 'rb')
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,10 @@
 | 
			
		||||
#    under the License.
 | 
			
		||||
 | 
			
		||||
import mock
 | 
			
		||||
from nova import exception
 | 
			
		||||
import socket
 | 
			
		||||
 | 
			
		||||
from hyperv.nova import serialproxy
 | 
			
		||||
from hyperv.nova import vmutils
 | 
			
		||||
from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +49,7 @@ class SerialProxyTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
 | 
			
		||||
        fake_socket.listen.side_effect = socket.error
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.NovaException,
 | 
			
		||||
                          self._proxy._setup_socket)
 | 
			
		||||
 | 
			
		||||
        fake_socket.setsockopt.assert_called_once_with(socket.SOL_SOCKET,
 | 
			
		||||
 
 | 
			
		||||
@@ -154,7 +154,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        mock_get_cached_image.return_value = fake_vhd_path
 | 
			
		||||
        fake_root_path = self._vmops._pathutils.get_root_vhd_path.return_value
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.VHDResizeException,
 | 
			
		||||
        self.assertRaises(exception.FlavorDiskSmallerThanImage,
 | 
			
		||||
                          self._vmops._create_root_vhd, self.context,
 | 
			
		||||
                          mock_instance)
 | 
			
		||||
 | 
			
		||||
@@ -256,7 +256,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    def test_is_resize_needed_exception(self):
 | 
			
		||||
        inst = mock.MagicMock()
 | 
			
		||||
        self.assertRaises(
 | 
			
		||||
            vmutils.VHDResizeException, self._vmops._is_resize_needed,
 | 
			
		||||
            exception.FlavorDiskSmallerThanImage,
 | 
			
		||||
            self._vmops._is_resize_needed,
 | 
			
		||||
            mock.sentinel.FAKE_PATH, self.FAKE_SIZE, self.FAKE_SIZE - 1, inst)
 | 
			
		||||
 | 
			
		||||
    def test_is_resize_needed_true(self):
 | 
			
		||||
@@ -284,7 +285,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        mock_create_root_device.assert_called_once_with(self.context,
 | 
			
		||||
            mock_instance)
 | 
			
		||||
        mock_check_vm_image_type.assert_called_once_with(
 | 
			
		||||
            mock.sentinel.VM_GEN_1, mock.sentinel.VHD_PATH)
 | 
			
		||||
            mock_instance.uuid, mock.sentinel.VM_GEN_1, mock.sentinel.VHD_PATH)
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(vmops.VMOps, '_create_root_iso')
 | 
			
		||||
    def test_create_root_device_type_iso(self, mock_create_root_iso):
 | 
			
		||||
@@ -427,7 +428,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                                                            fake_vm_gen)
 | 
			
		||||
            mock_create_ephemerals.assert_called_once_with(mock_instance,
 | 
			
		||||
                block_device_info['ephemerals'])
 | 
			
		||||
            mock_get_image_vm_gen.assert_called_once_with(mock_image_meta)
 | 
			
		||||
            mock_get_image_vm_gen.assert_called_once_with(
 | 
			
		||||
                mock_instance.uuid, mock_image_meta)
 | 
			
		||||
            mock_create_instance.assert_called_once_with(
 | 
			
		||||
                mock_instance, [fake_network_info], root_device_info,
 | 
			
		||||
                block_device_info, fake_vm_gen, mock_image_meta)
 | 
			
		||||
@@ -696,8 +698,9 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._vmops._hostutils.get_supported_vm_types.return_value = [
 | 
			
		||||
            constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2]
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.InstanceUnacceptable,
 | 
			
		||||
                          self._vmops.get_image_vm_generation,
 | 
			
		||||
                          mock.sentinel.instance_id,
 | 
			
		||||
                          image_meta)
 | 
			
		||||
 | 
			
		||||
    def test_get_image_vm_generation_default(self):
 | 
			
		||||
@@ -707,7 +710,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._vmops._hostutils.get_supported_vm_types.return_value = [
 | 
			
		||||
            constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2]
 | 
			
		||||
 | 
			
		||||
        response = self._vmops.get_image_vm_generation(image_meta)
 | 
			
		||||
        response = self._vmops.get_image_vm_generation(
 | 
			
		||||
            mock.sentinel.instance_id, image_meta)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(constants.VM_GEN_1, response)
 | 
			
		||||
 | 
			
		||||
@@ -717,7 +721,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._vmops._hostutils.get_supported_vm_types.return_value = [
 | 
			
		||||
            constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2]
 | 
			
		||||
 | 
			
		||||
        response = self._vmops.get_image_vm_generation(image_meta)
 | 
			
		||||
        response = self._vmops.get_image_vm_generation(
 | 
			
		||||
            mock.sentinel.instance_id, image_meta)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(constants.VM_GEN_2, response)
 | 
			
		||||
 | 
			
		||||
@@ -728,9 +733,9 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        self._vmops._vhdutils.get_vhd_format = mock.MagicMock(
 | 
			
		||||
            return_value=constants.DISK_FORMAT_VHD)
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
            self._vmops.check_vm_image_type, constants.VM_GEN_2,
 | 
			
		||||
            mock.sentinel.FAKE_VHD_PATH)
 | 
			
		||||
        self.assertRaises(exception.InstanceUnacceptable,
 | 
			
		||||
            self._vmops.check_vm_image_type, mock.sentinel.instance_id,
 | 
			
		||||
            constants.VM_GEN_2, mock.sentinel.FAKE_VHD_PATH)
 | 
			
		||||
 | 
			
		||||
    @mock.patch('nova.api.metadata.base.InstanceMetadata')
 | 
			
		||||
    @mock.patch('nova.virt.configdrive.ConfigDriveBuilder')
 | 
			
		||||
@@ -766,7 +771,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
            expected_get_configdrive_path_calls.append(expected_call)
 | 
			
		||||
 | 
			
		||||
        if config_drive_format != self.ISO9660:
 | 
			
		||||
            self.assertRaises(vmutils.UnsupportedConfigDriveFormatException,
 | 
			
		||||
            self.assertRaises(exception.ConfigDriveUnsupportedFormat,
 | 
			
		||||
                              self._vmops._create_config_drive,
 | 
			
		||||
                              mock_instance, [mock.sentinel.FILE],
 | 
			
		||||
                              mock.sentinel.PASSWORD,
 | 
			
		||||
@@ -1278,36 +1283,39 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(vmops.VMOps, '_create_root_vhd')
 | 
			
		||||
    @mock.patch.object(vmops.VMOps, 'get_image_vm_generation')
 | 
			
		||||
    def _test_rescue_instance_exception(self, mock_get_image_vm_gen,
 | 
			
		||||
                                        mock_create_root_vhd,
 | 
			
		||||
                                        wrong_vm_gen=False,
 | 
			
		||||
                                        boot_from_volume=False):
 | 
			
		||||
        mock_vm_gen = constants.VM_GEN_1
 | 
			
		||||
        image_vm_gen = (mock_vm_gen
 | 
			
		||||
                        if not wrong_vm_gen else constants.VM_GEN_2)
 | 
			
		||||
    def test_rescue_instance_boot_from_volume(self, mock_get_image_vm_gen,
 | 
			
		||||
                                              mock_create_root_vhd):
 | 
			
		||||
        mock_image_meta = {'id': mock.sentinel.rescue_image_id}
 | 
			
		||||
 | 
			
		||||
        mock_instance = fake_instance.fake_instance_obj(self.context)
 | 
			
		||||
        mock_get_image_vm_gen.return_value = image_vm_gen
 | 
			
		||||
        self._vmops._vmutils.get_vm_gen.return_value = mock_vm_gen
 | 
			
		||||
        self._vmops._pathutils.lookup_root_vhd_path.return_value = (
 | 
			
		||||
            mock.sentinel.root_vhd_path if not boot_from_volume else None)
 | 
			
		||||
        mock_get_image_vm_gen.return_value = constants.VM_GEN_1
 | 
			
		||||
        self._vmops._vmutils.get_vm_gen.return_value = constants.VM_GEN_1
 | 
			
		||||
        self._vmops._pathutils.lookup_root_vhd_path.return_value = None
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.InstanceNotRescuable,
 | 
			
		||||
                          self._vmops.rescue_instance,
 | 
			
		||||
                          self.context, mock_instance,
 | 
			
		||||
                          mock.sentinel.network_info,
 | 
			
		||||
                          mock_image_meta,
 | 
			
		||||
                          mock.sentinel.rescue_password)
 | 
			
		||||
 | 
			
		||||
    def test_rescue_instance_wrong_vm_gen(self):
 | 
			
		||||
    @mock.patch.object(vmops.VMOps, '_create_root_vhd')
 | 
			
		||||
    @mock.patch.object(vmops.VMOps, 'get_image_vm_generation')
 | 
			
		||||
    def test_rescue_instance_wrong_vm_gen(self, mock_get_image_vm_gen,
 | 
			
		||||
                                          mock_create_root_vhd):
 | 
			
		||||
        # Test the case when the rescue image requires a different
 | 
			
		||||
        # vm generation than the actual rescued instance.
 | 
			
		||||
        self._test_rescue_instance_exception(wrong_vm_gen=True)
 | 
			
		||||
        mock_image_meta = {'id': mock.sentinel.rescue_image_id}
 | 
			
		||||
        mock_instance = fake_instance.fake_instance_obj(self.context)
 | 
			
		||||
        mock_get_image_vm_gen.return_value = constants.VM_GEN_1
 | 
			
		||||
        self._vmops._vmutils.get_vm_gen.return_value = constants.VM_GEN_2
 | 
			
		||||
 | 
			
		||||
    def test_rescue_instance_boot_from_volume(self):
 | 
			
		||||
        # Rescuing instances booted from volume is not supported.
 | 
			
		||||
        self._test_rescue_instance_exception(boot_from_volume=True)
 | 
			
		||||
        self.assertRaises(exception.ImageUnacceptable,
 | 
			
		||||
                          self._vmops.rescue_instance,
 | 
			
		||||
                          self.context, mock_instance,
 | 
			
		||||
                          mock.sentinel.network_info,
 | 
			
		||||
                          mock_image_meta,
 | 
			
		||||
                          mock.sentinel.rescue_password)
 | 
			
		||||
 | 
			
		||||
    @mock.patch.object(fileutils, 'delete_if_exists')
 | 
			
		||||
    @mock.patch.object(vmops.VMOps, '_attach_drive')
 | 
			
		||||
@@ -1363,7 +1371,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        mock_instance.vm_state = vm_states.RESCUED
 | 
			
		||||
        self._vmops._pathutils.lookup_root_vhd_path.return_value = None
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.InstanceNotRescuable,
 | 
			
		||||
                          self._vmops.unrescue_instance,
 | 
			
		||||
                          mock_instance)
 | 
			
		||||
 | 
			
		||||
@@ -1423,7 +1431,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    def test_get_instance_vnuma_config_no_topology(self):
 | 
			
		||||
        self._check_get_instance_vnuma_config()
 | 
			
		||||
 | 
			
		||||
    def _test_configure_remotefx(self, exception=False):
 | 
			
		||||
    def _test_configure_remotefx(self, fail=False):
 | 
			
		||||
        self.flags(enable_remotefx=True, group='hyperv')
 | 
			
		||||
        mock_instance = fake_instance.fake_instance_obj(self.context)
 | 
			
		||||
 | 
			
		||||
@@ -1435,9 +1443,9 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        enable_remotefx = self._vmops._vmutils.enable_remotefx_video_adapter
 | 
			
		||||
        self._vmops._hostutils.check_server_feature = mock.MagicMock()
 | 
			
		||||
 | 
			
		||||
        if exception:
 | 
			
		||||
        if fail:
 | 
			
		||||
            self._vmops._hostutils.check_server_feature.return_value = False
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
            self.assertRaises(exception.InstanceUnacceptable,
 | 
			
		||||
                              self._vmops._configure_remotefx,
 | 
			
		||||
                              mock_instance, fake_config)
 | 
			
		||||
        else:
 | 
			
		||||
@@ -1447,7 +1455,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                                                    fake_resolution)
 | 
			
		||||
 | 
			
		||||
    def test_configure_remotefx_exception(self):
 | 
			
		||||
        self._test_configure_remotefx(exception=True)
 | 
			
		||||
        self._test_configure_remotefx(fail=True)
 | 
			
		||||
 | 
			
		||||
    def test_configure_remotefx(self):
 | 
			
		||||
        self._test_configure_remotefx()
 | 
			
		||||
@@ -1570,7 +1578,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        expected_exception = not (logging_port in acceptable_ports and
 | 
			
		||||
                                  interactive_port in acceptable_ports)
 | 
			
		||||
        if expected_exception:
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
            self.assertRaises(exception.ImageSerialPortNumberInvalid,
 | 
			
		||||
                              self._vmops._get_image_serial_port_settings,
 | 
			
		||||
                              mock_image_meta)
 | 
			
		||||
        else:
 | 
			
		||||
@@ -1707,11 +1715,13 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
    def _test_requires_certificate(self, os_type):
 | 
			
		||||
        image_meta = {'properties': {'os_type': os_type}}
 | 
			
		||||
        if not os_type:
 | 
			
		||||
            self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
                              self._vmops._requires_certificate, image_meta)
 | 
			
		||||
            self.assertRaises(exception.InstanceUnacceptable,
 | 
			
		||||
                              self._vmops._requires_certificate,
 | 
			
		||||
                              mock.sentinel.instance_id, image_meta)
 | 
			
		||||
        else:
 | 
			
		||||
            expected_result = os_type == 'linux'
 | 
			
		||||
            result = self._vmops._requires_certificate(image_meta)
 | 
			
		||||
            result = self._vmops._requires_certificate(
 | 
			
		||||
                mock.sentinel.instance_id, image_meta)
 | 
			
		||||
            self.assertEqual(expected_result, result)
 | 
			
		||||
 | 
			
		||||
    def test_requires_certificate_windows(self):
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,8 @@ from hyperv.tests.unit import test_base
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
 | 
			
		||||
connection_data = {'target_lun': mock.sentinel.fake_lun,
 | 
			
		||||
connection_data = {'volume_id': 'fake_vol_id',
 | 
			
		||||
                   'target_lun': mock.sentinel.fake_lun,
 | 
			
		||||
                   'target_iqn': mock.sentinel.fake_iqn,
 | 
			
		||||
                   'target_portal': mock.sentinel.fake_portal,
 | 
			
		||||
                   'auth_method': 'chap',
 | 
			
		||||
@@ -217,7 +218,7 @@ class VolumeOpsTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
            'min_iops_sec': 2
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.Invalid,
 | 
			
		||||
                          self._volumeops.parse_disk_qos_specs,
 | 
			
		||||
                          fake_qos_specs)
 | 
			
		||||
 | 
			
		||||
@@ -244,7 +245,7 @@ class ISCSIVolumeDriverTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
        connection_info = get_fake_connection_info(
 | 
			
		||||
            auth_method='fake_auth_method')
 | 
			
		||||
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.UnsupportedBDMVolumeAuthMethod,
 | 
			
		||||
                          self._volume_driver.login_storage_target,
 | 
			
		||||
                          connection_info)
 | 
			
		||||
 | 
			
		||||
@@ -483,7 +484,8 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                                                        _FAKE_PASSWORD)
 | 
			
		||||
    _FAKE_CONNECTION_INFO = {'data': {'export': _FAKE_SHARE,
 | 
			
		||||
                                      'name': _FAKE_DISK_NAME,
 | 
			
		||||
                                      'options': _FAKE_SMB_OPTIONS}}
 | 
			
		||||
                                      'options': _FAKE_SMB_OPTIONS,
 | 
			
		||||
                                      'volume_id': 'fake_vol_id'}}
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(SMBFSVolumeDriverTestCase, self).setUp()
 | 
			
		||||
@@ -542,7 +544,7 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
 | 
			
		||||
                                       mock_ensure_share_mounted):
 | 
			
		||||
        self._volume_driver._vmutils.attach_drive.side_effect = (
 | 
			
		||||
            vmutils.HyperVException())
 | 
			
		||||
        self.assertRaises(vmutils.HyperVException,
 | 
			
		||||
        self.assertRaises(exception.VolumeAttachFailed,
 | 
			
		||||
                          self._volume_driver.attach_volume,
 | 
			
		||||
                          self._FAKE_CONNECTION_INFO,
 | 
			
		||||
                          mock.sentinel.instance_name)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user