From a9de2c26432b0b6c77e941db0199fd72a54e2d69 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Wed, 22 Jun 2011 22:40:00 -0400 Subject: Added flavor extra specs controller --- nova/api/openstack/__init__.py | 6 ++ nova/api/openstack/flavor_extra_specs.py | 106 +++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 nova/api/openstack/flavor_extra_specs.py (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index ddd9580d7..464ba1a9a 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -32,6 +32,7 @@ from nova.api.openstack import faults from nova.api.openstack import backup_schedules from nova.api.openstack import consoles from nova.api.openstack import flavors +from nova.api.openstack import flavor_extra_specs from nova.api.openstack import images from nova.api.openstack import image_metadata from nova.api.openstack import ips @@ -178,3 +179,8 @@ class APIRouterV11(APIRouter): controller=server_metadata.create_resource(), parent_resource=dict(member_name='server', collection_name='servers')) + + mapper.resource("flavor_extra_specs", "extra", + controller=flavor_extra_specs.create_resource(), + parent_resource=dict(member_name='flavor', + collection_name='flavors')) diff --git a/nova/api/openstack/flavor_extra_specs.py b/nova/api/openstack/flavor_extra_specs.py new file mode 100644 index 000000000..2dcd85688 --- /dev/null +++ b/nova/api/openstack/flavor_extra_specs.py @@ -0,0 +1,106 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 University of Southern California +# 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. + +from webob import exc + +from nova import db +from nova import quota +from nova.api.openstack import faults +from nova.api.openstack import wsgi + + +class Controller(object): + """ The flavor extra specs API controller for the Openstack API """ + + def __init__(self): + self.compute_api = compute.API() + super(Controller, self).__init__() + + def _get_extra_specs(self, context, flavor_id): + extra_specs = self.db.instance_type_extra_specs_get(context, flavor_id) + specs_dict = {} + for key, value in specs.iteritems(): + specs_dict[key] = value + return dict(extra=specs_dict) + + def _check_body(self, body): + if body == None or body == "": + expl = _('No Request Body') + raise exc.HTTPBadRequest(explanation=expl) + + def index(self, req, flavor_id): + """ Returns the list of extra specs for a givenflavor """ + context = req.environ['nova.context'] + return self._get_extra_specs(context, flavor_id) + + def create(self, req, flavor_id, body): + self._check_body(body) + context = req.environ['nova.context'] + specs = body.get('extra') + try: + self.db.instance_type_extra_specs_update_or_create(context, + flavor_id, + specs) + except quota.QuotaError as error: + self._handle_quota_error(error) + return body + + def update(self, req, flavor_id, id, body): + self._check_body(body) + context = req.environ['nova.context'] + if not id in body: + expl = _('Request body and URI mismatch') + raise exc.HTTPBadRequest(explanation=expl) + if len(body) > 1: + expl = _('Request body contains too many items') + raise exc.HTTPBadRequest(explanation=expl) + try: + self.db.instance_type_extra_specs_update_or_create(context, + flavor_id, + body) + except quota.QuotaError as error: + self._handle_quota_error(error) + + return body + + def show(self, req, flavor_id, id): + """ Return a single extra spec item """ + context = req.environ['nova.context'] + specs = self._get_extra_specs(context, flavor_id) + if id in specs['extra']: + return {id: specs['extra'][id]} + else: + return faults.Fault(exc.HTTPNotFound()) + + def delete(self, req, flavor_id, id): + """ Deletes an existing extra spec """ + context = req.environ['nova.context'] + self.instance_type_extra_specs_delete(context, flavor_id, id) + + def _handle_quota_error(self, error): + """Reraise quota errors as api-specific http exceptions.""" + if error.code == "MetadataLimitExceeded": + raise exc.HTTPBadRequest(explanation=error.message) + raise error + + +def create_resource(): + serializers = { + 'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V11), + } + + return wsgi.Resource(Controller(), serializers=serializers) -- cgit From 173bb3c54b7ce9874f6bf880a5df8966fd508c38 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Wed, 22 Jun 2011 22:43:44 -0400 Subject: Bug fixing --- nova/api/openstack/flavor_extra_specs.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavor_extra_specs.py b/nova/api/openstack/flavor_extra_specs.py index 2dcd85688..d14bed813 100644 --- a/nova/api/openstack/flavor_extra_specs.py +++ b/nova/api/openstack/flavor_extra_specs.py @@ -26,14 +26,10 @@ from nova.api.openstack import wsgi class Controller(object): """ The flavor extra specs API controller for the Openstack API """ - def __init__(self): - self.compute_api = compute.API() - super(Controller, self).__init__() - def _get_extra_specs(self, context, flavor_id): - extra_specs = self.db.instance_type_extra_specs_get(context, flavor_id) + extra_specs = db.instance_type_extra_specs_get(context, flavor_id) specs_dict = {} - for key, value in specs.iteritems(): + for key, value in extra_specs.iteritems(): specs_dict[key] = value return dict(extra=specs_dict) -- cgit From 6afcabac7442aa2e3944a3fef3d3452c189c1901 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Wed, 22 Jun 2011 23:14:39 -0400 Subject: Now passing unit tests --- nova/api/openstack/flavor_extra_specs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavor_extra_specs.py b/nova/api/openstack/flavor_extra_specs.py index d14bed813..6a6d2f7a1 100644 --- a/nova/api/openstack/flavor_extra_specs.py +++ b/nova/api/openstack/flavor_extra_specs.py @@ -27,7 +27,7 @@ class Controller(object): """ The flavor extra specs API controller for the Openstack API """ def _get_extra_specs(self, context, flavor_id): - extra_specs = db.instance_type_extra_specs_get(context, flavor_id) + extra_specs = db.api.instance_type_extra_specs_get(context, flavor_id) specs_dict = {} for key, value in extra_specs.iteritems(): specs_dict[key] = value @@ -48,9 +48,9 @@ class Controller(object): context = req.environ['nova.context'] specs = body.get('extra') try: - self.db.instance_type_extra_specs_update_or_create(context, - flavor_id, - specs) + db.api.instance_type_extra_specs_update_or_create(context, + flavor_id, + specs) except quota.QuotaError as error: self._handle_quota_error(error) return body @@ -65,7 +65,7 @@ class Controller(object): expl = _('Request body contains too many items') raise exc.HTTPBadRequest(explanation=expl) try: - self.db.instance_type_extra_specs_update_or_create(context, + db.api.instance_type_extra_specs_update_or_create(context, flavor_id, body) except quota.QuotaError as error: @@ -85,7 +85,7 @@ class Controller(object): def delete(self, req, flavor_id, id): """ Deletes an existing extra spec """ context = req.environ['nova.context'] - self.instance_type_extra_specs_delete(context, flavor_id, id) + db.api.instance_type_extra_specs_delete(context, flavor_id, id) def _handle_quota_error(self, error): """Reraise quota errors as api-specific http exceptions.""" -- cgit From 188dd9117318cc4f5ebe0be9d19b9737a43ce68b Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Thu, 23 Jun 2011 23:42:44 -0400 Subject: Starting to transition instance type extra specs API to an extension API --- nova/api/openstack/__init__.py | 5 - nova/api/openstack/contrib/flavorextraspecs.py | 123 +++++++++++++++++++++++++ nova/api/openstack/flavor_extra_specs.py | 102 -------------------- 3 files changed, 123 insertions(+), 107 deletions(-) create mode 100644 nova/api/openstack/contrib/flavorextraspecs.py delete mode 100644 nova/api/openstack/flavor_extra_specs.py (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 857a5431b..859cac669 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -178,8 +178,3 @@ class APIRouterV11(APIRouter): controller=server_metadata.create_resource(), parent_resource=dict(member_name='server', collection_name='servers')) - - mapper.resource("flavor_extra_specs", "extra", - controller=flavor_extra_specs.create_resource(), - parent_resource=dict(member_name='flavor', - collection_name='flavors')) diff --git a/nova/api/openstack/contrib/flavorextraspecs.py b/nova/api/openstack/contrib/flavorextraspecs.py new file mode 100644 index 000000000..24c5da7b2 --- /dev/null +++ b/nova/api/openstack/contrib/flavorextraspecs.py @@ -0,0 +1,123 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 University of Southern California +# 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 instance type extra specs extension""" + +from webob import exc + +from nova import db +from nova import quota +from nova.api.openstack import extensions +from nova.api.openstack import faults +from nova.api.openstack import wsgi + + +class FlavorExtraSpecsController(object): + """ The flavor extra specs API controller for the Openstack API """ + + def _get_extra_specs(self, context, flavor_id): + extra_specs = db.api.instance_type_extra_specs_get(context, flavor_id) + specs_dict = {} + for key, value in extra_specs.iteritems(): + specs_dict[key] = value + return dict(extra=specs_dict) + + def _check_body(self, body): + if body == None or body == "": + expl = _('No Request Body') + raise exc.HTTPBadRequest(explanation=expl) + + def index(self, req, flavor_id): + """ Returns the list of extra specs for a givenflavor """ + context = req.environ['nova.context'] + return self._get_extra_specs(context, flavor_id) + + def create(self, req, flavor_id, body): + self._check_body(body) + context = req.environ['nova.context'] + specs = body.get('extra') + try: + db.api.instance_type_extra_specs_update_or_create(context, + flavor_id, + specs) + except quota.QuotaError as error: + self._handle_quota_error(error) + return body + + def update(self, req, flavor_id, id, body): + self._check_body(body) + context = req.environ['nova.context'] + if not id in body: + expl = _('Request body and URI mismatch') + raise exc.HTTPBadRequest(explanation=expl) + if len(body) > 1: + expl = _('Request body contains too many items') + raise exc.HTTPBadRequest(explanation=expl) + try: + db.api.instance_type_extra_specs_update_or_create(context, + flavor_id, + body) + except quota.QuotaError as error: + self._handle_quota_error(error) + + return body + + def show(self, req, flavor_id, id): + """ Return a single extra spec item """ + context = req.environ['nova.context'] + specs = self._get_extra_specs(context, flavor_id) + if id in specs['extra']: + return {id: specs['extra'][id]} + else: + return faults.Fault(exc.HTTPNotFound()) + + def delete(self, req, flavor_id, id): + """ Deletes an existing extra spec """ + context = req.environ['nova.context'] + db.api.instance_type_extra_specs_delete(context, flavor_id, id) + + def _handle_quota_error(self, error): + """Reraise quota errors as api-specific http exceptions.""" + if error.code == "MetadataLimitExceeded": + raise exc.HTTPBadRequest(explanation=error.message) + raise error + +class Flavorextraspecs(extensions.ExtensionDescriptor): + def get_name(self): + return "FlavorExtraSpecs" + + def get_alias(self): + return "flavor-extra-specs" + + def get_description(self): + return "Instance type (flavor) extra specs" + + def get_namespace(self): + return \ + "http://docs.openstack.org/ext/flavor-extra-specs/api/v1.1" + + def get_updated(self): + return "2011-06-23T00:00:00+00:00" + + def get_resources(self): + resources = [] + + res = extensions.ResourceExtension('flavor-extra-specs', + FlavorExtraSpecsController()) + resources.append(res) + + return resources diff --git a/nova/api/openstack/flavor_extra_specs.py b/nova/api/openstack/flavor_extra_specs.py deleted file mode 100644 index 6a6d2f7a1..000000000 --- a/nova/api/openstack/flavor_extra_specs.py +++ /dev/null @@ -1,102 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 University of Southern California -# 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. - -from webob import exc - -from nova import db -from nova import quota -from nova.api.openstack import faults -from nova.api.openstack import wsgi - - -class Controller(object): - """ The flavor extra specs API controller for the Openstack API """ - - def _get_extra_specs(self, context, flavor_id): - extra_specs = db.api.instance_type_extra_specs_get(context, flavor_id) - specs_dict = {} - for key, value in extra_specs.iteritems(): - specs_dict[key] = value - return dict(extra=specs_dict) - - def _check_body(self, body): - if body == None or body == "": - expl = _('No Request Body') - raise exc.HTTPBadRequest(explanation=expl) - - def index(self, req, flavor_id): - """ Returns the list of extra specs for a givenflavor """ - context = req.environ['nova.context'] - return self._get_extra_specs(context, flavor_id) - - def create(self, req, flavor_id, body): - self._check_body(body) - context = req.environ['nova.context'] - specs = body.get('extra') - try: - db.api.instance_type_extra_specs_update_or_create(context, - flavor_id, - specs) - except quota.QuotaError as error: - self._handle_quota_error(error) - return body - - def update(self, req, flavor_id, id, body): - self._check_body(body) - context = req.environ['nova.context'] - if not id in body: - expl = _('Request body and URI mismatch') - raise exc.HTTPBadRequest(explanation=expl) - if len(body) > 1: - expl = _('Request body contains too many items') - raise exc.HTTPBadRequest(explanation=expl) - try: - db.api.instance_type_extra_specs_update_or_create(context, - flavor_id, - body) - except quota.QuotaError as error: - self._handle_quota_error(error) - - return body - - def show(self, req, flavor_id, id): - """ Return a single extra spec item """ - context = req.environ['nova.context'] - specs = self._get_extra_specs(context, flavor_id) - if id in specs['extra']: - return {id: specs['extra'][id]} - else: - return faults.Fault(exc.HTTPNotFound()) - - def delete(self, req, flavor_id, id): - """ Deletes an existing extra spec """ - context = req.environ['nova.context'] - db.api.instance_type_extra_specs_delete(context, flavor_id, id) - - def _handle_quota_error(self, error): - """Reraise quota errors as api-specific http exceptions.""" - if error.code == "MetadataLimitExceeded": - raise exc.HTTPBadRequest(explanation=error.message) - raise error - - -def create_resource(): - serializers = { - 'application/xml': wsgi.XMLDictSerializer(xmlns=wsgi.XMLNS_V11), - } - - return wsgi.Resource(Controller(), serializers=serializers) -- cgit From 7a9dc4adc343aa9cf8c21cef741b3bfe409fc41e Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Fri, 24 Jun 2011 00:45:53 -0400 Subject: Committing some broken code in advance of trying a different strategy for specifying args to extensions.ResoruceExtensions, using parent --- nova/api/openstack/contrib/flavorextraspecs.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/flavorextraspecs.py b/nova/api/openstack/contrib/flavorextraspecs.py index 24c5da7b2..f2f740bff 100644 --- a/nova/api/openstack/contrib/flavorextraspecs.py +++ b/nova/api/openstack/contrib/flavorextraspecs.py @@ -34,7 +34,7 @@ class FlavorExtraSpecsController(object): specs_dict = {} for key, value in extra_specs.iteritems(): specs_dict[key] = value - return dict(extra=specs_dict) + return dict(extra_specs=specs_dict) def _check_body(self, body): if body == None or body == "": @@ -43,13 +43,14 @@ class FlavorExtraSpecsController(object): def index(self, req, flavor_id): """ Returns the list of extra specs for a givenflavor """ + print req.environ context = req.environ['nova.context'] return self._get_extra_specs(context, flavor_id) def create(self, req, flavor_id, body): self._check_body(body) context = req.environ['nova.context'] - specs = body.get('extra') + specs = body.get('extra_specs') try: db.api.instance_type_extra_specs_update_or_create(context, flavor_id, @@ -80,8 +81,8 @@ class FlavorExtraSpecsController(object): """ Return a single extra spec item """ context = req.environ['nova.context'] specs = self._get_extra_specs(context, flavor_id) - if id in specs['extra']: - return {id: specs['extra'][id]} + if id in specs['extra_specs']: + return {id: specs['extra_specs'][id]} else: return faults.Fault(exc.HTTPNotFound()) @@ -108,16 +109,18 @@ class Flavorextraspecs(extensions.ExtensionDescriptor): def get_namespace(self): return \ - "http://docs.openstack.org/ext/flavor-extra-specs/api/v1.1" + "http://docs.openstack.org/ext/flavor_extra_specs/api/v1.1" def get_updated(self): return "2011-06-23T00:00:00+00:00" def get_resources(self): resources = [] - - res = extensions.ResourceExtension('flavor-extra-specs', - FlavorExtraSpecsController()) + res = extensions.ResourceExtension('flavor_extra_specs/:(flavor_id)', + FlavorExtraSpecsController(), + member_actions={ + 'show' : 'flavor_extra_specs/:(flavor_id)/extra/:(id)' }) resources.append(res) - return resources + + -- cgit From 4a0fcd6c1d5540c4bec29ef2585987300654c8b7 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Fri, 24 Jun 2011 01:01:30 -0400 Subject: All tests passing --- nova/api/openstack/contrib/flavorextraspecs.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/flavorextraspecs.py b/nova/api/openstack/contrib/flavorextraspecs.py index f2f740bff..ac67fbf43 100644 --- a/nova/api/openstack/contrib/flavorextraspecs.py +++ b/nova/api/openstack/contrib/flavorextraspecs.py @@ -43,7 +43,6 @@ class FlavorExtraSpecsController(object): def index(self, req, flavor_id): """ Returns the list of extra specs for a givenflavor """ - print req.environ context = req.environ['nova.context'] return self._get_extra_specs(context, flavor_id) @@ -97,7 +96,9 @@ class FlavorExtraSpecsController(object): raise exc.HTTPBadRequest(explanation=error.message) raise error + class Flavorextraspecs(extensions.ExtensionDescriptor): + def get_name(self): return "FlavorExtraSpecs" @@ -116,11 +117,11 @@ class Flavorextraspecs(extensions.ExtensionDescriptor): def get_resources(self): resources = [] - res = extensions.ResourceExtension('flavor_extra_specs/:(flavor_id)', - FlavorExtraSpecsController(), - member_actions={ - 'show' : 'flavor_extra_specs/:(flavor_id)/extra/:(id)' }) - resources.append(res) - return resources + res = extensions.ResourceExtension( + 'flavor_extra_specs', + FlavorExtraSpecsController(), + parent=dict(member_name='flavor', collection_name='flavors')) + resources.append(res) + return resources -- cgit From 52319f7e4e55e78f4fdd9c76b3ab593322edc875 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Fri, 24 Jun 2011 01:02:28 -0400 Subject: Renamed from flavor_extra_specs to extra_specs --- nova/api/openstack/contrib/flavorextraspecs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/flavorextraspecs.py b/nova/api/openstack/contrib/flavorextraspecs.py index ac67fbf43..7fc8e7954 100644 --- a/nova/api/openstack/contrib/flavorextraspecs.py +++ b/nova/api/openstack/contrib/flavorextraspecs.py @@ -118,7 +118,7 @@ class Flavorextraspecs(extensions.ExtensionDescriptor): def get_resources(self): resources = [] res = extensions.ResourceExtension( - 'flavor_extra_specs', + 'extra_specs', FlavorExtraSpecsController(), parent=dict(member_name='flavor', collection_name='flavors')) -- cgit From 48f3bccc3372023c35a75671e25e9089dd4ed836 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Fri, 24 Jun 2011 01:34:47 -0400 Subject: pep8 fixes --- nova/api/openstack/contrib/flavorextraspecs.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/flavorextraspecs.py b/nova/api/openstack/contrib/flavorextraspecs.py index 7fc8e7954..8518bf2bd 100644 --- a/nova/api/openstack/contrib/flavorextraspecs.py +++ b/nova/api/openstack/contrib/flavorextraspecs.py @@ -122,6 +122,5 @@ class Flavorextraspecs(extensions.ExtensionDescriptor): FlavorExtraSpecsController(), parent=dict(member_name='flavor', collection_name='flavors')) - resources.append(res) return resources -- cgit From 4c46c44d7c1458ccaa3919110de12dfceef406c1 Mon Sep 17 00:00:00 2001 From: Lorin Hochstein Date: Fri, 24 Jun 2011 10:37:43 -0400 Subject: Removed an import --- nova/api/openstack/__init__.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 859cac669..f24017df0 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -32,7 +32,6 @@ from nova.api.openstack import faults from nova.api.openstack import backup_schedules from nova.api.openstack import consoles from nova.api.openstack import flavors -from nova.api.openstack import flavor_extra_specs from nova.api.openstack import images from nova.api.openstack import image_metadata from nova.api.openstack import ips -- cgit