Пример #1
0
    def disconnect_switch_port(self, switch_port_name, vnic_deleted,
                               delete_port):
        """Disconnects the switch port."""
        switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0]
        switch_port_path = self._get_switch_port_path_by_name(
            switch_port_name)
        if not switch_port_path:
            # Port not found. It happens when the VM was already deleted.
            return

        if not vnic_deleted:
            (ret_val, ) = switch_svc.DisconnectSwitchPort(
                SwitchPort=switch_port_path)
            if ret_val != 0:
                data = {'switch_port_name': switch_port_name,
                        'ret_val': ret_val}
                raise exceptions.HyperVException(
                    message=_('Failed to disconnect port %(switch_port_name)s '
                              'with error %(ret_val)s') % data)
        if delete_port:
            (ret_val, ) = switch_svc.DeleteSwitchPort(
                SwitchPort=switch_port_path)
            if ret_val != 0:
                data = {'switch_port_name': switch_port_name,
                        'ret_val': ret_val}
                raise exceptions.HyperVException(
                    message=_('Failed to delete port %(switch_port_name)s '
                              'with error %(ret_val)s') % data)
Пример #2
0
 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 exceptions.HyperVException(_('Duplicate VM name found: %s')
                                          % vm_name)
     return vms[0]
Пример #3
0
 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'))
Пример #4
0
 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 exceptions.HyperVException(msg)
Пример #5
0
    def _lookup_vm_check(self, vm_name):

        vm = self._lookup_vm(vm_name)
        if not vm:
            raise exceptions.HyperVVMNotFoundException(
                _('VM not found: %s') % vm_name)
        return vm
Пример #6
0
 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]
Пример #7
0
 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)
Пример #8
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
Пример #9
0
 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]
Пример #10
0
    def create_dynamic_vhd(self, path, max_internal_size, format):
        vhd_format = self._vhd_format_map.get(format)
        if not vhd_format:
            raise exceptions.HyperVException(_("Unsupported disk format: %s") %
                                             format)

        self._create_vhd(self._VHD_TYPE_DYNAMIC, vhd_format, path,
                         max_internal_size=max_internal_size)
Пример #11
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"))
Пример #12
0
 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]
Пример #13
0
    def create_dynamic_vhd(self, path, max_internal_size, format):
        if format != constants.DISK_FORMAT_VHD:
            raise exceptions.HyperVException(_("Unsupported disk format: %s") %
                                             format)

        image_man_svc = self._conn.Msvm_ImageManagementService()[0]

        (job_path, ret_val) = image_man_svc.CreateDynamicVirtualHardDisk(
            Path=path, MaxInternalSize=max_internal_size)
        self._jobutils.check_ret_val(ret_val, job_path)
Пример #14
0
    def host_power_action(self, action):
        win32_os = self._conn_cimv2.Win32_OperatingSystem()[0]

        if action == constants.HOST_POWER_ACTION_SHUTDOWN:
            win32_os.Win32Shutdown(self._HOST_FORCED_SHUTDOWN)
        elif action == constants.HOST_POWER_ACTION_REBOOT:
            win32_os.Win32Shutdown(self._HOST_FORCED_REBOOT)
        else:
            raise NotImplementedError(
                _("Host %(action)s is not supported by the Hyper-V driver") %
                {"action": action})
Пример #15
0
 def _get_vhd_dynamic_blk_size(self, vhd_path):
     blk_size_offset = VHD_BLK_SIZE_OFFSET
     try:
         with open(vhd_path, "rb") as f:
             f.seek(blk_size_offset)
             version = f.read(4)
     except IOError:
         raise exceptions.HyperVException(_("Unable to obtain block size "
                                            "from VHD %(vhd_path)s") %
                                            {"vhd_path": vhd_path})
     return struct.unpack('>i', version)[0]
Пример #16
0
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
            utils.check_min_windows_version(6, 3)):
        raise exceptions.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)
Пример #17
0
 def copy(self, src, dest):
     # With large files this is 2x-3x faster than shutil.copy(src, dest),
     # especially when copying to a UNC target.
     # shutil.copyfileobj(...) with a proper buffer is better than
     # shutil.copy(...) but still 20% slower than a shell copy.
     # It can be replaced with Win32 API calls to avoid the process
     # spawning overhead.
     LOG.debug('Copying file from %s to %s', src, dest)
     output, ret = _utils.execute('cmd.exe', '/C', 'copy', '/Y', src, dest)
     if ret:
         raise IOError(_('The file copy from %(src)s to %(dest)s failed')
                        % {'src': src, 'dest': dest})
Пример #18
0
 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 exceptions.HyperVException(err_msg)
Пример #19
0
    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.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
Пример #20
0
    def get_internal_vhd_size_by_file_size(self, vhd_path,
                                           new_vhd_file_size):
        """Get internal size of a VHD according to new VHD file size.

        VHDX Size = Header (1MB) + Log + Metadata Region + BAT + Payload Blocks

        The chunk size is the maximum number of bytes described by a SB
        block.

        Chunk size = 2^{23} * LogicalSectorSize

        :param str vhd_path: VHD file path
        :param new_vhd_file_size: Size of the new VHD file.
        :return: Internal VHD size according to new VHD file size.
        """
        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 exceptions.HyperVException(
                        _("Unable to obtain internal size from VHDX: "
                          "%(vhd_path)s. Exception: %(ex)s") %
                          {"vhd_path": vhd_path, "ex": ex})
Пример #21
0
    def get_external_vswitch(self, vswitch_name):
        if vswitch_name:
            vswitches = self._conn.Msvm_VirtualSwitch(ElementName=vswitch_name)
        else:
            # Find the vswitch that is connected to the first physical nic.
            ext_port = self._conn.Msvm_ExternalEthernetPort(IsBound='TRUE')[0]
            port = ext_port.associators(wmi_result_class='Msvm_SwitchPort')[0]
            vswitches = port.associators(wmi_result_class='Msvm_VirtualSwitch')

        if not len(vswitches):
            raise exceptions.HyperVException(_('vswitch "%s" not found')
                                             % vswitch_name)
        return vswitches[0].path_()
Пример #22
0
    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 utils.HyperVException(msg=_('Cannot get VM summary data '
                                              'for: %s') % port.ElementName)

        return summary_info[0].EnabledState is self._HYPERV_VM_STATE_ENABLED
Пример #23
0
 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 exceptions.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
Пример #24
0
    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 exceptions.HyperVException(_('Unsupported virtual disk format'))
Пример #25
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)

        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)
Пример #26
0
 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 exceptions.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
Пример #27
0
    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 utils.HyperVException(
                msg=_('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)
Пример #28
0
    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 exceptions.HyperVException(
                        _("Could not unmount share: %s"), smbfs_share)
Пример #29
0
    def get_vm_summary_info(self, vm_name):
        vm = self._lookup_vm_check(vm_name)

        vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]
        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) = 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 = long(si.MemoryUsage)
        up_time = None
        if si.UpTime is not None:
            up_time = long(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
Пример #30
0
    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 exceptions.HyperVException(msg)

        vhd_info_xml = ElementTree.tostring(et)

        (job_path, ret_val) = image_man_svc.SetVirtualHardDiskSettingData(
            VirtualDiskSettingData=vhd_info_xml)

        self._jobutils.check_ret_val(ret_val, job_path)