From 2af6fb2a4d3659e9882a6f6d1c8e71bc8f040aba Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Tue, 29 Mar 2011 14:56:18 -0400 Subject: Added content_type to OSAPI faults. --- nova/api/openstack/faults.py | 1 + nova/tests/api/openstack/test_faults.py | 122 ++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 20 deletions(-) diff --git a/nova/api/openstack/faults.py b/nova/api/openstack/faults.py index 0e9c4b26f..940bd8771 100644 --- a/nova/api/openstack/faults.py +++ b/nova/api/openstack/faults.py @@ -60,6 +60,7 @@ class Fault(webob.exc.HTTPException): serializer = wsgi.Serializer(metadata) content_type = req.best_match_content_type() self.wrapped_exc.body = serializer.serialize(fault_data, content_type) + self.wrapped_exc.content_type = content_type return self.wrapped_exc diff --git a/nova/tests/api/openstack/test_faults.py b/nova/tests/api/openstack/test_faults.py index 7667753f4..0cda542de 100644 --- a/nova/tests/api/openstack/test_faults.py +++ b/nova/tests/api/openstack/test_faults.py @@ -15,6 +15,8 @@ # License for the specific language governing permissions and limitations # under the License. +import json + import webob import webob.dec import webob.exc @@ -24,35 +26,115 @@ from nova.api.openstack import faults class TestFaults(test.TestCase): + """Tests covering `nova.api.openstack.faults:Fault` class.""" - def test_fault_parts(self): - req = webob.Request.blank('/.xml') - f = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram')) - resp = req.get_response(f) + def _prepare_xml(self, xml_string): + """Remove characters from string which hinder XML equality testing.""" + xml_string = xml_string.replace(" ", "") + xml_string = xml_string.replace("\n", "") + xml_string = xml_string.replace("\t", "") + return xml_string - first_two_words = resp.body.strip().split()[:2] - self.assertEqual(first_two_words, ['']) - body_without_spaces = ''.join(resp.body.split()) - self.assertTrue('scram' in body_without_spaces) + def test_400_fault_xml(self): + """Test fault serialized to XML via file-extension and/or header.""" + requests = [ + webob.Request.blank('/.xml'), + webob.Request.blank('/', headers={"Accept": "application/xml"}), + ] - def test_retry_header(self): - req = webob.Request.blank('/.xml') - exc = webob.exc.HTTPRequestEntityTooLarge(explanation='sorry', - 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, ['']) - body_sans_spaces = ''.join(resp.body.split()) - self.assertTrue('sorry' in body_sans_spaces) - self.assertTrue('4' in body_sans_spaces) - self.assertEqual(resp.headers['Retry-After'], 4) + for request in requests: + fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram')) + response = request.get_response(fault) + + expected = self._prepare_xml(""" + + scram + + """) + actual = self._prepare_xml(response.body) + + self.assertEqual(response.content_type, "application/xml") + self.assertEqual(expected, actual) + + def test_400_fault_json(self): + """Test fault serialized to JSON via file-extension and/or header.""" + requests = [ + webob.Request.blank('/.json'), + webob.Request.blank('/', headers={"Accept": "application/json"}), + ] + + for request in requests: + fault = faults.Fault(webob.exc.HTTPBadRequest(explanation='scram')) + response = request.get_response(fault) + + expected = { + "badRequest": { + "message": "scram", + "code": 400, + }, + } + actual = json.loads(response.body) + + self.assertEqual(response.content_type, "application/json") + self.assertEqual(expected, actual) + + def test_413_fault_xml(self): + requests = [ + webob.Request.blank('/.xml'), + webob.Request.blank('/', headers={"Accept": "application/xml"}), + ] + + for request in requests: + exc = webob.exc.HTTPRequestEntityTooLarge + fault = faults.Fault(exc(explanation='sorry', + headers={'Retry-After': 4})) + response = request.get_response(fault) + + expected = self._prepare_xml(""" + + sorry + 4 + + """) + actual = self._prepare_xml(response.body) + + self.assertEqual(expected, actual) + self.assertEqual(response.content_type, "application/xml") + self.assertEqual(response.headers['Retry-After'], 4) + + def test_413_fault_json(self): + """Test fault serialized to JSON via file-extension and/or header.""" + requests = [ + webob.Request.blank('/.json'), + webob.Request.blank('/', headers={"Accept": "application/json"}), + ] + + for request in requests: + exc = webob.exc.HTTPRequestEntityTooLarge + fault = faults.Fault(exc(explanation='sorry', + headers={'Retry-After': 4})) + response = request.get_response(fault) + + expected = { + "overLimit": { + "message": "sorry", + "code": 413, + "retryAfter": 4, + }, + } + actual = json.loads(response.body) + + self.assertEqual(response.content_type, "application/json") + self.assertEqual(expected, actual) def test_raise(self): + """Ensure the ability to raise exceptions in WSGI-ified methods.""" @webob.dec.wsgify def raiser(req): raise faults.Fault(webob.exc.HTTPNotFound(explanation='whut?')) + req = webob.Request.blank('/.xml') resp = req.get_response(raiser) + self.assertEqual(resp.content_type, "application/xml") self.assertEqual(resp.status_int, 404) self.assertTrue('whut?' in resp.body) -- cgit From 047af2c506374aa44bb896a7df0cb5813bf3a123 Mon Sep 17 00:00:00 2001 From: Thierry Carrez Date: Wed, 30 Mar 2011 15:02:59 +0200 Subject: Add missing method that prevent HyperV compute nodes from starting up --- nova/virt/hyperv.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index a1ed5ebbf..13f403a66 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -485,3 +485,7 @@ class HyperVConnection(driver.ComputeDriver): def poll_rescued_instances(self, timeout): pass + + def update_available_resource(self, ctxt, host): + """This method is supported only by libvirt.""" + return -- cgit From b1589b5f034db95b1d18910e27cae516258a4311 Mon Sep 17 00:00:00 2001 From: Brian Lamar Date: Wed, 30 Mar 2011 09:39:35 -0400 Subject: exception -> Fault --- nova/tests/api/openstack/test_faults.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/api/openstack/test_faults.py b/nova/tests/api/openstack/test_faults.py index 0cda542de..9746e8168 100644 --- a/nova/tests/api/openstack/test_faults.py +++ b/nova/tests/api/openstack/test_faults.py @@ -128,7 +128,7 @@ class TestFaults(test.TestCase): self.assertEqual(expected, actual) def test_raise(self): - """Ensure the ability to raise exceptions in WSGI-ified methods.""" + """Ensure the ability to raise `Fault`s in WSGI-ified methods.""" @webob.dec.wsgify def raiser(req): raise faults.Fault(webob.exc.HTTPNotFound(explanation='whut?')) -- cgit From de9091a74107827b8f7157d6b89c2fb5dcf92dd2 Mon Sep 17 00:00:00 2001 From: Sandy Walsh Date: Wed, 30 Mar 2011 08:29:17 -0700 Subject: queues properly reconnect if rabbitmq is restarted --- nova/rpc.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/nova/rpc.py b/nova/rpc.py index 388f78d69..be7cb3f37 100644 --- a/nova/rpc.py +++ b/nova/rpc.py @@ -74,7 +74,12 @@ class Connection(carrot_connection.BrokerConnection): """Recreates the connection instance This is necessary to recover from some network errors/disconnects""" - del cls._instance + try: + del cls._instance + except AttributeError, e: + # The _instance stuff is for testing purposes. Usually we don't use + # it. So don't freak out if it doesn't exist. + pass return cls.instance() @@ -125,10 +130,12 @@ class Consumer(messaging.Consumer): # NOTE(vish): This is catching all errors because we really don't # want exceptions to be logged 10 times a second if some # persistent failure occurs. - except Exception: # pylint: disable=W0703 + except Exception, e: # pylint: disable=W0703 if not self.failed_connection: - LOG.exception(_("Failed to fetch message from queue")) + LOG.exception(_("Failed to fetch message from queue: %s" % e)) self.failed_connection = True + else: + LOG.exception(_("Unhandled exception %s" % e)) def attach_to_eventlet(self): """Only needed for unit tests!""" -- cgit From 23776e5b2bdb73df10be590b589c34788c28023a Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Wed, 30 Mar 2011 12:28:09 -0500 Subject: Avoid hard dependencies --- nova/virt/vmwareapi_conn.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index 87c3fa299..34d29a4e5 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -43,10 +43,12 @@ from nova import flags from nova import log as logging from nova import utils from nova.virt.vmwareapi import error_util -from nova.virt.vmwareapi import vim from nova.virt.vmwareapi import vim_util from nova.virt.vmwareapi.vmops import VMWareVMOps + +vim = None + LOG = logging.getLogger("nova.virt.vmwareapi_conn") FLAGS = flags.FLAGS @@ -78,6 +80,13 @@ flags.DEFINE_string('vmwareapi_vlan_interface', TIME_BETWEEN_API_CALL_RETRIES = 2.0 +def get_imported_vim(): + """Avoid any hard dependencies.""" + global vim + if vim is None: + vim = __import__("nova.virt.vmwareapi.vim") + + class Failure(Exception): """Base Exception class for handling task failures.""" @@ -109,7 +118,7 @@ class VMWareESXConnection(object): def __init__(self, host_ip, host_username, host_password, api_retry_count, scheme="https"): session = VMWareAPISession(host_ip, host_username, host_password, - api_retry_count, scheme=scheme) + api_retry_count, scheme=scheme) self._vmops = VMWareVMOps(session) def init_host(self, host): @@ -204,6 +213,7 @@ class VMWareAPISession(object): self._session_id = None self.vim = None self._create_session() + get_imported_vim() def _get_vim_object(self): """Create the VIM Object instance.""" -- cgit From be4be55bf03c907f46e76fffe3457743915d734a Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Wed, 30 Mar 2011 13:50:02 -0500 Subject: Handle in vim.py --- nova/virt/vmwareapi/vim.py | 15 +++++++++++---- nova/virt/vmwareapi_conn.py | 10 ---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/nova/virt/vmwareapi/vim.py b/nova/virt/vmwareapi/vim.py index ba14f1512..1c850595d 100644 --- a/nova/virt/vmwareapi/vim.py +++ b/nova/virt/vmwareapi/vim.py @@ -21,10 +21,14 @@ Classes for making VMware VI SOAP calls. import httplib -from suds import WebFault -from suds.client import Client -from suds.plugin import MessagePlugin -from suds.sudsobject import Property +try: + suds = True + from suds import WebFault + from suds.client import Client + from suds.plugin import MessagePlugin + from suds.sudsobject import Property +except ImportError: + suds = False from nova import flags from nova.virt.vmwareapi import error_util @@ -75,6 +79,9 @@ class Vim: protocol: http or https host : ESX IPAddress[:port] or ESX Hostname[:port] """ + if not suds: + raise Exception(_("Unable to import suds.")) + self._protocol = protocol self._host_name = host wsdl_url = FLAGS.vmwareapi_wsdl_loc diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index 34d29a4e5..b909e659d 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -47,8 +47,6 @@ from nova.virt.vmwareapi import vim_util from nova.virt.vmwareapi.vmops import VMWareVMOps -vim = None - LOG = logging.getLogger("nova.virt.vmwareapi_conn") FLAGS = flags.FLAGS @@ -80,13 +78,6 @@ flags.DEFINE_string('vmwareapi_vlan_interface', TIME_BETWEEN_API_CALL_RETRIES = 2.0 -def get_imported_vim(): - """Avoid any hard dependencies.""" - global vim - if vim is None: - vim = __import__("nova.virt.vmwareapi.vim") - - class Failure(Exception): """Base Exception class for handling task failures.""" @@ -213,7 +204,6 @@ class VMWareAPISession(object): self._session_id = None self.vim = None self._create_session() - get_imported_vim() def _get_vim_object(self): """Create the VIM Object instance.""" -- cgit From 2eadc55dbd66af7b5adb3c21fe9cc91cd04b0f8b Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Wed, 30 Mar 2011 13:56:02 -0500 Subject: Whoops --- nova/virt/vmwareapi_conn.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index b909e659d..20c1b2b45 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -43,6 +43,7 @@ from nova import flags from nova import log as logging from nova import utils from nova.virt.vmwareapi import error_util +from nova.virt.vmwareapi import vim from nova.virt.vmwareapi import vim_util from nova.virt.vmwareapi.vmops import VMWareVMOps -- cgit