~ttx/nova/mp820962

« back to all changes in this revision

Viewing changes to nova/api/openstack/common.py

  • Committer: Tarmac
  • Author(s): Vishvananda Ishaya, Chris Behrens, Brian Waldon, Nikolay Sokolov, Alex Meade, Soren Hansen, matt.dietz at rackspace, throughnothing at gmail, John Tran, Josh Kearney, Tushar Patil, Jake Dahn, Ed Leafe, Isaku Yamahata, Ryu Ishimoto, Thierry Carrez, vladimir.p, Jason Koelker, Donal Lafferty, Christopher MacGown, kevin.mitchell at rackspace, Kei Masumoto, Matthew Hooker, Sandy Walsh, Kei masumoto, Johannes Erdfelt, Dave Walker (Daviey), Zed Shaw, Naveed Massjouni, Brian Lamar, Launchpad Translations on behalf of nova-core, Anthony Young, matt.dietz at rackspace, Jake Dahn, Justin Shepherd, Gabe Westmaas, Rick Harris, Dan Prince, Ilya Alekseyev, Jake Dahn, Monsyne Dragon, Dan Wendlandt, Kevin Bringard, Troy Toman, Jesse Andrews, Yoshiaki Tamura, Trey Morris, Ken Pepple, Adam Gandelman, Rick Harris, Mandell Degerness, termie, Lorin Hochstein, Joseph Suh, Jason Kölker, Salvatore Orlando, Cerberus, Devendra Modium, Kevin L. Mitchell, Jimmy Bergman, Mohammed Naser, Lvov Maxim, danwent, asomya at cisco, Mike Scherbakov, Arvind Somy, Yuriy Taraday, Scott Moser, Anne Gentle, Chuck Short, Adam Johnson, Mark Washenberger, Stephanie Reese, Alexander Sakhnov, Nickolay Sokolov, Ilya Alekseyev, William Wolf, Todd Willey, Eldar Nugaev, Jason Cannavale, Ewan Mellor, Eldar Nugaev, Kirill Shileev
  • Date: 2011-08-23 13:49:00 UTC
  • mfrom: (1143.1.1 milestone-proposed)
  • Revision ID: tarmac-20110823134900-rr76tc1uljuxwcfx
Merge diablo-4 development from trunk (rev1479)

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#    License for the specific language governing permissions and limitations
16
16
#    under the License.
17
17
 
 
18
import functools
18
19
import re
19
 
from urlparse import urlparse
 
20
import urlparse
 
21
from xml.dom import minidom
20
22
 
21
23
import webob
22
24
 
23
25
from nova import exception
24
26
from nova import flags
25
27
from nova import log as logging
 
28
from nova import quota
 
29
from nova.api.openstack import wsgi
 
30
from nova.compute import power_state as compute_power_state
26
31
 
27
32
 
28
33
LOG = logging.getLogger('nova.api.openstack.common')
33
38
XML_NS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
34
39
 
35
40
 
 
41
_STATUS_MAP = {
 
42
    None: 'BUILD',
 
43
    compute_power_state.NOSTATE: 'BUILD',
 
44
    compute_power_state.RUNNING: 'ACTIVE',
 
45
    compute_power_state.BLOCKED: 'ACTIVE',
 
46
    compute_power_state.SUSPENDED: 'SUSPENDED',
 
47
    compute_power_state.PAUSED: 'PAUSED',
 
48
    compute_power_state.SHUTDOWN: 'SHUTDOWN',
 
49
    compute_power_state.SHUTOFF: 'SHUTOFF',
 
50
    compute_power_state.CRASHED: 'ERROR',
 
51
    compute_power_state.FAILED: 'ERROR',
 
52
    compute_power_state.BUILDING: 'BUILD',
 
53
}
 
54
 
 
55
 
 
56
def status_from_power_state(power_state):
 
57
    """Map the power state to the server status string"""
 
58
    return _STATUS_MAP[power_state]
 
59
 
 
60
 
 
61
def power_states_from_status(status):
 
62
    """Map the server status string to a list of power states"""
 
63
    power_states = []
 
64
    for power_state, status_map in _STATUS_MAP.iteritems():
 
65
        # Skip the 'None' state
 
66
        if power_state is None:
 
67
            continue
 
68
        if status.lower() == status_map.lower():
 
69
            power_states.append(power_state)
 
70
    return power_states
 
71
 
 
72
 
36
73
def get_pagination_params(request):
37
74
    """Return marker, limit tuple from request.
38
75
 
132
169
    Returns: 123
133
170
 
134
171
    """
135
 
    if re.match(r'\d+$', str(href)):
 
172
    LOG.debug(_("Attempting to treat %(href)s as an integer ID.") % locals())
 
173
 
 
174
    try:
136
175
        return int(href)
 
176
    except ValueError:
 
177
        pass
 
178
 
 
179
    LOG.debug(_("Attempting to treat %(href)s as a URL.") % locals())
 
180
 
137
181
    try:
138
 
        return int(urlparse(href).path.split('/')[-1])
139
 
    except:
140
 
        LOG.debug(_("Error extracting id from href: %s") % href)
141
 
        raise ValueError(_('could not parse id from href'))
 
182
        return int(urlparse.urlsplit(href).path.split('/')[-1])
 
183
    except ValueError as error:
 
184
        LOG.debug(_("Failed to parse ID from %(href)s: %(error)s") % locals())
 
185
        raise
142
186
 
143
187
 
144
188
def remove_version_from_href(href):
151
195
    Returns: 'http://www.nova.com'
152
196
 
153
197
    """
154
 
    try:
155
 
        #removes the first instance that matches /v#.#/
156
 
        new_href = re.sub(r'[/][v][0-9]+\.[0-9]+[/]', '/', href, count=1)
157
 
 
158
 
        #if no version was found, try finding /v#.# at the end of the string
159
 
        if new_href == href:
160
 
            new_href = re.sub(r'[/][v][0-9]+\.[0-9]+$', '', href, count=1)
161
 
    except:
162
 
        LOG.debug(_("Error removing version from href: %s") % href)
163
 
        msg = _('could not parse version from href')
164
 
        raise ValueError(msg)
165
 
 
166
 
    if new_href == href:
167
 
        msg = _('href does not contain version')
168
 
        raise ValueError(msg)
169
 
    return new_href
 
198
    parsed_url = urlparse.urlsplit(href)
 
199
    new_path = re.sub(r'^/v[0-9]+\.[0-9]+(/|$)', r'\1', parsed_url.path,
 
200
                      count=1)
 
201
 
 
202
    if new_path == parsed_url.path:
 
203
        msg = _('href %s does not contain version') % href
 
204
        LOG.debug(msg)
 
205
        raise ValueError(msg)
 
206
 
 
207
    parsed_url = list(parsed_url)
 
208
    parsed_url[2] = new_path
 
209
    return urlparse.urlunsplit(parsed_url)
170
210
 
171
211
 
172
212
def get_version_from_href(href):
192
232
    except IndexError:
193
233
        version = '1.0'
194
234
    return version
 
235
 
 
236
 
 
237
def check_img_metadata_quota_limit(context, metadata):
 
238
    if metadata is None:
 
239
        return
 
240
    num_metadata = len(metadata)
 
241
    quota_metadata = quota.allowed_metadata_items(context, num_metadata)
 
242
    if quota_metadata < num_metadata:
 
243
        expl = _("Image metadata limit exceeded")
 
244
        raise webob.exc.HTTPRequestEntityTooLarge(explanation=expl,
 
245
                                                headers={'Retry-After': 0})
 
246
 
 
247
 
 
248
class MetadataXMLDeserializer(wsgi.XMLDeserializer):
 
249
 
 
250
    def extract_metadata(self, metadata_node):
 
251
        """Marshal the metadata attribute of a parsed request"""
 
252
        if metadata_node is None:
 
253
            return {}
 
254
        metadata = {}
 
255
        for meta_node in self.find_children_named(metadata_node, "meta"):
 
256
            key = meta_node.getAttribute("key")
 
257
            metadata[key] = self.extract_text(meta_node)
 
258
        return metadata
 
259
 
 
260
    def _extract_metadata_container(self, datastring):
 
261
        dom = minidom.parseString(datastring)
 
262
        metadata_node = self.find_first_child_named(dom, "metadata")
 
263
        metadata = self.extract_metadata(metadata_node)
 
264
        return {'body': {'metadata': metadata}}
 
265
 
 
266
    def create(self, datastring):
 
267
        return self._extract_metadata_container(datastring)
 
268
 
 
269
    def update_all(self, datastring):
 
270
        return self._extract_metadata_container(datastring)
 
271
 
 
272
    def update(self, datastring):
 
273
        dom = minidom.parseString(datastring)
 
274
        metadata_item = self.extract_metadata(dom)
 
275
        return {'body': {'meta': metadata_item}}
 
276
 
 
277
 
 
278
class MetadataHeadersSerializer(wsgi.ResponseHeadersSerializer):
 
279
 
 
280
    def delete(self, response, data):
 
281
        response.status_int = 204
 
282
 
 
283
 
 
284
class MetadataXMLSerializer(wsgi.XMLDictSerializer):
 
285
    def __init__(self, xmlns=wsgi.XMLNS_V11):
 
286
        super(MetadataXMLSerializer, self).__init__(xmlns=xmlns)
 
287
 
 
288
    def _meta_item_to_xml(self, doc, key, value):
 
289
        node = doc.createElement('meta')
 
290
        doc.appendChild(node)
 
291
        node.setAttribute('key', '%s' % key)
 
292
        text = doc.createTextNode('%s' % value)
 
293
        node.appendChild(text)
 
294
        return node
 
295
 
 
296
    def meta_list_to_xml(self, xml_doc, meta_items):
 
297
        container_node = xml_doc.createElement('metadata')
 
298
        for (key, value) in meta_items:
 
299
            item_node = self._meta_item_to_xml(xml_doc, key, value)
 
300
            container_node.appendChild(item_node)
 
301
        return container_node
 
302
 
 
303
    def _meta_list_to_xml_string(self, metadata_dict):
 
304
        xml_doc = minidom.Document()
 
305
        items = metadata_dict['metadata'].items()
 
306
        container_node = self.meta_list_to_xml(xml_doc, items)
 
307
        xml_doc.appendChild(container_node)
 
308
        self._add_xmlns(container_node)
 
309
        return xml_doc.toxml('UTF-8')
 
310
 
 
311
    def index(self, metadata_dict):
 
312
        return self._meta_list_to_xml_string(metadata_dict)
 
313
 
 
314
    def create(self, metadata_dict):
 
315
        return self._meta_list_to_xml_string(metadata_dict)
 
316
 
 
317
    def update_all(self, metadata_dict):
 
318
        return self._meta_list_to_xml_string(metadata_dict)
 
319
 
 
320
    def _meta_item_to_xml_string(self, meta_item_dict):
 
321
        xml_doc = minidom.Document()
 
322
        item_key, item_value = meta_item_dict.items()[0]
 
323
        item_node = self._meta_item_to_xml(xml_doc, item_key, item_value)
 
324
        xml_doc.appendChild(item_node)
 
325
        self._add_xmlns(item_node)
 
326
        return xml_doc.toxml('UTF-8')
 
327
 
 
328
    def show(self, meta_item_dict):
 
329
        return self._meta_item_to_xml_string(meta_item_dict['meta'])
 
330
 
 
331
    def update(self, meta_item_dict):
 
332
        return self._meta_item_to_xml_string(meta_item_dict['meta'])
 
333
 
 
334
    def default(self, *args, **kwargs):
 
335
        return ''
 
336
 
 
337
 
 
338
def check_snapshots_enabled(f):
 
339
    @functools.wraps(f)
 
340
    def inner(*args, **kwargs):
 
341
        if not FLAGS.allow_instance_snapshots:
 
342
            LOG.warn(_('Rejecting snapshot request, snapshots currently'
 
343
                       ' disabled'))
 
344
            msg = _("Instance snapshots are not permitted at this time.")
 
345
            raise webob.exc.HTTPBadRequest(explanation=msg)
 
346
        return f(*args, **kwargs)
 
347
    return inner