Ejemplo n.º 1
0
    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
Ejemplo n.º 2
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 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'))
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
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 vmutils.HyperVException(_('Duplicate VM name found: %s')
                                       % vm_name)
     return vms[0]
Ejemplo n.º 6
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)
Ejemplo n.º 7
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
            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)
Ejemplo n.º 8
0
 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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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_()
Ejemplo n.º 11
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 vmutils.HyperVException(err_msg)
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
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 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)
Ejemplo n.º 15
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 vmutils.HyperVException(msg)
Ejemplo n.º 16
0
    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})
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
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 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
Ejemplo n.º 19
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 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)
Ejemplo n.º 20
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 vmutils.HyperVException(
                        _("Could not unmount share: %s"), smbfs_share)
Ejemplo n.º 21
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 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)
Ejemplo n.º 22
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 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
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
 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
Ejemplo n.º 25
0
 def fake_login_storage_target(self, connection_info):
     raise vmutils.HyperVException('Fake connection exception')
Ejemplo n.º 26
0
 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'))