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:
Claudiu Belu
2015-12-04 16:02:28 +02:00
parent 22f7ee6a0d
commit e155510be7
22 changed files with 236 additions and 203 deletions

View File

@@ -19,12 +19,12 @@ Module contains helper methods for dealing with block device information
""" """
from nova import block_device from nova import block_device
from nova import exception
from nova.virt import configdrive from nova.virt import configdrive
from nova.virt import driver from nova.virt import driver
from hyperv.i18n import _ from hyperv.i18n import _
from hyperv.nova import constants from hyperv.nova import constants
from hyperv.nova import vmutils
from hyperv.nova import volumeops from hyperv.nova import volumeops
@@ -86,9 +86,8 @@ class BlockDeviceInfoManager(object):
root_disk['type'] = self._TYPE_FOR_DISK_FORMAT.get( root_disk['type'] = self._TYPE_FOR_DISK_FORMAT.get(
image_meta['disk_format']) image_meta['disk_format'])
if root_disk['type'] is None: if root_disk['type'] is None:
msg = _("Hyper-V driver does not support image type " raise exception.InvalidDiskFormat(
"%s.") % image_meta['disk_format'] disk_format=image_meta['disk_format'])
raise vmutils.HyperVException(msg)
root_disk['path'] = None root_disk['path'] = None
root_disk['connection_info'] = None root_disk['connection_info'] = None
@@ -115,7 +114,7 @@ class BlockDeviceInfoManager(object):
msg = _("There are no more free slots on controller %s" msg = _("There are no more free slots on controller %s"
) % controller_type ) % controller_type
raise vmutils.HyperVException(msg) raise exception.Invalid(msg)
def is_boot_from_volume(self, block_device_info): def is_boot_from_volume(self, block_device_info):
if block_device_info: if block_device_info:
@@ -156,7 +155,7 @@ class BlockDeviceInfoManager(object):
"for generation %(vm_gen)s instances." "for generation %(vm_gen)s instances."
) % {'disk_bus': disk_bus, ) % {'disk_bus': disk_bus,
'vm_gen': vm_gen} 'vm_gen': vm_gen}
raise vmutils.HyperVException(msg) raise exception.InvalidDiskInfo(reason=msg)
device_type = bdm.get('device_type') device_type = bdm.get('device_type')
if not device_type: if not device_type:
@@ -164,7 +163,7 @@ class BlockDeviceInfoManager(object):
elif device_type != 'disk': elif device_type != 'disk':
msg = _("Hyper-V does not support disk type %s for ephemerals " msg = _("Hyper-V does not support disk type %s for ephemerals "
"or volumes.") % device_type "or volumes.") % device_type
raise vmutils.HyperVException(msg) raise exception.InvalidDiskInfo(reason=msg)
(bdm['drive_addr'], (bdm['drive_addr'],
bdm['ctrl_disk_addr']) = self._get_available_controller_slot( bdm['ctrl_disk_addr']) = self._get_available_controller_slot(

View File

@@ -19,6 +19,7 @@ A Hyper-V Nova Compute driver.
import platform import platform
from nova import exception
from nova.virt import driver from nova.virt import driver
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
@@ -34,7 +35,6 @@ from hyperv.nova import rdpconsoleops
from hyperv.nova import serialconsoleops from hyperv.nova import serialconsoleops
from hyperv.nova import snapshotops from hyperv.nova import snapshotops
from hyperv.nova import vmops from hyperv.nova import vmops
from hyperv.nova import vmutils
from hyperv.nova import volumeops from hyperv.nova import volumeops
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@@ -69,12 +69,11 @@ class HyperVDriver(driver.ComputeDriver):
# the version is of Windows is older than Windows Server 2012 R2. # the version is of Windows is older than Windows Server 2012 R2.
# Log an error, lettingusers know that this version is not # Log an error, lettingusers know that this version is not
# supported any longer. # 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 ' 'version of Windows (older than Windows / Hyper-V '
'Server 2012). The support for this version of ' 'Server 2012). The support for this version of '
'Windows has been removed in Mitaka.') 'Windows has been removed in Mitaka.'))
LOG.error(err_msg) raise exception.HypervisorTooOld(version='6.2')
raise vmutils.HyperVException(err_msg)
@property @property
def need_legacy_block_device_info(self): def need_legacy_block_device_info(self):

View File

@@ -40,7 +40,6 @@ from hyperv.i18n import _, _LE, _LI
from hyperv.nova import constants from hyperv.nova import constants
from hyperv.nova import utilsfactory from hyperv.nova import utilsfactory
from hyperv.nova import vmops from hyperv.nova import vmops
from hyperv.nova import vmutils
hyper_host_opts = [ hyper_host_opts = [
cfg.IntOpt('evacuate_task_state_timeout', cfg.IntOpt('evacuate_task_state_timeout',
@@ -270,8 +269,8 @@ class HostOps(object):
LOG.info(_LI('All vms have been migrated successfully.' LOG.info(_LI('All vms have been migrated successfully.'
'Host is down for maintenance')) 'Host is down for maintenance'))
return 'on_maintenance' return 'on_maintenance'
raise vmutils.HyperVException( raise exception.MigrationError(
_('Not all vms have been migrated: %s remaining instances.') reason=_('Not all vms have been migrated: %s remaining instances.')
% remaining_vms) % remaining_vms)
def _set_service_state(self, host, binary, is_disabled): def _set_service_state(self, host, binary, is_disabled):

View File

@@ -18,6 +18,7 @@ Image caching and management.
import os import os
import re import re
from nova import exception
from nova import utils from nova import utils
from nova.virt import imagecache from nova.virt import imagecache
from nova.virt import images from nova.virt import images
@@ -29,7 +30,6 @@ from oslo_utils import uuidutils
from hyperv.i18n import _ from hyperv.i18n import _
from hyperv.nova import utilsfactory from hyperv.nova import utilsfactory
from hyperv.nova import vmutils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@@ -78,12 +78,8 @@ class ImageCache(imagecache.ImageCacheManager):
vhd_path, root_vhd_size)) vhd_path, root_vhd_size))
if root_vhd_internal_size < vhd_size: if root_vhd_internal_size < vhd_size:
raise vmutils.HyperVException( raise exception.FlavorDiskSmallerThanImage(
_("Cannot resize the image to a size smaller than the VHD " flavor_size=root_vhd_size, image_size=vhd_size)
"max. internal size: %(vhd_size)s. Requested disk size: "
"%(root_vhd_size)s") %
{'vhd_size': vhd_size, 'root_vhd_size': root_vhd_size}
)
if root_vhd_internal_size > vhd_size: if root_vhd_internal_size > vhd_size:
path_parts = os.path.splitext(vhd_path) path_parts = os.path.splitext(vhd_path)
resized_vhd_path = '%s_%s%s' % (path_parts[0], resized_vhd_path = '%s_%s%s' % (path_parts[0],
@@ -179,7 +175,7 @@ class ImageCache(imagecache.ImageCacheManager):
'Rescue image size: %(rescue_image_size)s. ' 'Rescue image size: %(rescue_image_size)s. '
'Flavor disk size:%(flavor_disk_size)s. ' 'Flavor disk size:%(flavor_disk_size)s. '
'Rescue image id %(rescue_image_id)s.') 'Rescue image id %(rescue_image_id)s.')
raise vmutils.HyperVException(err_msg % raise exception.FlavorDiskSmallerThanImage(err_msg %
{'rescue_image_size': rescue_image_size, {'rescue_image_size': rescue_image_size,
'flavor_disk_size': flavor_disk_size, 'flavor_disk_size': flavor_disk_size,
'rescue_image_id': rescue_image_id}) 'rescue_image_id': rescue_image_id})

View File

@@ -31,7 +31,6 @@ from hyperv.nova import constants
from hyperv.nova import imagecache from hyperv.nova import imagecache
from hyperv.nova import utilsfactory from hyperv.nova import utilsfactory
from hyperv.nova import vmops from hyperv.nova import vmops
from hyperv.nova import vmutils
from hyperv.nova import volumeops from hyperv.nova import volumeops
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@@ -114,21 +113,21 @@ class MigrationOps(object):
if new_root_gb < curr_root_gb: if new_root_gb < curr_root_gb:
raise exception.InstanceFaultRollback( raise exception.InstanceFaultRollback(
vmutils.VHDResizeException( exception.CannotResizeDisk(
_("Cannot resize the root disk to a smaller size. " reason=_("Cannot resize the root disk to a smaller size. "
"Current size: %(curr_root_gb)s GB. Requested size: " "Current size: %(curr_root_gb)s GB. Requested "
"%(new_root_gb)s GB") % "size: %(new_root_gb)s GB.") % {
{'curr_root_gb': curr_root_gb, 'curr_root_gb': curr_root_gb,
'new_root_gb': new_root_gb})) 'new_root_gb': new_root_gb}))
if new_eph_gb < curr_eph_gb: if new_eph_gb < curr_eph_gb:
raise exception.InstanceFaultRollback( raise exception.InstanceFaultRollback(
vmutils.VHDResizeException( exception.CannotResizeDisk(
_("Cannot resize the ephemeral disk(s) to a smaller " reason=_("Cannot resize the ephemeral disk(s) to a smaller"
" size. Current total ephemeral size: " " size. Current total ephemeral size: "
"%(curr_eph_gb)s GB. Requested total size: " "%(curr_eph_gb)s GB. Requested total size: "
"%(new_eph_gb)s GB") % "%(new_eph_gb)s GB") % {
{'curr_eph_gb': curr_eph_gb, 'curr_eph_gb': curr_eph_gb,
'new_eph_gb': new_eph_gb})) 'new_eph_gb': new_eph_gb}))
def migrate_disk_and_power_off(self, context, instance, dest, def migrate_disk_and_power_off(self, context, instance, dest,
@@ -174,9 +173,8 @@ class MigrationOps(object):
self._vmops.attach_config_drive(instance, configdrive_path, self._vmops.attach_config_drive(instance, configdrive_path,
vm_gen) vm_gen)
else: else:
raise vmutils.HyperVException( raise exception.ConfigDriveNotFound(
_("Config drive is required by instance: %s, " instance_uuid=instance.uuid)
"but it does not exist.") % instance.name)
def finish_revert_migration(self, context, instance, network_info, def finish_revert_migration(self, context, instance, network_info,
block_device_info=None, power_on=True): block_device_info=None, power_on=True):
@@ -186,7 +184,7 @@ class MigrationOps(object):
self._revert_migration_files(instance_name) self._revert_migration_files(instance_name)
image_meta = self._imagecache.get_image_details(context, instance) 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( self._block_dev_manager.validate_and_update_bdi(
instance, image_meta, vm_gen, block_device_info) instance, image_meta, vm_gen, block_device_info)
@@ -196,7 +194,7 @@ class MigrationOps(object):
root_device['path'] = self._pathutils.lookup_root_vhd_path( root_device['path'] = self._pathutils.lookup_root_vhd_path(
instance_name) instance_name)
if not root_device['path']: if not root_device['path']:
raise vmutils.HyperVException( raise exception.DiskNotFound(
_("Cannot find boot VHD file for instance: %s") _("Cannot find boot VHD file for instance: %s")
% instance_name) % instance_name)
@@ -246,8 +244,12 @@ class MigrationOps(object):
def _check_resize_vhd(self, vhd_path, vhd_info, new_size): def _check_resize_vhd(self, vhd_path, vhd_info, new_size):
curr_size = vhd_info['MaxInternalSize'] curr_size = vhd_info['MaxInternalSize']
if new_size < curr_size: if new_size < curr_size:
raise vmutils.VHDResizeException(_("Cannot resize a VHD " raise exception.CannotResizeDisk(
"to a smaller size")) 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: elif new_size > curr_size:
self._resize_vhd(vhd_path, new_size) self._resize_vhd(vhd_path, new_size)
@@ -286,7 +288,7 @@ class MigrationOps(object):
instance_name = instance.name 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( self._block_dev_manager.validate_and_update_bdi(
instance, image_meta, vm_gen, block_device_info) instance, image_meta, vm_gen, block_device_info)
@@ -296,7 +298,7 @@ class MigrationOps(object):
root_device['path'] = self._pathutils.lookup_root_vhd_path( root_device['path'] = self._pathutils.lookup_root_vhd_path(
instance_name) instance_name)
if not root_device['path']: if not root_device['path']:
raise vmutils.HyperVException(_("Cannot find boot VHD " raise exception.DiskNotFound(_("Cannot find boot VHD "
"file for instance: %s") % "file for instance: %s") %
instance_name) instance_name)
@@ -332,7 +334,7 @@ class MigrationOps(object):
instance_name, eph_name) instance_name, eph_name)
if not eph['path'] and not resize_instance: if not eph['path'] and not resize_instance:
raise vmutils.HyperVException(_("Cannot find ephemeral VHD " raise exception.DiskNotFound(_("Cannot find ephemeral VHD "
"file for instance: %s") % "file for instance: %s") %
instance_name) instance_name)
if resize_instance and not eph['path'] and new_eph_gb: if resize_instance and not eph['path'] and new_eph_gb:

View File

@@ -21,6 +21,7 @@ import time
if sys.platform == 'win32': if sys.platform == 'win32':
import wmi import wmi
from nova import exception
from nova import utils from nova import utils
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
@@ -166,7 +167,7 @@ class PathUtils(object):
return path return path
except WindowsError as ex: except WindowsError as ex:
if ex.winerror == ERROR_INVALID_NAME: if ex.winerror == ERROR_INVALID_NAME:
raise vmutils.HyperVException(_( raise exception.AdminRequired(_(
"Cannot access \"%(instances_path)s\", make sure the " "Cannot access \"%(instances_path)s\", make sure the "
"path exists and that you have the proper permissions. " "path exists and that you have the proper permissions. "
"In particular Nova-Compute must not be executed with the " "In particular Nova-Compute must not be executed with the "

View File

@@ -27,7 +27,6 @@ from hyperv.nova import ioutils
from hyperv.nova import namedpipe from hyperv.nova import namedpipe
from hyperv.nova import serialproxy from hyperv.nova import serialproxy
from hyperv.nova import utilsfactory from hyperv.nova import utilsfactory
from hyperv.nova import vmutils
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@@ -139,7 +138,7 @@ class SerialConsoleHandler(object):
if not serial_port_conns: if not serial_port_conns:
err_msg = _("No suitable serial port pipe was found " err_msg = _("No suitable serial port pipe was found "
"for instance %(instance_name)s") "for instance %(instance_name)s")
raise vmutils.HyperVException( raise exception.NovaException(
err_msg % {'instance_name': self._instance_name}) err_msg % {'instance_name': self._instance_name})
serial_port_mapping = {} serial_port_mapping = {}

View File

@@ -17,14 +17,14 @@ import functools
import os import os
from nova import exception from nova import exception
from nova.i18n import _, _LI, _LE # noqa from nova.i18n import _LI, _LE # noqa
from nova import utils from nova import utils
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
import six
from hyperv.nova import serialconsolehandler from hyperv.nova import serialconsolehandler
from hyperv.nova import utilsfactory from hyperv.nova import utilsfactory
from hyperv.nova import vmutils
CONF = cfg.CONF CONF = cfg.CONF
@@ -101,11 +101,8 @@ class SerialConsoleOps(object):
log += fp.read() log += fp.read()
return log return log
except IOError as err: except IOError as err:
msg = (_("Could not get instance %(instance_name)s " raise exception.ConsoleLogOutputException(
"console output. Error: %(err)s") % instance_id=instance_name, reason=six.text_type(err))
{'instance_name': instance_name,
'err': err})
raise vmutils.HyperVException(msg)
def start_console_handlers(self): def start_console_handlers(self):
active_instances = self._vmutils.get_active_instances() active_instances = self._vmutils.get_active_instances()

View File

@@ -18,10 +18,10 @@ from eventlet import patcher
import functools import functools
import socket import socket
from nova import exception
from nova.i18n import _ from nova.i18n import _
from hyperv.nova import constants from hyperv.nova import constants
from hyperv.nova import vmutils
threading = patcher.original('threading') threading = patcher.original('threading')
@@ -69,7 +69,7 @@ class SerialProxy(threading.Thread):
{'addr': self._addr, 'port': self._port, {'addr': self._addr, 'port': self._port,
'instance_name': self._instance_name, 'instance_name': self._instance_name,
'error': err}) 'error': err})
raise vmutils.HyperVException(msg) raise exception.NovaException(msg)
def stop(self): def stop(self):
self._stopped.set() self._stopped.set()

View File

@@ -172,7 +172,7 @@ class VMOps(object):
path = None path = None
if root_disk_info['type'] == constants.DISK: if root_disk_info['type'] == constants.DISK:
path = self._create_root_vhd(context, instance) 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: elif root_disk_info['type'] == constants.DVD:
path = self._create_root_iso(context, instance) path = self._create_root_iso(context, instance)
root_disk_info['path'] = path root_disk_info['path'] = path
@@ -249,12 +249,8 @@ class VMOps(object):
def _is_resize_needed(self, vhd_path, old_size, new_size, instance): def _is_resize_needed(self, vhd_path, old_size, new_size, instance):
if new_size < old_size: if new_size < old_size:
error_msg = _("Cannot resize a VHD to a smaller size, the" raise exception.FlavorDiskSmallerThanImage(
" original size is %(old_size)s, the" flavor_size=new_size, image_size=old_size)
" newer size is %(new_size)s"
) % {'old_size': old_size,
'new_size': new_size}
raise vmutils.VHDResizeException(error_msg)
elif new_size > old_size: elif new_size > old_size:
LOG.debug("Resizing VHD %(vhd_path)s to new " LOG.debug("Resizing VHD %(vhd_path)s to new "
"size %(new_size)s" % "size %(new_size)s" %
@@ -296,7 +292,7 @@ class VMOps(object):
# Make sure we're starting with a clean slate. # Make sure we're starting with a clean slate.
self._delete_disk_files(instance_name) 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( self._block_device_manager.validate_and_update_bdi(
instance, image_meta, vm_gen, block_device_info) instance, image_meta, vm_gen, block_device_info)
@@ -322,12 +318,13 @@ class VMOps(object):
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
self.destroy(instance) 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) os_type = image_meta.get('properties', {}).get('os_type', None)
if not os_type: if not os_type:
raise vmutils.HyperVException( reason = _('For secure boot, os_type must be specified in image '
_('For secure boot, os_type must be specified in image ' 'properties.')
'properties.')) raise exception.InstanceUnacceptable(instance_id=instance_id,
reason=reason)
elif os_type == 'windows': elif os_type == 'windows':
return False return False
return True return True
@@ -349,7 +346,10 @@ class VMOps(object):
else: else:
requires_secure_boot = image_prop_secure_boot == constants.REQUIRED requires_secure_boot = image_prop_secure_boot == constants.REQUIRED
if vm_gen != constants.VM_GEN_2 and requires_secure_boot: 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 return requires_secure_boot
def create_instance(self, instance, network_info, root_device, def create_instance(self, instance, network_info, root_device,
@@ -391,9 +391,10 @@ class VMOps(object):
constants.FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY) constants.FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY)
if remote_fx_config: if remote_fx_config:
if vm_gen == constants.VM_GEN_2: if vm_gen == constants.VM_GEN_2:
raise vmutils.HyperVException(_("RemoteFX is not supported " reason = _("RemoteFX is not supported on generation 2 virtual "
"on generation 2 virtual " "machines.")
"machines.")) raise exception.InstanceUnacceptable(instance_id=instance.uuid,
reason=reason)
else: else:
self._configure_remotefx(instance, remote_fx_config) self._configure_remotefx(instance, remote_fx_config)
@@ -452,36 +453,33 @@ class VMOps(object):
self._vmutils.attach_ide_drive(instance_name, path, drive_addr, self._vmutils.attach_ide_drive(instance_name, path, drive_addr,
ctrl_disk_addr, drive_type) 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'] image_props = image_meta['properties']
default_vm_gen = self._hostutils.get_default_vm_generation() default_vm_gen = self._hostutils.get_default_vm_generation()
image_prop_vm = image_props.get(constants.IMAGE_PROP_VM_GEN, image_prop_vm = image_props.get(constants.IMAGE_PROP_VM_GEN,
default_vm_gen) default_vm_gen)
if image_prop_vm not in self._hostutils.get_supported_vm_types(): if image_prop_vm not in self._hostutils.get_supported_vm_types():
LOG.error(_LE('Requested VM Generation %s is not supported on ' reason = _LE('Requested VM Generation %s is not supported on '
' this OS.'), image_prop_vm) 'this OS.') % image_prop_vm
raise vmutils.HyperVException( raise exception.InstanceUnacceptable(instance_id=instance_id,
_('Requested VM Generation %s is not supported on this ' reason=reason)
'OS.') % image_prop_vm)
return VM_GENERATIONS[image_prop_vm] 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 if (vm_gen != constants.VM_GEN_1 and root_vhd_path and
self._vhdutils.get_vhd_format( self._vhdutils.get_vhd_format(
root_vhd_path) == constants.DISK_FORMAT_VHD): root_vhd_path) == constants.DISK_FORMAT_VHD):
LOG.error(_LE('Requested VM Generation %s, but provided VHD ' reason = _LE('Requested VM Generation %s is not supported on '
'instead of VHDX.'), vm_gen) 'this OS.') % vm_gen
raise vmutils.HyperVException( raise exception.InstanceUnacceptable(instance_id=instance_id,
_('Requested VM Generation %s, but provided VHD instead of ' reason=reason)
'VHDX.') % vm_gen)
def _create_config_drive(self, instance, injected_files, admin_password, def _create_config_drive(self, instance, injected_files, admin_password,
network_info, rescue=False): network_info, rescue=False):
if CONF.config_drive_format != 'iso9660': if CONF.config_drive_format != 'iso9660':
raise vmutils.UnsupportedConfigDriveFormatException( raise exception.ConfigDriveUnsupportedFormat(
_('Invalid config_drive_format "%s"') % format=CONF.config_drive_format)
CONF.config_drive_format)
LOG.info(_LI('Using config drive for instance'), instance=instance) LOG.info(_LI('Using config drive for instance'), instance=instance)
@@ -570,15 +568,17 @@ class VMOps(object):
def _configure_remotefx(self, instance, config): def _configure_remotefx(self, instance, config):
if not CONF.hyperv.enable_remotefx: if not CONF.hyperv.enable_remotefx:
raise vmutils.HyperVException( reason = _("enable_remotefx configuration option needs to be set "
_("enable_remotefx configuration option needs to be set to " "to True in order to use RemoteFX")
"True in order to use RemoteFX")) raise exception.InstanceUnacceptable(instance_id=instance.uuid,
reason=reason)
if not self._hostutils.check_server_feature( if not self._hostutils.check_server_feature(
self._hostutils.FEATURE_RDS_VIRTUALIZATION): self._hostutils.FEATURE_RDS_VIRTUALIZATION):
raise vmutils.HyperVException( reason = _("The RDS-Virtualization feature must be installed in "
_("The RDS-Virtualization feature must be installed " "order to use RemoteFX")
"in order to use RemoteFX")) raise exception.InstanceUnacceptable(instance_id=instance.uuid,
reason=reason)
instance_name = instance.name instance_name = instance.name
LOG.debug('Configuring RemoteFX for instance: %s', 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]: if port_number not in [1, 2]:
err_msg = _("Invalid serial port number: %(port_number)s. " err_msg = _("Invalid serial port number: %(port_number)s. "
"Only COM 1 and COM 2 are available.") "Only COM 1 and COM 2 are available.") % dict(
raise vmutils.HyperVException( port_number=port_number)
err_msg % {'port_number': port_number}) raise exception.ImageSerialPortNumberInvalid(err_msg)
existing_type = serial_ports.get(port_number) existing_type = serial_ports.get(port_number)
if (not existing_type or if (not existing_type or
@@ -854,24 +854,27 @@ class VMOps(object):
rescue_vhd_path = self._create_root_vhd( rescue_vhd_path = self._create_root_vhd(
context, instance, rescue_image_id=rescue_image_id) 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) vm_gen = self._vmutils.get_vm_gen(instance.name)
if rescue_vm_gen != vm_gen: if rescue_vm_gen != vm_gen:
err_msg = _('The requested rescue image requires a different VM ' err_msg = _('The requested rescue image requires a different VM '
'generation than the actual rescued instance. ' 'generation than the actual rescued instance. '
'Rescue image VM generation: %(rescue_vm_gen)s. ' 'Rescue image VM generation: %(rescue_vm_gen)s. '
'Rescued instance VM generation: %(vm_gen)s.') 'Rescued instance VM generation: %(vm_gen)s.') % dict(
raise vmutils.HyperVException(err_msg % rescue_vm_gen=rescue_vm_gen,
{'rescue_vm_gen': rescue_vm_gen, vm_gen=vm_gen)
'vm_gen': vm_gen}) raise exception.ImageUnacceptable(reason=err_msg,
self.check_vm_image_type(rescue_vm_gen, rescue_vhd_path) 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) root_vhd_path = self._pathutils.lookup_root_vhd_path(instance.name)
if not root_vhd_path: if not root_vhd_path:
err_msg = _('Instance root disk image could not be found. ' err_msg = _('Instance root disk image could not be found. '
'Rescuing instances booted from volume is ' 'Rescuing instances booted from volume is '
'not supported.') '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] controller_type = VM_GENERATIONS_CONTROLLER_TYPES[vm_gen]
@@ -904,9 +907,9 @@ class VMOps(object):
if (instance.vm_state == vm_states.RESCUED and if (instance.vm_state == vm_states.RESCUED and
not (rescue_vhd_path and root_vhd_path)): not (rescue_vhd_path and root_vhd_path)):
err_msg = _('Missing instance root and/or rescue image. ' err_msg = _('Missing instance root and/or rescue image.')
'The instance cannot be unrescued.') raise exception.InstanceNotRescuable(reason=err_msg,
raise vmutils.HyperVException(err_msg) instance_id=instance.uuid)
vm_gen = self._vmutils.get_vm_gen(instance.name) vm_gen = self._vmutils.get_vm_gen(instance.name)
controller_type = VM_GENERATIONS_CONTROLLER_TYPES[vm_gen] controller_type = VM_GENERATIONS_CONTROLLER_TYPES[vm_gen]

View File

@@ -177,7 +177,7 @@ class VolumeOps(object):
"Requested maximum IOPS: %(total_iops)s.") % "Requested maximum IOPS: %(total_iops)s.") %
{'min_iops': min_iops, {'min_iops': min_iops,
'total_iops': total_iops}) 'total_iops': total_iops})
raise vmutils.HyperVException(err_msg) raise exception.Invalid(err_msg)
unsupported_specs = [spec for spec in qos_specs if unsupported_specs = [spec for spec in qos_specs if
spec not in self._SUPPORTED_QOS_SPECS] spec not in self._SUPPORTED_QOS_SPECS]
@@ -224,11 +224,12 @@ class ISCSIVolumeDriver(object):
auth_password = data.get('auth_password') auth_password = data.get('auth_password')
if auth_method and auth_method.upper() != 'CHAP': if auth_method and auth_method.upper() != 'CHAP':
raise vmutils.HyperVException( LOG.error(_LE("Cannot log in target %(target_iqn)s. Unsupported "
_("Cannot log in target %(target_iqn)s. Unsupported iSCSI " "iSCSI authentication method: %(auth_method)s."),
"authentication method: %(auth_method)s.") %
{'target_iqn': target_iqn, {'target_iqn': target_iqn,
'auth_method': auth_method}) 'auth_method': auth_method})
raise exception.UnsupportedBDMVolumeAuthMethod(
auth_method=auth_method)
# Check if we already logged in # Check if we already logged in
if self._volutils.get_device_number_for_target(target_iqn, target_lun): if self._volutils.get_device_number_for_target(target_iqn, target_lun):
@@ -443,9 +444,12 @@ class SMBFSVolumeDriver(object):
ctrller_path, ctrller_path,
slot) slot)
except vmutils.HyperVException as exn: except vmutils.HyperVException as exn:
LOG.exception(_LE('Attach volume failed: %s'), exn) LOG.exception(_LE('Attach volume failed to %(instance_name)s: '
raise vmutils.HyperVException(_('Unable to attach volume ' '%(exn)s'), {'instance_name': instance_name,
'to instance %s') % 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): def detach_volume(self, connection_info, instance_name):
LOG.debug("Detaching volume: %(connection_info)s " LOG.debug("Detaching volume: %(connection_info)s "

View File

@@ -14,10 +14,10 @@
import mock import mock
from nova import exception
from hyperv.nova import block_device_manager from hyperv.nova import block_device_manager
from hyperv.nova import constants from hyperv.nova import constants
from hyperv.nova import vmutils
from hyperv.tests.unit import test_base from hyperv.tests.unit import test_base
@@ -106,7 +106,7 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
mock_get_avail_ctrl_slot, mock_get_avail_ctrl_slot,
disk_format, disk_format,
vm_gen=constants.VM_GEN_1, vm_gen=constants.VM_GEN_1,
exception=False, fail=False,
boot_from_volume=False): boot_from_volume=False):
image_meta = {'disk_format': disk_format} image_meta = {'disk_format': disk_format}
bdi = {'root_device': '/dev/sda', 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_is_boot_from_vol.return_value = boot_from_volume
mock_get_avail_ctrl_slot.return_value = (0, 0) mock_get_avail_ctrl_slot.return_value = (0, 0)
if exception: if fail:
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InvalidDiskFormat,
self._bdman._check_and_update_root_device, self._bdman._check_and_update_root_device,
vm_gen, image_meta, bdi, vm_gen, image_meta, bdi,
mock.sentinel.SLOT_MAP) mock.sentinel.SLOT_MAP)
@@ -148,7 +148,7 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
def test_check_and_update_root_device_exception(self): def test_check_and_update_root_device_exception(self):
self._test_check_and_update_root_device(disk_format='fake_format', self._test_check_and_update_root_device(disk_format='fake_format',
exception=True) fail=True)
def test_check_and_update_root_device_gen1(self): def test_check_and_update_root_device_gen1(self):
self._test_check_and_update_root_device(disk_format='vhd') 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) @mock.patch('nova.virt.configdrive.required_by', return_value=True)
def _test_get_available_controller_slot(self, mock_config_drive_req, def _test_get_available_controller_slot(self, mock_config_drive_req,
bus=constants.CTRL_TYPE_IDE, bus=constants.CTRL_TYPE_IDE,
exception=False): fail=False):
slot_map = self._bdman._initialize_controller_slot_counter( slot_map = self._bdman._initialize_controller_slot_counter(
mock.sentinel.FAKE_VM, constants.VM_GEN_1) 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][0] = 0
slot_map[constants.CTRL_TYPE_IDE][1] = 0 slot_map[constants.CTRL_TYPE_IDE][1] = 0
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.Invalid,
self._bdman._get_available_controller_slot, self._bdman._get_available_controller_slot,
constants.CTRL_TYPE_IDE, constants.CTRL_TYPE_IDE,
slot_map) slot_map)
@@ -196,7 +196,7 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
self._test_get_available_controller_slot() self._test_get_available_controller_slot()
def test_get_available_controller_slot_exception(self): 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): def test_get_available_controller_slot_scsi_ctrl(self):
self._test_get_available_controller_slot(bus=constants.CTRL_TYPE_SCSI) 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, @mock.patch.object(block_device_manager.BlockDeviceInfoManager,
'_get_available_controller_slot') '_get_available_controller_slot')
def _test_check_and_update_bdm(self, mock_get_ctrl_slot, def _test_check_and_update_bdm(self, mock_get_ctrl_slot,
bdm, exception=False, bdm, fail=False,
vm_gen=constants.VM_GEN_1, vm_gen=constants.VM_GEN_1,
slot_map=None): slot_map=None):
mock_get_ctrl_slot.return_value = ((mock.sentinel.DRIVE_ADDR, mock_get_ctrl_slot.return_value = ((mock.sentinel.DRIVE_ADDR,
mock.sentinel.CTRL_DISK_ADDR)) mock.sentinel.CTRL_DISK_ADDR))
if exception: if fail:
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InvalidDiskInfo,
self._bdman._check_and_update_bdm, self._bdman._check_and_update_bdm,
slot_map, vm_gen, bdm) slot_map, vm_gen, bdm)
else: else:
@@ -297,14 +297,14 @@ class BlockDeviceManagerTestCase(test_base.HyperVBaseTestCase):
bdm = {'device_type': 'cdrom', bdm = {'device_type': 'cdrom',
'disk_bus': 'IDE'} '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) slot_map=mock.sentinel.FAKE_SLOT_MAP)
def test_check_and_update_bdm_exception_disk_bus(self): def test_check_and_update_bdm_exception_disk_bus(self):
bdm = {'device_type': 'disk', bdm = {'device_type': 'disk',
'disk_bus': 'fake_bus'} '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) slot_map=mock.sentinel.FAKE_SLOT_MAP)
def test_sort_by_boot_order(self): def test_sort_by_boot_order(self):

View File

@@ -20,10 +20,10 @@ Unit tests for the Hyper-V Driver.
import platform import platform
import mock import mock
from nova import exception
from nova.virt import driver as base_driver from nova.virt import driver as base_driver
from hyperv.nova import driver from hyperv.nova import driver
from hyperv.nova import vmutils
from hyperv.tests.unit import test_base 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): def test_check_minimum_windows_version(self, mock_check_min_win_version):
mock_check_min_win_version.return_value = False mock_check_min_win_version.return_value = False
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.HypervisorTooOld,
self.driver._check_minimum_windows_version) self.driver._check_minimum_windows_version)
def test_public_api_signatures(self): def test_public_api_signatures(self):

View File

@@ -26,7 +26,6 @@ import six
from hyperv.nova import constants from hyperv.nova import constants
from hyperv.nova import hostops from hyperv.nova import hostops
from hyperv.nova import vmutils
from hyperv.tests.unit import test_base from hyperv.tests.unit import test_base
CONF = cfg.CONF CONF = cfg.CONF
@@ -254,7 +253,7 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
host=mock.sentinel.HOST, mode=True) host=mock.sentinel.HOST, mode=True)
self.assertEqual('on_maintenance', result) self.assertEqual('on_maintenance', result)
else: else:
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.MigrationError,
self._hostops.host_maintenance_mode, self._hostops.host_maintenance_mode,
host=mock.sentinel.HOST, host=mock.sentinel.HOST,
mode=True) mode=True)

View File

@@ -20,10 +20,10 @@ from nova import exception
from nova import objects from nova import objects
from nova.tests.unit.objects import test_flavor from nova.tests.unit.objects import test_flavor
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import units
from hyperv.nova import constants from hyperv.nova import constants
from hyperv.nova import imagecache from hyperv.nova import imagecache
from hyperv.nova import vmutils
from hyperv.tests import fake_instance from hyperv.tests import fake_instance
from hyperv.tests.unit import test_base from hyperv.tests.unit import test_base
@@ -36,6 +36,7 @@ class ImageCacheTestCase(test_base.HyperVBaseTestCase):
FAKE_BASE_DIR = 'fake/base/dir' FAKE_BASE_DIR = 'fake/base/dir'
FAKE_FORMAT = 'fake_format' FAKE_FORMAT = 'fake_format'
FAKE_IMAGE_REF = 'fake_image_ref' FAKE_IMAGE_REF = 'fake_image_ref'
FAKE_VHD_SIZE_GB = 1
def setUp(self): def setUp(self):
super(ImageCacheTestCase, self).setUp() super(ImageCacheTestCase, self).setUp()
@@ -47,6 +48,27 @@ class ImageCacheTestCase(test_base.HyperVBaseTestCase):
self.imagecache._pathutils = mock.MagicMock() self.imagecache._pathutils = mock.MagicMock()
self.imagecache._vhdutils = 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): def _test_get_root_vhd_size_gb(self, old_flavor=True):
if old_flavor: if old_flavor:
mock_flavor = objects.Flavor(**test_flavor.fake_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( expected_vhd_path) = self._prepare_get_cached_image(
rescue_image_id=fake_rescue_image_id, rescue_image_id=fake_rescue_image_id,
image_format=constants.DISK_FORMAT_VHD) image_format=constants.DISK_FORMAT_VHD)
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.FlavorDiskSmallerThanImage,
self.imagecache.get_cached_image, self.imagecache.get_cached_image,
self.context, self.instance, self.context, self.instance,
fake_rescue_image_id) fake_rescue_image_id)

View File

@@ -171,7 +171,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
instance.config_drive = 'True' instance.config_drive = 'True'
self._migrationops._pathutils.lookup_configdrive_path.return_value = ( self._migrationops._pathutils.lookup_configdrive_path.return_value = (
None) None)
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.ConfigDriveNotFound,
self._migrationops._check_and_attach_config_drive, self._migrationops._check_and_attach_config_drive,
instance, instance,
mock.sentinel.FAKE_VM_GEN) mock.sentinel.FAKE_VM_GEN)
@@ -260,7 +260,8 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
image_meta = ( image_meta = (
self._migrationops._imagecache.get_image_details.return_value) self._migrationops._imagecache.get_image_details.return_value)
get_image_vm_gen = self._migrationops._vmops.get_image_vm_generation 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( self._migrationops._vmops.create_instance.assert_called_once_with(
mock_instance, mock.sentinel.network_info, root_device, mock_instance, mock.sentinel.network_info, root_device,
block_device_info, get_image_vm_gen.return_value, 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._migrationops._pathutils.lookup_root_vhd_path.return_value = None
self.assertRaises( self.assertRaises(
vmutils.HyperVException, exception.DiskNotFound,
self._migrationops.finish_revert_migration, self.context, self._migrationops.finish_revert_migration, self.context,
mock_instance, mock.sentinel.network_info, bdi, True) 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) mock_resize_vhd.assert_called_once_with(mock.sentinel.vhd_path, 2)
def test_check_resize_vhd_exception(self): def test_check_resize_vhd_exception(self):
self.assertRaises(vmutils.VHDResizeException, self.assertRaises(exception.CannotResizeDisk,
self._migrationops._check_resize_vhd, self._migrationops._check_resize_vhd,
mock.sentinel.vhd_path, mock.sentinel.vhd_path,
{'MaxInternalSize': 1}, 0) {'MaxInternalSize': 1}, 0)
@@ -436,7 +437,8 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
self._migrationops._vhdutils.get_vhd_info.assert_has_calls( self._migrationops._vhdutils.get_vhd_info.assert_has_calls(
expected_get_info) expected_get_info)
get_image_vm_gen = self._migrationops._vmops.get_image_vm_generation 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( self._migrationops._vmops.create_instance.assert_called_once_with(
mock_instance, mock.sentinel.network_info, root_device, mock_instance, mock.sentinel.network_info, root_device,
block_device_info, get_image_vm_gen.return_value, 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) mock_instance = fake_instance.fake_instance_obj(self.context)
self._migrationops._pathutils.lookup_root_vhd_path.return_value = None self._migrationops._pathutils.lookup_root_vhd_path.return_value = None
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.DiskNotFound,
self._migrationops.finish_migration, self._migrationops.finish_migration,
self.context, mock.sentinel.migration, self.context, mock.sentinel.migration,
mock_instance, mock.sentinel.disk_info, mock_instance, mock.sentinel.disk_info,
@@ -481,7 +483,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
mock.sentinel.image_meta, True, mock.sentinel.image_meta, True,
bdi, True) bdi, True)
def _test_check_ephemeral_disks(self, exception, resize): def _test_check_ephemeral_disks(self, exc, resize):
mock_ephemerals = [dict(), dict()] mock_ephemerals = [dict(), dict()]
mock_instance = fake_instance.fake_instance_obj(self.context) mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.ephemeral_gb = 2 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 = mock_vhdutils.get_best_supported_vhd_format
mock_get_vhd_format.return_value = mock.sentinel.VHD_FORMAT mock_get_vhd_format.return_value = mock.sentinel.VHD_FORMAT
if exception: if exc:
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.DiskNotFound,
self._migrationops._check_ephemeral_disks, self._migrationops._check_ephemeral_disks,
mock_instance, mock_ephemerals) mock_instance, mock_ephemerals)
else: else:
@@ -518,7 +520,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
mock_instance.name, mock_ephemerals[1]) mock_instance.name, mock_ephemerals[1])
def test_check_ephemeral_disks_exception(self): 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): def test_check_ephemeral_disks(self):
self._test_check_ephemeral_disks(exception=False, resize=True) self._test_check_ephemeral_disks(exc=False, resize=True)

View File

@@ -16,6 +16,7 @@ import os
import time import time
import mock import mock
from nova import exception
from six.moves import builtins from six.moves import builtins
from hyperv.nova import constants from hyperv.nova import constants
@@ -200,7 +201,7 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
side_effect=WindowsError(pathutils.ERROR_INVALID_NAME)) side_effect=WindowsError(pathutils.ERROR_INVALID_NAME))
with mock.patch.object(builtins, 'WindowsError', with mock.patch.object(builtins, 'WindowsError',
fake_windows_error, create=True): fake_windows_error, create=True):
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.AdminRequired,
self._pathutils._get_instances_sub_dir, self._pathutils._get_instances_sub_dir,
fake_dir_name) fake_dir_name)

View File

@@ -23,7 +23,6 @@ from hyperv.nova import namedpipe
from hyperv.nova import serialconsolehandler from hyperv.nova import serialconsolehandler
from hyperv.nova import serialproxy from hyperv.nova import serialproxy
from hyperv.nova import utilsfactory from hyperv.nova import utilsfactory
from hyperv.nova import vmutils
from hyperv.tests.unit import test_base 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): def test_get_vm_serial_port_mapping_exception(self):
self._mock_get_port_connections([]) self._mock_get_port_connections([])
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.NovaException,
self._consolehandler._get_vm_serial_port_mapping) self._consolehandler._get_vm_serial_port_mapping)
@mock.patch('nova.console.type.ConsoleSerial') @mock.patch('nova.console.type.ConsoleSerial')

View File

@@ -20,7 +20,6 @@ from nova import exception
from hyperv.nova import serialconsolehandler from hyperv.nova import serialconsolehandler
from hyperv.nova import serialconsoleops from hyperv.nova import serialconsoleops
from hyperv.nova import vmutils
from hyperv.tests.unit import test_base from hyperv.tests.unit import test_base
@@ -98,7 +97,7 @@ class SerialConsoleOpsTestCase(test_base.HyperVBaseTestCase):
fake_open.side_effect = IOError fake_open.side_effect = IOError
fake_path_exists.return_value = True fake_path_exists.return_value = True
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.ConsoleLogOutputException,
self._serialops.get_console_output, self._serialops.get_console_output,
mock.sentinel.instance_name) mock.sentinel.instance_name)
fake_open.assert_called_once_with(mock.sentinel.log_path, 'rb') fake_open.assert_called_once_with(mock.sentinel.log_path, 'rb')

View File

@@ -14,10 +14,10 @@
# under the License. # under the License.
import mock import mock
from nova import exception
import socket import socket
from hyperv.nova import serialproxy from hyperv.nova import serialproxy
from hyperv.nova import vmutils
from hyperv.tests.unit import test_base from hyperv.tests.unit import test_base
@@ -49,7 +49,7 @@ class SerialProxyTestCase(test_base.HyperVBaseTestCase):
fake_socket.listen.side_effect = socket.error fake_socket.listen.side_effect = socket.error
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.NovaException,
self._proxy._setup_socket) self._proxy._setup_socket)
fake_socket.setsockopt.assert_called_once_with(socket.SOL_SOCKET, fake_socket.setsockopt.assert_called_once_with(socket.SOL_SOCKET,

View File

@@ -154,7 +154,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_get_cached_image.return_value = fake_vhd_path mock_get_cached_image.return_value = fake_vhd_path
fake_root_path = self._vmops._pathutils.get_root_vhd_path.return_value 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, self._vmops._create_root_vhd, self.context,
mock_instance) mock_instance)
@@ -256,7 +256,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
def test_is_resize_needed_exception(self): def test_is_resize_needed_exception(self):
inst = mock.MagicMock() inst = mock.MagicMock()
self.assertRaises( 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) mock.sentinel.FAKE_PATH, self.FAKE_SIZE, self.FAKE_SIZE - 1, inst)
def test_is_resize_needed_true(self): 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_create_root_device.assert_called_once_with(self.context,
mock_instance) mock_instance)
mock_check_vm_image_type.assert_called_once_with( 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') @mock.patch.object(vmops.VMOps, '_create_root_iso')
def test_create_root_device_type_iso(self, mock_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) fake_vm_gen)
mock_create_ephemerals.assert_called_once_with(mock_instance, mock_create_ephemerals.assert_called_once_with(mock_instance,
block_device_info['ephemerals']) 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_create_instance.assert_called_once_with(
mock_instance, [fake_network_info], root_device_info, mock_instance, [fake_network_info], root_device_info,
block_device_info, fake_vm_gen, mock_image_meta) 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 = [ self._vmops._hostutils.get_supported_vm_types.return_value = [
constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2] 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, self._vmops.get_image_vm_generation,
mock.sentinel.instance_id,
image_meta) image_meta)
def test_get_image_vm_generation_default(self): 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 = [ self._vmops._hostutils.get_supported_vm_types.return_value = [
constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2] 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) 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 = [ self._vmops._hostutils.get_supported_vm_types.return_value = [
constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2] 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) self.assertEqual(constants.VM_GEN_2, response)
@@ -728,9 +733,9 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._vmops._vhdutils.get_vhd_format = mock.MagicMock( self._vmops._vhdutils.get_vhd_format = mock.MagicMock(
return_value=constants.DISK_FORMAT_VHD) return_value=constants.DISK_FORMAT_VHD)
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InstanceUnacceptable,
self._vmops.check_vm_image_type, constants.VM_GEN_2, self._vmops.check_vm_image_type, mock.sentinel.instance_id,
mock.sentinel.FAKE_VHD_PATH) constants.VM_GEN_2, mock.sentinel.FAKE_VHD_PATH)
@mock.patch('nova.api.metadata.base.InstanceMetadata') @mock.patch('nova.api.metadata.base.InstanceMetadata')
@mock.patch('nova.virt.configdrive.ConfigDriveBuilder') @mock.patch('nova.virt.configdrive.ConfigDriveBuilder')
@@ -766,7 +771,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
expected_get_configdrive_path_calls.append(expected_call) expected_get_configdrive_path_calls.append(expected_call)
if config_drive_format != self.ISO9660: if config_drive_format != self.ISO9660:
self.assertRaises(vmutils.UnsupportedConfigDriveFormatException, self.assertRaises(exception.ConfigDriveUnsupportedFormat,
self._vmops._create_config_drive, self._vmops._create_config_drive,
mock_instance, [mock.sentinel.FILE], mock_instance, [mock.sentinel.FILE],
mock.sentinel.PASSWORD, 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, '_create_root_vhd')
@mock.patch.object(vmops.VMOps, 'get_image_vm_generation') @mock.patch.object(vmops.VMOps, 'get_image_vm_generation')
def _test_rescue_instance_exception(self, mock_get_image_vm_gen, def test_rescue_instance_boot_from_volume(self, mock_get_image_vm_gen,
mock_create_root_vhd, 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)
mock_image_meta = {'id': mock.sentinel.rescue_image_id} mock_image_meta = {'id': mock.sentinel.rescue_image_id}
mock_instance = fake_instance.fake_instance_obj(self.context) mock_instance = fake_instance.fake_instance_obj(self.context)
mock_get_image_vm_gen.return_value = image_vm_gen mock_get_image_vm_gen.return_value = constants.VM_GEN_1
self._vmops._vmutils.get_vm_gen.return_value = mock_vm_gen self._vmops._vmutils.get_vm_gen.return_value = constants.VM_GEN_1
self._vmops._pathutils.lookup_root_vhd_path.return_value = ( self._vmops._pathutils.lookup_root_vhd_path.return_value = None
mock.sentinel.root_vhd_path if not boot_from_volume else None)
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InstanceNotRescuable,
self._vmops.rescue_instance, self._vmops.rescue_instance,
self.context, mock_instance, self.context, mock_instance,
mock.sentinel.network_info, mock.sentinel.network_info,
mock_image_meta, mock_image_meta,
mock.sentinel.rescue_password) 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 # Test the case when the rescue image requires a different
# vm generation than the actual rescued instance. # 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): self.assertRaises(exception.ImageUnacceptable,
# Rescuing instances booted from volume is not supported. self._vmops.rescue_instance,
self._test_rescue_instance_exception(boot_from_volume=True) 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(fileutils, 'delete_if_exists')
@mock.patch.object(vmops.VMOps, '_attach_drive') @mock.patch.object(vmops.VMOps, '_attach_drive')
@@ -1363,7 +1371,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_instance.vm_state = vm_states.RESCUED mock_instance.vm_state = vm_states.RESCUED
self._vmops._pathutils.lookup_root_vhd_path.return_value = None self._vmops._pathutils.lookup_root_vhd_path.return_value = None
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InstanceNotRescuable,
self._vmops.unrescue_instance, self._vmops.unrescue_instance,
mock_instance) mock_instance)
@@ -1423,7 +1431,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
def test_get_instance_vnuma_config_no_topology(self): def test_get_instance_vnuma_config_no_topology(self):
self._check_get_instance_vnuma_config() 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') self.flags(enable_remotefx=True, group='hyperv')
mock_instance = fake_instance.fake_instance_obj(self.context) 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 enable_remotefx = self._vmops._vmutils.enable_remotefx_video_adapter
self._vmops._hostutils.check_server_feature = mock.MagicMock() self._vmops._hostutils.check_server_feature = mock.MagicMock()
if exception: if fail:
self._vmops._hostutils.check_server_feature.return_value = False self._vmops._hostutils.check_server_feature.return_value = False
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InstanceUnacceptable,
self._vmops._configure_remotefx, self._vmops._configure_remotefx,
mock_instance, fake_config) mock_instance, fake_config)
else: else:
@@ -1447,7 +1455,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
fake_resolution) fake_resolution)
def test_configure_remotefx_exception(self): def test_configure_remotefx_exception(self):
self._test_configure_remotefx(exception=True) self._test_configure_remotefx(fail=True)
def test_configure_remotefx(self): def test_configure_remotefx(self):
self._test_configure_remotefx() self._test_configure_remotefx()
@@ -1570,7 +1578,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
expected_exception = not (logging_port in acceptable_ports and expected_exception = not (logging_port in acceptable_ports and
interactive_port in acceptable_ports) interactive_port in acceptable_ports)
if expected_exception: if expected_exception:
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.ImageSerialPortNumberInvalid,
self._vmops._get_image_serial_port_settings, self._vmops._get_image_serial_port_settings,
mock_image_meta) mock_image_meta)
else: else:
@@ -1707,11 +1715,13 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
def _test_requires_certificate(self, os_type): def _test_requires_certificate(self, os_type):
image_meta = {'properties': {'os_type': os_type}} image_meta = {'properties': {'os_type': os_type}}
if not os_type: if not os_type:
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.InstanceUnacceptable,
self._vmops._requires_certificate, image_meta) self._vmops._requires_certificate,
mock.sentinel.instance_id, image_meta)
else: else:
expected_result = os_type == 'linux' 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) self.assertEqual(expected_result, result)
def test_requires_certificate_windows(self): def test_requires_certificate_windows(self):

View File

@@ -31,7 +31,8 @@ from hyperv.tests.unit import test_base
CONF = cfg.CONF 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_iqn': mock.sentinel.fake_iqn,
'target_portal': mock.sentinel.fake_portal, 'target_portal': mock.sentinel.fake_portal,
'auth_method': 'chap', 'auth_method': 'chap',
@@ -217,7 +218,7 @@ class VolumeOpsTestCase(test_base.HyperVBaseTestCase):
'min_iops_sec': 2 'min_iops_sec': 2
} }
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.Invalid,
self._volumeops.parse_disk_qos_specs, self._volumeops.parse_disk_qos_specs,
fake_qos_specs) fake_qos_specs)
@@ -244,7 +245,7 @@ class ISCSIVolumeDriverTestCase(test_base.HyperVBaseTestCase):
connection_info = get_fake_connection_info( connection_info = get_fake_connection_info(
auth_method='fake_auth_method') auth_method='fake_auth_method')
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.UnsupportedBDMVolumeAuthMethod,
self._volume_driver.login_storage_target, self._volume_driver.login_storage_target,
connection_info) connection_info)
@@ -483,7 +484,8 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
_FAKE_PASSWORD) _FAKE_PASSWORD)
_FAKE_CONNECTION_INFO = {'data': {'export': _FAKE_SHARE, _FAKE_CONNECTION_INFO = {'data': {'export': _FAKE_SHARE,
'name': _FAKE_DISK_NAME, 'name': _FAKE_DISK_NAME,
'options': _FAKE_SMB_OPTIONS}} 'options': _FAKE_SMB_OPTIONS,
'volume_id': 'fake_vol_id'}}
def setUp(self): def setUp(self):
super(SMBFSVolumeDriverTestCase, self).setUp() super(SMBFSVolumeDriverTestCase, self).setUp()
@@ -542,7 +544,7 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
mock_ensure_share_mounted): mock_ensure_share_mounted):
self._volume_driver._vmutils.attach_drive.side_effect = ( self._volume_driver._vmutils.attach_drive.side_effect = (
vmutils.HyperVException()) vmutils.HyperVException())
self.assertRaises(vmutils.HyperVException, self.assertRaises(exception.VolumeAttachFailed,
self._volume_driver.attach_volume, self._volume_driver.attach_volume,
self._FAKE_CONNECTION_INFO, self._FAKE_CONNECTION_INFO,
mock.sentinel.instance_name) mock.sentinel.instance_name)