예제 #1
0
    def terminate_connection(self, volume, hostname, wwn=None, iqn=None):
        """Driver entry point to unattach a volume from an instance."""
        # does 3par know this host by a different name?
        hosts = None
        if wwn:
            hosts = self.client.queryHost(wwns=wwn)
        elif iqn:
            hosts = self.client.queryHost(iqns=[iqn])

        if hosts and hosts['members'] and 'name' in hosts['members'][0]:
            hostname = hosts['members'][0]['name']

        try:
            self.delete_vlun(volume, hostname)
            return
        except hpeexceptions.HTTPNotFound as e:
            if 'host does not exist' in e.get_description():
                # use the wwn to see if we can find the hostname
                hostname = self._get_3par_hostname_from_wwn_iqn(wwn, iqn)
                # no 3par host, re-throw
                if hostname is None:
                    LOG.error(_LE("Exception: %s"), e)
                    raise
            else:
                # not a 'host does not exist' HTTPNotFound exception, re-throw
                LOG.error(_LE("Exception: %s"), e)
                raise

        # try again with name retrieved from 3par
        self.delete_vlun(volume, hostname)
    def terminate_connection(self, volume, hostname, wwn=None, iqn=None):
        """Driver entry point to unattach a volume from an instance."""
        # does 3par know this host by a different name?
        hosts = None
        if wwn:
            hosts = self.client.queryHost(wwns=wwn)
        elif iqn:
            hosts = self.client.queryHost(iqns=[iqn])

        if hosts and hosts['members'] and 'name' in hosts['members'][0]:
            hostname = hosts['members'][0]['name']

        try:
            self.delete_vlun(volume, hostname)
            return
        except hpeexceptions.HTTPNotFound as e:
            if 'host does not exist' in e.get_description():
                # use the wwn to see if we can find the hostname
                hostname = self._get_3par_hostname_from_wwn_iqn(wwn, iqn)
                # no 3par host, re-throw
                if hostname is None:
                    LOG.error(_LE("Exception: %s"), e)
                    raise
            else:
                # not a 'host does not exist' HTTPNotFound exception, re-throw
                LOG.error(_LE("Exception: %s"), e)
                raise

        # try again with name retrieved from 3par
        self.delete_vlun(volume, hostname)
 def _set_flash_cache_policy_in_vvs(self, flash_cache, vvs_name):
     # Update virtual volume set
     if flash_cache:
         try:
             self.client.modifyVolumeSet(vvs_name,
                                         flashCachePolicy=flash_cache)
             LOG.info(_LI("Flash Cache policy set to %s"), flash_cache)
         except Exception as ex:
             LOG.error(_LE("Error setting Flash Cache policy "
                           "to %s - exception"), flash_cache)
             exception.PluginException(ex)
예제 #4
0
 def delete_volume(self, volume):
     """Deletes a volume."""
     client = self._login()
     try:
         volume_info = client.getVolumeByName(volume['name'])
         client.deleteVolume(volume_info['id'])
     except hpeexceptions.HTTPNotFound:
         LOG.error(_LE("Volume did not exist. It will not be deleted"))
     except Exception as ex:
         raise exception.VolumeBackendAPIException(ex)
     finally:
         self._logout(client)
예제 #5
0
 def _set_flash_cache_policy_in_vvs(self, flash_cache, vvs_name):
     # Update virtual volume set
     if flash_cache:
         try:
             self.client.modifyVolumeSet(vvs_name,
                                         flashCachePolicy=flash_cache)
             LOG.info(_LI("Flash Cache policy set to %s"), flash_cache)
         except Exception as ex:
             LOG.error(
                 _LE("Error setting Flash Cache policy "
                     "to %s - exception"), flash_cache)
             exception.PluginException(ex)
    def delete_volume(self, volume):
        try:
            volume_name = self._get_3par_vol_name(volume['id'])
            # Try and delete the volume, it might fail here because
            # the volume is part of a volume set which will have the
            # volume set name in the error.
            try:
                self.client.deleteVolume(volume_name)
            except hpeexceptions.HTTPBadRequest as ex:
                if ex.get_code() == 29:
                    if self.client.isOnlinePhysicalCopy(volume_name):
                        LOG.debug("Found an online copy for %(volume)s",
                                  {'volume': volume_name})
                        # the volume is in process of being cloned.
                        # stopOnlinePhysicalCopy will also delete
                        # the volume once it stops the copy.
                        self.client.stopOnlinePhysicalCopy(volume_name)
                    else:
                        LOG.error(_LE("Exception: %s"), ex)
                        raise
                else:
                    LOG.error(_LE("Exception: %s"), ex)
                    raise
            except hpeexceptions.HTTPConflict as ex:
                if ex.get_code() == 34:
                    # This is a special case which means the
                    # volume is part of a volume set.
                    vvset_name = self.client.findVolumeSet(volume_name)
                    LOG.debug("Returned vvset_name = %s", vvset_name)
                    if vvset_name is not None and \
                       vvset_name.startswith('vvs-'):
                        # We have a single volume per volume set, so
                        # remove the volume set.
                        self.client.deleteVolumeSet(
                            self._get_3par_vvs_name(volume['id']))
                    elif vvset_name is not None:
                        # We have a pre-defined volume set just remove the
                        # volume and leave the volume set.
                        self.client.removeVolumeFromVolumeSet(vvset_name,
                                                              volume_name)
                    self.client.deleteVolume(volume_name)
                elif (ex.get_code() == 151 or ex.get_code() == 32):
                    # the volume is being operated on in a background
                    # task on the 3PAR.
                    # TODO(walter-boring) do a retry a few times.
                    # for now lets log a better message
                    msg = _("The volume is currently busy on the 3PAR"
                            " and cannot be deleted at this time. "
                            "You can try again later.")
                    LOG.error(msg)
                    raise exception.VolumeIsBusy(message=msg)
                else:
                    LOG.error(_LE("Exception: %s"), ex)
                    raise exception.VolumeIsBusy(message=ex.get_description())

        except hpeexceptions.HTTPNotFound as ex:
            LOG.warning(_LW("Delete volume id not found. Ex: %(msg)s"),
                        {'msg': ex})
        except hpeexceptions.HTTPForbidden as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.NotAuthorized(ex.get_description())
        except hpeexceptions.HTTPConflict as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.VolumeIsBusy(message=ex.get_description())
        except Exception as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.PluginException(ex)
    def create_volume(self, volume):
        LOG.debug('CREATE VOLUME (%(disp_name)s: %(vol_name)s %(id)s on '
                  '%(host)s)',
                  {'disp_name': volume['display_name'],
                   'vol_name': volume['name'],
                   'id': self._get_3par_vol_name(volume['id']),
                   'host': volume['host']})
        try:
            comments = {'volume_id': volume['id'],
                        'name': volume['name'],
                        'type': 'Docker'}

            name = volume.get('display_name', None)
            if name:
                comments['display_name'] = name

            # TODO(leeantho): Choose the first CPG for now. In the future
            # support selecting different CPGs if multiple are provided.
            cpg = self.config.hpe3par_cpg[0]

            # check for valid provisioning type
            prov_value = volume['provisioning']
            if prov_value not in self.valid_prov_values:
                err = (_("Must specify a valid provisioning type %(valid)s, "
                         "value '%(prov)s' is invalid.") %
                       {'valid': self.valid_prov_values,
                        'prov': prov_value})
                LOG.error(err)
                raise exception.InvalidInput(reason=err)

            tpvv = True
            tdvv = False

            if prov_value == "full":
                tpvv = False
            elif prov_value == "dedup":
                tpvv = False
                tdvv = True

            if tdvv and (self.API_VERSION < DEDUP_API_VERSION):
                err = (_("Dedup is a valid provisioning type, "
                         "but requires WSAPI version '%(dedup_version)s' "
                         "version '%(version)s' is installed.") %
                       {'dedup_version': DEDUP_API_VERSION,
                        'version': self.API_VERSION})
                LOG.error(err)
                raise exception.InvalidInput(reason=err)

            extras = {'comment': json.dumps(comments),
                      'tpvv': tpvv, }

            # Only set the dedup option if the backend supports it.
            if self.API_VERSION >= DEDUP_API_VERSION:
                extras['tdvv'] = tdvv

            capacity = self._capacity_from_size(volume['size'])
            volume_name = self._get_3par_vol_name(volume['id'])
            self.client.createVolume(volume_name, cpg, capacity, extras)

            # Check if flash cache needs to be enabled
            flash_cache = self.get_flash_cache_policy(volume['flash_cache'])

            if flash_cache is not None:
                try:
                    self._add_volume_to_volume_set(volume, volume_name,
                                                   cpg, flash_cache)
                except exception.InvalidInput as ex:
                    # Delete the volume if unable to add it to the volume set
                    self.client.deleteVolume(volume_name)
                    LOG.error(_LE("Exception: %s"), ex)
                    raise exception.PluginException(ex)
        except hpeexceptions.HTTPConflict:
            msg = _("Volume (%s) already exists on array") % volume_name
            LOG.error(msg)
            raise exception.Duplicate(msg)
        except hpeexceptions.HTTPBadRequest as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.Invalid(ex.get_description())
        except exception.InvalidInput as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise
        except exception.PluginException as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise
        except Exception as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.PluginException(ex)
예제 #8
0
    def delete_volume(self, volume):
        try:
            volume_name = self._get_3par_vol_name(volume['id'])
            # Try and delete the volume, it might fail here because
            # the volume is part of a volume set which will have the
            # volume set name in the error.
            try:
                self.client.deleteVolume(volume_name)
            except hpeexceptions.HTTPBadRequest as ex:
                if ex.get_code() == 29:
                    if self.client.isOnlinePhysicalCopy(volume_name):
                        LOG.debug("Found an online copy for %(volume)s",
                                  {'volume': volume_name})
                        # the volume is in process of being cloned.
                        # stopOnlinePhysicalCopy will also delete
                        # the volume once it stops the copy.
                        self.client.stopOnlinePhysicalCopy(volume_name)
                    else:
                        LOG.error(_LE("Exception: %s"), ex)
                        raise
                else:
                    LOG.error(_LE("Exception: %s"), ex)
                    raise
            except hpeexceptions.HTTPConflict as ex:
                if ex.get_code() == 34:
                    # This is a special case which means the
                    # volume is part of a volume set.
                    vvset_name = self.client.findVolumeSet(volume_name)
                    LOG.debug("Returned vvset_name = %s", vvset_name)
                    if vvset_name is not None and \
                       vvset_name.startswith('vvs-'):
                        # We have a single volume per volume set, so
                        # remove the volume set.
                        self.client.deleteVolumeSet(
                            self._get_3par_vvs_name(volume['id']))
                    elif vvset_name is not None:
                        # We have a pre-defined volume set just remove the
                        # volume and leave the volume set.
                        self.client.removeVolumeFromVolumeSet(
                            vvset_name, volume_name)
                    self.client.deleteVolume(volume_name)
                elif (ex.get_code() == 151 or ex.get_code() == 32):
                    # the volume is being operated on in a background
                    # task on the 3PAR.
                    # TODO(walter-boring) do a retry a few times.
                    # for now lets log a better message
                    msg = _("The volume is currently busy on the 3PAR"
                            " and cannot be deleted at this time. "
                            "You can try again later.")
                    LOG.error(msg)
                    raise exception.VolumeIsBusy(message=msg)
                else:
                    LOG.error(_LE("Exception: %s"), ex)
                    raise exception.VolumeIsBusy(message=ex.get_description())

        except hpeexceptions.HTTPNotFound as ex:
            LOG.warning(_LW("Delete volume id not found. Ex: %(msg)s"),
                        {'msg': ex})
        except hpeexceptions.HTTPForbidden as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.NotAuthorized(ex.get_description())
        except hpeexceptions.HTTPConflict as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.VolumeIsBusy(message=ex.get_description())
        except Exception as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.PluginException(ex)
예제 #9
0
    def create_volume(self, volume):
        LOG.debug(
            'CREATE VOLUME (%(disp_name)s: %(vol_name)s %(id)s on '
            '%(host)s)', {
                'disp_name': volume['display_name'],
                'vol_name': volume['name'],
                'id': self._get_3par_vol_name(volume['id']),
                'host': volume['host']
            })
        try:
            comments = {
                'volume_id': volume['id'],
                'name': volume['name'],
                'type': 'Docker'
            }

            name = volume.get('display_name', None)
            if name:
                comments['display_name'] = name

            # TODO(leeantho): Choose the first CPG for now. In the future
            # support selecting different CPGs if multiple are provided.
            cpg = self.config.hpe3par_cpg[0]

            # check for valid provisioning type
            prov_value = volume['provisioning']
            if prov_value not in self.valid_prov_values:
                err = (_("Must specify a valid provisioning type %(valid)s, "
                         "value '%(prov)s' is invalid.") % {
                             'valid': self.valid_prov_values,
                             'prov': prov_value
                         })
                LOG.error(err)
                raise exception.InvalidInput(reason=err)

            tpvv = True
            tdvv = False

            if prov_value == "full":
                tpvv = False
            elif prov_value == "dedup":
                tpvv = False
                tdvv = True

            if tdvv and (self.API_VERSION < DEDUP_API_VERSION):
                err = (_("Dedup is a valid provisioning type, "
                         "but requires WSAPI version '%(dedup_version)s' "
                         "version '%(version)s' is installed.") % {
                             'dedup_version': DEDUP_API_VERSION,
                             'version': self.API_VERSION
                         })
                LOG.error(err)
                raise exception.InvalidInput(reason=err)

            extras = {
                'comment': json.dumps(comments),
                'tpvv': tpvv,
            }

            # Only set the dedup option if the backend supports it.
            if self.API_VERSION >= DEDUP_API_VERSION:
                extras['tdvv'] = tdvv

            capacity = self._capacity_from_size(volume['size'])
            volume_name = self._get_3par_vol_name(volume['id'])
            self.client.createVolume(volume_name, cpg, capacity, extras)

            # Check if flash cache needs to be enabled
            flash_cache = self.get_flash_cache_policy(volume['flash_cache'])

            if flash_cache is not None:
                try:
                    self._add_volume_to_volume_set(volume, volume_name, cpg,
                                                   flash_cache)
                except exception.InvalidInput as ex:
                    # Delete the volume if unable to add it to the volume set
                    self.client.deleteVolume(volume_name)
                    LOG.error(_LE("Exception: %s"), ex)
                    raise exception.PluginException(ex)
        except hpeexceptions.HTTPConflict:
            msg = _("Volume (%s) already exists on array") % volume_name
            LOG.error(msg)
            raise exception.Duplicate(msg)
        except hpeexceptions.HTTPBadRequest as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.Invalid(ex.get_description())
        except exception.InvalidInput as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise
        except exception.PluginException as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise
        except Exception as ex:
            LOG.error(_LE("Exception: %s"), ex)
            raise exception.PluginException(ex)