def _set_vm_state(self, vm_name, req_state): try: self._vmutils.set_vm_state(vm_name, req_state) LOG.debug( _("Successfully changed state of VM %(vm_name)s" " to: %(req_state)s") % locals()) except Exception as ex: LOG.exception(ex) msg = _("Failed to change vm state of %(vm_name)s" " to %(req_state)s") % locals() raise vmutils.HyperVException(msg)
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 _create_root_vhd(self, context, instance): base_vhd_path = self._imagecache.get_cached_image(context, instance) format_ext = base_vhd_path.split('.')[-1] root_vhd_path = self._pathutils.get_root_vhd_path(instance['name'], format_ext) try: if CONF.use_cow_images: LOG.debug(_("Creating differencing VHD. Parent: " "%(base_vhd_path)s, Target: %(root_vhd_path)s"), {'base_vhd_path': base_vhd_path, 'root_vhd_path': root_vhd_path}, instance=instance) self._vhdutils.create_differencing_vhd(root_vhd_path, base_vhd_path) else: LOG.debug(_("Copying VHD image %(base_vhd_path)s to target: " "%(root_vhd_path)s"), {'base_vhd_path': base_vhd_path, 'root_vhd_path': root_vhd_path}, instance=instance) self._pathutils.copyfile(base_vhd_path, root_vhd_path) base_vhd_info = self._vhdutils.get_vhd_info(base_vhd_path) base_vhd_size = base_vhd_info['MaxInternalSize'] root_vhd_size = instance['root_gb'] * units.Gi root_vhd_internal_size = ( self._vhdutils.get_internal_vhd_size_by_file_size( root_vhd_path, root_vhd_size)) if root_vhd_internal_size < base_vhd_size: error_msg = _("Cannot resize a VHD to a smaller size, the" " original size is %(base_vhd_size)s, the" " newer size is %(root_vhd_size)s" ) % {'base_vhd_size': base_vhd_size, 'root_vhd_size': root_vhd_internal_size} raise vmutils.HyperVException(error_msg) elif root_vhd_internal_size > base_vhd_size: LOG.debug(_("Resizing VHD %(root_vhd_path)s to new " "size %(root_vhd_size)s"), {'root_vhd_size': root_vhd_internal_size, 'root_vhd_path': root_vhd_path}, instance=instance) self._vhdutils.resize_vhd(root_vhd_path, root_vhd_internal_size, is_file_max_size=False) except Exception: with excutils.save_and_reraise_exception(): if self._pathutils.exists(root_vhd_path): self._pathutils.remove(root_vhd_path) return root_vhd_path
def _create_scsi_controller(self, vm_name): """ Create an iscsi controller ready to mount volumes """ LOG.debug(_('Creating a scsi controller for %(vm_name)s for volume ' 'attaching') % locals()) vms = self._conn.MSVM_ComputerSystem(ElementName=vm_name) vm = vms[0] scsicontrldefault = self._conn.query( "SELECT * FROM Msvm_ResourceAllocationSettingData \ WHERE ResourceSubType = 'Microsoft Synthetic SCSI Controller'\ AND InstanceID LIKE '%Default%'")[0] if scsicontrldefault is None: raise vmutils.HyperVException(_('Controller not found')) scsicontrl = self._vmutils.clone_wmi_obj(self._conn, 'Msvm_ResourceAllocationSettingData', scsicontrldefault) scsicontrl.VirtualSystemIdentifiers = ['{' + str(uuid.uuid4()) + '}'] scsiresource = self._vmutils.add_virt_resource(self._conn, scsicontrl, vm) if scsiresource is None: raise vmutils.HyperVException( _('Failed to add scsi controller to VM %s') % vm_name)
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 execute(self, *args, **kwargs): proc = subprocess.Popen( [args], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) stdout_value, stderr_value = proc.communicate() if stdout_value.find('The operation completed successfully') == -1: raise vmutils.HyperVException( _('An error has occurred when ' 'calling the iscsi initiator: %s') % stdout_value)
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 _cache_image(self, fn, target, fname, cow=False, Size=None, *args, **kwargs): """Wrapper for a method that creates an image that caches the image. This wrapper will save the image into a common store and create a copy for use by the hypervisor. The underlying method should specify a kwarg of target representing where the image will be saved. fname is used as the filename of the base image. The filename needs to be unique to a given image. If cow is True, it will make a CoW image instead of a copy. """ @lockutils.synchronized(fname, 'nova-') def call_if_not_exists(path, fn, *args, **kwargs): if not os.path.exists(path): fn(target=path, *args, **kwargs) if not os.path.exists(target): LOG.debug(_("use_cow_image:%s"), cow) if cow: base = self._vmutils.get_base_vhd_path(fname) call_if_not_exists(base, fn, *args, **kwargs) image_service = self._conn.query( "Select * from Msvm_ImageManagementService")[0] (job, ret_val) = \ image_service.CreateDifferencingVirtualHardDisk( Path=target, ParentPath=base) LOG.debug( "Creating difference disk: JobID=%s, Source=%s, Target=%s", job, base, target) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job) else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _('Failed to create Difference Disk from ' '%(base)s to %(target)s') % locals()) else: call_if_not_exists(target, fn, *args, **kwargs)
def _get_mounted_disk_from_lun(self, target_iqn, target_lun): device_number = self._volutils.get_device_number_for_target(target_iqn, target_lun) if device_number is None: raise vmutils.HyperVException(_('Unable to find a mounted ' 'disk for target_iqn: %s') % target_iqn) LOG.debug(_('Device number: %(device_number)s, ' 'target lun: %(target_lun)s') % locals()) #Finding Mounted disk drive for i in range(1, CONF.hyperv.volume_attach_retry_count): mounted_disk_path = self._vmutils.get_mounted_disk_by_drive_number( device_number) if mounted_disk_path: break time.sleep(CONF.hyperv.volume_attach_retry_interval) if not mounted_disk_path: raise vmutils.HyperVException(_('Unable to find a mounted disk ' 'for target_iqn: %s') % target_iqn) return mounted_disk_path
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 destroy(self, instance, network_info=None, cleanup=True, destroy_disks=True): """Destroy the VM. Also destroy the associated VHD disk files.""" LOG.debug(_("Got request to destroy vm %s"), instance['name']) vm = self._vmutils.lookup(self._conn, instance['name']) if vm is None: return vm = self._conn.Msvm_ComputerSystem(ElementName=instance['name'])[0] vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] #Stop the VM first. self._set_vm_state(instance['name'], 'Disabled') vmsettings = vm.associators( wmi_result_class='Msvm_VirtualSystemSettingData') rasds = vmsettings[0].associators( wmi_result_class='MSVM_ResourceAllocationSettingData') disks = [r for r in rasds if r.ResourceSubType == 'Microsoft Virtual Hard Disk'] disk_files = [] volumes = [r for r in rasds if r.ResourceSubType == 'Microsoft Physical Disk Drive'] volumes_drives_list = [] #collect the volumes information before destroying the VM. for volume in volumes: hostResources = volume.HostResource drive_path = hostResources[0] #Appending the Msvm_Disk path volumes_drives_list.append(drive_path) #Collect disk file information before destroying the VM. for disk in disks: disk_files.extend([c for c in disk.Connection]) #Nuke the VM. Does not destroy disks. (job, ret_val) = vs_man_svc.DestroyVirtualSystem(vm.path_()) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job) elif ret_val == 0: success = True if not success: raise vmutils.HyperVException(_('Failed to destroy vm %s') % instance['name']) if destroy_disks: #Disconnect volumes for volume_drive in volumes_drives_list: self._volumeops.disconnect_volume(volume_drive) #Delete associated vhd disk files. for disk in disk_files: vhdfile = self._conn_cimv2.query( "Select * from CIM_DataFile where Name = '" + disk.replace("'", "''") + "'")[0] LOG.debug(_("Del: disk %(vhdfile)s vm %(name)s") % {'vhdfile': vhdfile, 'name': instance['name']}) vhdfile.Delete()
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 * unit.Gi # NOTE(lpetrut): Checking the namespace is needed as the following # method is not yet implemented in the vhdutilsv2 module. if not isinstance(self._vhdutils, vhdutilsv2.VHDUtilsV2): root_vhd_internal_size = ( self._vhdutils.get_internal_vhd_size_by_file_size( vhd_path, root_vhd_size)) else: root_vhd_internal_size = 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_size) 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 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 get_console_output(self, instance): console_log_paths = (self._pathutils.get_vm_console_log_paths( instance['name'])) try: instance_log = '' for console_log_path in console_log_paths: 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 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 _create_vm(self, instance): """Create a VM but don't start it. """ instance_name = instance["name"] vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] vs_gs_data = self._conn.Msvm_VirtualSystemGlobalSettingData.new() vs_gs_data.ElementName = instance_name (job, ret_val) = vs_man_svc.DefineVirtualSystem([], None, vs_gs_data.GetText_(1))[1:] if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job) else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _('Failed to create VM %s') % instance_name) LOG.debug(_('Created VM %s...'), instance_name) vm = self._conn.Msvm_ComputerSystem(ElementName=instance_name)[0] vmsettings = vm.associators( wmi_result_class='Msvm_VirtualSystemSettingData') vmsetting = [s for s in vmsettings if s.SettingType == 3][0] # avoid snapshots memsetting = vmsetting.associators( wmi_result_class='Msvm_MemorySettingData')[0] #No Dynamic Memory, so reservation, limit and quantity are identical. mem = long(str(instance['memory_mb'])) memsetting.VirtualQuantity = mem memsetting.Reservation = mem memsetting.Limit = mem (job, ret_val) = vs_man_svc.ModifyVirtualSystemResources( vm.path_(), [memsetting.GetText_(1)]) LOG.debug(_('Set memory for vm %s...'), instance_name) procsetting = vmsetting.associators( wmi_result_class='Msvm_ProcessorSettingData')[0] vcpus = long(instance['vcpus']) procsetting.VirtualQuantity = vcpus procsetting.Reservation = vcpus procsetting.Limit = 100000 # static assignment to 100% if FLAGS.limit_cpu_features: procsetting.LimitProcessorFeatures = True (job, ret_val) = vs_man_svc.ModifyVirtualSystemResources( vm.path_(), [procsetting.GetText_(1)]) LOG.debug(_('Set vcpus for vm %s...'), instance_name)
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 _create_config_drive(self, instance, injected_files, admin_password): if CONF.config_drive_format != 'iso9660': vmutils.HyperVException( _('Invalid config_drive_format "%s"') % CONF.config_drive_format) LOG.info(_('Using config drive for instance: %s'), instance=instance) extra_md = {} if admin_password and CONF.hyperv.config_drive_inject_password: extra_md['admin_pass'] = admin_password inst_md = instance_metadata.InstanceMetadata(instance, content=injected_files, extra_md=extra_md) instance_path = self._pathutils.get_instance_dir(instance['name']) configdrive_path_iso = os.path.join(instance_path, 'configdrive.iso') LOG.info(_('Creating config drive at %(path)s'), {'path': configdrive_path_iso}, instance=instance) with configdrive.ConfigDriveBuilder(instance_md=inst_md) as cdb: try: cdb.make_drive(configdrive_path_iso) except processutils.ProcessExecutionError as e: with excutils.save_and_reraise_exception(): LOG.error(_('Creating config drive failed with error: %s'), e, instance=instance) if not CONF.hyperv.config_drive_cdrom: drive_type = constants.IDE_DISK configdrive_path = os.path.join(instance_path, 'configdrive.vhd') utils.execute(CONF.hyperv.qemu_img_cmd, 'convert', '-f', 'raw', '-O', 'vpc', configdrive_path_iso, configdrive_path, attempts=1) self._pathutils.remove(configdrive_path_iso) else: drive_type = constants.IDE_DVD configdrive_path = configdrive_path_iso self._vmutils.attach_ide_drive(instance['name'], configdrive_path, 1, 0, drive_type)
def _test_live_migration(self, test_failure=False, with_volumes=False): dest_server = 'fake_server' instance_data = self._get_instance_data() instance_name = instance_data['name'] fake_post_method = self._mox.CreateMockAnything() if not test_failure: fake_post_method(self._context, instance_data, dest_server, False) fake_recover_method = self._mox.CreateMockAnything() if test_failure: fake_recover_method(self._context, instance_data, dest_server, False) fake_ide_controller_path = 'fakeide' fake_scsi_controller_path = 'fakescsi' if with_volumes: fake_scsi_disk_path = 'fake_scsi_disk_path' fake_target_iqn = 'fake_target_iqn' fake_target_lun = 1 fake_scsi_paths = {0: fake_scsi_disk_path} else: fake_scsi_paths = {} m = livemigrationutils.LiveMigrationUtils.live_migrate_vm( instance_data['name'], dest_server) if test_failure: m.AndRaise(vmutils.HyperVException('Simulated failure')) if with_volumes: m.AndReturn([(fake_target_iqn, fake_target_lun)]) volumeutils.VolumeUtils.logout_storage_target(fake_target_iqn) else: m.AndReturn([]) self._mox.ReplayAll() try: self._conn.live_migration(self._context, instance_data, dest_server, fake_post_method, fake_recover_method) exception_raised = False except vmutils.HyperVException: exception_raised = True self.assertTrue(not test_failure ^ exception_raised) self._mox.VerifyAll()
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(ex) 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 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") % locals()) return new_port
def get_image_vm_generation(self, root_vhd_path, image_meta): default_vm_gen = self._hostutils.get_default_vm_generation() image_prop_vm = image_meta.properties.get( 'hw_machine_type', 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 get_vhd_format(self, path): with open(path, 'rb') as f: # Read header if f.read(8) == VHDX_SIGNATURE: return constants.DISK_FORMAT_VHDX # Read footer f.seek(0, 2) file_size = f.tell() if file_size >= 512: f.seek(-512, 2) if f.read(8) == VHD_SIGNATURE: return constants.DISK_FORMAT_VHD raise vmutils.HyperVException(_('Unsupported virtual disk format'))
def _create_root_vhd(self, context, instance): base_vhd_path = self._imagecache.get_cached_image(context, instance) format_ext = base_vhd_path.split('.')[-1] root_vhd_path = self._pathutils.get_root_vhd_path( instance['name'], format_ext) try: if CONF.use_cow_images: LOG.debug( _("Creating differencing VHD. Parent: " "%(base_vhd_path)s, Target: %(root_vhd_path)s"), { 'base_vhd_path': base_vhd_path, 'root_vhd_path': root_vhd_path }) self._vhdutils.create_differencing_vhd(root_vhd_path, base_vhd_path) else: LOG.debug( _("Copying VHD image %(base_vhd_path)s to target: " "%(root_vhd_path)s"), { 'base_vhd_path': base_vhd_path, 'root_vhd_path': root_vhd_path }) self._pathutils.copyfile(base_vhd_path, root_vhd_path) base_vhd_info = self._vhdutils.get_vhd_info(base_vhd_path) base_vhd_size = base_vhd_info['MaxInternalSize'] root_vhd_size = instance['root_gb'] * 1024**3 if root_vhd_size < base_vhd_size: raise vmutils.HyperVException( _("Cannot resize a VHD to a " "smaller size")) elif root_vhd_size > base_vhd_size: LOG.debug( _("Resizing VHD %(root_vhd_path)s to new " "size %(root_vhd_size)s"), { 'base_vhd_path': base_vhd_path, 'root_vhd_path': root_vhd_path }) self._vhdutils.resize_vhd(root_vhd_path, root_vhd_size) except Exception: with excutils.save_and_reraise_exception(): if self._pathutils.exists(root_vhd_path): self._pathutils.remove(root_vhd_path) return root_vhd_path
def _create_config_drive(self, instance, injected_files, admin_password): if CONF.config_drive_format != 'iso9660': vmutils.HyperVException( _('Invalid config_drive_format "%s"') % CONF.config_drive_format) LOG.info(_('Using config drive'), instance=instance) extra_md = {} if admin_password and CONF.config_drive_inject_password: extra_md['admin_pass'] = admin_password inst_md = instance_metadata.InstanceMetadata(instance, content=injected_files, extra_md=extra_md) instance_path = self._vmutils.get_instance_path(instance['name']) configdrive_path_iso = os.path.join(instance_path, 'configdrive.iso') LOG.info(_('Creating config drive at %(path)s'), {'path': configdrive_path_iso}, instance=instance) cdb = configdrive.ConfigDriveBuilder(instance_md=inst_md) try: cdb.make_drive(configdrive_path_iso) finally: cdb.cleanup() if not CONF.config_drive_cdrom: drive_type = constants.IDE_DISK configdrive_path = os.path.join(instance_path, 'configdrive.vhd') utils.execute(CONF.qemu_img_cmd, 'convert', '-f', 'raw', '-O', 'vpc', configdrive_path_iso, configdrive_path, attempts=1) os.remove(configdrive_path_iso) else: drive_type = constants.IDE_DVD configdrive_path = configdrive_path_iso self._attach_ide_drive(instance['name'], configdrive_path, 1, 0, drive_type)
def _attach_volume_to_controller(self, controller, address, mounted_disk, instance): """Attach a volume to a controller """ #Find the default disk drive object for the vm and clone it. diskdflt = self._conn.query( "SELECT * FROM Msvm_ResourceAllocationSettingData \ WHERE ResourceSubType LIKE 'Microsoft Physical Disk Drive'\ AND InstanceID LIKE '%Default%'")[0] diskdrive = self._vmutils.clone_wmi_obj( self._conn, 'Msvm_ResourceAllocationSettingData', diskdflt) diskdrive.Address = address diskdrive.Parent = controller[0].path_() diskdrive.HostResource = [mounted_disk[0].path_()] new_resources = self._vmutils.add_virt_resource( self._conn, diskdrive, instance) if new_resources is None: raise vmutils.HyperVException( _('Failed to add volume to VM %s') % instance)
def attach_volume(self, connection_info, instance_name, ebs_root=False): """ Attach a volume to the SCSI controller or to the IDE controller if ebs_root is True """ target_iqn = None LOG.debug(_("Attach_volume: %(connection_info)s to %(instance_name)s"), { 'connection_info': connection_info, 'instance_name': instance_name }) try: self._login_storage_target(connection_info) data = connection_info['data'] target_lun = data['target_lun'] target_iqn = data['target_iqn'] #Getting the mounted disk mounted_disk_path = self._get_mounted_disk_from_lun( target_iqn, target_lun) if ebs_root: #Find the IDE controller for the vm. ctrller_path = self._vmutils.get_vm_ide_controller( instance_name, 0) #Attaching to the first slot slot = 0 else: #Find the SCSI controller for the vm ctrller_path = self._vmutils.get_vm_scsi_controller( instance_name) slot = self._get_free_controller_slot(ctrller_path) self._vmutils.attach_volume_to_controller(instance_name, ctrller_path, slot, mounted_disk_path) except Exception as exn: LOG.exception(_('Attach volume failed: %s'), exn) if target_iqn: self._volutils.logout_storage_target(target_iqn) raise vmutils.HyperVException( _('Unable to attach volume ' 'to instance %s') % instance_name)
def _cache_image(self, fn, target, fname, cow=False, size=None, *args, **kwargs): """Wrapper for a method that creates and caches an image. This wrapper will save the image into a common store and create a copy for use by the hypervisor. The underlying method should specify a kwarg of target representing where the image will be saved. fname is used as the filename of the base image. The filename needs to be unique to a given image. If cow is True, it will make a CoW image instead of a copy. """ @lockutils.synchronized(fname, 'nova-') def call_if_not_exists(path, fn, *args, **kwargs): if not os.path.exists(path): fn(target=path, *args, **kwargs) if not self._pathutils.vhd_exists(target): LOG.debug(_("Use CoW image: %s"), cow) if cow: parent_path = self._pathutils.get_base_vhd_path(fname) call_if_not_exists(parent_path, fn, *args, **kwargs) LOG.debug( _("Creating differencing VHD. Parent: " "%(parent_path)s, Target: %(target)s") % locals()) try: self._vhdutils.create_differencing_vhd(target, parent_path) except Exception as ex: LOG.exception(ex) raise vmutils.HyperVException( _('Failed to create a differencing disk from ' '%(parent_path)s to %(target)s') % locals()) else: call_if_not_exists(target, fn, *args, **kwargs)
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.get_vhd_path(instance_name) if not self._pathutils.exists(root_vhd_path): raise vmutils.HyperVException( _("Cannot find boot VHD " "file: %s") % root_vhd_path) vhd_info = self._vhdutils.get_vhd_info(root_vhd_path) src_base_disk_path = 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: curr_size = vhd_info['MaxInternalSize'] new_size = instance['root_gb'] * 1024**3 if new_size < curr_size: raise vmutils.VHDResizeException( _("Cannot resize a VHD " "to a smaller size")) elif new_size > curr_size: self._resize_vhd(root_vhd_path, new_size) self._vmops.create_instance(instance, network_info, block_device_info, root_vhd_path) if power_on: self._vmops.power_on(instance)
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)