def delete(self, context, group, force=False): if not group.host: self.update_quota(context, group, -1, group.project_id) LOG.debug( "No host for consistency group %s. Deleting from " "the database.", group.id) group.destroy() return if not force and group.status not in ([ c_fields.ConsistencyGroupStatus.AVAILABLE, c_fields.ConsistencyGroupStatus.ERROR ]): msg = _("Consistency group status must be available or error, " "but current status is: %s") % group.status raise exception.InvalidConsistencyGroup(reason=msg) cgsnapshots = storage.CGSnapshotList.get_all_by_group( context.elevated(), group.id) if cgsnapshots: msg = _("Consistency group %s still has dependent " "cgsnapshots.") % group.id LOG.error(msg) raise exception.InvalidConsistencyGroup(reason=msg) volumes = self.db.volume_get_all_by_group(context.elevated(), group.id) if volumes and not force: msg = _("Consistency group %s still contains volumes. " "The force flag is required to delete it.") % group.id LOG.error(msg) raise exception.InvalidConsistencyGroup(reason=msg) for volume in volumes: if volume['attach_status'] == "attached": msg = _("Volume in consistency group %s is attached. " "Need to detach first.") % group.id LOG.error(msg) raise exception.InvalidConsistencyGroup(reason=msg) snapshots = storage.SnapshotList.get_all_for_volume( context, volume['id']) if snapshots: msg = _("Volume in consistency group still has " "dependent snapshots.") LOG.error(msg) raise exception.InvalidConsistencyGroup(reason=msg) group.status = c_fields.ConsistencyGroupStatus.DELETING group.terminated_at = timeutils.utcnow() group.save() self.jacket_rpcapi.delete_consistencygroup(context, group)
def _create_cg_from_cgsnapshot(self, context, group, cgsnapshot): try: snapshots = storage.SnapshotList.get_all_for_cgsnapshot( context, cgsnapshot.id) if not snapshots: msg = _("Cgsnahost is empty. No consistency group " "will be created.") raise exception.InvalidConsistencyGroup(reason=msg) for snapshot in snapshots: kwargs = {} kwargs['availability_zone'] = group.availability_zone kwargs['cgsnapshot'] = cgsnapshot kwargs['consistencygroup'] = group kwargs['snapshot'] = snapshot volume_type_id = snapshot.volume_type_id if volume_type_id: kwargs['volume_type'] = volume_types.get_volume_type( context, volume_type_id) # Since cgsnapshot is passed in, the following call will # create a db entry for the volume, but will not call the # volume manager to create a real volume in the backend yet. # If error happens, taskflow will handle rollback of quota # and removal of volume entry in the db. try: self.volume_api.create(context, snapshot.volume_size, None, None, **kwargs) except exception.CinderException: with excutils.save_and_reraise_exception(): LOG.error( _LE("Error occurred when creating volume " "entry from snapshot in the process of " "creating consistency group %(group)s " "from cgsnapshot %(cgsnap)s."), { 'group': group.id, 'cgsnap': cgsnapshot.id }) except Exception: with excutils.save_and_reraise_exception(): try: group.destroy() finally: LOG.error( _LE("Error occurred when creating consistency " "group %(group)s from cgsnapshot " "%(cgsnap)s."), { 'group': group.id, 'cgsnap': cgsnapshot.id }) volumes = self.db.volume_get_all_by_group(context, group.id) for vol in volumes: # Update the host field for the volume. self.db.volume_update(context, vol['id'], {'host': group.get('host')}) self.jacket_rpcapi.create_consistencygroup_from_src( context, group, cgsnapshot)
def _create_cg_from_source_cg(self, context, group, source_cg): try: source_vols = self.db.volume_get_all_by_group( context, source_cg.id) if not source_vols: msg = _("Source CG is empty. No consistency group " "will be created.") raise exception.InvalidConsistencyGroup(reason=msg) for source_vol in source_vols: kwargs = {} kwargs['availability_zone'] = group.availability_zone kwargs['source_cg'] = source_cg kwargs['consistencygroup'] = group kwargs['source_volume'] = source_vol volume_type_id = source_vol.get('volume_type_id') if volume_type_id: kwargs['volume_type'] = volume_types.get_volume_type( context, volume_type_id) # Since source_cg is passed in, the following call will # create a db entry for the volume, but will not call the # volume manager to create a real volume in the backend yet. # If error happens, taskflow will handle rollback of quota # and removal of volume entry in the db. try: self.volume_api.create(context, source_vol['size'], None, None, **kwargs) except exception.CinderException: with excutils.save_and_reraise_exception(): LOG.error( _LE("Error occurred when creating cloned " "volume in the process of creating " "consistency group %(group)s from " "source CG %(source_cg)s."), { 'group': group.id, 'source_cg': source_cg.id }) except Exception: with excutils.save_and_reraise_exception(): try: group.destroy() finally: LOG.error( _LE("Error occurred when creating consistency " "group %(group)s from source CG " "%(source_cg)s."), { 'group': group.id, 'source_cg': source_cg.id }) volumes = self.db.volume_get_all_by_group(context, group.id) for vol in volumes: # Update the host field for the volume. self.db.volume_update(context, vol['id'], {'host': group.host}) self.jacket_rpcapi.create_consistencygroup_from_src( context, group, None, source_cg)
def _create_cgsnapshot(self, context, group, name, description): volumes = self.db.volume_get_all_by_group(context.elevated(), group.id) if not volumes: msg = _("Consistency group is empty. No cgsnapshot " "will be created.") raise exception.InvalidConsistencyGroup(reason=msg) options = { 'consistencygroup_id': group.id, 'user_id': context.user_id, 'project_id': context.project_id, 'status': "creating", 'name': name, 'description': description } cgsnapshot = None cgsnapshot_id = None try: cgsnapshot = storage.CGSnapshot(context, **options) cgsnapshot.create() cgsnapshot_id = cgsnapshot.id snap_name = cgsnapshot.name snap_desc = cgsnapshot.description self.volume_api.create_snapshots_in_db(context, volumes, snap_name, snap_desc, True, cgsnapshot_id) except Exception: with excutils.save_and_reraise_exception(): try: if cgsnapshot: cgsnapshot.destroy() finally: LOG.error( _LE("Error occurred when creating cgsnapshot" " %s."), cgsnapshot_id) self.jacket_rpcapi.create_cgsnapshot(context, cgsnapshot) return cgsnapshot
def update(self, context, group, name, description, add_volumes, remove_volumes): """Update consistency group.""" if group.status != c_fields.ConsistencyGroupStatus.AVAILABLE: msg = _("Consistency group status must be available, " "but current status is: %s.") % group.status raise exception.InvalidConsistencyGroup(reason=msg) add_volumes_list = [] remove_volumes_list = [] if add_volumes: add_volumes = add_volumes.strip(',') add_volumes_list = add_volumes.split(',') if remove_volumes: remove_volumes = remove_volumes.strip(',') remove_volumes_list = remove_volumes.split(',') invalid_uuids = [] for uuid in add_volumes_list: if uuid in remove_volumes_list: invalid_uuids.append(uuid) if invalid_uuids: msg = _("UUIDs %s are in both add and remove volume " "list.") % invalid_uuids raise exception.InvalidVolume(reason=msg) volumes = self.db.volume_get_all_by_group(context, group.id) # Validate name. if not name or name == group.name: name = None # Validate description. if not description or description == group.description: description = None # Validate volumes in add_volumes and remove_volumes. add_volumes_new = "" remove_volumes_new = "" if add_volumes_list: add_volumes_new = self._validate_add_volumes( context, volumes, add_volumes_list, group) if remove_volumes_list: remove_volumes_new = self._validate_remove_volumes( volumes, remove_volumes_list, group) if (not name and not description and not add_volumes_new and not remove_volumes_new): msg = (_("Cannot update consistency group %(group_id)s " "because no valid name, description, add_volumes, " "or remove_volumes were provided.") % { 'group_id': group.id }) raise exception.InvalidConsistencyGroup(reason=msg) fields = {'updated_at': timeutils.utcnow()} # Update name and description in db now. No need to # to send them over through an RPC call. if name: fields['name'] = name if description: fields['description'] = description if not add_volumes_new and not remove_volumes_new: # Only update name or description. Set status to available. fields['status'] = 'available' else: fields['status'] = 'updating' group.update(fields) group.save() # Do an RPC call only if the update request includes # adding/removing volumes. add_volumes_new and remove_volumes_new # are strings of volume UUIDs separated by commas with no spaces # in between. if add_volumes_new or remove_volumes_new: self.jacket_rpcapi.update_consistencygroup( context, group, add_volumes=add_volumes_new, remove_volumes=remove_volumes_new)
def create_from_src(self, context, name, description=None, cgsnapshot_id=None, source_cgid=None): check_policy(context, 'create') cgsnapshot = None orig_cg = None if cgsnapshot_id: try: cgsnapshot = storage.CGSnapshot.get_by_id( context, cgsnapshot_id) except exception.CgSnapshotNotFound: with excutils.save_and_reraise_exception(): LOG.error( _LE("CG snapshot %(cgsnap)s not found when " "creating consistency group %(cg)s from " "source."), { 'cg': name, 'cgsnap': cgsnapshot_id }) else: orig_cg = cgsnapshot.consistencygroup source_cg = None if source_cgid: try: source_cg = storage.ConsistencyGroup.get_by_id( context, source_cgid) except exception.ConsistencyGroupNotFound: with excutils.save_and_reraise_exception(): LOG.error( _LE("Source CG %(source_cg)s not found when " "creating consistency group %(cg)s from " "source."), { 'cg': name, 'source_cg': source_cgid }) kwargs = { 'user_id': context.user_id, 'project_id': context.project_id, 'status': c_fields.ConsistencyGroupStatus.CREATING, 'name': name, 'description': description, 'cgsnapshot_id': cgsnapshot_id, 'source_cgid': source_cgid, } if orig_cg: kwargs['volume_type_id'] = orig_cg.volume_type_id kwargs['availability_zone'] = orig_cg.availability_zone kwargs['host'] = orig_cg.host if source_cg: kwargs['volume_type_id'] = source_cg.volume_type_id kwargs['availability_zone'] = source_cg.availability_zone kwargs['host'] = source_cg.host group = None try: group = storage.ConsistencyGroup(context=context, **kwargs) group.create() except Exception: with excutils.save_and_reraise_exception(): LOG.error( _LE("Error occurred when creating consistency group" " %(cg)s from cgsnapshot %(cgsnap)s."), { 'cg': name, 'cgsnap': cgsnapshot_id }) # Update quota for consistencygroups self.update_quota(context, group, 1) if not group.host: msg = _("No host to create consistency group %s.") % group.id LOG.error(msg) raise exception.InvalidConsistencyGroup(reason=msg) if cgsnapshot: self._create_cg_from_cgsnapshot(context, group, cgsnapshot) elif source_cg: self._create_cg_from_source_cg(context, group, source_cg) return group