# Copyright (C) 2016 EMC Corporation. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """The group_snapshots API.""" from http import HTTPStatus from oslo_log import log as logging import webob from webob import exc from cinder.api import common from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.schemas import group_snapshots as snapshot from cinder.api.v3.views import group_snapshots as group_snapshot_views from cinder.api import validation from cinder import exception from cinder import group as group_api from cinder.i18n import _ from cinder import rpc from cinder.volume import group_types LOG = logging.getLogger(__name__) class GroupSnapshotsController(wsgi.Controller): """The group_snapshots API controller for the OpenStack API.""" _view_builder_class = group_snapshot_views.ViewBuilder def __init__(self): self.group_snapshot_api = group_api.API() super(GroupSnapshotsController, self).__init__() def _check_default_cgsnapshot_type(self, group_type_id): if group_types.is_default_cgsnapshot_type(group_type_id): msg = (_("Group_type %(group_type)s is reserved for migrating " "CGs to groups. Migrated group snapshots can only be " "operated by CG snapshot APIs.") % {'group_type': group_type_id}) raise exc.HTTPBadRequest(explanation=msg) @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def show(self, req, id): """Return data about the given group_snapshot.""" LOG.debug('show called for member %s', id) context = req.environ['cinder.context'] group_snapshot = self.group_snapshot_api.get_group_snapshot( context, group_snapshot_id=id) self._check_default_cgsnapshot_type(group_snapshot.group_type_id) return self._view_builder.detail(req, group_snapshot) @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def delete(self, req, id): """Delete a group_snapshot.""" LOG.debug('delete called for member %s', id) context = req.environ['cinder.context'] LOG.info('Delete group_snapshot with id: %s', id, context=context) try: group_snapshot = self.group_snapshot_api.get_group_snapshot( context, group_snapshot_id=id) self._check_default_cgsnapshot_type(group_snapshot.group_type_id) self.group_snapshot_api.delete_group_snapshot(context, group_snapshot) except exception.InvalidGroupSnapshot as e: raise exc.HTTPBadRequest(explanation=str(e)) except (exception.GroupSnapshotNotFound, exception.PolicyNotAuthorized): # Not found exception will be handled at the wsgi level raise except Exception: msg = _("Error occurred when deleting group snapshot %s.") % id LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) return webob.Response(status_int=HTTPStatus.ACCEPTED) @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def index(self, req): """Returns a summary list of group_snapshots.""" return self._get_group_snapshots(req, is_detail=False) @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def detail(self, req): """Returns a detailed list of group_snapshots.""" return self._get_group_snapshots(req, is_detail=True) def _get_group_snapshots(self, req, is_detail): """Returns a list of group_snapshots through view builder.""" context = req.environ['cinder.context'] req_version = req.api_version_request filters = marker = limit = offset = sort_keys = sort_dirs = None if req_version.matches(mv.GROUP_SNAPSHOT_PAGINATION): filters = req.params.copy() marker, limit, offset = common.get_pagination_params(filters) sort_keys, sort_dirs = common.get_sort_params(filters) if req_version.matches(mv.RESOURCE_FILTER): support_like = (True if req_version.matches( mv.LIKE_FILTER) else False) common.reject_invalid_filters(context, filters, 'group_snapshot', support_like) group_snapshots = self.group_snapshot_api.get_all_group_snapshots( context, filters=filters, marker=marker, limit=limit, offset=offset, sort_keys=sort_keys, sort_dirs=sort_dirs) if is_detail: group_snapshots = self._view_builder.detail_list(req, group_snapshots) else: group_snapshots = self._view_builder.summary_list(req, group_snapshots) new_group_snapshots = [] for grp_snap in group_snapshots['group_snapshots']: try: # Only show group snapshots not migrated from CG snapshots self._check_default_cgsnapshot_type(grp_snap['group_type_id']) if not is_detail: grp_snap.pop('group_type_id', None) new_group_snapshots.append(grp_snap) except exc.HTTPBadRequest: # Skip migrated group snapshot pass group_snapshots['group_snapshots'] = new_group_snapshots return group_snapshots @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) @wsgi.response(HTTPStatus.ACCEPTED) @validation.schema(snapshot.create) def create(self, req, body): """Create a new group_snapshot.""" LOG.debug('Creating new group_snapshot %s', body) context = req.environ['cinder.context'] group_snapshot = body['group_snapshot'] group_id = group_snapshot['group_id'] group = self.group_snapshot_api.get(context, group_id) self._check_default_cgsnapshot_type(group.group_type_id) name = group_snapshot.get('name', None) description = group_snapshot.get('description', None) LOG.info("Creating group_snapshot %(name)s.", {'name': name}, context=context) try: new_group_snapshot = self.group_snapshot_api.create_group_snapshot( context, group, name, description) except (exception.InvalidGroup, exception.InvalidGroupSnapshot, exception.InvalidVolume) as error: raise exc.HTTPBadRequest(explanation=error.msg) retval = self._view_builder.summary(req, new_group_snapshot) return retval @wsgi.Controller.api_version(mv.GROUP_SNAPSHOT_RESET_STATUS) @wsgi.action("reset_status") @validation.schema(snapshot.reset_status) def reset_status(self, req, id, body): return self._reset_status(req, id, body) def _reset_status(self, req, id, body): """Reset status on group snapshots""" context = req.environ['cinder.context'] status = body['reset_status']['status'].lower() LOG.debug("Updating group '%(id)s' with " "'%(update)s'", {'id': id, 'update': status}) try: notifier = rpc.get_notifier('groupSnapshotStatusUpdate') notifier.info(context, 'groupsnapshots.reset_status.start', {'id': id, 'update': status}) gsnapshot = self.group_snapshot_api.get_group_snapshot(context, id) self.group_snapshot_api.reset_group_snapshot_status(context, gsnapshot, status) notifier.info(context, 'groupsnapshots.reset_status.end', {'id': id, 'update': status}) except exception.GroupSnapshotNotFound as error: # Not found exception will be handled at the wsgi level notifier.error(context, 'groupsnapshots.reset_status', {'error_message': error.msg, 'id': id}) raise except exception.InvalidGroupSnapshotStatus as error: notifier.error(context, 'groupsnapshots.reset_status', {'error_message': error.msg, 'id': id}) raise exc.HTTPBadRequest(explanation=error.msg) return webob.Response(status_int=HTTPStatus.ACCEPTED) def create_resource(): return wsgi.Resource(GroupSnapshotsController())