From 92f076c981343e09c240533acf49a6fdd0384555 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 16:39:04 -0700 Subject: Set XML namespace when returning XML --- nova/wsgi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nova/wsgi.py b/nova/wsgi.py index ba0819466..f0a60582d 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -478,6 +478,9 @@ class Serializer(object): root_key = data.keys()[0] doc = minidom.Document() node = self._to_xml_node(doc, metadata, root_key, data[root_key]) + node.setAttribute('xmlns', + 'http://docs.rackspacecloud.com/servers/api/v1.0') + return node.toprettyxml(indent=' ') def _to_xml_node(self, doc, metadata, nodename, data): -- cgit From 5c31b423ba5b5347aac62559c4e5c0a02f264213 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 16:59:03 -0700 Subject: Support setting the xmlns intelligently --- nova/wsgi.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/nova/wsgi.py b/nova/wsgi.py index f0a60582d..5d286bb3b 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -355,7 +355,8 @@ class Controller(object): if type(result) is dict: content_type = req.best_match_content_type() - body = self._serialize(result, content_type) + default_xmlns = self.get_default_xmlns(req) + body = self._serialize(result, content_type, default_xmlns) response = webob.Response() response.headers["Content-Type"] = content_type @@ -365,14 +366,15 @@ class Controller(object): else: return result - def _serialize(self, data, content_type): + def _serialize(self, data, content_type, default_xmlns): """ Serialize the given dict to the provided content_type. Uses self._serialization_metadata if it exists, which is a dict mapping MIME types to information needed to serialize to that type. """ _metadata = getattr(type(self), "_serialization_metadata", {}) - serializer = Serializer(_metadata) + + serializer = Serializer(_metadata, default_xmlns) try: return serializer.serialize(data, content_type) except exception.InvalidContentType: @@ -388,19 +390,23 @@ class Controller(object): serializer = Serializer(_metadata) return serializer.deserialize(data, content_type) + def get_default_xmlns(self, req): + return 'http://docs.rackspacecloud.com/servers/api/v1.0' + class Serializer(object): """ Serializes and deserializes dictionaries to certain MIME types. """ - def __init__(self, metadata=None): + def __init__(self, metadata=None, default_xmlns=None): """ Create a serializer based on the given WSGI environment. 'metadata' is an optional dict mapping MIME types to information needed to serialize a dictionary to that type. """ self.metadata = metadata or {} + self.default_xmlns = default_xmlns def _get_serialize_handler(self, content_type): handlers = { @@ -478,14 +484,23 @@ class Serializer(object): root_key = data.keys()[0] doc = minidom.Document() node = self._to_xml_node(doc, metadata, root_key, data[root_key]) - node.setAttribute('xmlns', - 'http://docs.rackspacecloud.com/servers/api/v1.0') + + xmlns = node.getAttribute('xmlns') + if not xmlns and self.default_xmlns: + node.setAttribute('xmlns', self.default_xmlns) return node.toprettyxml(indent=' ') def _to_xml_node(self, doc, metadata, nodename, data): """Recursive method to convert data members to XML nodes.""" result = doc.createElement(nodename) + + # Set the xml namespace if one is specified + # TODO(justinsb): We could also use prefixes on the keys + xmlns = metadata.get('xmlns', None) + if xmlns: + result.setAttribute('xmlns', xmlns) + if type(data) is list: singular = metadata.get('plurals', {}).get(nodename, None) if singular is None: -- cgit From 45d28dfb035b4e219845d44e00073d70211e8175 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 21:14:26 -0700 Subject: Fixed up unit tests and direct api that was also calling _serialize (naughty!) --- nova/api/direct.py | 4 +++- nova/tests/api/openstack/test_limits.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/nova/api/direct.py b/nova/api/direct.py index dfca250e0..153871e9f 100644 --- a/nova/api/direct.py +++ b/nova/api/direct.py @@ -206,7 +206,9 @@ class ServiceWrapper(wsgi.Controller): params = dict([(str(k), v) for (k, v) in params.iteritems()]) result = method(context, **params) if type(result) is dict or type(result) is list: - return self._serialize(result, req.best_match_content_type()) + content_type = req.best_match_content_type() + default_xmlns = self.get_default_xmlns(req) + return self._serialize(result, content_type, default_xmlns) else: return result diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 05cfacc60..df367005d 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -136,10 +136,17 @@ class LimitsControllerTest(BaseLimitTestSuite): request = self._get_index_request("application/xml") response = request.get_response(self.controller) - expected = "" - body = response.body.replace("\n", "").replace(" ", "") + expected = parseString(""" + + + + + """.replace(" ", "")) - self.assertEqual(expected, body) + body = parseString(response.body.replace(" ", "")) + + self.assertEqual(expected.toxml(), body.toxml()) def test_index_xml(self): """Test getting limit details in XML.""" @@ -148,7 +155,8 @@ class LimitsControllerTest(BaseLimitTestSuite): response = request.get_response(self.controller) expected = parseString(""" - + -- cgit From 9686b3a296c53486a64a949ae2f7430e25df2dcb Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 22 Mar 2011 21:18:31 -0700 Subject: Added note agreeing with Brian Lamar that the namespace doesn't belong in wsgi --- nova/wsgi.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova/wsgi.py b/nova/wsgi.py index 5d286bb3b..1bcc08f7f 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -391,6 +391,10 @@ class Controller(object): return serializer.deserialize(data, content_type) def get_default_xmlns(self, req): + # NOTE(justinsb): This doesn't really belong here.. + # We'll probably end up moving this into a new OpenstackApiController + # class or something like that, once we know what's going to happen + # with v1.1 return 'http://docs.rackspacecloud.com/servers/api/v1.0' -- cgit From 12505c6bae61e72b6c75ac647323c3ec15997df1 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 30 Mar 2011 10:05:06 -0700 Subject: Add XML namespaces to the OpenStack API --- nova/api/openstack/accounts.py | 5 ++- nova/api/openstack/backup_schedules.py | 4 +-- nova/api/openstack/common.py | 11 +++++++ nova/api/openstack/consoles.py | 4 +-- nova/api/openstack/extensions.py | 7 +++-- nova/api/openstack/flavors.py | 7 +++-- nova/api/openstack/image_metadata.py | 3 +- nova/api/openstack/images.py | 5 ++- nova/api/openstack/limits.py | 4 +-- nova/api/openstack/server_metadata.py | 3 +- nova/api/openstack/servers.py | 5 ++- nova/api/openstack/shared_ip_groups.py | 4 +-- nova/api/openstack/users.py | 3 +- nova/api/openstack/zones.py | 6 ++-- nova/tests/integrated/test_xml.py | 56 ++++++++++++++++++++++++++++++++++ nova/wsgi.py | 8 ++--- 16 files changed, 103 insertions(+), 32 deletions(-) create mode 100644 nova/tests/integrated/test_xml.py diff --git a/nova/api/openstack/accounts.py b/nova/api/openstack/accounts.py index 86066fa20..6e3763e47 100644 --- a/nova/api/openstack/accounts.py +++ b/nova/api/openstack/accounts.py @@ -13,15 +13,14 @@ # License for the specific language governing permissions and limitations # under the License. -import common import webob.exc from nova import exception from nova import flags from nova import log as logging -from nova import wsgi from nova.auth import manager +from nova.api.openstack import common from nova.api.openstack import faults FLAGS = flags.FLAGS @@ -35,7 +34,7 @@ def _translate_keys(account): manager=account.project_manager_id) -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): _serialization_metadata = { 'application/xml': { diff --git a/nova/api/openstack/backup_schedules.py b/nova/api/openstack/backup_schedules.py index f2d2d86e8..4bf744046 100644 --- a/nova/api/openstack/backup_schedules.py +++ b/nova/api/openstack/backup_schedules.py @@ -19,7 +19,7 @@ import time from webob import exc -from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults import nova.image.service @@ -29,7 +29,7 @@ def _translate_keys(inst): return dict(backupSchedule=inst) -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """ The backup schedule API controller for the Openstack API """ _serialization_metadata = { diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 75aeb0a5f..234f921ab 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -22,6 +22,7 @@ import webob from nova import exception from nova import flags from nova import log as logging +from nova import wsgi LOG = logging.getLogger('common') @@ -30,6 +31,10 @@ LOG = logging.getLogger('common') FLAGS = flags.FLAGS +XML_NS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0' +XML_NS_V11 = 'http://docs.openstack.org/compute/api/v1.1' + + def limited(items, request, max_limit=FLAGS.osapi_max_limit): """ Return a slice of items according to requested offset and limit. @@ -128,3 +133,9 @@ def get_id_from_href(href): except: LOG.debug(_("Error extracting id from href: %s") % href) raise webob.exc.HTTPBadRequest(_('could not parse id from href')) + + +class OpenstackController(wsgi.Controller): + def get_default_xmlns(self, req): + # Use V10 by default + return XML_NS_V10 diff --git a/nova/api/openstack/consoles.py b/nova/api/openstack/consoles.py index 8c291c2eb..1a77f25d7 100644 --- a/nova/api/openstack/consoles.py +++ b/nova/api/openstack/consoles.py @@ -19,7 +19,7 @@ from webob import exc from nova import console from nova import exception -from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults @@ -43,7 +43,7 @@ def _translate_detail_keys(cons): return dict(console=info) -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """The Consoles Controller for the Openstack API""" _serialization_metadata = { diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index fb1dccb28..75f369cac 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -28,6 +28,7 @@ from nova import exception from nova import flags from nova import log as logging from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults @@ -115,7 +116,7 @@ class ExtensionDescriptor(object): return response_exts -class ActionExtensionController(wsgi.Controller): +class ActionExtensionController(common.OpenstackController): def __init__(self, application): @@ -136,7 +137,7 @@ class ActionExtensionController(wsgi.Controller): return res -class ResponseExtensionController(wsgi.Controller): +class ResponseExtensionController(common.OpenstackController): def __init__(self, application): self.application = application @@ -163,7 +164,7 @@ class ResponseExtensionController(wsgi.Controller): return res -class ExtensionController(wsgi.Controller): +class ExtensionController(common.OpenstackController): def __init__(self, extension_manager): self.extension_manager = extension_manager diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index 5b99b5a6f..40787bd17 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -19,11 +19,11 @@ import webob from nova import db from nova import exception -from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import views -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """Flavor controller for the OpenStack API.""" _serialization_metadata = { @@ -76,3 +76,6 @@ class ControllerV11(Controller): def _get_view_builder(self, req): base_url = req.application_url return views.flavors.ViewBuilderV11(base_url) + + def get_default_xmlns(self, req): + return common.XML_NS_V11 diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index c9d6ac532..e673e5f7b 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -20,13 +20,14 @@ from webob import exc from nova import flags from nova import utils from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults FLAGS = flags.FLAGS -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """The image metadata API controller for the Openstack API""" def __init__(self): diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index e77100d7b..5550ee532 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -32,7 +32,7 @@ LOG = log.getLogger('nova.api.openstack.images') FLAGS = flags.FLAGS -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """Base `wsgi.Controller` for retrieving/displaying images.""" _serialization_metadata = { @@ -153,3 +153,6 @@ class ControllerV11(Controller): """Property to get the ViewBuilder class we need to use.""" base_url = request.application_url return images_view.ViewBuilderV11(base_url) + + def get_default_xmlns(self, req): + return common.XML_NS_V11 diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index efc7d193d..9877af191 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -31,8 +31,8 @@ from collections import defaultdict from webob.dec import wsgify from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults -from nova.wsgi import Controller from nova.wsgi import Middleware @@ -43,7 +43,7 @@ PER_HOUR = 60 * 60 PER_DAY = 60 * 60 * 24 -class LimitsController(Controller): +class LimitsController(common.OpenstackController): """ Controller for accessing limits in the OpenStack API. """ diff --git a/nova/api/openstack/server_metadata.py b/nova/api/openstack/server_metadata.py index 45bbac99d..5c1390b9c 100644 --- a/nova/api/openstack/server_metadata.py +++ b/nova/api/openstack/server_metadata.py @@ -19,10 +19,11 @@ from webob import exc from nova import compute from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """ The server metadata API controller for the Openstack API """ def __init__(self): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f7696d918..64090d830 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -44,7 +44,7 @@ LOG = logging.getLogger('server') FLAGS = flags.FLAGS -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """ The Server API controller for the OpenStack API """ _serialization_metadata = { @@ -632,6 +632,9 @@ class ControllerV11(Controller): def _limit_items(self, items, req): return common.limited_by_marker(items, req) + def get_default_xmlns(self, req): + return common.XML_NS_V11 + class ServerCreateRequestXMLDeserializer(object): """ diff --git a/nova/api/openstack/shared_ip_groups.py b/nova/api/openstack/shared_ip_groups.py index ee7991d7f..996db3648 100644 --- a/nova/api/openstack/shared_ip_groups.py +++ b/nova/api/openstack/shared_ip_groups.py @@ -17,7 +17,7 @@ from webob import exc -from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults @@ -32,7 +32,7 @@ def _translate_detail_keys(inst): return dict(sharedIpGroups=inst) -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): """ The Shared IP Groups Controller for the Openstack API """ _serialization_metadata = { diff --git a/nova/api/openstack/users.py b/nova/api/openstack/users.py index d3ab3d553..077ccfc79 100644 --- a/nova/api/openstack/users.py +++ b/nova/api/openstack/users.py @@ -18,7 +18,6 @@ from webob import exc from nova import exception from nova import flags from nova import log as logging -from nova import wsgi from nova.api.openstack import common from nova.api.openstack import faults from nova.auth import manager @@ -35,7 +34,7 @@ def _translate_keys(user): admin=user.admin) -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): _serialization_metadata = { 'application/xml': { diff --git a/nova/api/openstack/zones.py b/nova/api/openstack/zones.py index 846cb48a1..227ffecdc 100644 --- a/nova/api/openstack/zones.py +++ b/nova/api/openstack/zones.py @@ -13,12 +13,10 @@ # License for the specific language governing permissions and limitations # under the License. -import common - from nova import db from nova import flags from nova import log as logging -from nova import wsgi +from nova.api.openstack import common from nova.scheduler import api @@ -43,7 +41,7 @@ def _scrub_zone(zone): 'deleted', 'deleted_at', 'updated_at')) -class Controller(wsgi.Controller): +class Controller(common.OpenstackController): _serialization_metadata = { 'application/xml': { diff --git a/nova/tests/integrated/test_xml.py b/nova/tests/integrated/test_xml.py new file mode 100644 index 000000000..8a9754777 --- /dev/null +++ b/nova/tests/integrated/test_xml.py @@ -0,0 +1,56 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Justin Santa Barbara +# 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 nova import flags +from nova.log import logging +from nova.tests.integrated import integrated_helpers +from nova.api.openstack import common + + +LOG = logging.getLogger('nova.tests.integrated') + + +FLAGS = flags.FLAGS +FLAGS.verbose = True + + +class XmlTests(integrated_helpers._IntegratedTestBase): + """"Some basic XML sanity checks.""" + + def test_namespace_limits(self): + """/limits should have v1.0 namespace (hasn't changed in 1.1).""" + headers = {} + headers['Accept'] = 'application/xml' + + response = self.api.api_request('/limits', headers=headers) + data = response.read() + LOG.debug("data: %s" % data) + + prefix = ' Date: Wed, 30 Mar 2011 10:41:22 -0700 Subject: Some tests actually tested for the lack of a namespace :-) --- nova/api/openstack/extensions.py | 3 ++- nova/api/openstack/faults.py | 5 +++-- nova/api/openstack/images.py | 3 --- nova/tests/api/openstack/test_images.py | 16 +++++++++++----- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 75f369cac..7ea7afef6 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -156,7 +156,8 @@ class ResponseExtensionController(common.OpenstackController): body = res.body headers = res.headers except AttributeError: - body = self._serialize(res, content_type) + default_xmlns = None + body = self._serialize(res, content_type, default_xmlns) headers = {"Content-Type": content_type} res = webob.Response() res.body = body diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py index 0e9c4b26f..a05e97021 100644 --- a/nova/api/openstack/faults.py +++ b/nova/api/openstack/faults.py @@ -20,10 +20,10 @@ import webob.dec import webob.exc from nova import wsgi +from nova.api.openstack import common class Fault(webob.exc.HTTPException): - """An RS API fault response.""" _fault_names = { @@ -57,7 +57,8 @@ class Fault(webob.exc.HTTPException): fault_data[fault_name]['retryAfter'] = retry # 'code' is an attribute on the fault tag itself metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} - serializer = wsgi.Serializer(metadata) + default_xmlns = common.XML_NS_V10 + serializer = wsgi.Serializer(metadata, default_xmlns) content_type = req.best_match_content_type() self.wrapped_exc.body = serializer.serialize(fault_data, content_type) return self.wrapped_exc diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 5550ee532..77baf5947 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -13,8 +13,6 @@ # License for the specific language governing permissions and limitations # under the License. -import datetime - import webob.exc from nova import compute @@ -22,7 +20,6 @@ from nova import exception from nova import flags from nova import log from nova import utils -from nova import wsgi from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack.views import images as images_view diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index 57e447dce..ff3fe8976 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -146,7 +146,7 @@ class LocalImageServiceTest(_BaseImageServiceTests): for x in [1, 2, 3]: tempfile.mkstemp(prefix='ami-', dir=self.tempdir) # create some valid image directories names - for x in ["1485baed", "1a60f0ee", "3123a73d"]: + for x in ["1485baed", "1a60f0ee", "3123a73d"]: os.makedirs(os.path.join(self.tempdir, x)) found_image_ids = self.service._ids() self.assertEqual(True, isinstance(found_image_ids, list)) @@ -334,7 +334,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): name="public image" updated="%(expected_now)s" created="%(expected_now)s" - status="ACTIVE" /> + status="ACTIVE" + xmlns="http://docs.rackspacecloud.com/servers/api/v1.0" /> """ % (locals())) self.assertEqual(expected_image.toxml(), actual_image.toxml()) @@ -353,7 +354,8 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): name="public image" updated="%(expected_now)s" created="%(expected_now)s" - status="ACTIVE"> + status="ACTIVE" + xmlns="http://docs.openstack.org/compute/api/v1.1"> + Image not found. @@ -422,8 +425,11 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): response = request.get_response(fakes.wsgi_app()) self.assertEqual(404, response.status_int) + # NOTE(justinsb): I believe this should still use the v1.0 XSD, + # because the element hasn't changed definition expected = minidom.parseString(""" - + Image not found. -- cgit From d2aa73efed6f4eb731c4fe8dca3f4ceb5b36caeb Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 30 Mar 2011 10:49:09 -0700 Subject: More tests that were checking for no-namespace --- nova/tests/api/openstack/test_faults.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/nova/tests/api/openstack/test_faults.py b/nova/tests/api/openstack/test_faults.py index 7667753f4..505e7e308 100644 --- a/nova/tests/api/openstack/test_faults.py +++ b/nova/tests/api/openstack/test_faults.py @@ -20,6 +20,7 @@ import webob.dec import webob.exc from nova import test +from nova.api.openstack import common from nova.api.openstack import faults @@ -30,8 +31,11 @@ class TestFaults(test.TestCase): f = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram')) resp = req.get_response(f) - first_two_words = resp.body.strip().split()[:2] - self.assertEqual(first_two_words, ['']) + first_three_words = resp.body.strip().split()[:3] + self.assertEqual(first_three_words, + ['' % common.XML_NS_V10]) body_without_spaces = ''.join(resp.body.split()) self.assertTrue('scram' in body_without_spaces) @@ -41,8 +45,11 @@ class TestFaults(test.TestCase): headers={'Retry-After': 4}) f = faults.Fault(exc) resp = req.get_response(f) - first_two_words = resp.body.strip().split()[:2] - self.assertEqual(first_two_words, ['']) + first_three_words = resp.body.strip().split()[:3] + self.assertEqual(first_three_words, + ['' % common.XML_NS_V10]) body_sans_spaces = ''.join(resp.body.split()) self.assertTrue('sorry' in body_sans_spaces) self.assertTrue('4' in body_sans_spaces) -- cgit From 168fdb09f369287f3ec8c19ef73915280ff79d20 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 30 Mar 2011 11:15:16 -0700 Subject: Refixed unit test to check XML ns --- nova/tests/api/openstack/test_faults.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/tests/api/openstack/test_faults.py b/nova/tests/api/openstack/test_faults.py index b3433f45f..4d86ffb26 100644 --- a/nova/tests/api/openstack/test_faults.py +++ b/nova/tests/api/openstack/test_faults.py @@ -48,10 +48,10 @@ class TestFaults(test.TestCase): response = request.get_response(fault) expected = self._prepare_xml(""" - + scram - """) + """ % common.XML_NS_V10) actual = self._prepare_xml(response.body) self.assertEqual(response.content_type, "application/xml") @@ -92,11 +92,11 @@ class TestFaults(test.TestCase): response = request.get_response(fault) expected = self._prepare_xml(""" - + sorry 4 - """) + """ % common.XML_NS_V10) actual = self._prepare_xml(response.body) self.assertEqual(expected, actual) -- cgit From 7285694cb83ed618bea0d8c9170b725dd5566a27 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 5 Apr 2011 14:53:56 +0200 Subject: Add a find_data_files method to setup.py. Use it to get tools/ installed under /usr/(local/)/share/nova --- setup.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/setup.py b/setup.py index 20f4c1947..6c45109bc 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ # License for the specific language governing permissions and limitations # under the License. +import glob import os import subprocess import sys @@ -86,6 +87,19 @@ try: except: pass + +def find_data_files(destdir, srcdir): + package_data = [] + files = [] + for d in glob.glob('%s/*' % (srcdir, )): + if os.path.isdir(d): + package_data += find_data_files( + os.path.join(destdir, os.path.basename(d)), d) + else: + files += [d] + package_data += [(destdir, files)] + return package_data + DistUtilsExtra.auto.setup(name='nova', version=version.canonical_version_string(), description='cloud computing fabric controller', @@ -96,6 +110,7 @@ DistUtilsExtra.auto.setup(name='nova', packages=find_packages(exclude=['bin', 'smoketests']), include_package_data=True, test_suite='nose.collector', + data_files=find_data_files('share/nova', 'tools'), scripts=['bin/nova-ajax-console-proxy', 'bin/nova-api', 'bin/nova-compute', -- cgit From 669c0214ec77127ca7efe4d1e347ccaf2c2ae8b0 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 5 Apr 2011 14:54:11 +0200 Subject: Move api-paste.ini into a nova/ subdir of etc/ --- etc/api-paste.ini | 101 ------------------------------------------------- etc/nova/api-paste.ini | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 101 deletions(-) delete mode 100644 etc/api-paste.ini create mode 100644 etc/nova/api-paste.ini diff --git a/etc/api-paste.ini b/etc/api-paste.ini deleted file mode 100644 index abe8c20c4..000000000 --- a/etc/api-paste.ini +++ /dev/null @@ -1,101 +0,0 @@ -####### -# EC2 # -####### - -[composite:ec2] -use = egg:Paste#urlmap -/: ec2versions -/services/Cloud: ec2cloud -/services/Admin: ec2admin -/latest: ec2metadata -/2007-01-19: ec2metadata -/2007-03-01: ec2metadata -/2007-08-29: ec2metadata -/2007-10-10: ec2metadata -/2007-12-15: ec2metadata -/2008-02-01: ec2metadata -/2008-09-01: ec2metadata -/2009-04-04: ec2metadata -/1.0: ec2metadata - -[pipeline:ec2cloud] -pipeline = logrequest authenticate cloudrequest authorizer ec2executor -#pipeline = logrequest ec2lockout authenticate cloudrequest authorizer ec2executor - -[pipeline:ec2admin] -pipeline = logrequest authenticate adminrequest authorizer ec2executor - -[pipeline:ec2metadata] -pipeline = logrequest ec2md - -[pipeline:ec2versions] -pipeline = logrequest ec2ver - -[filter:logrequest] -paste.filter_factory = nova.api.ec2:RequestLogging.factory - -[filter:ec2lockout] -paste.filter_factory = nova.api.ec2:Lockout.factory - -[filter:authenticate] -paste.filter_factory = nova.api.ec2:Authenticate.factory - -[filter:cloudrequest] -controller = nova.api.ec2.cloud.CloudController -paste.filter_factory = nova.api.ec2:Requestify.factory - -[filter:adminrequest] -controller = nova.api.ec2.admin.AdminController -paste.filter_factory = nova.api.ec2:Requestify.factory - -[filter:authorizer] -paste.filter_factory = nova.api.ec2:Authorizer.factory - -[app:ec2executor] -paste.app_factory = nova.api.ec2:Executor.factory - -[app:ec2ver] -paste.app_factory = nova.api.ec2:Versions.factory - -[app:ec2md] -paste.app_factory = nova.api.ec2.metadatarequesthandler:MetadataRequestHandler.factory - -############# -# Openstack # -############# - -[composite:osapi] -use = egg:Paste#urlmap -/: osversions -/v1.0: openstackapi10 -/v1.1: openstackapi11 - -[pipeline:openstackapi10] -pipeline = faultwrap auth ratelimit osapiapp10 - -[pipeline:openstackapi11] -pipeline = faultwrap auth ratelimit extensions osapiapp11 - -[filter:faultwrap] -paste.filter_factory = nova.api.openstack:FaultWrapper.factory - -[filter:auth] -paste.filter_factory = nova.api.openstack.auth:AuthMiddleware.factory - -[filter:ratelimit] -paste.filter_factory = nova.api.openstack.limits:RateLimitingMiddleware.factory - -[filter:extensions] -paste.filter_factory = nova.api.openstack.extensions:ExtensionMiddleware.factory - -[app:osapiapp10] -paste.app_factory = nova.api.openstack:APIRouterV10.factory - -[app:osapiapp11] -paste.app_factory = nova.api.openstack:APIRouterV11.factory - -[pipeline:osversions] -pipeline = faultwrap osversionapp - -[app:osversionapp] -paste.app_factory = nova.api.openstack.versions:Versions.factory diff --git a/etc/nova/api-paste.ini b/etc/nova/api-paste.ini new file mode 100644 index 000000000..abe8c20c4 --- /dev/null +++ b/etc/nova/api-paste.ini @@ -0,0 +1,101 @@ +####### +# EC2 # +####### + +[composite:ec2] +use = egg:Paste#urlmap +/: ec2versions +/services/Cloud: ec2cloud +/services/Admin: ec2admin +/latest: ec2metadata +/2007-01-19: ec2metadata +/2007-03-01: ec2metadata +/2007-08-29: ec2metadata +/2007-10-10: ec2metadata +/2007-12-15: ec2metadata +/2008-02-01: ec2metadata +/2008-09-01: ec2metadata +/2009-04-04: ec2metadata +/1.0: ec2metadata + +[pipeline:ec2cloud] +pipeline = logrequest authenticate cloudrequest authorizer ec2executor +#pipeline = logrequest ec2lockout authenticate cloudrequest authorizer ec2executor + +[pipeline:ec2admin] +pipeline = logrequest authenticate adminrequest authorizer ec2executor + +[pipeline:ec2metadata] +pipeline = logrequest ec2md + +[pipeline:ec2versions] +pipeline = logrequest ec2ver + +[filter:logrequest] +paste.filter_factory = nova.api.ec2:RequestLogging.factory + +[filter:ec2lockout] +paste.filter_factory = nova.api.ec2:Lockout.factory + +[filter:authenticate] +paste.filter_factory = nova.api.ec2:Authenticate.factory + +[filter:cloudrequest] +controller = nova.api.ec2.cloud.CloudController +paste.filter_factory = nova.api.ec2:Requestify.factory + +[filter:adminrequest] +controller = nova.api.ec2.admin.AdminController +paste.filter_factory = nova.api.ec2:Requestify.factory + +[filter:authorizer] +paste.filter_factory = nova.api.ec2:Authorizer.factory + +[app:ec2executor] +paste.app_factory = nova.api.ec2:Executor.factory + +[app:ec2ver] +paste.app_factory = nova.api.ec2:Versions.factory + +[app:ec2md] +paste.app_factory = nova.api.ec2.metadatarequesthandler:MetadataRequestHandler.factory + +############# +# Openstack # +############# + +[composite:osapi] +use = egg:Paste#urlmap +/: osversions +/v1.0: openstackapi10 +/v1.1: openstackapi11 + +[pipeline:openstackapi10] +pipeline = faultwrap auth ratelimit osapiapp10 + +[pipeline:openstackapi11] +pipeline = faultwrap auth ratelimit extensions osapiapp11 + +[filter:faultwrap] +paste.filter_factory = nova.api.openstack:FaultWrapper.factory + +[filter:auth] +paste.filter_factory = nova.api.openstack.auth:AuthMiddleware.factory + +[filter:ratelimit] +paste.filter_factory = nova.api.openstack.limits:RateLimitingMiddleware.factory + +[filter:extensions] +paste.filter_factory = nova.api.openstack.extensions:ExtensionMiddleware.factory + +[app:osapiapp10] +paste.app_factory = nova.api.openstack:APIRouterV10.factory + +[app:osapiapp11] +paste.app_factory = nova.api.openstack:APIRouterV11.factory + +[pipeline:osversions] +pipeline = faultwrap osversionapp + +[app:osversionapp] +paste.app_factory = nova.api.openstack.versions:Versions.factory -- cgit -- cgit From 6c8c454826263b334eb674c9ab1c8d62e5fd491f Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 5 Apr 2011 14:55:19 +0200 Subject: Help paste_config_file find the api config now that we moved it. --- nova/wsgi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/wsgi.py b/nova/wsgi.py index ba0819466..05e7d5924 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -532,6 +532,7 @@ def paste_config_file(basename): """ configfiles = [basename, + os.path.join(FLAGS.state_path, 'etc', 'nova', basename), os.path.join(FLAGS.state_path, 'etc', basename), os.path.join(FLAGS.state_path, basename), '/etc/nova/%s' % basename] -- cgit From d99a40d0a34a0d7ec05dcaa188a58535f0e41953 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 6 Apr 2011 14:05:12 +0200 Subject: Only create ca_path directory if it does not already exist. --- nova/api/ec2/cloud.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 99520b302..58effd134 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -110,7 +110,8 @@ class CloudController(object): 'genrootca.sh') start = os.getcwd() - os.makedirs(FLAGS.ca_path) + if not os.path.exists(FLAGS.ca_path): + os.makedirs(FLAGS.ca_path) os.chdir(FLAGS.ca_path) # TODO(vish): Do this with M2Crypto instead utils.runthis(_("Generating root CA: %s"), "sh", genrootca_sh_path) -- cgit -- cgit From 0a8ca1bb7f123718ae48bb842b1c532b07f03890 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 6 Apr 2011 18:10:42 +0200 Subject: Create ca_folder if it does not already exist. --- nova/crypto.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/crypto.py b/nova/crypto.py index 2b122e560..9b1897926 100644 --- a/nova/crypto.py +++ b/nova/crypto.py @@ -269,6 +269,8 @@ def _sign_csr(csr_text, ca_folder): LOG.debug(_("Flags path: %s"), ca_folder) start = os.getcwd() # Change working dir to CA + if not os.path.exists(ca_folder): + os.makedirs(ca_folder) os.chdir(ca_folder) utils.execute('openssl', 'ca', '-batch', '-out', outbound, '-config', './openssl.cnf', '-infiles', inbound) -- cgit