Make endpoint type configurable

Allow to specify the endpoint type to use for each service. Not everybody will
want to use publicURL, so let's make this configurable.

Closes-Bug: #1178083
Change-Id: Idb414aef7510178efef59cb48149ff1d86f11cb1
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 025d0f3..b779068 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -261,6 +261,10 @@
 # value)
 #region=
 
+# The endpoint type to use for the compute service. (string
+# value)
+#endpoint_type=publicURL
+
 # Catalog type of the Compute v3 service. (string value)
 #catalog_v3_type=computev3
 
@@ -407,6 +411,10 @@
 # one is used. (string value)
 #region=RegionOne
 
+# The endpoint type to use for the identity service. (string
+# value)
+#endpoint_type=publicURL
+
 # Username to use for Nova API requests. (string value)
 #username=demo
 
@@ -475,6 +483,10 @@
 # value)
 #region=
 
+# The endpoint type to use for the image service. (string
+# value)
+#endpoint_type=publicURL
+
 # http accessible image (string value)
 #http_image=http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
 
@@ -530,6 +542,10 @@
 # value)
 #region=
 
+# The endpoint type to use for the network service. (string
+# value)
+#endpoint_type=publicURL
+
 # The cidr block to allocate tenant ipv4 subnets from (string
 # value)
 #tenant_network_cidr=10.100.0.0/16
@@ -591,6 +607,10 @@
 # (string value)
 #region=
 
+# The endpoint type to use for the object-store service.
+# (string value)
+#endpoint_type=publicURL
+
 # Number of seconds to time on waiting for a container to
 # container synchronization complete. (integer value)
 #container_sync_timeout=120
@@ -631,6 +651,10 @@
 # value)
 #region=
 
+# The endpoint type to use for the orchestration service.
+# (string value)
+#endpoint_type=publicURL
+
 # Time in seconds between build status checks. (integer value)
 #build_interval=1
 
@@ -804,6 +828,10 @@
 # value)
 #region=
 
+# The endpoint type to use for the volume service. (string
+# value)
+#endpoint_type=publicURL
+
 # Name of the backend1 (must be declared in cinder.conf)
 # (string value)
 #backend1_name=BACKEND_1
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 212d41d..72224da 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -58,7 +58,7 @@
     def __init__(self, auth_provider):
         self.auth_provider = auth_provider
 
-        self.endpoint_url = 'publicURL'
+        self.endpoint_url = None
         self.service = None
         # The version of the API this client implements
         self.api_version = None
@@ -121,6 +121,28 @@
             service_region = CONF.identity.region
         return service_region
 
+    def _get_endpoint_type(self, service):
+        """
+        Returns the endpoint type for a specific service
+        """
+        # If the client requests a specific endpoint type, then be it
+        if self.endpoint_url:
+            return self.endpoint_url
+        endpoint_type = None
+        for cfgname in dir(CONF._config):
+            # Find all config.FOO.catalog_type and assume FOO is a service.
+            cfg = getattr(CONF, cfgname)
+            catalog_type = getattr(cfg, 'catalog_type', None)
+            if catalog_type == service:
+                endpoint_type = getattr(cfg, 'endpoint_type', 'publicURL')
+                break
+        # Special case for compute v3 service which hasn't its own
+        # configuration group
+        else:
+            if service == CONF.compute.catalog_v3_type:
+                endpoint_type = CONF.compute.endpoint_type
+        return endpoint_type
+
     @property
     def user(self):
         return self.auth_provider.credentials.get('username', None)
@@ -145,7 +167,7 @@
     def filters(self):
         _filters = dict(
             service=self.service,
-            endpoint_type=self.endpoint_url,
+            endpoint_type=self._get_endpoint_type(self.service),
             region=self._get_region(self.service)
         )
         if self.api_version is not None:
diff --git a/tempest/config.py b/tempest/config.py
index 210c857..224f99c 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -53,6 +53,11 @@
                     "services' region name unless they are set explicitly. "
                     "If no such region is found in the service catalog, the "
                     "first found one is used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the identity service."),
     cfg.StrOpt('username',
                default='demo',
                help="Username to use for Nova API requests."),
@@ -193,6 +198,11 @@
                     "of identity.region is used instead. If no such region "
                     "is found in the service catalog, the first found one is "
                     "used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the compute service."),
     cfg.StrOpt('catalog_v3_type',
                default='computev3',
                help="Catalog type of the Compute v3 service."),
@@ -286,6 +296,11 @@
                     "of identity.region is used instead. If no such region "
                     "is found in the service catalog, the first found one is "
                     "used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the image service."),
     cfg.StrOpt('http_image',
                default='http://download.cirros-cloud.net/0.3.1/'
                'cirros-0.3.1-x86_64-uec.tar.gz',
@@ -317,6 +332,11 @@
                     "of identity.region is used instead. If no such region "
                     "is found in the service catalog, the first found one is "
                     "used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the network service."),
     cfg.StrOpt('tenant_network_cidr',
                default="10.100.0.0/16",
                help="The cidr block to allocate tenant ipv4 subnets from"),
@@ -373,6 +393,11 @@
                     "of identity.region is used instead. If no such region "
                     "is found in the service catalog, the first found one is "
                     "used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the volume service."),
     cfg.StrOpt('backend1_name',
                default='BACKEND_1',
                help="Name of the backend1 (must be declared in cinder.conf)"),
@@ -423,6 +448,11 @@
                     "value of identity.region is used instead. If no such "
                     "region is found in the service catalog, the first found "
                     "one is used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the object-store service."),
     cfg.IntOpt('container_sync_timeout',
                default=120,
                help="Number of seconds to time on waiting for a container "
@@ -463,6 +493,11 @@
                     "value of identity.region is used instead. If no such "
                     "region is found in the service catalog, the first found "
                     "one is used."),
+    cfg.StrOpt('endpoint_type',
+               default='publicURL',
+               choices=['public', 'admin', 'internal',
+                        'publicURL', 'adminURL', 'internalURL'],
+               help="The endpoint type to use for the orchestration service."),
     cfg.BoolOpt('allow_tenant_isolation',
                 default=False,
                 help="Allows test cases to create/destroy tenants and "
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 0fc304a..f5c0b92 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -99,9 +99,11 @@
 
         # Create our default Nova client to use in testing
         service_type = CONF.compute.catalog_type
+        endpoint_type = CONF.compute.endpoint_type
         return novaclient.client.Client(self.NOVACLIENT_VERSION,
                                         *client_args,
                                         service_type=service_type,
+                                        endpoint_type=endpoint_type,
                                         region_name=region,
                                         no_cache=True,
                                         insecure=dscv,
@@ -110,9 +112,10 @@
     def _get_image_client(self):
         token = self.identity_client.auth_token
         region = CONF.identity.region
+        endpoint_type = CONF.image.endpoint_type
         endpoint = self.identity_client.service_catalog.url_for(
             attr='region', filter_value=region,
-            service_type=CONF.image.catalog_type, endpoint_type='publicURL')
+            service_type=CONF.image.catalog_type, endpoint_type=endpoint_type)
         dscv = CONF.identity.disable_ssl_certificate_validation
         return glanceclient.Client('1', endpoint=endpoint, token=token,
                                    insecure=dscv)
@@ -120,12 +123,14 @@
     def _get_volume_client(self, username, password, tenant_name):
         auth_url = CONF.identity.uri
         region = CONF.identity.region
+        endpoint_type = CONF.volume.endpoint_type
         return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
                                           username,
                                           password,
                                           tenant_name,
                                           auth_url,
                                           region_name=region,
+                                          endpoint_type=endpoint_type,
                                           http_log_debug=True)
 
     def _get_object_storage_client(self, username, password, tenant_name):
@@ -149,9 +154,12 @@
         except keystoneclient.exceptions.Conflict:
             pass
 
+        endpoint_type = CONF.object_storage.endpoint_type
+        os_options = {'endpoint_type': endpoint_type}
         return swiftclient.Connection(auth_url, username, password,
                                       tenant_name=tenant_name,
-                                      auth_version='2')
+                                      auth_version='2',
+                                      os_options=os_options)
 
     def _get_orchestration_client(self, username=None, password=None,
                                   tenant_name=None):
@@ -166,6 +174,7 @@
 
         keystone = self._get_identity_client(username, password, tenant_name)
         region = CONF.identity.region
+        endpoint_type = CONF.orchestration.endpoint_type
         token = keystone.auth_token
         service_type = CONF.orchestration.catalog_type
         try:
@@ -173,7 +182,7 @@
                 attr='region',
                 filter_value=region,
                 service_type=service_type,
-                endpoint_type='publicURL')
+                endpoint_type=endpoint_type)
         except keystoneclient.exceptions.EndpointNotFound:
             return None
         else:
@@ -212,10 +221,12 @@
 
         auth_url = CONF.identity.uri
         dscv = CONF.identity.disable_ssl_certificate_validation
+        endpoint_type = CONF.network.endpoint_type
 
         return neutronclient.v2_0.client.Client(username=username,
                                                 password=password,
                                                 tenant_name=tenant_name,
+                                                endpoint_type=endpoint_type,
                                                 auth_url=auth_url,
                                                 insecure=dscv)