Esempio n. 1
0
    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)
Esempio n. 2
0
    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)
Esempio n. 3
0
File: api.py Progetto: NetApp/cinder
    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)
Esempio n. 4
0
    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()
Esempio n. 5
0
File: api.py Progetto: NetApp/cinder
    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()