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)
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)
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)
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
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
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)
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)
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
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)