def _clone_object(self, oname, coname): """Creates a clone of specified object :param: oname: name of an object to clone :param: coname: name of a new clone """ LOG.debug('cloning %(oname)s to %(coname)s', { "oname": oname, "coname": coname }) try: self.ra.create_snapshot(oname, coname) except jexc.JDSSSnapshotExistsException: try: self.ra.delete_snapshot(oname, coname) except jexc.JDSSSnapshotIsBusyException as jerrisbusy: raise exception.Duplicate() from jerrisbusy except jexc.JDSSException as jerr: raise exception.VolumeBackendAPIException( (_("Unable to create volume %s.") % coname)) from jerr except jexc.JDSSResourceNotFoundException as jerrnotfound: if jcom.is_volume(oname): raise exception.VolumeNotFound( volume_id=jcom.idname(oname)) from jerrnotfound raise exception.SnapshotNotFound( snapshot_id=jcom.idname(oname)) from jerrnotfound except jexc.JDSSException as jerr: args = {'snapshot': coname, 'object': oname, 'err': jerr} msg = (_('Failed to create tmp snapshot %(snapshot)s ' 'for object %(object)s: %(err)s') % args) raise exception.VolumeBackendAPIException(msg) try: self.ra.create_volume_from_snapshot(coname, coname, oname, sparse=self.jovian_sparse) except jexc.JDSSResourceExistsException as jerr: raise exception.Duplicate() from jerr except jexc.JDSSException as jerr: try: self.ra.delete_snapshot(oname, coname, recursively_children=True, recursively_dependents=True, force_umount=True) except jexc.JDSSException as jerrd: LOG.warning( "Because of %s physical snapshot %s of volume" " %s have to be removed manually", jerrd, coname, oname) raise exception.VolumeBackendAPIException( _("Unable to create volume %(vol)s because of %(err)s.") % { 'vol': coname, 'err': jerr }) from jerr
def save(self, session=None): """Save this object.""" if not session: session = get_session() session.add(self) try: session.flush() except IntegrityError, e: if str(e).endswith('is not unique'): raise exception.Duplicate(str(e)) else: raise
def create(self, context, metadata, data=None): """Store the image data and return the new image id. :raises: Duplicate if the image already exist. """ image_id = str(metadata.get('id', uuid.uuid4())) metadata['id'] = image_id if image_id in self.images: raise exception.Duplicate() self.images[image_id] = copy.deepcopy(metadata) if data: self._imagedata[image_id] = data.read() return self.images[image_id]
def _create_target(self, target_name, use_chap=True): """Creates target and handles exceptions Tryes to create target. :param target_name: name of target :param use_chap: flag for using chap """ try: self.ra.create_target(target_name, use_chap=use_chap) except jexc.JDSSResourceExistsException: raise exception.Duplicate() except jexc.JDSSException as ex: msg = (_('Unable to create target %(target)s ' 'because of %(error)s.') % {'target': target_name, 'error': ex}) raise exception.VolumeBackendAPIException(msg)
def create_volume(self, volume, client): LOG.debug("CREATE VOLUME (%s : %s %s)" % (volume['display_name'], volume['name'], self._get_3par_vol_name(volume['id']))) try: comments = { 'volume_id': volume['id'], 'name': volume['name'], 'type': 'OpenStack' } name = volume.get('display_name', None) if name: comments['display_name'] = name # get the options supported by volume types volume_type = None type_id = volume.get('volume_type_id', None) if type_id is not None: volume_type = self._get_volume_type(type_id) cpg = self._get_volume_type_value(volume_type, 'cpg', self.config.hp3par_cpg) # if provisioning is not set use thin default_prov = self.valid_prov_values[0] prov_value = self._get_volume_type_value(volume_type, 'provisioning', default_prov) # check for valid provisioning type 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}) raise exception.InvalidInput(reason=err) ttpv = True if prov_value == "full": ttpv = False # default to hp3par_cpg if hp3par_cpg_snap is not set. if self.config.hp3par_cpg_snap == "": snap_default = self.config.hp3par_cpg else: snap_default = self.config.hp3par_cpg_snap snap_cpg = self._get_volume_type_value(volume_type, 'snap_cpg', snap_default) # check for valid persona even if we don't use it until # attach time, this will given end user notice that the # persona type is invalid at volume creation time self.get_persona_type(volume) if type_id is not None: comments['volume_type_name'] = volume_type.get('name') comments['volume_type_id'] = type_id extras = { 'comment': json.dumps(comments), 'snapCPG': snap_cpg, 'tpvv': ttpv } capacity = self._capacity_from_size(volume['size']) volume_name = self._get_3par_vol_name(volume['id']) client.createVolume(volume_name, cpg, capacity, extras) except hpexceptions.HTTPConflict: raise exception.Duplicate( _("Volume (%s) already exists on array") % volume_name) except hpexceptions.HTTPBadRequest as ex: LOG.error(str(ex)) raise exception.Invalid(ex.get_description()) except exception.InvalidInput as ex: LOG.error(str(ex)) raise ex except Exception as ex: LOG.error(str(ex)) raise exception.CinderException(ex.get_description()) metadata = { '3ParName': volume_name, 'CPG': self.config.hp3par_cpg, 'snapCPG': extras['snapCPG'] } return metadata
def create_volume(self, volume): LOG.debug("CREATE VOLUME (%s : %s %s)" % (volume['display_name'], volume['name'], self._get_3par_vol_name(volume['id']))) try: comments = {'volume_id': volume['id'], 'name': volume['name'], 'type': 'OpenStack'} name = volume.get('display_name', None) if name: comments['display_name'] = name # get the options supported by volume types type_info = self.get_volume_settings_from_type(volume) volume_type = type_info['volume_type'] vvs_name = type_info['vvs_name'] qos = type_info['qos'] cpg = type_info['cpg'] snap_cpg = type_info['snap_cpg'] tpvv = type_info['tpvv'] type_id = volume.get('volume_type_id', None) if type_id is not None: comments['volume_type_name'] = volume_type.get('name') comments['volume_type_id'] = type_id if vvs_name is not None: comments['vvs'] = vvs_name else: comments['qos'] = qos extras = {'comment': json.dumps(comments), 'snapCPG': snap_cpg, 'tpvv': tpvv} capacity = self._capacity_from_size(volume['size']) volume_name = self._get_3par_vol_name(volume['id']) self.client.createVolume(volume_name, cpg, capacity, extras) if qos or vvs_name is not None: try: self._add_volume_to_volume_set(volume, volume_name, cpg, vvs_name, qos) except exception.InvalidInput as ex: # Delete the volume if unable to add it to the volume set self.client.deleteVolume(volume_name) LOG.error(str(ex)) raise exception.CinderException(str(ex)) except hpexceptions.HTTPConflict: msg = _("Volume (%s) already exists on array") % volume_name LOG.error(msg) raise exception.Duplicate(msg) except hpexceptions.HTTPBadRequest as ex: LOG.error(str(ex)) raise exception.Invalid(ex.get_description()) except exception.InvalidInput as ex: LOG.error(str(ex)) raise ex except exception.CinderException as ex: LOG.error(str(ex)) raise ex except Exception as ex: LOG.error(str(ex)) raise exception.CinderException(str(ex))
def _convert_to_base_volume(self, volume, new_cpg=None): try: type_info = self.get_volume_settings_from_type(volume) if new_cpg: cpg = new_cpg else: cpg = type_info['cpg'] # Change the name such that it is unique since 3PAR # names must be unique across all CPGs volume_name = self._get_3par_vol_name(volume['id']) temp_vol_name = volume_name.replace("osv-", "omv-") # Create a physical copy of the volume task_id = self._copy_volume(volume_name, temp_vol_name, cpg, cpg, type_info['tpvv']) LOG.debug(_('Copy volume scheduled: convert_to_base_volume: ' 'id=%s.') % volume['id']) # Wait for the physical copy task to complete def _wait_for_task(task_id): status = self.client.getTask(task_id) LOG.debug("3PAR Task id %(id)s status = %(status)s" % {'id': task_id, 'status': status['status']}) if status['status'] is not self.client.TASK_ACTIVE: self._task_status = status raise loopingcall.LoopingCallDone() self._task_status = None timer = loopingcall.FixedIntervalLoopingCall( _wait_for_task, task_id) timer.start(interval=1).wait() if self._task_status['status'] is not self.client.TASK_DONE: dbg = {'status': self._task_status, 'id': volume['id']} msg = _('Copy volume task failed: convert_to_base_volume: ' 'id=%(id)s, status=%(status)s.') % dbg raise exception.CinderException(msg) else: LOG.debug(_('Copy volume completed: convert_to_base_volume: ' 'id=%s.') % volume['id']) comment = self._get_3par_vol_comment(volume_name) if comment: self.client.modifyVolume(temp_vol_name, {'comment': comment}) LOG.debug(_('Volume rename completed: convert_to_base_volume: ' 'id=%s.') % volume['id']) # Delete source volume after the copy is complete self.client.deleteVolume(volume_name) LOG.debug(_('Delete src volume completed: convert_to_base_volume: ' 'id=%s.') % volume['id']) # Rename the new volume to the original name self.client.modifyVolume(temp_vol_name, {'newName': volume_name}) LOG.info(_('Completed: convert_to_base_volume: ' 'id=%s.') % volume['id']) except hpexceptions.HTTPConflict: msg = _("Volume (%s) already exists on array.") % volume_name LOG.error(msg) raise exception.Duplicate(msg) except hpexceptions.HTTPBadRequest as ex: LOG.error(str(ex)) raise exception.Invalid(ex.get_description()) except exception.InvalidInput as ex: LOG.error(str(ex)) raise ex except exception.CinderException as ex: LOG.error(str(ex)) raise ex except Exception as ex: LOG.error(str(ex)) raise exception.CinderException(ex)
def create_volume(self, volume): LOG.debug("CREATE VOLUME (%s : %s %s)" % (volume['display_name'], volume['name'], self._get_3par_vol_name(volume['id']))) try: comments = { 'volume_id': volume['id'], 'name': volume['name'], 'type': 'OpenStack' } name = volume.get('display_name', None) if name: comments['display_name'] = name # get the options supported by volume types volume_type = None vvs_name = None hp3par_keys = {} qos = {} type_id = volume.get('volume_type_id', None) if type_id is not None: volume_type = self._get_volume_type(type_id) hp3par_keys = self._get_keys_by_volume_type(volume_type) vvs_name = self._get_key_value(hp3par_keys, 'vvs') if vvs_name is None: qos = self._get_qos_by_volume_type(volume_type) cpg = self._get_key_value(hp3par_keys, 'cpg', self.config.hp3par_cpg) if cpg is not self.config.hp3par_cpg: # The cpg was specified in a volume type extra spec so it # needs to be validiated that it's in the correct domain. self.validate_cpg(cpg) # Also, look to see if the snap_cpg was specified in volume # type extra spec, if not use the extra spec cpg as the # default. snap_cpg = self._get_key_value(hp3par_keys, 'snap_cpg', cpg) else: # default snap_cpg to hp3par_cpg_snap if it's not specified # in the volume type extra specs. snap_cpg = self.config.hp3par_cpg_snap # if it's still not set or empty then set it to the cpg # specified in the cinder.conf file. if not self.config.hp3par_cpg_snap: snap_cpg = cpg # if provisioning is not set use thin default_prov = self.valid_prov_values[0] prov_value = self._get_key_value(hp3par_keys, 'provisioning', default_prov) # check for valid provisioning type 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}) raise exception.InvalidInput(reason=err) ttpv = True if prov_value == "full": ttpv = False # check for valid persona even if we don't use it until # attach time, this will give the end user notice that the # persona type is invalid at volume creation time self.get_persona_type(volume, hp3par_keys) if type_id is not None: comments['volume_type_name'] = volume_type.get('name') comments['volume_type_id'] = type_id if vvs_name is not None: comments['vvs'] = vvs_name else: comments['qos'] = qos extras = { 'comment': json.dumps(comments), 'snapCPG': snap_cpg, 'tpvv': ttpv } capacity = self._capacity_from_size(volume['size']) volume_name = self._get_3par_vol_name(volume['id']) self.client.createVolume(volume_name, cpg, capacity, extras) if qos or vvs_name is not None: try: self._add_volume_to_volume_set(volume, volume_name, cpg, vvs_name, qos) except Exception as ex: # Delete the volume if unable to add it to the volume set self.client.deleteVolume(volume_name) LOG.error(str(ex)) raise exception.CinderException(ex.get_description()) except hpexceptions.HTTPConflict: raise exception.Duplicate( _("Volume (%s) already exists on array") % volume_name) except hpexceptions.HTTPBadRequest as ex: LOG.error(str(ex)) raise exception.Invalid(ex.get_description()) except exception.InvalidInput as ex: LOG.error(str(ex)) raise ex except Exception as ex: LOG.error(str(ex)) raise exception.CinderException(ex.get_description())