1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2010 OpenStack LLC.
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
19
from lxml import etree
21
from cinder.api.openstack import wsgi
22
from cinder.api.views import versions as views_versions
23
from cinder.api import xmlutil
30
"updated": "2012-11-21T11:33:21Z",
34
"type": "application/pdf",
35
"href": "http://jorgew.github.com/block-storage-api/"
36
"content/os-block-storage-1.0.pdf",
40
"type": "application/vnd.sun.wadl+xml",
42
"href": "http://docs.rackspacecloud.com/"
43
"servers/api/v1.1/application.wadl",
48
"base": "application/xml",
49
"type": "application/vnd.openstack.volume+xml;version=1",
52
"base": "application/json",
53
"type": "application/vnd.openstack.volume+json;version=1",
60
"updated": "2012-01-04T11:33:21Z",
64
"type": "application/pdf",
65
"href": "http://jorgew.github.com/block-storage-api/"
66
"content/os-block-storage-1.0.pdf",
70
"type": "application/vnd.sun.wadl+xml",
72
"href": "http://docs.rackspacecloud.com/"
73
"servers/api/v1.1/application.wadl",
78
"base": "application/xml",
79
"type": "application/vnd.openstack.volume+xml;version=1",
82
"base": "application/json",
83
"type": "application/vnd.openstack.volume+json;version=1",
91
class MediaTypesTemplateElement(xmlutil.TemplateElement):
92
def will_render(self, datum):
93
return 'media-types' in datum
96
def make_version(elem):
101
mts = MediaTypesTemplateElement('media-types')
104
mt = xmlutil.SubTemplateElement(mts, 'media-type', selector='media-types')
108
xmlutil.make_links(elem, 'links')
111
version_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM}
114
class VersionTemplate(xmlutil.TemplateBuilder):
116
root = xmlutil.TemplateElement('version', selector='version')
118
return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap)
121
class VersionsTemplate(xmlutil.TemplateBuilder):
123
root = xmlutil.TemplateElement('versions')
124
elem = xmlutil.SubTemplateElement(root, 'version', selector='versions')
126
return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap)
129
class ChoicesTemplate(xmlutil.TemplateBuilder):
131
root = xmlutil.TemplateElement('choices')
132
elem = xmlutil.SubTemplateElement(root, 'version', selector='choices')
134
return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap)
137
class AtomSerializer(wsgi.XMLDictSerializer):
139
NSMAP = {None: xmlutil.XMLNS_ATOM}
141
def __init__(self, metadata=None, xmlns=None):
142
self.metadata = metadata or {}
144
self.xmlns = wsgi.XMLNS_ATOM
148
def _get_most_recent_update(self, versions):
150
for version in versions:
151
updated = datetime.datetime.strptime(version['updated'],
152
'%Y-%m-%dT%H:%M:%SZ')
155
elif updated > recent:
158
return recent.strftime('%Y-%m-%dT%H:%M:%SZ')
160
def _get_base_url(self, link_href):
161
# Make sure no trailing /
162
link_href = link_href.rstrip('/')
163
return link_href.rsplit('/', 1)[0] + '/'
165
def _create_feed(self, versions, feed_title, feed_id):
166
feed = etree.Element('feed', nsmap=self.NSMAP)
167
title = etree.SubElement(feed, 'title')
168
title.set('type', 'text')
169
title.text = feed_title
171
# Set this updated to the most recently updated version
172
recent = self._get_most_recent_update(versions)
173
etree.SubElement(feed, 'updated').text = recent
175
etree.SubElement(feed, 'id').text = feed_id
177
link = etree.SubElement(feed, 'link')
178
link.set('rel', 'self')
179
link.set('href', feed_id)
181
author = etree.SubElement(feed, 'author')
182
etree.SubElement(author, 'name').text = 'Rackspace'
183
etree.SubElement(author, 'uri').text = 'http://www.rackspace.com/'
185
for version in versions:
186
feed.append(self._create_version_entry(version))
190
def _create_version_entry(self, version):
191
entry = etree.Element('entry')
192
etree.SubElement(entry, 'id').text = version['links'][0]['href']
193
title = etree.SubElement(entry, 'title')
194
title.set('type', 'text')
195
title.text = 'Version %s' % version['id']
196
etree.SubElement(entry, 'updated').text = version['updated']
198
for link in version['links']:
199
link_elem = etree.SubElement(entry, 'link')
200
link_elem.set('rel', link['rel'])
201
link_elem.set('href', link['href'])
203
link_elem.set('type', link['type'])
205
content = etree.SubElement(entry, 'content')
206
content.set('type', 'text')
207
content.text = 'Version %s %s (%s)' % (version['id'],
213
class VersionsAtomSerializer(AtomSerializer):
214
def default(self, data):
215
versions = data['versions']
216
feed_id = self._get_base_url(versions[0]['links'][0]['href'])
217
feed = self._create_feed(versions, 'Available API Versions', feed_id)
218
return self._to_xml(feed)
221
class VersionAtomSerializer(AtomSerializer):
222
def default(self, data):
223
version = data['version']
224
feed_id = version['links'][0]['href']
225
feed = self._create_feed([version], 'About This Version', feed_id)
226
return self._to_xml(feed)
229
class Versions(wsgi.Resource):
232
super(Versions, self).__init__(None)
234
@wsgi.serializers(xml=VersionsTemplate,
235
atom=VersionsAtomSerializer)
236
def index(self, req):
237
"""Return all versions."""
238
builder = views_versions.get_view_builder(req)
239
return builder.build_versions(VERSIONS)
241
@wsgi.serializers(xml=ChoicesTemplate)
243
def multi(self, req):
244
"""Return multiple choices."""
245
builder = views_versions.get_view_builder(req)
246
return builder.build_choices(VERSIONS, req)
248
def get_action_args(self, request_environment):
249
"""Parse dictionary created by routes library."""
251
if request_environment['PATH_INFO'] == '/':
252
args['action'] = 'index'
254
args['action'] = 'multi'
259
class VolumeVersionV1(object):
260
@wsgi.serializers(xml=VersionTemplate,
261
atom=VersionAtomSerializer)
263
builder = views_versions.get_view_builder(req)
264
return builder.build_version(VERSIONS['v1.0'])
267
def create_resource():
268
return wsgi.Resource(VolumeVersionV1())