summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorGaurav Gupta <gaurav@denali-systems.com>2011-10-29 17:20:08 -0700
committerVishvananda Ishaya <vishvananda@gmail.com>2011-12-12 15:28:33 -0800
commitbfefe6317fde87f8ca7a4d28bed11d99f7029186 (patch)
treeff2c44342880a617535ed1402c8ea8659ecf21ff /nova/api
parentd3b75b75aa937380f04b5320b70c8673821af203 (diff)
downloadnova-bfefe6317fde87f8ca7a4d28bed11d99f7029186.tar.gz
nova-bfefe6317fde87f8ca7a4d28bed11d99f7029186.tar.xz
nova-bfefe6317fde87f8ca7a4d28bed11d99f7029186.zip
Added support for creating nova volume snapshots using OS API.
Fixes bug 883676 blueprint nova-volume-snapshot-backup-api Change-Id: Id3e1ad39ef791b93dd014cada87c2d295454701f
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/openstack/v2/contrib/volumes.py155
1 files changed, 152 insertions, 3 deletions
diff --git a/nova/api/openstack/v2/contrib/volumes.py b/nova/api/openstack/v2/contrib/volumes.py
index 75d8af803..8a5e84c0d 100644
--- a/nova/api/openstack/v2/contrib/volumes.py
+++ b/nova/api/openstack/v2/contrib/volumes.py
@@ -24,11 +24,9 @@ from nova.api.openstack.v2 import servers
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
-from nova import db
from nova import exception
from nova import flags
from nova import log as logging
-from nova import quota
from nova import volume
from nova.volume import volume_types
@@ -72,6 +70,7 @@ def _translate_volume_summary_view(context, vol):
else:
d['volumeType'] = vol['volume_type_id']
+ d['snapshotId'] = vol['snapshot_id']
LOG.audit(_("vol=%s"), vol, context=context)
if vol.get('volume_metadata'):
@@ -153,7 +152,8 @@ class VolumeController(object):
metadata = vol.get('metadata', None)
- new_volume = self.volume_api.create(context, size, None,
+ new_volume = self.volume_api.create(context, size,
+ vol.get('snapshot_id'),
vol.get('display_name'),
vol.get('display_description'),
volume_type=vol_type,
@@ -176,6 +176,7 @@ def make_volume(elem):
elem.set('displayName')
elem.set('displayDescription')
elem.set('volumeType')
+ elem.set('snapshotId')
attachments = xmlutil.SubTemplateElement(elem, 'attachments')
attachment = xmlutil.SubTemplateElement(attachments, 'attachment',
@@ -394,6 +395,143 @@ class BootFromVolumeController(servers.Controller):
return data.get('block_device_mapping')
+def _translate_snapshot_detail_view(context, vol):
+ """Maps keys for snapshots details view."""
+
+ d = _translate_snapshot_summary_view(context, vol)
+
+ # NOTE(gagupta): No additional data / lookups at the moment
+ return d
+
+
+def _translate_snapshot_summary_view(context, vol):
+ """Maps keys for snapshots summary view."""
+ d = {}
+
+ d['id'] = vol['id']
+ d['volumeId'] = vol['volume_id']
+ d['status'] = vol['status']
+ # NOTE(gagupta): We map volume_size as the snapshot size
+ d['size'] = vol['volume_size']
+ d['createdAt'] = vol['created_at']
+ d['displayName'] = vol['display_name']
+ d['displayDescription'] = vol['display_description']
+ return d
+
+
+class SnapshotController(object):
+ """The Volumes API controller for the OpenStack API."""
+
+ def __init__(self):
+ self.volume_api = volume.API()
+ super(SnapshotController, self).__init__()
+
+ def show(self, req, id):
+ """Return data about the given snapshot."""
+ context = req.environ['nova.context']
+
+ try:
+ vol = self.volume_api.get_snapshot(context, id)
+ except exception.NotFound:
+ return exc.HTTPNotFound()
+
+ return {'snapshot': _translate_snapshot_detail_view(context, vol)}
+
+ def delete(self, req, id):
+ """Delete a snapshot."""
+ context = req.environ['nova.context']
+
+ LOG.audit(_("Delete snapshot with id: %s"), id, context=context)
+
+ try:
+ self.volume_api.delete_snapshot(context, snapshot_id=id)
+ except exception.NotFound:
+ return exc.HTTPNotFound()
+ return webob.Response(status_int=202)
+
+ def index(self, req):
+ """Returns a summary list of snapshots."""
+ return self._items(req, entity_maker=_translate_snapshot_summary_view)
+
+ def detail(self, req):
+ """Returns a detailed list of snapshots."""
+ return self._items(req, entity_maker=_translate_snapshot_detail_view)
+
+ def _items(self, req, entity_maker):
+ """Returns a list of snapshots, transformed through entity_maker."""
+ context = req.environ['nova.context']
+
+ snapshots = self.volume_api.get_all_snapshots(context)
+ limited_list = common.limited(snapshots, req)
+ res = [entity_maker(context, snapshot) for snapshot in limited_list]
+ return {'snapshots': res}
+
+ def create(self, req, body):
+ """Creates a new snapshot."""
+ context = req.environ['nova.context']
+
+ if not body:
+ return exc.HTTPUnprocessableEntity()
+
+ snapshot = body['snapshot']
+ volume_id = snapshot['volume_id']
+ force = snapshot.get('force', False)
+ LOG.audit(_("Create snapshot from volume %s"), volume_id,
+ context=context)
+
+ if force:
+ new_snapshot = self.volume_api.create_snapshot_force(context,
+ volume_id,
+ snapshot.get('display_name'),
+ snapshot.get('display_description'))
+ else:
+ new_snapshot = self.volume_api.create_snapshot(context,
+ volume_id,
+ snapshot.get('display_name'),
+ snapshot.get('display_description'))
+
+ retval = _translate_snapshot_detail_view(context, new_snapshot)
+
+ return {'snapshot': retval}
+
+
+def make_snapshot(elem):
+ elem.set('id')
+ elem.set('status')
+ elem.set('size')
+ elem.set('createdAt')
+ elem.set('displayName')
+ elem.set('displayDescription')
+ elem.set('volumeId')
+
+
+class SnapshotTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('snapshot', selector='snapshot')
+ make_snapshot(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class SnapshotsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('snapshots')
+ elem = xmlutil.SubTemplateElement(root, 'snapshot',
+ selector='snapshots')
+ make_snapshot(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class SnapshotSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return SnapshotTemplate()
+
+ def index(self):
+ return SnapshotsTemplate()
+
+ def detail(self):
+ return SnapshotsTemplate()
+
+
class Volumes(extensions.ExtensionDescriptor):
"""Volumes support"""
@@ -449,4 +587,15 @@ class Volumes(extensions.ExtensionDescriptor):
deserializer=deserializer)
resources.append(res)
+ snapshot_serializers = {
+ 'application/xml': SnapshotSerializer(),
+ }
+ snap_serializer = wsgi.ResponseSerializer(snapshot_serializers)
+
+ res = extensions.ResourceExtension('os-snapshots',
+ SnapshotController(),
+ serializer=snap_serializer,
+ collection_actions={'detail': 'GET'})
+ resources.append(res)
+
return resources