Add ca_certificates_file option to test against SSL servers

tempest has an option to ignore SSL errors
(disable_ssl_certificate_validation) but no way to pass in
a CA bundle to be used to do actual validation. This new option,
ca_certificates_file, will provide this bundle.

boto testing will be handled separately as it gets CA
certificates from its configuration file.

This is configured in either /etc/boto.cfg or the file pointed
to by $BOTO_CONFIG via:

[Boto]
ca_certificates_file = /path/to/ca-bundle.pem

Change-Id: I5662e881f7d71ed34a8fe4b9d0a2541a6ff1bad3
Closes-bug: #1395754
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index b70b446..3c6eb44 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -578,6 +578,10 @@
 # (string value)
 #auth_version = v2
 
+# Specify a CA bundle file to use in verifying a TLS (https) server
+# certificate. (string value)
+#ca_certificates_file = <None>
+
 # Catalog type of the Identity service. (string value)
 #catalog_type = identity
 
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index ac1217c..4c3905c 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -123,8 +123,9 @@
                                        'retry-after', 'server',
                                        'vary', 'www-authenticate'))
         dscv = CONF.identity.disable_ssl_certificate_validation
+        ca_certs = CONF.identity.ca_certificates_file
         self.http_obj = http.ClosingHttp(
-            disable_ssl_certificate_validation=dscv)
+            disable_ssl_certificate_validation=dscv, ca_certs=ca_certs)
 
     def _get_type(self):
         return self.TYPE
diff --git a/tempest/config.py b/tempest/config.py
index b467f83..03346c9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -71,6 +71,10 @@
     cfg.BoolOpt('disable_ssl_certificate_validation',
                 default=False,
                 help="Set to True if using self-signed SSL certificates."),
+    cfg.StrOpt('ca_certificates_file',
+               default=None,
+               help='Specify a CA bundle file to use in verifying a '
+                    'TLS (https) server certificate.'),
     cfg.StrOpt('uri',
                help="Full URI of the OpenStack Identity API (Keystone), v2"),
     cfg.StrOpt('uri_v3',
diff --git a/tempest/scenario/test_swift_basic_ops.py b/tempest/scenario/test_swift_basic_ops.py
index fcb9505..312fbc6 100644
--- a/tempest/scenario/test_swift_basic_ops.py
+++ b/tempest/scenario/test_swift_basic_ops.py
@@ -65,7 +65,10 @@
         obj_name, _ = self.upload_object_to_container(container_name)
         obj_url = '%s/%s/%s' % (self.object_client.base_url,
                                 container_name, obj_name)
-        http_client = http.ClosingHttp()
+        dscv = CONF.identity.disable_ssl_certificate_validation
+        ca_certs = CONF.identity.ca_certificates_file
+        http_client = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv, ca_certs=ca_certs)
         resp, _ = http_client.request(obj_url, 'GET')
         self.assertEqual(resp.status, 401)
         self.change_container_acl(container_name, '.r:*')
diff --git a/tempest/services/botoclients.py b/tempest/services/botoclients.py
index 7af904b..f581e89 100644
--- a/tempest/services/botoclients.py
+++ b/tempest/services/botoclients.py
@@ -38,6 +38,7 @@
         # FIXME(andreaf) replace credentials and auth_url with auth_provider
 
         insecure_ssl = CONF.identity.disable_ssl_certificate_validation
+        ca_cert = CONF.identity.ca_certificates_file
 
         self.connection_timeout = str(CONF.boto.http_socket_timeout)
         self.num_retries = str(CONF.boto.num_retries)
@@ -46,7 +47,8 @@
                         "password": password,
                         "auth_url": auth_url,
                         "tenant_name": tenant_name,
-                        "insecure": insecure_ssl}
+                        "insecure": insecure_ssl,
+                        "cacert": ca_cert}
 
     def _keystone_aws_get(self):
         # FIXME(andreaf) Move EC2 credentials to AuthProvider
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index d0d32e5..d60c9d9 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -106,9 +106,10 @@
 
     def _get_http(self):
         dscv = CONF.identity.disable_ssl_certificate_validation
+        ca_certs = CONF.identity.ca_certificates_file
         return glance_http.HTTPClient(auth_provider=self.auth_provider,
                                       filters=self.filters,
-                                      insecure=dscv)
+                                      insecure=dscv, ca_certs=ca_certs)
 
     def _create_with_data(self, headers, data):
         resp, body_iter = self.http.raw_request('POST', '/v1/images',
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 4865073..7421508 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -35,9 +35,10 @@
 
     def _get_http(self):
         dscv = CONF.identity.disable_ssl_certificate_validation
+        ca_certs = CONF.identity.ca_certificates_file
         return glance_http.HTTPClient(auth_provider=self.auth_provider,
                                       filters=self.filters,
-                                      insecure=dscv)
+                                      insecure=dscv, ca_certs=ca_certs)
 
     def _validate_schema(self, body, type='image'):
         if type in ['image', 'images']:
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 4417e3b..a2044ef 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -181,7 +181,11 @@
     def request(self, method, url, extra_headers=False, headers=None,
                 body=None):
         """A simple HTTP request interface."""
-        self.http_obj = http.ClosingHttp()
+        dscv = CONF.identity.disable_ssl_certificate_validation
+        ca_certs = CONF.identity.ca_certificates_file
+        self.http_obj = http.ClosingHttp(
+            disable_ssl_certificate_validation=dscv,
+            ca_certs=ca_certs)
         if headers is None:
             headers = {}
         elif extra_headers:
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 2231407..7a69fa8 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -197,8 +197,10 @@
                 body=None):
         """A simple HTTP request interface."""
         dscv = CONF.identity.disable_ssl_certificate_validation
+        ca_certs = CONF.identity.ca_certificates_file
         self.http_obj = http.ClosingHttp(
-            disable_ssl_certificate_validation=dscv)
+            disable_ssl_certificate_validation=dscv,
+            ca_certs=ca_certs)
         if headers is None:
             headers = {}
         elif extra_headers: