cinder/cinder/api/v1/volumes.py

144 lines
4.5 KiB
Python

# Copyright 2011 Justin Santa Barbara
# 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 volumes api."""
from oslo_log import log as logging
from six.moves import http_client
from webob import exc
from cinder.api.openstack import wsgi
from cinder.api.v2 import volumes as volumes_v2
LOG = logging.getLogger(__name__)
def _attachment_v2_to_v1(vol):
"""Converts v2 attachment details to v1 format."""
d = []
attachments = vol.pop('attachments', [])
for attachment in attachments:
a = {'id': attachment.get('id'),
'attachment_id': attachment.get('attachment_id'),
'volume_id': attachment.get('volume_id'),
'server_id': attachment.get('server_id'),
'host_name': attachment.get('host_name'),
'device': attachment.get('device'),
}
d.append(a)
return d
def _volume_v2_to_v1(volv2_results, image_id=None):
"""Converts v2 volume details to v1 format."""
volumes = volv2_results.get('volumes')
if volumes is None:
volumes = [volv2_results['volume']]
for vol in volumes:
# Need to form the string true/false explicitly here to
# maintain our API contract
if vol.get('multiattach'):
vol['multiattach'] = 'true'
else:
vol['multiattach'] = 'false'
if not vol.get('image_id') and image_id:
vol['image_id'] = image_id
vol['attachments'] = _attachment_v2_to_v1(vol)
if not vol.get('metadata'):
vol['metadata'] = {}
# Convert the name changes
vol['display_name'] = vol.pop('name')
vol['display_description'] = vol.pop('description', '')
# Remove the properties not present for v1
vol.pop('consistencygroup_id', None)
vol.pop('encryption_key_id', None)
vol.pop('links', None)
vol.pop('migration_status', None)
vol.pop('replication_status', None)
vol.pop('updated_at', None)
vol.pop('user_id', None)
LOG.debug("vol=%s", vol)
return volv2_results
class VolumeController(volumes_v2.VolumeController):
"""The Volumes API controller for the OpenStack API."""
def show(self, req, id):
"""Return data about the given volume."""
return _volume_v2_to_v1(super(VolumeController, self).show(
req, id))
def index(self, req):
"""Returns a summary list of volumes."""
# The v1 info was much more detailed than the v2 non-detailed result
return _volume_v2_to_v1(
super(VolumeController, self).detail(req))
def detail(self, req):
"""Returns a detailed list of volumes."""
return _volume_v2_to_v1(
super(VolumeController, self).detail(req))
@wsgi.response(http_client.OK)
def create(self, req, body):
"""Creates a new volume."""
if (body is None or not body.get('volume') or
not isinstance(body['volume'], dict)):
raise exc.HTTPUnprocessableEntity()
image_id = None
if body.get('volume'):
image_id = body['volume'].get('imageRef')
try:
return _volume_v2_to_v1(
super(VolumeController, self).create(req, body),
image_id=image_id)
except exc.HTTPBadRequest as e:
# Image failures are the only ones that actually used
# HTTPBadRequest
error_msg = '%s' % e
if 'Invalid image' in error_msg:
raise
raise exc.HTTPUnprocessableEntity()
def update(self, req, id, body):
"""Update a volume."""
if (body is None or not body.get('volume') or
not isinstance(body['volume'], dict)):
raise exc.HTTPUnprocessableEntity()
try:
return _volume_v2_to_v1(super(VolumeController, self).update(
req, id, body))
except exc.HTTPBadRequest:
raise exc.HTTPUnprocessableEntity()
def create_resource(ext_mgr):
return wsgi.Resource(VolumeController(ext_mgr))