close http connections

Running full tempest one might run out of file descriptors. httplib2
does not close the connection by default. This patch adds
connection:close header to every request, so that sockets won't be
hanging around.

fixes bug 1215804

Change-Id: Iea19936c45add98fc66588f623854e629cf448fb
diff --git a/tempest/common/http.py b/tempest/common/http.py
new file mode 100644
index 0000000..49dca18
--- /dev/null
+++ b/tempest/common/http.py
@@ -0,0 +1,27 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack, LLC
+# Copyright 2013 Citrix Systems, Inc.
+# 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.
+
+import httplib2
+
+
+class ClosingHttp(httplib2.Http):
+    def request(self, *args, **kwargs):
+        original_headers = kwargs.get('headers', {})
+        new_headers = dict(original_headers, connection='close')
+        new_kwargs = dict(kwargs, headers=new_headers)
+        return super(ClosingHttp, self).request(*args, **new_kwargs)
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index ea5b4f4..d744e3d 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -18,12 +18,12 @@
 
 import collections
 import hashlib
-import httplib2
 import json
 from lxml import etree
 import re
 import time
 
+from tempest.common import http
 from tempest import exceptions
 from tempest.openstack.common import log as logging
 from tempest.services.compute.xml.common import xml_to_json
@@ -64,7 +64,8 @@
                                        'retry-after', 'server',
                                        'vary', 'www-authenticate'))
         dscv = self.config.identity.disable_ssl_certificate_validation
-        self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv)
 
     def _set_auth(self):
         """
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index 90e64e7..47977df 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -12,9 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import httplib2
 import json
 
+from tempest.common import http
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
 
@@ -260,7 +260,8 @@
     def request(self, method, url, headers=None, body=None):
         """A simple HTTP request interface."""
         dscv = self.config.identity.disable_ssl_certificate_validation
-        self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv)
         if headers is None:
             headers = {}
 
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index f81fccf..e211cee 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -16,9 +16,9 @@
 #    under the License.
 import urlparse
 
-import httplib2
 from lxml import etree
 
+from tempest.common import http
 from tempest.common.rest_client import RestClientXML
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
@@ -50,7 +50,8 @@
     def request(self, method, url, headers=None, body=None, wait=None):
         """Overriding the existing HTTP request in super class RestClient."""
         dscv = self.config.identity.disable_ssl_certificate_validation
-        self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv)
         self._set_auth()
         self.base_url = self.base_url.replace(
             urlparse.urlparse(self.base_url).path, "/v3")
diff --git a/tempest/services/identity/v3/xml/policy_client.py b/tempest/services/identity/v3/xml/policy_client.py
index c3f6d99..0f07728 100644
--- a/tempest/services/identity/v3/xml/policy_client.py
+++ b/tempest/services/identity/v3/xml/policy_client.py
@@ -17,9 +17,9 @@
 
 from urlparse import urlparse
 
-import httplib2
 from lxml import etree
 
+from tempest.common import http
 from tempest.common.rest_client import RestClientXML
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
@@ -51,7 +51,8 @@
     def request(self, method, url, headers=None, body=None, wait=None):
         """Overriding the existing HTTP request in super class RestClient."""
         dscv = self.config.identity.disable_ssl_certificate_validation
-        self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv)
         self._set_auth()
         self.base_url = self.base_url.replace(urlparse(self.base_url).path,
                                               "/v3")
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
index 99a155a..7a00b84 100644
--- a/tempest/services/identity/xml/identity_client.py
+++ b/tempest/services/identity/xml/identity_client.py
@@ -15,11 +15,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import httplib2
 import json
 
 from lxml import etree
 
+from tempest.common import http
 from tempest.common.rest_client import RestClientXML
 from tempest import exceptions
 from tempest.services.compute.xml.common import Document
@@ -275,7 +275,8 @@
     def request(self, method, url, headers=None, body=None):
         """A simple HTTP request interface."""
         dscv = self.config.identity.disable_ssl_certificate_validation
-        self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv)
         if headers is None:
             headers = {}
         self._log_request(method, url, headers, body)
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 8defbbb..eb9910f 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -15,10 +15,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import httplib2
 import json
 import urllib
 
+from tempest.common import http
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
 
@@ -108,7 +108,7 @@
 
     def request(self, method, url, headers=None, body=None):
         """A simple HTTP request interface."""
-        self.http_obj = httplib2.Http()
+        self.http_obj = http.ClosingHttp()
         if headers is None:
             headers = {}
         if self.base_url is None:
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 181838e..1c97869 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -17,9 +17,9 @@
 
 import hashlib
 import hmac
-import httplib2
 import urlparse
 
+from tempest.common import http
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
 
@@ -162,7 +162,8 @@
     def request(self, method, url, headers=None, body=None):
         """A simple HTTP request interface."""
         dscv = self.config.identity.disable_ssl_certificate_validation
-        self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv)
         if headers is None:
             headers = {}
         if self.base_url is None: