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 force: expected = {} else: expected = {'status': (c_fields.ConsistencyGroupStatus.AVAILABLE, c_fields.ConsistencyGroupStatus.ERROR)} filters = [~db.cg_has_cgsnapshot_filter(), ~db.cg_has_volumes_filter(attached_or_with_snapshots=force), ~db.cg_creating_from_src(cg_id=group.id)] values = {'status': c_fields.ConsistencyGroupStatus.DELETING} if not group.conditional_update(values, expected, filters): if force: reason = _('Consistency group must not have attached volumes, ' 'volumes with snapshots, or dependent cgsnapshots') else: reason = _('Consistency group status must be available or ' 'error and must not have volumes or dependent ' 'cgsnapshots') msg = (_('Cannot delete consistency group %(id)s. %(reason)s, and ' 'it cannot be the source for an ongoing CG or CG ' 'Snapshot creation.') % {'id': group.id, 'reason': reason}) raise exception.InvalidConsistencyGroup(reason=msg) self.volume_rpcapi.delete_consistencygroup(context, group)
def delete_cgsnapshot(self, context, cgsnapshot, force=False): values = {'status': 'deleting'} expected = {'status': ('available', 'error')} filters = [~db.cg_creating_from_src(cgsnapshot_id=cgsnapshot.id)] res = cgsnapshot.conditional_update(values, expected, filters) if not res: msg = _('CgSnapshot status must be available or error, and no CG ' 'can be currently using it as source for its creation.') raise exception.InvalidCgSnapshot(reason=msg) self.volume_rpcapi.delete_cgsnapshot(context.elevated(), cgsnapshot)
def update(self, context, group, name, description, add_volumes, remove_volumes, allow_empty=False): """Update consistency group.""" 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) # Validate name. if name == group.name: name = None # Validate description. if description == group.description: description = None self._check_update(group, name, description, add_volumes, remove_volumes, allow_empty) fields = {'updated_at': timeutils.utcnow()} # Update name and description in db now. No need to # to send them over through an RPC call. if allow_empty: if name is not None: fields['name'] = name if description is not None: fields['description'] = description else: if name: fields['name'] = name if description: fields['description'] = description # NOTE(geguileo): We will use the updating status in the CG as a lock # mechanism to prevent volume add/remove races with other API, while we # figure out if we really need to add or remove volumes. if add_volumes or remove_volumes: fields['status'] = c_fields.ConsistencyGroupStatus.UPDATING # We cannot modify the members of this CG if the CG is being used # to create another CG or a CGsnapshot is being created filters = [ ~db.cg_creating_from_src(cg_id=group.id), ~db.cgsnapshot_creating_from_src() ] else: filters = [] expected = {'status': c_fields.ConsistencyGroupStatus.AVAILABLE} if not group.conditional_update(fields, expected, filters): msg = _("Cannot update consistency group %s, status must be " "available, and it cannot be the source for an ongoing " "CG or CG Snapshot creation.") % group.id raise exception.InvalidConsistencyGroup(reason=msg) # Now the CG is "locked" for updating try: # Validate volumes in add_volumes and remove_volumes. add_volumes_new = self._validate_add_volumes( context, group.volumes, add_volumes_list, group) remove_volumes_new = self._validate_remove_volumes( group.volumes, remove_volumes_list, group) self._check_update(group, name, description, add_volumes_new, remove_volumes_new, allow_empty) except Exception: # If we have an error on the volume_lists we must return status to # available as we were doing before removing API races with excutils.save_and_reraise_exception(): group.status = c_fields.ConsistencyGroupStatus.AVAILABLE 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.volume_rpcapi.update_consistencygroup( context, group, add_volumes=add_volumes_new, remove_volumes=remove_volumes_new) # If there are no new volumes to add or remove and we had changed # the status to updating, turn it back to available elif group.status == c_fields.ConsistencyGroupStatus.UPDATING: group.status = c_fields.ConsistencyGroupStatus.AVAILABLE group.save()
def update(self, context, group, name, description, add_volumes, remove_volumes, allow_empty=False): """Update consistency group.""" 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) # Validate name. if name == group.name: name = None # Validate description. if description == group.description: description = None self._check_update(group, name, description, add_volumes, remove_volumes, allow_empty) fields = {'updated_at': timeutils.utcnow()} # Update name and description in db now. No need to # to send them over through an RPC call. if allow_empty: if name is not None: fields['name'] = name if description is not None: fields['description'] = description else: if name: fields['name'] = name if description: fields['description'] = description # NOTE(geguileo): We will use the updating status in the CG as a lock # mechanism to prevent volume add/remove races with other API, while we # figure out if we really need to add or remove volumes. if add_volumes or remove_volumes: fields['status'] = c_fields.ConsistencyGroupStatus.UPDATING # We cannot modify the members of this CG if the CG is being used # to create another CG or a CGsnapshot is being created filters = [~db.cg_creating_from_src(cg_id=group.id), ~db.cgsnapshot_creating_from_src()] else: filters = [] expected = {'status': c_fields.ConsistencyGroupStatus.AVAILABLE} if not group.conditional_update(fields, expected, filters): msg = _("Cannot update consistency group %s, status must be " "available, and it cannot be the source for an ongoing " "CG or CG Snapshot creation.") % group.id raise exception.InvalidConsistencyGroup(reason=msg) # Now the CG is "locked" for updating try: # Validate volumes in add_volumes and remove_volumes. add_volumes_new = self._validate_add_volumes( context, group.volumes, add_volumes_list, group) remove_volumes_new = self._validate_remove_volumes( group.volumes, remove_volumes_list, group) self._check_update(group, name, description, add_volumes_new, remove_volumes_new, allow_empty) except Exception: # If we have an error on the volume_lists we must return status to # available as we were doing before removing API races with excutils.save_and_reraise_exception(): group.status = c_fields.ConsistencyGroupStatus.AVAILABLE 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.volume_rpcapi.update_consistencygroup( context, group, add_volumes=add_volumes_new, remove_volumes=remove_volumes_new) # If there are no new volumes to add or remove and we had changed # the status to updating, turn it back to available elif group.status == c_fields.ConsistencyGroupStatus.UPDATING: group.status = c_fields.ConsistencyGroupStatus.AVAILABLE group.save()