summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorSandy Walsh <sandy.walsh@rackspace.com>2011-09-21 13:17:05 -0700
committerSandy Walsh <sandy.walsh@rackspace.com>2011-09-21 13:17:05 -0700
commitcd4050422340d27ba6161e2b9c4ccc7f057fb4bb (patch)
tree8c4951d69e2625d14eaa28db350d1a1876d6254f /nova/api
parent1051adcfc88c7a9eacef2a7000f43f9e66e1cb47 (diff)
parentd9752d46554ffa87360bfd740177b40871cfbea6 (diff)
trunk merge fixup
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/ec2/cloud.py1
-rw-r--r--nova/api/ec2/ec2utils.py2
-rw-r--r--nova/api/openstack/common.py3
-rw-r--r--nova/api/openstack/contrib/deferred_delete.py76
-rw-r--r--nova/api/openstack/images.py2
-rw-r--r--nova/api/openstack/servers.py13
-rw-r--r--nova/api/openstack/views/images.py16
7 files changed, 107 insertions, 6 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 23ac30494..68d39042f 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -89,6 +89,7 @@ _STATE_DESCRIPTION_MAP = {
vm_states.BUILDING: 'pending',
vm_states.REBUILDING: 'pending',
vm_states.DELETED: 'terminated',
+ vm_states.SOFT_DELETE: 'terminated',
vm_states.STOPPED: 'stopped',
vm_states.MIGRATING: 'migrate',
vm_states.RESIZING: 'resize',
diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py
index bcdf2ba78..aac8f9a1e 100644
--- a/nova/api/ec2/ec2utils.py
+++ b/nova/api/ec2/ec2utils.py
@@ -116,7 +116,7 @@ def dict_from_dotted_str(items):
args = {}
for key, value in items:
parts = key.split(".")
- key = camelcase_to_underscore(parts[0])
+ key = str(camelcase_to_underscore(parts[0]))
if isinstance(value, str) or isinstance(value, unicode):
# NOTE(vish): Automatically convert strings back
# into their respective values
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index ca7848678..3ef9bdee5 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -78,6 +78,9 @@ _STATE_MAP = {
vm_states.DELETED: {
'default': 'DELETED',
},
+ vm_states.SOFT_DELETE: {
+ 'default': 'DELETED',
+ },
}
diff --git a/nova/api/openstack/contrib/deferred_delete.py b/nova/api/openstack/contrib/deferred_delete.py
new file mode 100644
index 000000000..13ee5511e
--- /dev/null
+++ b/nova/api/openstack/contrib/deferred_delete.py
@@ -0,0 +1,76 @@
+# Copyright 2011 Openstack, LLC
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""The deferred instance delete extension."""
+
+import webob
+from webob import exc
+
+from nova import compute
+from nova import exception
+from nova import log as logging
+from nova.api.openstack import common
+from nova.api.openstack import extensions
+from nova.api.openstack import faults
+from nova.api.openstack import servers
+
+
+LOG = logging.getLogger("nova.api.contrib.deferred-delete")
+
+
+class Deferred_delete(extensions.ExtensionDescriptor):
+ def __init__(self):
+ super(Deferred_delete, self).__init__()
+ self.compute_api = compute.API()
+
+ def _restore(self, input_dict, req, instance_id):
+ """Restore a previously deleted instance."""
+
+ context = req.environ["nova.context"]
+ self.compute_api.restore(context, instance_id)
+ return webob.Response(status_int=202)
+
+ def _force_delete(self, input_dict, req, instance_id):
+ """Force delete of instance before deferred cleanup."""
+
+ context = req.environ["nova.context"]
+ self.compute_api.force_delete(context, instance_id)
+ return webob.Response(status_int=202)
+
+ def get_name(self):
+ return "DeferredDelete"
+
+ def get_alias(self):
+ return "os-deferred-delete"
+
+ def get_description(self):
+ return "Instance deferred delete"
+
+ def get_namespace(self):
+ return "http://docs.openstack.org/ext/deferred-delete/api/v1.1"
+
+ def get_updated(self):
+ return "2011-09-01T00:00:00+00:00"
+
+ def get_actions(self):
+ """Return the actions the extension adds, as required by contract."""
+ actions = [
+ extensions.ActionExtension("servers", "restore",
+ self._restore),
+ extensions.ActionExtension("servers", "forceDelete",
+ self._force_delete),
+ ]
+
+ return actions
diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py
index 4340cbe3e..d579ae716 100644
--- a/nova/api/openstack/images.py
+++ b/nova/api/openstack/images.py
@@ -251,6 +251,8 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer):
elem = etree.SubElement(image_elem,
'{%s}link' % xmlutil.XMLNS_ATOM)
elem.set('rel', link['rel'])
+ if 'type' in link:
+ elem.set('type', link['type'])
elem.set('href', link['href'])
return image_elem
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 3b19e695f..1a4703069 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -47,7 +47,7 @@ FLAGS = flags.FLAGS
class ConvertedException(exc.WSGIHTTPException):
- def __init__(self, code, title, explaination):
+ def __init__(self, code, title, explanation):
self.code = code
self.title = title
self.explanation = explanation
@@ -192,7 +192,12 @@ class Controller(object):
server['server']['adminPass'] = extra_values['password']
return server
- @novaclient_exception_converter
+ def _delete(self, context, id):
+ if FLAGS.reclaim_instance_interval:
+ self.compute_api.soft_delete(context, id)
+ else:
+ self.compute_api.delete(context, id)
+
@scheduler_api.redirect_handler
def update(self, req, id, body):
"""Update server then pass on to version-specific controller"""
@@ -613,7 +618,7 @@ class ControllerV10(Controller):
def delete(self, req, id):
""" Destroys a server """
try:
- self.compute_api.delete(req.environ['nova.context'], id)
+ self._delete(req.environ['nova.context'], id)
except exception.NotFound:
raise exc.HTTPNotFound()
return webob.Response(status_int=202)
@@ -692,7 +697,7 @@ class ControllerV11(Controller):
def delete(self, req, id):
""" Destroys a server """
try:
- self.compute_api.delete(req.environ['nova.context'], id)
+ self._delete(req.environ['nova.context'], id)
except exception.NotFound:
raise exc.HTTPNotFound()
diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py
index 86e8d7f3a..659bfd463 100644
--- a/nova/api/openstack/views/images.py
+++ b/nova/api/openstack/views/images.py
@@ -18,6 +18,7 @@
import os.path
from nova.api.openstack import common
+from nova import utils
class ViewBuilder(object):
@@ -139,6 +140,7 @@ class ViewBuilderV11(ViewBuilder):
image = ViewBuilder.build(self, image_obj, detail)
href = self.generate_href(image_obj["id"])
bookmark = self.generate_bookmark(image_obj["id"])
+ alternate = self.generate_alternate(image_obj["id"])
image["links"] = [
{
@@ -149,6 +151,11 @@ class ViewBuilderV11(ViewBuilder):
"rel": "bookmark",
"href": bookmark,
},
+ {
+ "rel": "alternate",
+ "type": "application/vnd.openstack.image",
+ "href": alternate,
+ },
]
@@ -158,6 +165,13 @@ class ViewBuilderV11(ViewBuilder):
return image
def generate_bookmark(self, image_id):
- """Create an url that refers to a specific flavor id."""
+ """Create a URL that refers to a specific flavor id."""
return os.path.join(common.remove_version_from_href(self.base_url),
self.project_id, "images", str(image_id))
+
+ def generate_alternate(self, image_id):
+ """Create an alternate link for a specific flavor id."""
+ glance_url = utils.generate_glance_url()
+
+ return "%s/%s/images/%s" % (glance_url, self.project_id,
+ str(image_id))