Accommodate v2 and v3 auth for integration tests

devstack has moved default Keystone API version to v3[1].

[1] https://github.com/openstack-dev/devstack/commit/f4ce44bf3fbf06e53c2ae3ec6aa4996831cf4605

Though the above patch has been reverted, this would help
if devstack removes v2 support in the future.

Change-Id: I393750d00b3712a015e48a3cf38ab5f95bb61dae
Closes-Bug: #1539692
diff --git a/common/clients.py b/common/clients.py
index 9718d03..0ba7131 100644
--- a/common/clients.py
+++ b/common/clients.py
@@ -15,13 +15,49 @@
 import ceilometerclient.client
 import cinderclient.client
 import heatclient.client
+from keystoneclient.auth.identity.generic import password
+import keystoneclient.client
 import keystoneclient.exceptions
-import keystoneclient.v2_0.client
+from keystoneclient import session
 import neutronclient.v2_0.client
 import novaclient.client
 import swiftclient
 
 
+class KeystoneWrapperClient(object):
+    """Wrapper object for keystone client
+
+    This Wraps keystone client,so we can encpasulate certain
+    added properties like auth_token, project_id etc.
+    """
+    def __init__(self, auth_plugin, verify=True):
+        self.auth_plugin = auth_plugin
+        self.session = session.Session(
+            auth=auth_plugin,
+            verify=verify)
+
+    @property
+    def auth_token(self):
+        return self.auth_plugin.get_token(self.session)
+
+    @property
+    def auth_ref(self):
+        return self.auth_plugin.get_access(self.session)
+
+    @property
+    def project_id(self):
+        return self.auth_plugin.get_project_id(self.session)
+
+    def get_endpoint_url(self, service_type, region=None):
+        kwargs = {
+            'service_type': service_type,
+            'endpoint_type': 'publicURL'}
+        if region:
+            kwargs.update({'attr': 'region',
+                           'filter_value': region})
+        return self.auth_ref.service_catalog.url_for(**kwargs)
+
+
 class ClientManager(object):
     """Provides access to the official python clients for calling various APIs.
 
@@ -36,6 +72,8 @@
 
     def __init__(self, conf):
         self.conf = conf
+        self.v2_auth_url = self.conf.auth_url.replace('/v3', '/v2.0')
+        self.auth_version = self.conf.auth_url.split('/v')[1]
         self.identity_client = self._get_identity_client()
         self.orchestration_client = self._get_orchestration_client()
         self.compute_client = self._get_compute_client()
@@ -45,20 +83,15 @@
         self.metering_client = self._get_metering_client()
 
     def _get_orchestration_client(self):
-        region = self.conf.region
         endpoint = os.environ.get('HEAT_URL')
         if os.environ.get('OS_NO_CLIENT_AUTH') == 'True':
             token = None
         else:
-            keystone = self._get_identity_client()
-            token = keystone.auth_token
+            token = self.identity_client.auth_token
         try:
             if endpoint is None:
-                endpoint = keystone.service_catalog.url_for(
-                    attr='region',
-                    filter_value=region,
-                    service_type='orchestration',
-                    endpoint_type='publicURL')
+                endpoint = self.identity_client.get_endpoint_url(
+                    'orchestration', self.conf.region)
         except keystoneclient.exceptions.EndpointNotFound:
             return None
         else:
@@ -70,12 +103,22 @@
                 password=self.conf.password)
 
     def _get_identity_client(self):
-        return keystoneclient.v2_0.client.Client(
-            username=self.conf.username,
-            password=self.conf.password,
-            tenant_name=self.conf.tenant_name,
-            auth_url=self.conf.auth_url,
-            insecure=self.conf.disable_ssl_certificate_validation)
+        domain = self.conf.domain_name
+        kwargs = {
+            'username': self.conf.username,
+            'password': self.conf.password,
+            'tenant_name': self.conf.tenant_name,
+            'auth_url': self.conf.auth_url
+        }
+        # keystone v2 can't ignore domain details
+        if self.auth_version == '3':
+            kwargs.update({
+                'project_domain_name': domain,
+                'user_domain_name': domain})
+        auth = password.Password(**kwargs)
+        return KeystoneWrapperClient(
+            auth,
+            not self.conf.disable_ssl_certificate_validation)
 
     def _get_compute_client(self):
 
@@ -86,7 +129,8 @@
             self.conf.username,
             self.conf.password,
             self.conf.tenant_name,
-            self.conf.auth_url
+            # novaclient can not use v3 url
+            self.v2_auth_url
         )
 
         # Create our default Nova client to use in testing
@@ -101,7 +145,6 @@
             http_log_debug=True)
 
     def _get_network_client(self):
-        auth_url = self.conf.auth_url
         dscv = self.conf.disable_ssl_certificate_validation
 
         return neutronclient.v2_0.client.Client(
@@ -109,11 +152,11 @@
             password=self.conf.password,
             tenant_name=self.conf.tenant_name,
             endpoint_type='publicURL',
-            auth_url=auth_url,
+            # neutronclient can not use v3 url
+            auth_url=self.v2_auth_url,
             insecure=dscv)
 
     def _get_volume_client(self):
-        auth_url = self.conf.auth_url
         region = self.conf.region
         endpoint_type = 'publicURL'
         dscv = self.conf.disable_ssl_certificate_validation
@@ -122,7 +165,8 @@
             self.conf.username,
             self.conf.password,
             self.conf.tenant_name,
-            auth_url,
+            # cinderclient can not use v3 url
+            self.v2_auth_url,
             region_name=region,
             endpoint_type=endpoint_type,
             insecure=dscv,
@@ -131,7 +175,7 @@
     def _get_object_client(self):
         dscv = self.conf.disable_ssl_certificate_validation
         args = {
-            'auth_version': '2.0',
+            'auth_version': self.auth_version,
             'tenant_name': self.conf.tenant_name,
             'user': self.conf.username,
             'key': self.conf.password,
@@ -143,15 +187,10 @@
 
     def _get_metering_client(self):
         dscv = self.conf.disable_ssl_certificate_validation
-
-        keystone = self._get_identity_client()
+        domain = self.conf.domain_name
         try:
-            endpoint = keystone.service_catalog.url_for(
-                attr='region',
-                filter_value=self.conf.region,
-                service_type='metering',
-                endpoint_type='publicURL')
-
+            endpoint = self.identity_client.get_endpoint_url('metering',
+                                                             self.conf.region)
         except keystoneclient.exceptions.EndpointNotFound:
             return None
         else:
@@ -165,6 +204,12 @@
                 'endpoint_type': 'publicURL',
                 'service_type': 'metering',
             }
+            # ceilometerclient can't ignore domain details for
+            # v2 auth_url
+            if self.auth_version == '3':
+                args.update(
+                    {'user_domain_name': domain,
+                     'project_domain_name': domain})
 
             return ceilometerclient.client.Client(self.CEILOMETER_VERSION,
                                                   endpoint, **args)
diff --git a/common/config.py b/common/config.py
index 9ad6337..39c0846 100644
--- a/common/config.py
+++ b/common/config.py
@@ -32,10 +32,14 @@
                help="Tenant name to use for API requests."),
     cfg.StrOpt('auth_url',
                default=os.environ.get('OS_AUTH_URL'),
-               help="Full URI of the OpenStack Identity API (Keystone), v2"),
+               help="Full URI of the OpenStack Identity API (Keystone)"),
+    cfg.StrOpt('domain_name',
+               default='default',
+               help="User/project domain name, if keystone v3 auth_url"
+                    "is used"),
     cfg.StrOpt('region',
                default=os.environ.get('OS_REGION_NAME'),
-               help="The region name to us"),
+               help="The region name to use"),
     cfg.StrOpt('instance_type',
                help="Instance type for tests. Needs to be big enough for a "
                     "full OS plus the test workload"),
@@ -48,10 +52,6 @@
     cfg.StrOpt('minimal_image_ref',
                help="Name of minimal (e.g cirros) image to use when "
                     "launching test instances."),
-    cfg.StrOpt('auth_version',
-               default='v2',
-               help="Identity API version to be used for authentication "
-                    "for API tests."),
     cfg.BoolOpt('disable_ssl_certificate_validation',
                 default=False,
                 help="Set to True if using self-signed SSL certificates."),
@@ -124,6 +124,7 @@
     cfg.StrOpt('heat-config-notify-script',
                default=('heat-config-notify'),
                help="Path to the script heat-config-notify"),
+
 ]
 
 
diff --git a/functional/test_aws_stack.py b/functional/test_aws_stack.py
index 678ce7e..9649a02 100644
--- a/functional/test_aws_stack.py
+++ b/functional/test_aws_stack.py
@@ -77,7 +77,7 @@
     def setUp(self):
         super(AwsStackTest, self).setUp()
         self.object_container_name = test.rand_name()
-        self.project_id = self.identity_client.auth_ref.project_id
+        self.project_id = self.identity_client.project_id
         self.swift_key = hashlib.sha224(
             str(random.getrandbits(256))).hexdigest()[:32]
         key_header = 'x-container-meta-temp-url-key'
diff --git a/functional/test_conditional_exposure.py b/functional/test_conditional_exposure.py
index 90f7d7a..c1175f1 100644
--- a/functional/test_conditional_exposure.py
+++ b/functional/test_conditional_exposure.py
@@ -42,13 +42,9 @@
                           "Sahara resources availability.")
 
     def _is_sahara_deployed(self):
-        keystone = self.identity_client
         try:
-            keystone.service_catalog.url_for(
-                attr='region',
-                filter_value=self.conf.region,
-                service_type='data-processing',
-                endpoint_type='publicURL')
+            self.identity_client.get_endpoint_url('data-processing',
+                                                  self.conf.region)
         except keystoneclient.exceptions.EndpointNotFound:
             return False
         return True
diff --git a/functional/test_preview.py b/functional/test_preview.py
index b927a25..5846523 100644
--- a/functional/test_preview.py
+++ b/functional/test_preview.py
@@ -43,7 +43,7 @@
     def setUp(self):
         super(StackPreviewTest, self).setUp()
         self.client = self.orchestration_client
-        self.project_id = self.identity_client.auth_ref.project_id
+        self.project_id = self.identity_client.project_id
 
     def _assert_resource(self, res, stack_name):
         self.assertEqual(stack_name, res['stack_name'])