1
# Copyright 2011 Justin Santa Barbara
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
16
"""The volumes snapshots api."""
21
from nova.api.openstack import common
22
from nova.api.openstack import wsgi
23
from nova.api.openstack import xmlutil
24
from nova import exception
25
from nova import flags
26
from nova.openstack.common import log as logging
27
from nova import utils
28
from nova import volume
31
LOG = logging.getLogger(__name__)
37
def _translate_snapshot_detail_view(context, vol):
38
"""Maps keys for snapshots details view."""
40
d = _translate_snapshot_summary_view(context, vol)
42
# NOTE(gagupta): No additional data / lookups at the moment
46
def _translate_snapshot_summary_view(context, vol):
47
"""Maps keys for snapshots summary view."""
50
# TODO(bcwaldon): remove str cast once we use uuids
51
d['id'] = str(vol['id'])
52
d['volume_id'] = str(vol['volume_id'])
53
d['status'] = vol['status']
54
# NOTE(gagupta): We map volume_size as the snapshot size
55
d['size'] = vol['volume_size']
56
d['created_at'] = vol['created_at']
57
d['display_name'] = vol['display_name']
58
d['display_description'] = vol['display_description']
62
def make_snapshot(elem):
66
elem.set('created_at')
67
elem.set('display_name')
68
elem.set('display_description')
72
class SnapshotTemplate(xmlutil.TemplateBuilder):
74
root = xmlutil.TemplateElement('snapshot', selector='snapshot')
76
return xmlutil.MasterTemplate(root, 1)
79
class SnapshotsTemplate(xmlutil.TemplateBuilder):
81
root = xmlutil.TemplateElement('snapshots')
82
elem = xmlutil.SubTemplateElement(root, 'snapshot',
85
return xmlutil.MasterTemplate(root, 1)
88
class SnapshotsController(wsgi.Controller):
89
"""The Volumes API controller for the OpenStack API."""
91
def __init__(self, ext_mgr=None):
92
self.volume_api = volume.API()
93
self.ext_mgr = ext_mgr
94
super(SnapshotsController, self).__init__()
96
@wsgi.serializers(xml=SnapshotTemplate)
97
def show(self, req, id):
98
"""Return data about the given snapshot."""
99
context = req.environ['nova.context']
102
vol = self.volume_api.get_snapshot(context, id)
103
except exception.NotFound:
104
raise exc.HTTPNotFound()
106
return {'snapshot': _translate_snapshot_detail_view(context, vol)}
108
def delete(self, req, id):
109
"""Delete a snapshot."""
110
context = req.environ['nova.context']
112
LOG.audit(_("Delete snapshot with id: %s"), id, context=context)
115
snapshot = self.volume_api.get_snapshot(context, id)
116
self.volume_api.delete_snapshot(context, snapshot)
117
except exception.NotFound:
118
raise exc.HTTPNotFound()
119
return webob.Response(status_int=202)
121
@wsgi.serializers(xml=SnapshotsTemplate)
122
def index(self, req):
123
"""Returns a summary list of snapshots."""
124
return self._items(req, entity_maker=_translate_snapshot_summary_view)
126
@wsgi.serializers(xml=SnapshotsTemplate)
127
def detail(self, req):
128
"""Returns a detailed list of snapshots."""
129
return self._items(req, entity_maker=_translate_snapshot_detail_view)
131
def _items(self, req, entity_maker):
132
"""Returns a list of snapshots, transformed through entity_maker."""
133
context = req.environ['nova.context']
136
search_opts.update(req.GET)
138
snapshots = self.volume_api.get_all_snapshots(context,
139
search_opts=search_opts)
140
limited_list = common.limited(snapshots, req)
141
res = [entity_maker(context, snapshot) for snapshot in limited_list]
142
return {'snapshots': res}
144
@wsgi.serializers(xml=SnapshotTemplate)
145
def create(self, req, body):
146
"""Creates a new snapshot."""
147
context = req.environ['nova.context']
149
if not self.is_valid_body(body, 'snapshot'):
150
raise exc.HTTPUnprocessableEntity()
152
snapshot = body['snapshot']
153
volume_id = snapshot['volume_id']
154
volume = self.volume_api.get(context, volume_id)
155
force = snapshot.get('force', False)
156
msg = _("Create snapshot from volume %s")
157
LOG.audit(msg, volume_id, context=context)
159
if not utils.is_valid_boolstr(force):
160
msg = _("Invalid value '%s' for force. ") % force
161
raise exception.InvalidParameterValue(err=msg)
163
if utils.bool_from_str(force):
164
new_snapshot = self.volume_api.create_snapshot_force(context,
166
snapshot.get('display_name'),
167
snapshot.get('display_description'))
169
new_snapshot = self.volume_api.create_snapshot(context,
171
snapshot.get('display_name'),
172
snapshot.get('display_description'))
174
retval = _translate_snapshot_detail_view(context, new_snapshot)
176
return {'snapshot': retval}
179
def create_resource(ext_mgr):
180
return wsgi.Resource(SnapshotsController(ext_mgr))