summaryrefslogtreecommitdiffstats
path: root/nova/api
diff options
context:
space:
mode:
authorVishvananda Ishaya <vishvananda@gmail.com>2012-08-29 17:50:58 -0700
committerVishvananda Ishaya <vishvananda@gmail.com>2012-08-29 22:27:46 -0700
commitf9fa7a68a368cefd79ccc6d5d2b91cbdb4d17be7 (patch)
treef4ad838b04c86d34f20bc0eb7caa25eae52411e0 /nova/api
parent4a6193b5d2cab2aaf4a5b3dfeb9b460d77677a2d (diff)
downloadnova-f9fa7a68a368cefd79ccc6d5d2b91cbdb4d17be7.tar.gz
nova-f9fa7a68a368cefd79ccc6d5d2b91cbdb4d17be7.tar.xz
nova-f9fa7a68a368cefd79ccc6d5d2b91cbdb4d17be7.zip
Clean up non-spec output in flavor extensions
Adds option to cache flavors in the request object like instances. Modifies the flavorextradata extension to use the cache and optimizes tests. Adds flavor_disabled extension to control the extra data and includes tests. Fixes api samples to show the new extension. Fixes bug 1043585 Change-Id: Ie89df24a2891e3869d3fb604e07c79e8c913f290
Diffstat (limited to 'nova/api')
-rw-r--r--nova/api/openstack/compute/contrib/flavor_disabled.py89
-rw-r--r--nova/api/openstack/compute/contrib/flavorextradata.py72
-rw-r--r--nova/api/openstack/compute/contrib/flavormanage.py1
-rw-r--r--nova/api/openstack/compute/flavors.py2
-rw-r--r--nova/api/openstack/compute/views/flavors.py6
-rw-r--r--nova/api/openstack/wsgi.py61
6 files changed, 149 insertions, 82 deletions
diff --git a/nova/api/openstack/compute/contrib/flavor_disabled.py b/nova/api/openstack/compute/contrib/flavor_disabled.py
new file mode 100644
index 000000000..48181954b
--- /dev/null
+++ b/nova/api/openstack/compute/contrib/flavor_disabled.py
@@ -0,0 +1,89 @@
+# Copyright 2012 Nebula, Inc.
+#
+# 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 Flavor Disabled API extension."""
+
+from nova.api.openstack import extensions
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
+
+
+authorize = extensions.soft_extension_authorizer('compute', 'flavor_disabled')
+
+
+class FlavorDisabledController(wsgi.Controller):
+ def _extend_flavors(self, req, flavors):
+ for flavor in flavors:
+ db_flavor = req.get_db_flavor(flavor['id'])
+ key = "%s:disabled" % Flavor_disabled.alias
+ flavor[key] = db_flavor['disabled']
+
+ def _show(self, req, resp_obj):
+ if not authorize(req.environ['nova.context']):
+ return
+ if 'flavor' in resp_obj.obj:
+ resp_obj.attach(xml=FlavorDisabledTemplate())
+ self._extend_flavors(req, [resp_obj.obj['flavor']])
+
+ @wsgi.extends
+ def show(self, req, resp_obj, id):
+ return self._show(req, resp_obj)
+
+ @wsgi.extends(action='create')
+ def create(self, req, resp_obj, body):
+ return self._show(req, resp_obj)
+
+ @wsgi.extends
+ def detail(self, req, resp_obj):
+ if not authorize(req.environ['nova.context']):
+ return
+ resp_obj.attach(xml=FlavorsDisabledTemplate())
+ self._extend_flavors(req, list(resp_obj.obj['flavors']))
+
+
+class Flavor_disabled(extensions.ExtensionDescriptor):
+ """Support to show the disabled status of a flavor"""
+
+ name = "FlavorDisabled"
+ alias = "OS-FLV-DISABLED"
+ namespace = ("http://docs.openstack.org/compute/ext/"
+ "flavor_disabled/api/v1.1")
+ updated = "2012-08-29T00:00:00+00:00"
+
+ def get_controller_extensions(self):
+ controller = FlavorDisabledController()
+ extension = extensions.ControllerExtension(self, 'flavors', controller)
+ return [extension]
+
+
+def make_flavor(elem):
+ elem.set('{%s}disabled' % Flavor_disabled.namespace,
+ '%s:disabled' % Flavor_disabled.alias)
+
+
+class FlavorDisabledTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('flavor', selector='flavor')
+ make_flavor(root)
+ return xmlutil.SlaveTemplate(root, 1, nsmap={
+ Flavor_disabled.alias: Flavor_disabled.namespace})
+
+
+class FlavorsDisabledTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('flavors')
+ elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
+ make_flavor(elem)
+ return xmlutil.SlaveTemplate(root, 1, nsmap={
+ Flavor_disabled.alias: Flavor_disabled.namespace})
diff --git a/nova/api/openstack/compute/contrib/flavorextradata.py b/nova/api/openstack/compute/contrib/flavorextradata.py
index 834b68c60..e2bdadf16 100644
--- a/nova/api/openstack/compute/contrib/flavorextradata.py
+++ b/nova/api/openstack/compute/contrib/flavorextradata.py
@@ -27,71 +27,39 @@ attributes. This extension adds to that list:
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
-from nova.compute import instance_types
-from nova import exception
authorize = extensions.soft_extension_authorizer('compute', 'flavorextradata')
class FlavorextradataController(wsgi.Controller):
- def _get_flavor_refs(self, context):
- """Return a dictionary mapping flavorid to flavor_ref."""
-
- flavor_refs = instance_types.get_all_types(context)
- rval = {}
- for name, obj in flavor_refs.iteritems():
- rval[obj['flavorid']] = obj
- return rval
-
- def _extend_flavor(self, flavor_rval, flavor_ref):
- key = "%s:ephemeral" % (Flavorextradata.alias)
- flavor_rval[key] = flavor_ref['ephemeral_gb']
+ def _extend_flavors(self, req, flavors):
+ for flavor in flavors:
+ db_flavor = req.get_db_flavor(flavor['id'])
+ key = "%s:ephemeral" % Flavorextradata.alias
+ flavor[key] = db_flavor['ephemeral_gb']
+
+ def _show(self, req, resp_obj):
+ if not authorize(req.environ['nova.context']):
+ return
+ if 'flavor' in resp_obj.obj:
+ resp_obj.attach(xml=FlavorextradatumTemplate())
+ self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
def show(self, req, resp_obj, id):
- context = req.environ['nova.context']
- if authorize(context):
- # Attach our slave template to the response object
- resp_obj.attach(xml=FlavorextradatumTemplate())
+ return self._show(req, resp_obj)
- try:
- flavor_ref = instance_types.get_instance_type_by_flavor_id(id)
- except exception.FlavorNotFound:
- explanation = _("Flavor not found.")
- raise exception.HTTPNotFound(explanation=explanation)
-
- self._extend_flavor(resp_obj.obj['flavor'], flavor_ref)
+ @wsgi.extends(action='create')
+ def create(self, req, resp_obj, body):
+ return self._show(req, resp_obj)
@wsgi.extends
def detail(self, req, resp_obj):
- context = req.environ['nova.context']
- if authorize(context):
- # Attach our slave template to the response object
- resp_obj.attach(xml=FlavorextradataTemplate())
-
- flavors = list(resp_obj.obj['flavors'])
- flavor_refs = self._get_flavor_refs(context)
-
- for flavor_rval in flavors:
- flavor_ref = flavor_refs[flavor_rval['id']]
- self._extend_flavor(flavor_rval, flavor_ref)
-
- @wsgi.extends(action='create')
- def create(self, req, body, resp_obj):
- context = req.environ['nova.context']
- if authorize(context):
- # Attach our slave template to the response object
- resp_obj.attach(xml=FlavorextradatumTemplate())
-
- try:
- fid = resp_obj.obj['flavor']['id']
- flavor_ref = instance_types.get_instance_type_by_flavor_id(fid)
- except exception.FlavorNotFound:
- explanation = _("Flavor not found.")
- raise exception.HTTPNotFound(explanation=explanation)
-
- self._extend_flavor(resp_obj.obj['flavor'], flavor_ref)
+ if not authorize(req.environ['nova.context']):
+ return
+ resp_obj.attach(xml=FlavorextradataTemplate())
+ self._extend_flavors(req, list(resp_obj.obj['flavors']))
class Flavorextradata(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/compute/contrib/flavormanage.py b/nova/api/openstack/compute/contrib/flavormanage.py
index 3bcbf6981..e3d57f3a1 100644
--- a/nova/api/openstack/compute/contrib/flavormanage.py
+++ b/nova/api/openstack/compute/contrib/flavormanage.py
@@ -71,6 +71,7 @@ class FlavorManageController(wsgi.Controller):
flavor = instance_types.create(name, memory_mb, vcpus,
root_gb, ephemeral_gb, flavorid,
swap, rxtx_factor, is_public)
+ req.cache_db_flavor(flavor)
except exception.InstanceTypeExists as err:
raise webob.exc.HTTPConflict(explanation=str(err))
diff --git a/nova/api/openstack/compute/flavors.py b/nova/api/openstack/compute/flavors.py
index 1a96c1346..e04ade437 100644
--- a/nova/api/openstack/compute/flavors.py
+++ b/nova/api/openstack/compute/flavors.py
@@ -79,6 +79,7 @@ class Controller(wsgi.Controller):
def detail(self, req):
"""Return all flavors in detail."""
flavors = self._get_flavors(req)
+ req.cache_db_flavors(flavors)
return self._view_builder.detail(req, flavors)
@wsgi.serializers(xml=FlavorTemplate)
@@ -86,6 +87,7 @@ class Controller(wsgi.Controller):
"""Return data about the given flavor id."""
try:
flavor = instance_types.get_instance_type_by_flavor_id(id)
+ req.cache_db_flavor(flavor)
except exception.NotFound:
raise webob.exc.HTTPNotFound()
diff --git a/nova/api/openstack/compute/views/flavors.py b/nova/api/openstack/compute/views/flavors.py
index c299170b0..2900ccf64 100644
--- a/nova/api/openstack/compute/views/flavors.py
+++ b/nova/api/openstack/compute/views/flavors.py
@@ -49,12 +49,6 @@ class ViewBuilder(common.ViewBuilder):
},
}
- # NOTE(sirp): disabled attribute is namespaced for now for
- # compatability with the OpenStack API. This should ultimately be made
- # a first class attribute.
- flavor_dict["flavor"]["OS-FLV-DISABLED:disabled"] =\
- flavor.get("disabled", "")
-
return flavor_dict
def index(self, request, flavors):
diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py
index 9f8bf6367..658b59645 100644
--- a/nova/api/openstack/wsgi.py
+++ b/nova/api/openstack/wsgi.py
@@ -66,49 +66,62 @@ class Request(webob.Request):
def __init__(self, *args, **kwargs):
super(Request, self).__init__(*args, **kwargs)
- self._extension_data = {'db_instances': {}}
+ self._extension_data = {'db_items': {}}
- def cache_db_instances(self, instances):
+ def cache_db_items(self, key, items, item_key='id'):
"""
- Allow API methods to store instances from a DB query to be
+ Allow API methods to store objects from a DB query to be
used by API extensions within the same API request.
An instance of this class only lives for the lifetime of a
single API request, so there's no need to implement full
cache management.
"""
- db_instances = self._extension_data['db_instances']
- for instance in instances:
- db_instances[instance['uuid']] = instance
+ db_items = self._extension_data['db_items'].setdefault(key, {})
+ for item in items:
+ db_items[item[item_key]] = item
- def cache_db_instance(self, instance):
+ def get_db_items(self, key):
"""
- Allow API methods to store an instance from a DB query to be
- used by API extensions within the same API request.
+ Allow an API extension to get previously stored objects within
+ the same API request.
- An instance of this class only lives for the lifetime of a
- single API request, so there's no need to implement full
- cache management.
+ Note that the object data will be slightly stale.
"""
- self.cache_db_instances([instance])
+ return self._extension_data['db_items'][key]
- def get_db_instances(self):
+ def get_db_item(self, key, item_key):
"""
- Allow an API extension to get previously stored instances within
- the same API request.
+ Allow an API extension to get a previously stored object
+ within the same API request.
- Note that the instance data will be slightly stale.
+ Note that the object data will be slightly stale.
"""
- return self._extension_data['db_instances']
+ return self.get_db_items(key).get(item_key)
+
+ def cache_db_instances(self, instances):
+ self.cache_db_items('instances', instances, 'uuid')
+
+ def cache_db_instance(self, instance):
+ self.cache_db_items('instances', [instance], 'uuid')
+
+ def get_db_instances(self):
+ return self.get_db_items('instances')
def get_db_instance(self, instance_uuid):
- """
- Allow an API extension to get a previously stored instance
- within the same API request.
+ return self.get_db_item('instances', instance_uuid)
- Note that the instance data will be slightly stale.
- """
- return self._extension_data['db_instances'].get(instance_uuid)
+ def cache_db_flavors(self, flavors):
+ self.cache_db_items('flavors', flavors, 'flavorid')
+
+ def cache_db_flavor(self, flavor):
+ self.cache_db_items('flavors', [flavor], 'flavorid')
+
+ def get_db_flavors(self):
+ return self.get_db_items('flavors')
+
+ def get_db_flavor(self, flavorid):
+ return self.get_db_item('flavors', flavorid)
def best_match_content_type(self):
"""Determine the requested response content-type."""