def _get_class(class_type, *args, **kwargs): if class_type not in utils_map: raise exceptions.HyperVException( _('Class type %s does ' 'not exist') % class_type) windows_version = utils.get_windows_version() build = list(map(int, windows_version.split('.'))) windows_version = float("%i.%i" % (build[0], build[1])) existing_classes = utils_map.get(class_type) for class_variant in existing_classes.keys(): utils_class = existing_classes.get(class_variant) if (utils_class['min_version'] <= windows_version and (utils_class['max_version'] is None or windows_version < utils_class['max_version'])): return importutils.import_object(utils_class['path'], *args, **kwargs) raise exceptions.HyperVException( _('Could not find any %(class)s class for' 'this Windows version: %(win_version)s') % { 'class': class_type, 'win_version': windows_version })
def _get_class(class_type, *args, **kwargs): if class_type not in utils_map: raise exceptions.HyperVException( _('Class type %s does ' 'not exist') % class_type) windows_version = utils.get_windows_version() build = list(map(int, windows_version.split('.'))) windows_version = float("%i.%i" % (build[0], build[1])) existing_classes = utils_map.get(class_type, []) for class_variant in existing_classes: min_version = class_variant.get('min_version', DEFAULT_MIN_VERSION) max_version = class_variant.get('max_version', DEFAULT_MAX_VERSION) class_path = class_variant['path'] if (min_version <= windows_version and (max_version is None or windows_version < max_version)): return importutils.import_object(class_path, *args, **kwargs) raise exceptions.HyperVException( _('Could not find any %(class)s class for' 'this Windows version: %(win_version)s') % { 'class': class_type, 'win_version': windows_version })
def check_live_migration_config(self): migration_svc = ( self._compat_conn.Msvm_VirtualSystemMigrationService()[0]) vsmssd = ( self._compat_conn.Msvm_VirtualSystemMigrationServiceSettingData()) vsmssd = vsmssd[0] if not vsmssd.EnableVirtualSystemMigration: raise exceptions.HyperVException( _('Live migration is not enabled on this host')) if not migration_svc.MigrationServiceListenerIPAddressList: raise exceptions.HyperVException( _('Live migration networks are not configured on this host'))
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 exceptions.HyperVException( _('Live migration is not enabled on this host')) if not migration_svc.MigrationServiceListenerIPAddressList: raise exceptions.HyperVException( _('Live migration networks are not configured on this host'))
def _wait_for_job(self, job_path): """Poll WMI job state and wait for completion.""" job_wmi_path = job_path.replace('\\', '/') job = wmi.WMI(moniker=job_wmi_path) while job.JobState == constants.WMI_JOB_STATE_RUNNING: time.sleep(0.1) job = wmi.WMI(moniker=job_wmi_path) if job.JobState == constants.JOB_STATE_KILLED: LOG.debug("WMI job killed with status %s.", job.JobState) return job if job.JobState != constants.WMI_JOB_STATE_COMPLETED: job_state = job.JobState if job.path().Class == "Msvm_ConcreteJob": err_sum_desc = job.ErrorSummaryDescription err_desc = job.ErrorDescription err_code = job.ErrorCode data = { 'job_state': job_state, 'err_sum_desc': err_sum_desc, 'err_desc': err_desc, 'err_code': err_code } raise exceptions.HyperVException( _("WMI job failed with status %(job_state)d. " "Error details: %(err_sum_desc)s - %(err_desc)s - " "Error code: %(err_code)d") % data) else: (error, ret_val) = job.GetError() if not ret_val and error: data = {'job_state': job_state, 'error': error} raise exceptions.HyperVException( _("WMI job failed with status %(job_state)d. " "Error details: %(error)s") % data) else: raise exceptions.HyperVException( _("WMI job failed with status %d. No error " "description available") % job_state) desc = job.Description elap = job.ElapsedTime LOG.debug("WMI job succeeded: %(desc)s, Elapsed=%(elap)s", { 'desc': desc, 'elap': elap }) return job
def _set_switch_port_security_settings(self, switch_port_name, **kwargs): port_alloc = self._get_switch_port_allocation(switch_port_name)[0] sec_settings = self._get_security_setting_data_from_port_alloc( port_alloc) if sec_settings: if all(getattr(sec_settings, k) == v for k, v in kwargs.items()): # All desired properties already properly set. Nothing to do. return # Removing the feature because it cannot be modified # due to a wmi exception. self._jobutils.remove_virt_feature(sec_settings) else: sec_settings = self._create_default_setting_data( self._PORT_SECURITY_SET_DATA) for k, v in kwargs.items(): setattr(sec_settings, k, v) self._jobutils.add_virt_feature(sec_settings, port_alloc) # TODO(claudiub): This will help solve the missing VSID issue, but it # comes with a performance cost. The root cause of the problem must # be solved. sec_settings = self._get_security_setting_data_from_port_alloc( port_alloc) if not sec_settings: raise exceptions.HyperVException( _('Port Security Settings not found: %s') % switch_port_name)
def _get_vnic_settings(self, vnic_name): vnic_settings = self._conn.Msvm_SyntheticEthernetPortSettingData( ElementName=vnic_name) if not vnic_settings: raise exceptions.HyperVException(message=_('Vnic not found: %s') % vnic_name) return vnic_settings[0]
def execute(self, *args, **kwargs): stdout_value, stderr_value = _utils.execute(*args, **kwargs) if stdout_value.find('The operation completed successfully') == -1: raise exceptions.HyperVException( _('An error has occurred when calling the iscsi initiator: %s') % stdout_value) return stdout_value
def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name): port_alloc = self._get_switch_port_allocation(switch_port_name)[0] vlan_settings = self._get_vlan_setting_data_from_port_alloc(port_alloc) if vlan_settings: if (vlan_settings.OperationMode == self._OPERATION_MODE_ACCESS and vlan_settings.AccessVlanId == vlan_id): # VLAN already set to corect value, no need to change it. return # Removing the feature because it cannot be modified # due to a wmi exception. self._jobutils.remove_virt_feature(vlan_settings) # remove from cache. self._vlan_sds.pop(port_alloc.InstanceID, None) vlan_settings = self._create_default_setting_data( self._PORT_VLAN_SET_DATA) vlan_settings.AccessVlanId = vlan_id vlan_settings.OperationMode = self._OPERATION_MODE_ACCESS self._jobutils.add_virt_feature(vlan_settings, port_alloc) # TODO(claudiub): This will help solve the missing VLAN issue, but it # comes with a performance cost. The root cause of the problem must # be solved. vlan_settings = self._get_vlan_setting_data_from_port_alloc(port_alloc) if not vlan_settings: raise exceptions.HyperVException( _('Port VLAN not found: %s') % switch_port_name)
def set_vswitch_port_vsid(self, vsid, switch_port_name): port_alloc = self._get_switch_port_allocation(switch_port_name)[0] vsid_settings = self._get_security_setting_data_from_port_alloc( port_alloc) if vsid_settings: if vsid_settings.VirtualSubnetId == vsid: # VSID already added, no need to readd it. return # Removing the feature because it cannot be modified # due to a wmi exception. self._jobutils.remove_virt_feature(vsid_settings) # remove from cache. self._vsid_sds.pop(port_alloc.InstanceID, None) vsid_settings = self._create_default_setting_data( self._PORT_SECURITY_SET_DATA) vsid_settings.VirtualSubnetId = vsid self._jobutils.add_virt_feature(vsid_settings, port_alloc) # TODO(claudiub): This will help solve the missing VSID issue, but it # comes with a performance cost. The root cause of the problem must # be solved. vsid_settings = self._get_security_setting_data_from_port_alloc( port_alloc) if not vsid_settings: raise exceptions.HyperVException( _('Port VSID not found: %s') % switch_port_name)
def get_device_number_from_device_name(self, device_name): matches = self._phys_dev_name_regex.findall(device_name) if matches: return matches[0] else: err_msg = _("Could not find device number for device: %s") raise exceptions.HyperVException(err_msg % device_name)
def _get_vswitch(self, vswitch_name): vswitch = self._conn.Msvm_VirtualEthernetSwitch( ElementName=vswitch_name) if not len(vswitch): raise exceptions.HyperVException( _('VSwitch not found: %s') % vswitch_name) return vswitch[0]
def check_ret_val(self, ret_val, job_path, success_values=[0]): """Checks that the job represented by the given arguments succeeded. Some Hyper-V operations are not atomic, and will return a reference to a job. In this case, this method will wait for the job's completion. :param ret_val: integer, representing the return value of the job. if the value is WMI_JOB_STATUS_STARTED or WMI_JOB_STATE_RUNNING, a job_path cannot be None. :param job_path: string representing the WMI object path of a Hyper-V job. :param success_values: list of return values that can be considered successful. WMI_JOB_STATUS_STARTED and WMI_JOB_STATE_RUNNING values are ignored. :raises exceptions.HyperVException: if the given ret_val is WMI_JOB_STATUS_STARTED or WMI_JOB_STATE_RUNNING and the state of job represented by the given job_path is not WMI_JOB_STATE_COMPLETED, or if the given ret_val is not in the list of given success_values. """ if ret_val in [ constants.WMI_JOB_STATUS_STARTED, constants.WMI_JOB_STATE_RUNNING ]: return self._wait_for_job(job_path) elif ret_val not in success_values: raise exceptions.HyperVException( _('Operation failed with return value: %s') % ret_val)
def _get_vm(self, conn_v2, vm_name): vms = conn_v2.Msvm_ComputerSystem(ElementName=vm_name) n = len(vms) if not n: raise exceptions.HyperVVMNotFoundException(vm_name=vm_name) elif n > 1: raise exceptions.HyperVException( _('Duplicate VM name found: %s') % vm_name) return vms[0]
def get_free_controller_slot(self, scsi_controller_path): attached_disks = self.get_attached_disks(scsi_controller_path) used_slots = [int(disk.AddressOnParent) for disk in attached_disks] for slot in range(constants.SCSI_CONTROLLER_SLOTS_NUMBER): if slot not in used_slots: return slot raise exceptions.HyperVException( _("Exceeded the maximum number of slots"))
def check_ret_val(self, ret_val, job_path, success_values=[0]): if ret_val in [ constants.WMI_JOB_STATUS_STARTED, constants.WMI_JOB_STATE_RUNNING ]: return self._wait_for_job(job_path) elif ret_val not in success_values: raise exceptions.HyperVException( _('Operation failed with return value: %s') % ret_val)
def _get_planned_vm(self, vm_name, conn_v2=None, fail_if_not_found=False): if not conn_v2: conn_v2 = self._conn planned_vm = conn_v2.Msvm_PlannedComputerSystem(ElementName=vm_name) if planned_vm: return planned_vm[0] elif fail_if_not_found: raise exceptions.HyperVException( _('Cannot find planned VM with name: %s') % vm_name) return None
def _lookup_vm(self, vm_name): vms = self._conn.Msvm_ComputerSystem(ElementName=vm_name) n = len(vms) if n == 0: return None elif n > 1: raise exceptions.HyperVException( _('Duplicate VM name found: %s') % vm_name) else: return vms[0]
def test_remove_sg_port_rules_exception(self): mock_rule = mock.MagicMock() self._driver._sec_group_rules[self._FAKE_ID] = [mock_rule] self._driver._utils.remove_security_rules.side_effect = ( exceptions.HyperVException(msg='Generated Exception for testing.')) self.assertRaises(exceptions.HyperVException, self._driver._remove_sg_port_rules, self._FAKE_ID, [mock_rule]) self.assertIn(mock_rule, self._driver._sec_group_rules[self._FAKE_ID])
def test_add_sg_port_rules_exception(self): mock_port = self._get_port() mock_rule = mock.MagicMock() self._driver._sec_group_rules[self._FAKE_ID] = [] self._driver._utils.create_security_rules.side_effect = ( exceptions.HyperVException(msg='Generated Exception for testing.')) self.assertRaises(exceptions.HyperVException, self._driver._add_sg_port_rules, mock_port, [mock_rule]) self.assertNotIn(mock_rule, self._driver._sec_group_rules[self._FAKE_ID])
def _is_port_vm_started(self, port): vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] vmsettings = port.associators( wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA) # See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx (ret_val, summary_info) = vs_man_svc.GetSummaryInformation( [self._VM_SUMMARY_ENABLED_STATE], [v.path_() for v in vmsettings]) if ret_val or not summary_info: raise exceptions.HyperVException( _('Cannot get VM summary data ' 'for: %s') % port.ElementName) return summary_info[0].EnabledState is self._HYPERV_VM_STATE_ENABLED
def _is_port_vm_started(self, port): vmsettings_instance_id = port.InstanceID.split('\\')[0] vmsettings = self._conn.Msvm_VirtualSystemSettingData( InstanceID=vmsettings_instance_id) # See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx (ret_val, summary_info) = self._vs_man_svc.GetSummaryInformation( [self._VM_SUMMARY_ENABLED_STATE], [v.path_() for v in vmsettings]) if ret_val or not summary_info: raise exceptions.HyperVException( _('Cannot get VM summary data ' 'for: %s') % port.ElementName) return summary_info[0].EnabledState is self._HYPERV_VM_STATE_ENABLED
def get_external_vswitch(self, vswitch_name): if vswitch_name: vswitches = self._conn.Msvm_VirtualEthernetSwitch( ElementName=vswitch_name) if not len(vswitches): raise exceptions.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 exceptions.HyperVException( _('No external vswitch found')) return vswitches[0].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 range(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 exceptions.HyperVException( _('Failed to login target %s') % target_iqn)
def _get_conn_v2(self, host='localhost'): try: return self._get_wmi_obj(self._wmi_namespace % 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 exceptions.HyperVException(msg)
def _lookup_vm(self, vm_name, as_vssd=True, for_update=False): if as_vssd: conn = self._compat_conn if for_update else self._conn vms = conn.Msvm_VirtualSystemSettingData( ElementName=vm_name, VirtualSystemType=self._VIRTUAL_SYSTEM_TYPE_REALIZED) else: vms = self._conn.Msvm_ComputerSystem(ElementName=vm_name) n = len(vms) if n == 0: return None elif n > 1: raise exceptions.HyperVException( _('Duplicate VM name found: %s') % vm_name) else: return vms[0]
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 range(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 exceptions.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 exceptions.HyperVException( _('Failed to login target %s') % target_iqn)
def set_vswitch_port_profile_id(self, switch_port_name, profile_id, profile_data, profile_name, vendor_name, **kwargs): """Sets up the port profile id. :param switch_port_name: The ElementName of the vSwitch port. :param profile_id: The profile id to be set for the given switch port. :param profile_data: Additional data for the Port Profile. :param profile_name: The name of the Port Profile. :param net_cfg_instance_id: Unique device identifier of the sub-interface. :param cdn_label_id: The CDN Label Id. :param cdn_label_string: The CDN label string. :param vendor_id: The id of the Vendor defining the profile. :param vendor_name: The name of the Vendor defining the profile. """ port_alloc = self._get_switch_port_allocation(switch_port_name)[0] port_profile = self._get_profile_setting_data_from_port_alloc( port_alloc) new_port_profile = self._prepare_profile_sd(profile_id=profile_id, profile_data=profile_data, profile_name=profile_name, vendor_name=vendor_name, **kwargs) if port_profile: # Removing the feature because it cannot be modified # due to a wmi exception. self._jobutils.remove_virt_feature(port_profile) # remove from cache. self._profile_sds.pop(port_alloc.InstanceID, None) try: self._jobutils.add_virt_feature(new_port_profile, port_alloc) except Exception as ex: raise exceptions.HyperVException( 'Unable to set port profile settings %(port_profile)s ' 'for port %(port)s. Error: %(error)s' % dict(port_profile=new_port_profile, port=port_alloc, error=ex))
def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name): port_alloc, found = self._get_switch_port_allocation(switch_port_name) if not found: raise exceptions.HyperVException( _('Port Allocation not found: %s') % switch_port_name) vlan_settings = self._get_vlan_setting_data_from_port_alloc(port_alloc) if vlan_settings: if (vlan_settings.OperationMode == self._OPERATION_MODE_ACCESS and vlan_settings.AccessVlanId == vlan_id): # VLAN already set to corect value, no need to change it. return # Removing the feature because it cannot be modified # due to a wmi exception. self._jobutils.remove_virt_feature(vlan_settings) (vlan_settings, found) = self._get_vlan_setting_data(switch_port_name) vlan_settings.AccessVlanId = vlan_id vlan_settings.OperationMode = self._OPERATION_MODE_ACCESS self._jobutils.add_virt_feature(vlan_settings, port_alloc)
def get_vm_summary_info(self, vm_name): vm = self._lookup_vm_check(vm_name) vmsettings = vm.associators( wmi_association_class=self._SETTINGS_DEFINE_STATE_CLASS, wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS) settings_paths = [v.path_() for v in vmsettings] # See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx (ret_val, summary_info) = self._vs_man_svc.GetSummaryInformation([ constants.VM_SUMMARY_NUM_PROCS, constants.VM_SUMMARY_ENABLED_STATE, constants.VM_SUMMARY_MEMORY_USAGE, constants.VM_SUMMARY_UPTIME ], settings_paths) if ret_val: raise exceptions.HyperVException( _('Cannot get VM summary data for: %s') % vm_name) si = summary_info[0] memory_usage = None if si.MemoryUsage is not None: memory_usage = int(si.MemoryUsage) up_time = None if si.UpTime is not None: up_time = int(si.UpTime) # Nova requires a valid state to be returned. Hyper-V has more # states than Nova, typically intermediate ones and since there is # no direct mapping for those, ENABLED is the only reasonable option # considering that in all the non mappable states the instance # is running. enabled_state = self._enabled_states_map.get( si.EnabledState, constants.HYPERV_VM_STATE_ENABLED) summary_info_dict = { 'NumberOfProcessors': si.NumberOfProcessors, 'EnabledState': enabled_state, 'MemoryUsage': memory_usage, 'UpTime': up_time } return summary_info_dict