From eb2a6fe8a71636e2bbbc424ec9ef396646972184 Mon Sep 17 00:00:00 2001
From: Brian Hoenig <brian.hoenig@rackspace.com>
Date: Mon, 26 Sep 2011 17:15:50 -0500
Subject: [PATCH] Add new Exception class for failed http requests

---
 libcloud/common/base.py        |    6 +++++-
 libcloud/common/types.py       |   17 ++++++++++++++++-
 libcloud/compute/types.py      |    7 +++++--
 test/compute/test_openstack.py |   10 ++++++++++
 4 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/libcloud/common/base.py b/libcloud/common/base.py
index 2b51792..7d2a1da 100644
--- a/libcloud/common/base.py
+++ b/libcloud/common/base.py
@@ -26,6 +26,8 @@ from libcloud.common.types import LibcloudError
 
 from libcloud.httplib_ssl import LibcloudHTTPSConnection
 from httplib import HTTPConnection as LibcloudHTTPConnection
+from libcloud.compute.types import ProviderHTTPResponseError
+
 
 class Response(object):
     """
@@ -47,7 +49,9 @@ class Response(object):
         self.error = response.reason
 
         if not self.success():
-            raise Exception(self.parse_error())
+            raise ProviderHTTPResponseError(self.parse_error(),
+                                            self.status,
+                                            self.error)
 
         self.object = self.parse_body()
 
diff --git a/libcloud/common/types.py b/libcloud/common/types.py
index 17e7b84..4a38800 100644
--- a/libcloud/common/types.py
+++ b/libcloud/common/types.py
@@ -18,7 +18,8 @@ __all__ = [
     "MalformedResponseError",
     "InvalidCredsError",
     "InvalidCredsException",
-    "LazyList"
+    "ProviderHTTPResponseError",
+    "LazyList",
     ]
 
 
@@ -67,6 +68,20 @@ class InvalidCredsError(LibcloudError):
         return repr(self.value)
 
 
+class ProviderHTTPResponseError(Exception):
+    """Exception used when provider returns an HTTP Error Code"""
+
+    def __init__(self, value, error_code, error):
+
+        # previously this was a vanilla Exception, so make
+        # it behave as one for those expecting it
+        super(ProviderHTTPResponseError, self).__init__(value)
+
+        self.value = value
+        self.http_error_code = error_code
+        self.http_error_message = error
+
+
 # Deprecated alias of L{InvalidCredsError}
 InvalidCredsException = InvalidCredsError
 
diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py
index fd1af9e..ccab6ba 100644
--- a/libcloud/compute/types.py
+++ b/libcloud/compute/types.py
@@ -17,7 +17,9 @@ Base types used by other parts of libcloud
 """
 
 from libcloud.common.types import LibcloudError, MalformedResponseError
-from libcloud.common.types import InvalidCredsError, InvalidCredsException
+from libcloud.common.types import (InvalidCredsError,
+                                   InvalidCredsException,
+                                   ProviderHTTPResponseError)
 __all__ = [
     "Provider",
     "NodeState",
@@ -28,7 +30,8 @@ __all__ = [
     "LibcloudError",
     "MalformedResponseError",
     "InvalidCredsError",
-    "InvalidCredsException"
+    "InvalidCredsException",
+    "ProviderHTTPResponseError",
     ]
 class Provider(object):
     """
diff --git a/test/compute/test_openstack.py b/test/compute/test_openstack.py
index 8b2faf0..3b44712 100644
--- a/test/compute/test_openstack.py
+++ b/test/compute/test_openstack.py
@@ -20,6 +20,7 @@ from libcloud.common.types import InvalidCredsError, MalformedResponseError
 from libcloud.compute.drivers.rackspace import OpenStack_1_0_NodeDriver, OpenStack_1_0_Response
 from libcloud.compute.base import Node, NodeImage, NodeSize
 from libcloud.pricing import set_pricing, clear_pricing_data
+from libcloud.compute.types import ProviderHTTPResponseError
 
 from test import MockResponse, MockHttpTestCase, XML_HEADERS
 from test.file_fixtures import ComputeFileFixtures, OpenStackFixtures
@@ -31,6 +32,15 @@ from test.secrets import OPENSTACK_PARAMS
 class OpenStackResponseTestCase(unittest.TestCase):
     XML = """<?xml version="1.0" encoding="UTF-8"?><root/>"""
 
+    def test_http_error_response(self):
+        try:
+            http_response = MockResponse(httplib.BAD_REQUEST, OpenStackResponseTestCase.XML, headers={'content-type': 'application/xml'})
+            OpenStack_1_0_Response(http_response)
+        except ProviderHTTPResponseError, e:
+            self.assertEqual(e.http_error_code, httplib.BAD_REQUEST)
+        else:
+            self.fail('test should have thrown')
+
     def test_simple_xml_content_type_handling(self):
         http_response = MockResponse(200, OpenStackResponseTestCase.XML, headers={'content-type': 'application/xml'})
         body = OpenStack_1_0_Response(http_response).parse_body()
-- 
1.7.4.1

