def get_image_vm_generation(self, root_vhd_path, 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) vm_gen = VM_GENERATIONS[image_prop_vm] 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) return vm_gen
def check_live_migration_config(self): conn_v2 = self._get_conn_v2() migration_svc = conn_v2.Msvm_VirtualSystemMigrationService()[0] vsmssds = migration_svc.associators( wmi_association_class='Msvm_ElementSettingData', wmi_result_class='Msvm_VirtualSystemMigrationServiceSettingData') vsmssd = vsmssds[0] if not vsmssd.EnableVirtualSystemMigration: raise vmutils.HyperVException( _('Live migration is not enabled on this host')) if not migration_svc.MigrationServiceListenerIPAddressList: raise vmutils.HyperVException( _('Live migration networks are not configured on this host'))
def execute(self, *args, **kwargs): stdout_value, stderr_value = utils.execute(*args, **kwargs) if stdout_value.find('The operation completed successfully') == -1: raise vmutils.HyperVException( _('An error has occurred when ' 'calling the iscsi initiator: %s') % stdout_value) return stdout_value
def create_dynamic_vhd(self, path, max_internal_size, format): vhd_format = self._vhd_format_map.get(format) if not vhd_format: raise vmutils.HyperVException(_("Unsupported disk format: %s") % format) self._create_vhd(self._VHD_TYPE_DYNAMIC, vhd_format, path, max_internal_size=max_internal_size)
def _get_vm(self, conn_v2, vm_name): vms = conn_v2.Msvm_ComputerSystem(ElementName=vm_name) n = len(vms) if not n: raise exception.NotFound(_('VM not found: %s') % vm_name) elif n > 1: raise vmutils.HyperVException(_('Duplicate VM name found: %s') % vm_name) return vms[0]
def test_reboot_soft_exception(self, mock_soft_shutdown, mock_power_on): mock_soft_shutdown.return_value = True mock_power_on.side_effect = vmutils.HyperVException("Expected failure") instance = fake_instance.fake_instance_obj(self.context) self.assertRaises(vmutils.HyperVException, self._vmops.reboot, instance, {}, vmops.REBOOT_TYPE_SOFT) mock_soft_shutdown.assert_called_once_with(instance) mock_power_on.assert_called_once_with(instance)
def _get_virt_utils_class(v1_class, v2_class): # The "root/virtualization" WMI namespace is no longer supported on # Windows Server / Hyper-V Server 2012 R2 / Windows 8.1 # (kernel version 6.3) or above. if (CONF.hyperv.force_hyperv_utils_v1 and get_hostutils().check_min_windows_version(6, 3)): raise vmutils.HyperVException( _('The "force_hyperv_utils_v1" option cannot be set to "True" ' 'on Windows Server / Hyper-V Server 2012 R2 or above as the WMI ' '"root/virtualization" namespace is no longer supported.')) return _get_class(v1_class, v2_class, CONF.hyperv.force_hyperv_utils_v1)
def _check_and_attach_config_drive(self, instance, vm_gen): if configdrive.required_by(instance): configdrive_path = self._pathutils.lookup_configdrive_path( instance.name) if configdrive_path: 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)
def test_soft_shutdown_failed(self, mock_sleep): instance = fake_instance.fake_instance_obj(self.context) mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm mock_shutdown_vm.side_effect = vmutils.HyperVException( "Expected failure.") result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT) mock_shutdown_vm.assert_called_once_with(instance.name) self.assertFalse(result)
def get_external_vswitch(self, vswitch_name): if vswitch_name: vswitches = self._conn.Msvm_VirtualEthernetSwitch( ElementName=vswitch_name) if not len(vswitches): raise vmutils.HyperVException( _('vswitch "%s" not found') % vswitch_name) else: # Find the vswitch that is connected to the first physical nic. ext_port = self._conn.Msvm_ExternalEthernetPort(IsBound='TRUE')[0] lep = ext_port.associators(wmi_result_class='Msvm_LANEndpoint')[0] lep1 = lep.associators(wmi_result_class='Msvm_LANEndpoint')[0] esw = lep1.associators( wmi_result_class='Msvm_EthernetSwitchPort')[0] vswitches = esw.associators( wmi_result_class='Msvm_VirtualEthernetSwitch') if not len(vswitches): raise vmutils.HyperVException(_('No external vswitch found')) return vswitches[0].path_()
def mount_smb_share(self, smbfs_share, username=None, password=None): try: LOG.debug('Mounting share: %s', smbfs_share) self._smb_conn.Msft_SmbMapping.Create(RemotePath=smbfs_share, UserName=username, Password=password) except wmi.x_wmi as exc: err_msg = (_('Unable to mount SMBFS share: %(smbfs_share)s ' 'WMI exception: %(wmi_exc)s'), { 'smbfs_share': smbfs_share, 'wmi_exc': exc }) raise vmutils.HyperVException(err_msg)
def finish_migration(self, context, migration, instance, disk_info, network_info, image_meta, resize_instance=False, block_device_info=None, power_on=True): LOG.debug("finish_migration called", instance=instance) instance_name = instance.name if self._volumeops.ebs_root_in_block_devices(block_device_info): root_vhd_path = None else: root_vhd_path = self._pathutils.lookup_root_vhd_path(instance_name) if not root_vhd_path: raise vmutils.HyperVException( _("Cannot find boot VHD " "file for instance: %s") % instance_name) root_vhd_info = self._vhdutils.get_vhd_info(root_vhd_path) src_base_disk_path = root_vhd_info.get("ParentPath") if src_base_disk_path: self._check_base_disk(context, instance, root_vhd_path, src_base_disk_path) if resize_instance: new_size = instance.root_gb * units.Gi self._check_resize_vhd(root_vhd_path, root_vhd_info, new_size) eph_vhd_path = self._pathutils.lookup_ephemeral_vhd_path(instance_name) if resize_instance: new_size = instance.get('ephemeral_gb', 0) * units.Gi if not eph_vhd_path: if new_size: eph_vhd_path = self._vmops.create_ephemeral_vhd(instance) else: eph_vhd_info = self._vhdutils.get_vhd_info(eph_vhd_path) self._check_resize_vhd(eph_vhd_path, eph_vhd_info, new_size) vm_gen = self._vmops.get_image_vm_generation(root_vhd_path, image_meta) self._vmops.create_instance(instance, network_info, block_device_info, root_vhd_path, eph_vhd_path, vm_gen) self._check_and_attach_config_drive(instance, vm_gen) if power_on: self._vmops.power_on(instance)
def _resize_and_cache_vhd(self, instance, vhd_path): vhd_info = self._vhdutils.get_vhd_info(vhd_path) vhd_size = vhd_info['MaxInternalSize'] root_vhd_size_gb = self._get_root_vhd_size_gb(instance) root_vhd_size = root_vhd_size_gb * units.Gi root_vhd_internal_size = ( self._vhdutils.get_internal_vhd_size_by_file_size( 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 }) if root_vhd_internal_size > vhd_size: path_parts = os.path.splitext(vhd_path) resized_vhd_path = '%s_%s%s' % (path_parts[0], root_vhd_size_gb, path_parts[1]) @utils.synchronized(resized_vhd_path) def copy_and_resize_vhd(): if not self._pathutils.exists(resized_vhd_path): try: LOG.debug( "Copying VHD %(vhd_path)s to " "%(resized_vhd_path)s", { 'vhd_path': vhd_path, 'resized_vhd_path': resized_vhd_path }) self._pathutils.copyfile(vhd_path, resized_vhd_path) LOG.debug( "Resizing VHD %(resized_vhd_path)s to new " "size %(root_vhd_size)s", { 'resized_vhd_path': resized_vhd_path, 'root_vhd_size': root_vhd_size }) self._vhdutils.resize_vhd(resized_vhd_path, root_vhd_internal_size, is_file_max_size=False) except Exception: with excutils.save_and_reraise_exception(): if self._pathutils.exists(resized_vhd_path): self._pathutils.remove(resized_vhd_path) copy_and_resize_vhd() return resized_vhd_path
def login_storage_target(self, target_lun, target_iqn, target_portal, auth_username=None, auth_password=None): """Ensure that the target is logged in.""" self._login_target_portal(target_portal) retry_count = CONF.hyperv.volume_attach_retry_count # If the target is not connected, at least two iterations are needed: # one for performing the login and another one for checking if the # target was logged in successfully. if retry_count < 2: retry_count = 2 for attempt in xrange(retry_count): target = self._conn_storage.query("SELECT * FROM MSFT_iSCSITarget " "WHERE NodeAddress='%s' " % target_iqn) if target and target[0].IsConnected: if attempt == 0: # The target was already connected but an update may be # required target[0].Update() return try: target = self._conn_storage.MSFT_iSCSITarget auth = {} if auth_username and auth_password: auth['AuthenticationType'] = self._CHAP_AUTH_TYPE auth['ChapUsername'] = auth_username auth['ChapSecret'] = auth_password target.Connect(NodeAddress=target_iqn, IsPersistent=True, **auth) time.sleep(CONF.hyperv.volume_attach_retry_interval) except wmi.x_wmi as exc: LOG.debug("Attempt %(attempt)d to connect to target " "%(target_iqn)s failed. Retrying. " "WMI exception: %(exc)s " % { 'target_iqn': target_iqn, 'exc': exc, 'attempt': attempt }) raise vmutils.HyperVException( _('Failed to login target %s') % target_iqn)
def _get_conn_v2(self, host='localhost'): try: return wmi.WMI(moniker='//%s/root/virtualization/v2' % host) except wmi.x_wmi as ex: LOG.exception(_LE('Get version 2 connection error')) if ex.com_error.hresult == -2147217394: msg = (_('Live migration is not supported on target host "%s"') % host) elif ex.com_error.hresult == -2147023174: msg = (_('Target live migration host "%s" is unreachable') % host) else: msg = _('Live migration failed: %s') % ex.message raise vmutils.HyperVException(msg)
def get_internal_vhd_size_by_file_size(self, vhd_path, new_vhd_file_size): """VHDX Size = Header (1 MB) + Log + Metadata Region + BAT + Payload Blocks Chunk size = maximum number of bytes described by a SB block = 2 ** 23 * LogicalSectorSize """ vhd_format = self.get_vhd_format(vhd_path) if vhd_format == constants.DISK_FORMAT_VHD: return super(VHDUtilsV2, self).get_internal_vhd_size_by_file_size( vhd_path, new_vhd_file_size) else: vhd_info = self.get_vhd_info(vhd_path) vhd_type = vhd_info['Type'] if vhd_type == self._VHD_TYPE_DIFFERENCING: vhd_parent = self.get_vhd_parent_path(vhd_path) return self.get_internal_vhd_size_by_file_size(vhd_parent, new_vhd_file_size) else: try: with open(vhd_path, 'rb') as f: hs = VHDX_HEADER_SECTION_SIZE bes = VHDX_BAT_ENTRY_SIZE lss = vhd_info['LogicalSectorSize'] bs = self._get_vhdx_block_size(f) ls = self._get_vhdx_log_size(f) ms = self._get_vhdx_metadata_size_and_offset(f)[0] chunk_ratio = (1 << 23) * lss / bs size = new_vhd_file_size max_internal_size = (bs * chunk_ratio * (size - hs - ls - ms - bes - bes / chunk_ratio) / (bs * chunk_ratio + bes * chunk_ratio + bes)) return max_internal_size - (max_internal_size % bs) except IOError as ex: raise vmutils.HyperVException(_("Unable to obtain " "internal size from VHDX: " "%(vhd_path)s. Exception: " "%(ex)s") % {"vhd_path": vhd_path, "ex": ex})
def get_console_output(self, instance): console_log_paths = (self._pathutils.get_vm_console_log_paths( instance.name)) try: instance_log = '' # Start with the oldest console log file. for console_log_path in console_log_paths[::-1]: if os.path.exists(console_log_path): with open(console_log_path, 'rb') as fp: instance_log += fp.read() return instance_log except IOError as err: msg = _("Could not get instance console log. Error: %s") % err raise vmutils.HyperVException(msg, instance=instance)
def create_vswitch_port(self, vswitch_path, port_name): switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0] # Create a port on the vswitch. (new_port, ret_val) = switch_svc.CreateSwitchPort(Name=str(uuid.uuid4()), FriendlyName=port_name, ScopeOfResidence="", VirtualSwitch=vswitch_path) if ret_val != 0: raise vmutils.HyperVException( _("Failed to create vswitch port " "%(port_name)s on switch " "%(vswitch_path)s") % { 'port_name': port_name, 'vswitch_path': vswitch_path }) return new_port
def login_storage_target(self, target_lun, target_iqn, target_portal, auth_username=None, auth_password=None): """Ensure that the target is logged in.""" self._login_target_portal(target_portal) # Listing targets self.execute('iscsicli.exe', 'ListTargets') retry_count = CONF.hyperv.volume_attach_retry_count # If the target is not connected, at least two iterations are needed: # one for performing the login and another one for checking if the # target was logged in successfully. if retry_count < 2: retry_count = 2 for attempt in xrange(retry_count): try: session_info = self.execute('iscsicli.exe', 'SessionList') if session_info.find(target_iqn) == -1: # Sending login self.execute('iscsicli.exe', 'qlogintarget', target_iqn, auth_username, auth_password) else: return except vmutils.HyperVException as exc: LOG.debug( "Attempt %(attempt)d to connect to target " "%(target_iqn)s failed. Retrying. " "Exceptipn: %(exc)s ", { 'target_iqn': target_iqn, 'exc': exc, 'attempt': attempt }) time.sleep(CONF.hyperv.volume_attach_retry_interval) raise vmutils.HyperVException( _('Failed to login target %s') % target_iqn)
def unmount_smb_share(self, smbfs_share, force=False): mappings = self._smb_conn.Msft_SmbMapping(RemotePath=smbfs_share) if not mappings: LOG.debug('Share %s is not mounted. Skipping unmount.', smbfs_share) for mapping in mappings: # Due to a bug in the WMI module, getting the output of # methods returning None will raise an AttributeError try: mapping.Remove(Force=force) except AttributeError: pass except wmi.x_wmi: # If this fails, a 'Generic Failure' exception is raised. # This happens even if we unforcefully unmount an in-use # share, for which reason we'll simply ignore it in this # case. if force: raise vmutils.HyperVException( _("Could not unmount share: %s"), smbfs_share)
def reconnect_parent_vhd(self, child_vhd_path, parent_vhd_path): image_man_svc = self._conn.Msvm_ImageManagementService()[0] vhd_info_xml = self._get_vhd_info_xml(image_man_svc, child_vhd_path) et = ElementTree.fromstring(vhd_info_xml) item = et.find(".//PROPERTY[@NAME='ParentPath']/VALUE") if item is not None: item.text = parent_vhd_path else: msg = (_("Failed to reconnect image %(child_vhd_path)s to " "parent %(parent_vhd_path)s. The child image has no " "parent path property.") % {'child_vhd_path': child_vhd_path, 'parent_vhd_path': parent_vhd_path}) raise vmutils.HyperVException(msg) vhd_info_xml = ElementTree.tostring(et) (job_path, ret_val) = image_man_svc.SetVirtualHardDiskSettingData( VirtualDiskSettingData=vhd_info_xml) self._vmutils.check_ret_val(ret_val, job_path)
def _get_instances_sub_dir(self, dir_name, remote_server=None, create_dir=True, remove_dir=False): instances_path = self.get_instances_dir(remote_server) path = os.path.join(instances_path, dir_name) try: if remove_dir: self._check_remove_dir(path) if create_dir: self._check_create_dir(path) return path except WindowsError as ex: if ex.winerror == ERROR_INVALID_NAME: raise vmutils.HyperVException( _("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 " "builtin SYSTEM account or other accounts unable to " "authenticate on a remote host.") % {'instances_path': instances_path}) raise
def _test_attach_volume(self, mock_attach_drive, mock_get_free_controller_slot, mock_get_vm_scsi_controller, mock_get_disk_path, mock_ensure_share_mounted, mock_parse_credentials, image_exists=True): mock_parse_credentials.return_value = (mock.sentinel.username, self._FAKE_PASSWORD) mock_get_vm_scsi_controller.return_value = ( mock.sentinel.controller_path) mock_get_free_controller_slot.return_value = ( mock.sentinel.controller_slot) mock_get_disk_path.return_value = (mock.sentinel.disk_path) if image_exists: self._volume_driver.attach_volume(self._FAKE_CONNECTION_INFO, mock.sentinel.instance_name) mock_ensure_share_mounted.assert_called_with( self._FAKE_CONNECTION_INFO) mock_get_disk_path.assert_called_with(self._FAKE_CONNECTION_INFO) mock_get_vm_scsi_controller.assert_called_with( mock.sentinel.instance_name) mock_get_free_controller_slot.assert_called_with( mock.sentinel.controller_path) mock_attach_drive.assert_called_with(mock.sentinel.instance_name, mock.sentinel.disk_path, mock.sentinel.controller_path, mock.sentinel.controller_slot) else: mock_attach_drive.side_effect = (vmutils.HyperVException()) self.assertRaises(vmutils.HyperVException, self._volume_driver.attach_volume, self._FAKE_CONNECTION_INFO, mock.sentinel.instance_name)
def update(self_fake, context, image_id, image_metadata, f): if self._update_image_raise_exception: raise vmutils.HyperVException( "Simulated update failure") self._image_metadata = image_metadata
def fake_login_storage_target(self, connection_info): raise vmutils.HyperVException('Fake connection exception')
def _mock_get_mounted_disk_from_lun_error(self, target_iqn, target_lun, fake_mounted_disk, fake_device_number): m = volumeutils.VolumeUtils.get_device_number_for_target( target_iqn, target_lun) m.AndRaise(vmutils.HyperVException('Simulated failure'))