summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-08-05 07:13:52 -0700
committerSandy Walsh <sandy.walsh@rackspace.com>2011-08-05 07:13:52 -0700
commit781025f246375c19a4dc663b42551c47d07f701a (patch)
tree7301b288e54a00ccbe022ffe882bc2633c7f701d /nova/api
parentab1ba7cbcffc92c2c82c468fb0a2a81f93db3f85 (diff)
parent56ec8f040ba65e3b5ec1da768afaf0671fdb79f6 (diff)
downloadnova-781025f246375c19a4dc663b42551c47d07f701a.tar.gz
nova-781025f246375c19a4dc663b42551c47d07f701a.tar.xz
nova-781025f246375c19a4dc663b42551c47d07f701a.zip
trunk merge
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/direct.py5
-rw-r--r--nova/api/ec2/__init__.py4
-rw-r--r--nova/api/ec2/apirequest.py2
-rw-r--r--nova/api/openstack/__init__.py13
-rw-r--r--nova/api/openstack/common.py43
-rw-r--r--nova/api/openstack/create_instance_helper.py11
-rw-r--r--nova/api/openstack/images.py8
-rw-r--r--nova/api/openstack/server_metadata.py113
-rw-r--r--nova/api/openstack/servers.py22
9 files changed, 140 insertions, 81 deletions
diff --git a/nova/api/direct.py b/nova/api/direct.py
index 993815fc7..139c46d63 100644
--- a/nova/api/direct.py
+++ b/nova/api/direct.py
@@ -48,7 +48,6 @@ import nova.api.openstack.wsgi
# Global storage for registering modules.
ROUTES = {}
-
def register_service(path, handle):
"""Register a service handle at a given path.
@@ -296,8 +295,8 @@ class ServiceWrapper(object):
'application/json': nova.api.openstack.wsgi.JSONDictSerializer(),
}[content_type]
return serializer.serialize(result)
- except:
- raise exception.Error("returned non-serializable type: %s"
+ except Exception, e:
+ raise exception.Error(_("Returned non-serializable type: %s")
% result)
diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py
index af232edda..804e54ef9 100644
--- a/nova/api/ec2/__init__.py
+++ b/nova/api/ec2/__init__.py
@@ -147,7 +147,7 @@ class Authenticate(wsgi.Middleware):
try:
signature = req.params['Signature']
access = req.params['AWSAccessKeyId']
- except:
+ except KeyError, e:
raise webob.exc.HTTPBadRequest()
# Make a copy of args for authentication and signature verification.
@@ -211,7 +211,7 @@ class Requestify(wsgi.Middleware):
for non_arg in non_args:
# Remove, but raise KeyError if omitted
args.pop(non_arg)
- except:
+ except KeyError, e:
raise webob.exc.HTTPBadRequest()
LOG.debug(_('action: %s'), action)
diff --git a/nova/api/ec2/apirequest.py b/nova/api/ec2/apirequest.py
index 7d78c5cfa..9a3e55925 100644
--- a/nova/api/ec2/apirequest.py
+++ b/nova/api/ec2/apirequest.py
@@ -104,7 +104,7 @@ class APIRequest(object):
for key in data.keys():
val = data[key]
el.appendChild(self._render_data(xml, key, val))
- except:
+ except Exception:
LOG.debug(data)
raise
diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py
index 9ab8aeb58..d6a98c2cd 100644
--- a/nova/api/openstack/__init__.py
+++ b/nova/api/openstack/__init__.py
@@ -170,7 +170,9 @@ class APIRouterV11(APIRouter):
def _setup_routes(self, mapper):
super(APIRouterV11, self)._setup_routes(mapper, '1.1')
+
image_metadata_controller = image_metadata.create_resource()
+
mapper.resource("image_meta", "metadata",
controller=image_metadata_controller,
parent_resource=dict(member_name='image',
@@ -181,7 +183,14 @@ class APIRouterV11(APIRouter):
action='update_all',
conditions={"method": ['PUT']})
- mapper.resource("server_meta", "meta",
- controller=server_metadata.create_resource(),
+ server_metadata_controller = server_metadata.create_resource()
+
+ mapper.resource("server_meta", "metadata",
+ controller=server_metadata_controller,
parent_resource=dict(member_name='server',
collection_name='servers'))
+
+ mapper.connect("metadata", "/servers/{server_id}/metadata",
+ controller=server_metadata_controller,
+ action='update_all',
+ conditions={"method": ['PUT']})
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index efa4ab385..715b9e4a4 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -16,7 +16,7 @@
# under the License.
import re
-from urlparse import urlparse
+import urlparse
from xml.dom import minidom
import webob
@@ -137,8 +137,8 @@ def get_id_from_href(href):
if re.match(r'\d+$', str(href)):
return int(href)
try:
- return int(urlparse(href).path.split('/')[-1])
- except:
+ return int(urlparse.urlsplit(href).path.split('/')[-1])
+ except ValueError, e:
LOG.debug(_("Error extracting id from href: %s") % href)
raise ValueError(_('could not parse id from href'))
@@ -153,22 +153,17 @@ def remove_version_from_href(href):
Returns: 'http://www.nova.com'
"""
- try:
- #removes the first instance that matches /v#.#/
- new_href = re.sub(r'[/][v][0-9]+\.[0-9]+[/]', '/', href, count=1)
+ parsed_url = urlparse.urlsplit(href)
+ new_path = re.sub(r'^/v[0-9]+\.[0-9]+(/|$)', r'\1', parsed_url.path, count=1)
- #if no version was found, try finding /v#.# at the end of the string
- if new_href == href:
- new_href = re.sub(r'[/][v][0-9]+\.[0-9]+$', '', href, count=1)
- except:
- LOG.debug(_("Error removing version from href: %s") % href)
- msg = _('could not parse version from href')
+ if new_path == parsed_url.path:
+ msg = _('href %s does not contain version') % href
+ LOG.debug(msg)
raise ValueError(msg)
- if new_href == href:
- msg = _('href does not contain version')
- raise ValueError(msg)
- return new_href
+ parsed_url = list(parsed_url)
+ parsed_url[2] = new_path
+ return urlparse.urlunsplit(parsed_url)
def get_version_from_href(href):
@@ -196,7 +191,17 @@ def get_version_from_href(href):
return version
-class MetadataXMLDeserializer(wsgi.MetadataXMLDeserializer):
+class MetadataXMLDeserializer(wsgi.XMLDeserializer):
+
+ def extract_metadata(self, metadata_node):
+ """Marshal the metadata attribute of a parsed request"""
+ if metadata_node is None:
+ return {}
+ metadata = {}
+ for meta_node in self.find_children_named(metadata_node, "meta"):
+ key = meta_node.getAttribute("key")
+ metadata[key] = self.extract_text(meta_node)
+ return metadata
def _extract_metadata_container(self, datastring):
dom = minidom.parseString(datastring)
@@ -247,7 +252,7 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer):
container_node = self.meta_list_to_xml(xml_doc, items)
xml_doc.appendChild(container_node)
self._add_xmlns(container_node)
- return xml_doc.toprettyxml(indent=' ', encoding='UTF-8')
+ return xml_doc.toxml('UTF-8')
def index(self, metadata_dict):
return self._meta_list_to_xml_string(metadata_dict)
@@ -264,7 +269,7 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer):
item_node = self._meta_item_to_xml(xml_doc, item_key, item_value)
xml_doc.appendChild(item_node)
self._add_xmlns(item_node)
- return xml_doc.toprettyxml(indent=' ', encoding='UTF-8')
+ return xml_doc.toxml('UTF-8')
def show(self, meta_item_dict):
return self._meta_item_to_xml_string(meta_item_dict['meta'])
diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py
index 333994fcc..2a8e7fd7e 100644
--- a/nova/api/openstack/create_instance_helper.py
+++ b/nova/api/openstack/create_instance_helper.py
@@ -29,6 +29,7 @@ from nova import quota
from nova import utils
from nova.compute import instance_types
+from nova.api.openstack import common
from nova.api.openstack import wsgi
@@ -293,7 +294,7 @@ class CreateInstanceHelper(object):
return password
-class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
+class ServerXMLDeserializer(wsgi.XMLDeserializer):
"""
Deserializer to handle xml-formatted server create requests.
@@ -301,6 +302,8 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
and personality attributes
"""
+ metadata_deserializer = common.MetadataXMLDeserializer()
+
def action(self, string):
dom = minidom.parseString(string)
action_node = dom.childNodes[0]
@@ -329,7 +332,8 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
if value:
data[attribute] = value
metadata_node = self.find_first_child_named(node, 'metadata')
- data['metadata'] = self.extract_metadata(metadata_node)
+ metadata = self.metadata_deserializer.extract_metadata(metadata_node)
+ data['metadata'] = metadata
return data
def create(self, string):
@@ -350,7 +354,8 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
server[attr] = server_node.getAttribute(attr)
metadata_node = self.find_first_child_named(server_node, "metadata")
- server["metadata"] = self.extract_metadata(metadata_node)
+ server["metadata"] = self.metadata_deserializer.extract_metadata(
+ metadata_node)
server["personality"] = self._extract_personality(server_node)
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index 0834adfa5..c76738d30 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -116,13 +116,17 @@ class ControllerV10(Controller):
try:
image_name = image["name"]
- server_id = image["serverId"]
+ instance_id = image["serverId"]
except KeyError as missing_key:
msg = _("Image entity requires %s") % missing_key
raise webob.exc.HTTPBadRequest(explanation=msg)
context = req.environ["nova.context"]
- image = self._compute_service.snapshot(context, server_id, image_name)
+ props = {'instance_id': instance_id}
+ image = self._compute_service.snapshot(context,
+ instance_id,
+ image_name,
+ extra_properties=props)
return dict(image=self.get_builder(req).build(image, detail=True))
diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py
index d4f42bbf5..b0b014f86 100644
--- a/nova/api/openstack/server_metadata.py
+++ b/nova/api/openstack/server_metadata.py
@@ -18,6 +18,7 @@
from webob import exc
from nova import compute
+from nova.api.openstack import common
from nova.api.openstack import wsgi
from nova import exception
from nova import quota
@@ -31,36 +32,37 @@ class Controller(object):
super(Controller, self).__init__()
def _get_metadata(self, context, server_id):
- metadata = self.compute_api.get_instance_metadata(context, server_id)
+ try:
+ meta = self.compute_api.get_instance_metadata(context, server_id)
+ except exception.InstanceNotFound:
+ msg = _('Server does not exist')
+ raise exc.HTTPNotFound(explanation=msg)
+
meta_dict = {}
- for key, value in metadata.iteritems():
+ for key, value in meta.iteritems():
meta_dict[key] = value
- return dict(metadata=meta_dict)
-
- def _check_body(self, body):
- if body == None or body == "":
- expl = _('No Request Body')
- raise exc.HTTPBadRequest(explanation=expl)
+ return meta_dict
def index(self, req, server_id):
""" Returns the list of metadata for a given instance """
context = req.environ['nova.context']
- try:
- return self._get_metadata(context, server_id)
- except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
- raise exc.HTTPNotFound(explanation=msg)
+ return {'metadata': self._get_metadata(context, server_id)}
def create(self, req, server_id, body):
- self._check_body(body)
+ try:
+ metadata = body['metadata']
+ except (KeyError, TypeError):
+ msg = _("Malformed request body")
+ raise exc.HTTPBadRequest(explanation=msg)
+
context = req.environ['nova.context']
- metadata = body.get('metadata')
+
try:
self.compute_api.update_or_create_instance_metadata(context,
server_id,
metadata)
except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
+ msg = _('Server does not exist')
raise exc.HTTPNotFound(explanation=msg)
except quota.QuotaError as error:
@@ -69,51 +71,80 @@ class Controller(object):
return body
def update(self, req, server_id, id, body):
- self._check_body(body)
- context = req.environ['nova.context']
- if not id in body:
+ try:
+ meta_item = body['meta']
+ except (TypeError, KeyError):
+ expl = _('Malformed request body')
+ raise exc.HTTPBadRequest(explanation=expl)
+
+ try:
+ meta_value = meta_item.pop(id)
+ except (AttributeError, KeyError):
expl = _('Request body and URI mismatch')
raise exc.HTTPBadRequest(explanation=expl)
- if len(body) > 1:
+
+ if len(meta_item) > 0:
expl = _('Request body contains too many items')
raise exc.HTTPBadRequest(explanation=expl)
+
+ context = req.environ['nova.context']
+ self._set_instance_metadata(context, server_id, meta_item)
+
+ return {'meta': {id: meta_value}}
+
+ def update_all(self, req, server_id, body):
+ try:
+ metadata = body['metadata']
+ except (TypeError, KeyError):
+ expl = _('Malformed request body')
+ raise exc.HTTPBadRequest(explanation=expl)
+
+ context = req.environ['nova.context']
+ self._set_instance_metadata(context, server_id, metadata)
+
+ return {'metadata': metadata}
+
+ def _set_instance_metadata(self, context, server_id, metadata):
try:
self.compute_api.update_or_create_instance_metadata(context,
server_id,
- body)
+ metadata)
except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
+ msg = _('Server does not exist')
raise exc.HTTPNotFound(explanation=msg)
+ except ValueError:
+ msg = _("Malformed request body")
+ raise exc.HTTPBadRequest(explanation=msg)
+
except quota.QuotaError as error:
self._handle_quota_error(error)
- return body
-
def show(self, req, server_id, id):
""" Return a single metadata item """
context = req.environ['nova.context']
- try:
- data = self._get_metadata(context, server_id)
- except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
- raise exc.HTTPNotFound(explanation=msg)
+ data = self._get_metadata(context, server_id)
try:
- return {id: data['metadata'][id]}
+ return {'meta': {id: data[id]}}
except KeyError:
- msg = _("metadata item %s was not found" % (id))
+ msg = _("Metadata item was not found")
raise exc.HTTPNotFound(explanation=msg)
def delete(self, req, server_id, id):
""" Deletes an existing metadata """
context = req.environ['nova.context']
+
+ metadata = self._get_metadata(context, server_id)
+
try:
- self.compute_api.delete_instance_metadata(context, server_id, id)
- except exception.InstanceNotFound:
- msg = _('Server %(server_id)s does not exist') % locals()
+ meta_key = metadata[id]
+ except KeyError:
+ msg = _("Metadata item was not found")
raise exc.HTTPNotFound(explanation=msg)
+ self.compute_api.delete_instance_metadata(context, server_id, meta_key)
+
def _handle_quota_error(self, error):
"""Reraise quota errors as api-specific http exceptions."""
if error.code == "MetadataLimitExceeded":
@@ -122,10 +153,16 @@ class Controller(object):
def create_resource():
- body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V11),
+ headers_serializer = common.MetadataHeadersSerializer()
+
+ body_deserializers = {
+ 'application/xml': common.MetadataXMLDeserializer(),
}
- serializer = wsgi.ResponseSerializer(body_serializers)
+ body_serializers = {
+ 'application/xml': common.MetadataXMLSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers, headers_serializer)
+ deserializer = wsgi.RequestDeserializer(body_deserializers)
- return wsgi.Resource(Controller(), serializer=serializer)
+ return wsgi.Resource(Controller(), deserializer, serializer)
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index d17714371..3930982dc 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -290,7 +290,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.lock(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::lock %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -306,7 +306,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.unlock(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unlock %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -321,7 +321,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.get_lock(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::get_lock %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -336,7 +336,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.reset_network(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::reset_network %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -351,7 +351,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.inject_network_info(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::inject_network_info %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -363,7 +363,7 @@ class Controller(object):
ctxt = req.environ['nova.context']
try:
self.compute_api.pause(ctxt, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::pause %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -375,7 +375,7 @@ class Controller(object):
ctxt = req.environ['nova.context']
try:
self.compute_api.unpause(ctxt, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unpause %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -387,7 +387,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.suspend(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::suspend %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -399,7 +399,7 @@ class Controller(object):
context = req.environ['nova.context']
try:
self.compute_api.resume(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::resume %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -420,7 +420,7 @@ class Controller(object):
context = req.environ["nova.context"]
try:
self.compute_api.rescue(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::rescue %s"), readable)
raise exc.HTTPUnprocessableEntity()
@@ -432,7 +432,7 @@ class Controller(object):
context = req.environ["nova.context"]
try:
self.compute_api.unrescue(context, id)
- except:
+ except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::unrescue %s"), readable)
raise exc.HTTPUnprocessableEntity()