Ejemplo n.º 1
0
    def delete(self, context, group, delete_volumes=False):
        if not group.host:
            self.update_quota(context, group, -1, group.project_id)

            LOG.debug("No host for group %s. Deleting from "
                      "the database.", group.id)
            group.destroy()

            return

        group.assert_not_frozen()

        if not delete_volumes and group.status not in (
                [c_fields.GroupStatus.AVAILABLE,
                 c_fields.GroupStatus.ERROR]):
            msg = _("Group status must be available or error, "
                    "but current status is: %s") % group.status
            raise exception.InvalidGroup(reason=msg)

        # NOTE(tommylikehu): Admin context is required to load group snapshots.
        with group.obj_as_admin():
            if group.group_snapshots:
                raise exception.InvalidGroup(
                    reason=_("Group has existing snapshots."))

        volumes = self.db.volume_get_all_by_generic_group(context.elevated(),
                                                          group.id)
        if volumes and not delete_volumes:
            msg = (_("Group %s still contains volumes. "
                     "The delete-volumes flag is required to delete it.")
                   % group.id)
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        volumes_model_update = []
        for volume in volumes:
            if volume['attach_status'] == "attached":
                msg = _("Volume in group %s is attached. "
                        "Need to detach first.") % group.id
                LOG.error(msg)
                raise exception.InvalidGroup(reason=msg)

            snapshots = objects.SnapshotList.get_all_for_volume(context,
                                                                volume['id'])
            if snapshots:
                msg = _("Volume in group still has "
                        "dependent snapshots.")
                LOG.error(msg)
                raise exception.InvalidGroup(reason=msg)

            volumes_model_update.append({'id': volume['id'],
                                         'status': 'deleting'})

        self.db.volumes_update(context, volumes_model_update)

        group.status = c_fields.GroupStatus.DELETING
        group.terminated_at = timeutils.utcnow()
        group.save()

        self.volume_rpcapi.delete_group(context, group)
Ejemplo n.º 2
0
    def enable_replication(self, context, group):
        self._check_type(group)

        valid_status = [c_fields.GroupStatus.AVAILABLE]
        if group.status not in valid_status:
            params = {'valid': valid_status,
                      'current': group.status,
                      'id': group.id}
            msg = _("Group %(id)s status must be %(valid)s, "
                    "but current status is: %(current)s. "
                    "Cannot enable replication.") % params
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        valid_rep_status = [c_fields.ReplicationStatus.DISABLED,
                            c_fields.ReplicationStatus.ENABLED]
        if group.replication_status not in valid_rep_status:
            params = {'valid': valid_rep_status,
                      'current': group.replication_status,
                      'id': group.id}
            msg = _("Group %(id)s replication status must be %(valid)s, "
                    "but current status is: %(current)s. "
                    "Cannot enable replication.") % params
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        volumes = objects.VolumeList.get_all_by_generic_group(
            context.elevated(), group.id)

        valid_status = ['available', 'in-use']
        for vol in volumes:
            if vol.status not in valid_status:
                params = {'valid': valid_status,
                          'current': vol.status,
                          'id': vol.id}
                msg = _("Volume %(id)s status must be %(valid)s, "
                        "but current status is: %(current)s. "
                        "Cannot enable replication.") % params
                LOG.error(msg)
                raise exception.InvalidVolume(reason=msg)
                # replication_status could be set to enabled when volume is
                # created and the mirror is built.
            if vol.replication_status not in valid_rep_status:
                params = {'valid': valid_rep_status,
                          'current': vol.replication_status,
                          'id': vol.id}
                msg = _("Volume %(id)s replication status must be %(valid)s, "
                        "but current status is: %(current)s. "
                        "Cannot enable replication.") % params
                LOG.error(msg)
                raise exception.InvalidVolume(reason=msg)

            vol.replication_status = c_fields.ReplicationStatus.ENABLING
            vol.save()

        group.replication_status = c_fields.ReplicationStatus.ENABLING
        group.save()

        self.volume_rpcapi.enable_replication(context, group)
Ejemplo n.º 3
0
    def disable_replication(self, context, group):
        self._check_type(group)

        valid_status = [
            c_fields.GroupStatus.AVAILABLE, c_fields.GroupStatus.ERROR
        ]
        if group.status not in valid_status:
            params = {
                'valid': valid_status,
                'current': group.status,
                'id': group.id
            }
            msg = _("Group %(id)s status must be %(valid)s, "
                    "but current status is: %(current)s. "
                    "Cannot disable replication.") % params
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        valid_rep_status = [
            c_fields.ReplicationStatus.ENABLED,
            c_fields.ReplicationStatus.ERROR
        ]
        if group.replication_status not in valid_rep_status:
            params = {
                'valid': valid_rep_status,
                'current': group.replication_status,
                'id': group.id
            }
            msg = _("Group %(id)s replication status must be %(valid)s, "
                    "but current status is: %(current)s. "
                    "Cannot disable replication.") % params
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        volumes = objects.VolumeList.get_all_by_generic_group(
            context.elevated(), group.id)

        for vol in volumes:
            if vol.replication_status not in valid_rep_status:
                params = {
                    'valid': valid_rep_status,
                    'current': vol.replication_status,
                    'id': vol.id
                }
                msg = _("Volume %(id)s replication status must be %(valid)s, "
                        "but current status is: %(current)s. "
                        "Cannot disable replication.") % params
                LOG.error(msg)
                raise exception.InvalidVolume(reason=msg)

            vol.replication_status = c_fields.ReplicationStatus.DISABLING
            vol.save()

        group.replication_status = c_fields.ReplicationStatus.DISABLING
        group.save()

        self.volume_rpcapi.disable_replication(context, group)
Ejemplo n.º 4
0
 def _get_infinidat_cg(self, cinder_group):
     group_name = self._make_cg_name(cinder_group)
     infinidat_cg = self._system.cons_groups.safe_get(name=group_name)
     if infinidat_cg is None:
         msg = _('Consistency group "%s" not found') % group_name
         LOG.error(msg)
         raise exception.InvalidGroup(message=msg)
     return infinidat_cg
Ejemplo n.º 5
0
Archivo: api.py Proyecto: Jchuan/cinder
    def create_from_src(self, context, name, description=None,
                        group_snapshot_id=None, source_group_id=None):
        check_policy(context, 'create')

        kwargs = {
            'user_id': context.user_id,
            'project_id': context.project_id,
            'status': c_fields.GroupStatus.CREATING,
            'name': name,
            'description': description,
            'group_snapshot_id': group_snapshot_id,
            'source_group_id': source_group_id,
        }

        group = None
        try:
            group = objects.Group(context=context, **kwargs)
            group.create(group_snapshot_id=group_snapshot_id,
                         source_group_id=source_group_id)
        except exception.GroupNotFound:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Source Group %(source_group)s not found when "
                              "creating group %(group)s from "
                              "source."),
                          {'group': name, 'source_group': source_group_id})
        except exception.GroupSnapshotNotFound:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Group snapshot %(group_snap)s not found when "
                              "creating group %(group)s from source."),
                          {'group': name, 'group_snap': group_snapshot_id})
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Error occurred when creating group"
                              " %(group)s from group_snapshot %(grp_snap)s."),
                          {'group': name, 'grp_snap': group_snapshot_id})

        # Update quota for groups
        self.update_quota(context, group, 1)

        if not group.host:
            msg = _("No host to create group %s.") % group.id
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        if group_snapshot_id:
            self._create_group_from_group_snapshot(context, group,
                                                   group_snapshot_id)
        elif source_group_id:
            self._create_group_from_source_group(context, group,
                                                 source_group_id)

        return group
Ejemplo n.º 6
0
    def update(self, context, group, name, description, add_volumes,
               remove_volumes):
        """Update group."""
        if group.status != c_fields.GroupStatus.AVAILABLE:
            msg = _("Group status must be available, "
                    "but current status is: %s.") % group.status
            raise exception.InvalidGroup(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_generic_group(context, group.id)

        # Validate name.
        if name == group.name:
            name = None

        # Validate description.
        if 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 (name is None and description is None and not add_volumes_new
                and not remove_volumes_new):
            msg = (_("Cannot update group %(group_id)s "
                     "because no valid name, description, add_volumes, "
                     "or remove_volumes were provided.") % {
                         'group_id': group.id
                     })
            raise exception.InvalidGroup(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 is not None:
            fields['name'] = name
        if description is not None:
            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.volume_rpcapi.update_group(context,
                                            group,
                                            add_volumes=add_volumes_new,
                                            remove_volumes=remove_volumes_new)
Ejemplo n.º 7
0
    def _create_group_from_source_group(self, context, group, source_group_id):
        try:
            source_group = objects.Group.get_by_id(context, source_group_id)
            source_vols = objects.VolumeList.get_all_by_generic_group(
                context, source_group.id)

            if not source_vols:
                msg = _("Source Group is empty. No group " "will be created.")
                raise exception.InvalidGroup(reason=msg)

            for source_vol in source_vols:
                kwargs = {}
                kwargs['availability_zone'] = group.availability_zone
                kwargs['source_group'] = source_group
                kwargs['group'] = group
                kwargs['source_volume'] = source_vol
                volume_type_id = source_vol.volume_type_id
                if volume_type_id:
                    kwargs['volume_type'] = volume_types.get_volume_type(
                        context, volume_type_id)
                    # Create group volume_type mapping entries
                    try:
                        db.group_volume_type_mapping_create(
                            context, group.id, volume_type_id)
                    except exception.GroupVolumeTypeMappingExists:
                        # Only need to create one group volume_type mapping
                        # entry for the same combination, skipping.
                        LOG.info(
                            _LI("A mapping entry already exists for group"
                                " %(grp)s and volume type %(vol_type)s. "
                                "Do not need to create again."), {
                                    'grp': group.id,
                                    'vol_type': volume_type_id
                                })
                        pass

                # Since source_group 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 "
                                "group %(group)s from "
                                "source group %(source_group)s."), {
                                    'group': group.id,
                                    'source_group': source_group.id
                                })
        except Exception:
            with excutils.save_and_reraise_exception():
                try:
                    group.destroy()
                finally:
                    LOG.error(
                        _LE("Error occurred when creating "
                            "group %(group)s from source group "
                            "%(source_group)s."), {
                                'group': group.id,
                                'source_group': source_group.id
                            })

        volumes = objects.VolumeList.get_all_by_generic_group(
            context, group.id)
        for vol in volumes:
            # Update the host field for the volume.
            vol.host = group.host
            vol.save()

        self.volume_rpcapi.create_group_from_src(context, group, None,
                                                 source_group)
Ejemplo n.º 8
0
    def create_from_src(self,
                        context,
                        name,
                        description=None,
                        group_snapshot_id=None,
                        source_group_id=None):
        check_policy(context, 'create')

        # Populate group_type_id and volume_type_ids
        group_type_id = None
        volume_type_ids = []
        if group_snapshot_id:
            grp_snap = self.get_group_snapshot(context, group_snapshot_id)
            group_type_id = grp_snap.group_type_id
            grp_snap_src_grp = self.get(context, grp_snap.group_id)
            volume_type_ids = [vt.id for vt in grp_snap_src_grp.volume_types]
        elif source_group_id:
            source_group = self.get(context, source_group_id)
            group_type_id = source_group.group_type_id
            volume_type_ids = [vt.id for vt in source_group.volume_types]

        kwargs = {
            'user_id': context.user_id,
            'project_id': context.project_id,
            'status': c_fields.GroupStatus.CREATING,
            'name': name,
            'description': description,
            'group_snapshot_id': group_snapshot_id,
            'source_group_id': source_group_id,
            'group_type_id': group_type_id,
            'volume_type_ids': volume_type_ids,
            'replication_status': c_fields.ReplicationStatus.DISABLED
        }

        group = None
        try:
            group = objects.Group(context=context, **kwargs)
            group.create(group_snapshot_id=group_snapshot_id,
                         source_group_id=source_group_id)
        except exception.GroupNotFound:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    "Source Group %(source_group)s not found when "
                    "creating group %(group)s from source.", {
                        'group': name,
                        'source_group': source_group_id
                    })
        except exception.GroupSnapshotNotFound:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    "Group snapshot %(group_snap)s not found when "
                    "creating group %(group)s from source.", {
                        'group': name,
                        'group_snap': group_snapshot_id
                    })
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    "Error occurred when creating group"
                    " %(group)s from group_snapshot %(grp_snap)s.", {
                        'group': name,
                        'grp_snap': group_snapshot_id
                    })

        # Update quota for groups
        self.update_quota(context, group, 1)

        if not group.host:
            msg = _("No host to create group %s.") % group.id
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        group.assert_not_frozen()

        if group_snapshot_id:
            self._create_group_from_group_snapshot(context, group,
                                                   group_snapshot_id)
        elif source_group_id:
            self._create_group_from_source_group(context, group,
                                                 source_group_id)

        return group
Ejemplo n.º 9
0
    def failover_replication(self,
                             context,
                             group,
                             allow_attached_volume=False,
                             secondary_backend_id=None):
        self._check_type(group)

        valid_status = [c_fields.GroupStatus.AVAILABLE]
        if group.status not in valid_status:
            params = {
                'valid': valid_status,
                'current': group.status,
                'id': group.id
            }
            msg = _("Group %(id)s status must be %(valid)s, "
                    "but current status is: %(current)s. "
                    "Cannot failover replication.") % params
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        valid_rep_status = [
            c_fields.ReplicationStatus.ENABLED,
            c_fields.ReplicationStatus.FAILED_OVER
        ]
        if group.replication_status not in valid_rep_status:
            params = {
                'valid': valid_rep_status,
                'current': group.replication_status,
                'id': group.id
            }
            msg = _("Group %(id)s replication status must be %(valid)s, "
                    "but current status is: %(current)s. "
                    "Cannot failover replication.") % params
            LOG.error(msg)
            raise exception.InvalidGroup(reason=msg)

        volumes = objects.VolumeList.get_all_by_generic_group(
            context.elevated(), group.id)

        valid_status = ['available', 'in-use']
        for vol in volumes:
            if vol.status not in valid_status:
                params = {
                    'valid': valid_status,
                    'current': vol.status,
                    'id': vol.id
                }
                msg = _("Volume %(id)s status must be %(valid)s, "
                        "but current status is: %(current)s. "
                        "Cannot failover replication.") % params
                LOG.error(msg)
                raise exception.InvalidVolume(reason=msg)
            if vol.status == 'in-use' and not allow_attached_volume:
                msg = _("Volume %s is attached but allow_attached_volume flag "
                        "is False. Cannot failover replication.") % vol.id
                LOG.error(msg)
                raise exception.InvalidVolume(reason=msg)
            if vol.replication_status not in valid_rep_status:
                params = {
                    'valid': valid_rep_status,
                    'current': vol.replication_status,
                    'id': vol.id
                }
                msg = _("Volume %(id)s replication status must be %(valid)s, "
                        "but current status is: %(current)s. "
                        "Cannot failover replication.") % params
                LOG.error(msg)
                raise exception.InvalidVolume(reason=msg)

            vol.replication_status = c_fields.ReplicationStatus.FAILING_OVER
            vol.save()

        group.replication_status = c_fields.ReplicationStatus.FAILING_OVER
        group.save()

        self.volume_rpcapi.failover_replication(context, group,
                                                allow_attached_volume,
                                                secondary_backend_id)