summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorBrian Waldon <brian.waldon@rackspace.com>2011-07-28 16:21:12 -0400
committerBrian Waldon <brian.waldon@rackspace.com>2011-07-28 16:21:12 -0400
commit8141ef4139fbf8512150ce970cea4dc4bee22e1a (patch)
tree455720c324ca50cc7a9e3bc9d0dd573f13355d0f /nova/api
parent84909f4a7733dde453afcc5cc540854ac1bc458c (diff)
downloadnova-8141ef4139fbf8512150ce970cea4dc4bee22e1a.tar.gz
nova-8141ef4139fbf8512150ce970cea4dc4bee22e1a.tar.xz
nova-8141ef4139fbf8512150ce970cea4dc4bee22e1a.zip
moving server backup to /servers/<id>/action instead of POST /images
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/openstack/create_instance_helper.py12
-rw-r--r--nova/api/openstack/images.py112
-rw-r--r--nova/api/openstack/servers.py133
3 files changed, 111 insertions, 146 deletions
diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py
index 73ff191e8..e165899e7 100644
--- a/nova/api/openstack/create_instance_helper.py
+++ b/nova/api/openstack/create_instance_helper.py
@@ -300,6 +300,7 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
action_deserializer = {
'createImage': self._action_create_image,
+ 'createBackup': self._action_create_image,
}.get(action_name, self.default)
action_data = action_deserializer(action_node)
@@ -308,7 +309,16 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer):
def _action_create_image(self, node):
data = {}
- attributes = ['name', 'image_type', 'backup_type', 'rotation']
+ value = node.getAttribute('name')
+ if value:
+ data['name'] = value
+ metadata_node = self.find_first_child_named(node, 'metadata')
+ data['metadata'] = self.extract_metadata(metadata_node)
+ return data
+
+ def _action_create_image(self, node):
+ data = {}
+ attributes = ['name', 'backup_type', 'rotation']
for attribute in attributes:
value = node.getAttribute(attribute)
if value:
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index 517a51662..b3e16c997 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -102,72 +102,27 @@ class Controller(object):
"""Indicates that you must use a Controller subclass."""
raise NotImplementedError()
- def _server_id_from_req(self, req, data):
- raise NotImplementedError()
-
- def _get_extra_properties(self, req, data):
- return {}
-
class ControllerV10(Controller):
"""Version 1.0 specific controller logic."""
def create(self, req, body):
- """Snapshot or backup a server instance and save the image.
-
- Images now have an `image_type` associated with them, which can be
- 'snapshot' or the backup type, like 'daily' or 'weekly'.
-
- If the image_type is backup-like, then the rotation factor can be
- included and that will cause the oldest backups that exceed the
- rotation factor to be deleted.
-
- :param req: `wsgi.Request` object
- """
- def get_param(param):
- try:
- return body["image"][param]
- except KeyError:
- raise webob.exc.HTTPBadRequest(explanation="Missing required "
- "param: %s" % param)
-
- context = req.environ['nova.context']
- content_type = req.get_content_type()
-
- if not body:
- raise webob.exc.HTTPBadRequest()
-
- image_type = body["image"].get("image_type", "snapshot")
+ """Snapshot a server instance and save the image."""
+ try:
+ image = body["image"]
+ except (KeyError, TypeError):
+ msg = _("Invalid image entity")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
try:
- server_id = self._server_id_from_req(req, body)
- except KeyError:
- raise webob.exc.HTTPBadRequest()
-
- image_name = get_param("name")
- props = self._get_extra_properties(req, body)
-
- if image_type == "snapshot":
- image = self._compute_service.snapshot(
- context, server_id, image_name,
- extra_properties=props)
- elif image_type == "backup":
- # NOTE(sirp): Unlike snapshot, backup is not a customer facing
- # API call; rather, it's used by the internal backup scheduler
- if not FLAGS.allow_admin_api:
- raise webob.exc.HTTPBadRequest(
- explanation="Admin API Required")
-
- backup_type = get_param("backup_type")
- rotation = int(get_param("rotation"))
-
- image = self._compute_service.backup(
- context, server_id, image_name,
- backup_type, rotation, extra_properties=props)
- else:
- LOG.error(_("Invalid image_type '%s' passed") % image_type)
- raise webob.exc.HTTPBadRequest(explanation="Invalue image_type: "
- "%s" % image_type)
+ image_name = image["name"]
+ server_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)
return dict(image=self.get_builder(req).build(image, detail=True))
@@ -202,13 +157,6 @@ class ControllerV10(Controller):
builder = self.get_builder(req).build
return dict(images=[builder(image, detail=True) for image in images])
- def _server_id_from_req(self, req, data):
- try:
- return data['image']['serverId']
- except KeyError:
- msg = _("Expected serverId attribute on server entity.")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
class ControllerV11(Controller):
"""Version 1.1 specific controller logic."""
@@ -246,38 +194,6 @@ class ControllerV11(Controller):
builder = self.get_builder(req).build
return dict(images=[builder(image, detail=True) for image in images])
- def _server_id_from_req(self, req, data):
- try:
- server_ref = data['image']['serverRef']
- except KeyError:
- msg = _("Expected serverRef attribute on server entity.")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
- if not server_ref.startswith('http'):
- return server_ref
-
- passed = urlparse.urlparse(server_ref)
- expected = urlparse.urlparse(req.application_url)
- version = expected.path.split('/')[1]
- expected_prefix = "/%s/servers/" % version
- _empty, _sep, server_id = passed.path.partition(expected_prefix)
- scheme_ok = passed.scheme == expected.scheme
- host_ok = passed.hostname == expected.hostname
- port_ok = (passed.port == expected.port or
- passed.port == FLAGS.osapi_port)
- if not (scheme_ok and port_ok and host_ok and server_id):
- msg = _("serverRef must match request url")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
- return server_id
-
- def _get_extra_properties(self, req, data):
- server_ref = data['image']['serverRef']
- if not server_ref.startswith('http'):
- server_ref = os.path.join(req.application_url, 'servers',
- server_ref)
- return {'instance_ref': server_ref}
-
def create(self, *args, **kwargs):
raise webob.exc.HTTPMethodNotAllowed()
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 0cc81009b..fafde1c15 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -166,11 +166,79 @@ class Controller(object):
'createImage': self._action_create_image,
}
+ if FLAGS.allow_admin_api:
+ admin_actions = {
+ 'createBackup': self._action_create_backup,
+ }
+ self.actions.update(admin_actions)
+
for key in self.actions.keys():
if key in body:
return self.actions[key](body, req, id)
+
raise exc.HTTPNotImplemented()
+ def _action_create_backup(self, input_dict, req, instance_id):
+ """Backup a server instance.
+
+ Images now have an `image_type` associated with them, which can be
+ 'snapshot' or the backup type, like 'daily' or 'weekly'.
+
+ If the image_type is backup-like, then the rotation factor can be
+ included and that will cause the oldest backups that exceed the
+ rotation factor to be deleted.
+
+ """
+ entity = input_dict["createBackup"]
+
+ try:
+ image_name = entity["name"]
+ backup_type = entity["backup_type"]
+ rotation = entity["rotation"]
+
+ except KeyError as missing_key:
+ msg = _("createBackup entity requires %s attribute") % missing_key
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ except TypeError:
+ msg = _("Malformed createBackup entity")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ try:
+ rotation = int(rotation)
+ except ValueError:
+ msg = _("createBackup attribute 'rotation' must be an integer")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ # preserve link to server in image properties
+ server_ref = os.path.join(req.application_url,
+ 'servers',
+ str(instance_id))
+ props = {'instance_ref': server_ref}
+
+ metadata = entity.get('metadata', {})
+ try:
+ props.update(metadata)
+ except ValueError:
+ msg = _("Invalid metadata")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ context = req.environ["nova.context"]
+ image = self.compute_api.backup(context,
+ instance_id,
+ image_name,
+ backup_type,
+ rotation,
+ extra_properties=props)
+
+ # build location of newly-created image entity
+ image_id = str(image['id'])
+ image_ref = os.path.join(req.application_url, 'images', image_id)
+
+ resp = webob.Response(status_int=202)
+ resp.headers['Location'] = image_ref
+ return resp
+
def _action_create_image(self, input_dict, req, id):
return exc.HTTPNotImplemented()
@@ -599,30 +667,22 @@ class ControllerV11(Controller):
return webob.Response(status_int=202)
- def _action_create_image(self, input_dict, req, instance_id):
- """Snapshot or backup a server instance and save the image.
-
- Images now have an `image_type` associated with them, which can be
- 'snapshot' or the backup type, like 'daily' or 'weekly'.
- If the image_type is backup-like, then the rotation factor can be
- included and that will cause the oldest backups that exceed the
- rotation factor to be deleted.
- """
- entity = input_dict.get('createImage', {})
+ def _action_create_image(self, input_dict, req, instance_id):
+ """Snapshot a server instance."""
+ entity = input_dict.get("createImage", {})
- def get_param(param):
- try:
- return entity[param]
- except KeyError:
- msg = _("Missing required param: %s") % param
- raise webob.exc.HTTPBadRequest(explanation=msg)
+ try:
+ image_name = entity["name"]
- context = req.environ['nova.context']
+ except KeyError:
+ msg = _("createImage entity requires name attribute")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
- image_name = get_param("name")
- image_type = entity.get("image_type", "snapshot")
+ except TypeError:
+ msg = _("Malformed createImage entity")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
# preserve link to server in image properties
server_ref = os.path.join(req.application_url,
@@ -637,36 +697,15 @@ class ControllerV11(Controller):
msg = _("Invalid metadata")
raise webob.exc.HTTPBadRequest(explanation=msg)
- if image_type == "snapshot":
- image = self.compute_api.snapshot(context,
- instance_id,
- image_name,
- extra_properties=props)
-
- elif image_type == "backup":
- # NOTE(sirp): Unlike snapshot, backup is not a customer facing
- # API call; rather, it's used by the internal backup scheduler
- if not FLAGS.allow_admin_api:
- msg = _("Admin API Required")
- raise webob.exc.HTTPBadRequest(explanation=msg)
-
- backup_type = get_param("backup_type")
- rotation = int(get_param("rotation"))
-
- image = self.compute_api.backup(context,
- instance_id,
- image_name,
- backup_type,
- rotation,
- extra_properties=props)
- else:
- msg = _("Invalid image_type '%s'") % image_type
- raise webob.exc.HTTPBadRequest(explanation=msg)
+ context = req.environ['nova.context']
+ image = self.compute_api.snapshot(context,
+ instance_id,
+ image_name,
+ extra_properties=props)
# build location of newly-created image entity
- image_ref = os.path.join(req.application_url,
- 'images',
- str(image['id']))
+ image_id = str(image['id'])
+ image_ref = os.path.join(req.application_url, 'images', image_id)
resp = webob.Response(status_int=202)
resp.headers['Location'] = image_ref