diff options
| author | Vishvananda Ishaya <vishvananda@gmail.com> | 2012-08-29 17:50:58 -0700 |
|---|---|---|
| committer | Vishvananda Ishaya <vishvananda@gmail.com> | 2012-08-29 22:27:46 -0700 |
| commit | f9fa7a68a368cefd79ccc6d5d2b91cbdb4d17be7 (patch) | |
| tree | f4ad838b04c86d34f20bc0eb7caa25eae52411e0 /nova/api | |
| parent | 4a6193b5d2cab2aaf4a5b3dfeb9b460d77677a2d (diff) | |
| download | nova-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.py | 89 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/flavorextradata.py | 72 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/flavormanage.py | 1 | ||||
| -rw-r--r-- | nova/api/openstack/compute/flavors.py | 2 | ||||
| -rw-r--r-- | nova/api/openstack/compute/views/flavors.py | 6 | ||||
| -rw-r--r-- | nova/api/openstack/wsgi.py | 61 |
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.""" |
