Merge "Fix verify config API version checks"
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 8e71ecc..714a476 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -30,6 +30,8 @@
 from tempest.common import credentials_factory as credentials
 from tempest import config
 import tempest.lib.common.http
+from tempest.lib import exceptions as lib_exc
+from tempest.services import object_storage
 
 
 CONF = config.CONF
@@ -69,7 +71,25 @@
 
 def verify_glance_api_versions(os, update):
     # Check glance api versions
-    _, versions = os.image_client.get_versions()
+    # Since we want to verify that the configuration is correct, we cannot
+    # rely on a specific version of the API being available.
+    try:
+        _, versions = os.image_v1.ImagesClient().get_versions()
+    except lib_exc.NotFound:
+        # If not found, we use v2. The assumption is that either v1 or v2
+        # are available, since glance is marked as available in the catalog.
+        # If not, glance should be disabled in Tempest conf.
+        try:
+            versions = os.image_v2.VersionsClient().list_versions()['versions']
+            versions = [x['id'] for x in versions]
+        except lib_exc.NotFound:
+            msg = ('Glance is available in the catalog, but no known version, '
+                   '(v1.x or v2.x) of Glance could be found, so Glance should '
+                   'be configured as not available')
+            LOG.warn(msg)
+            print_and_or_update('glance', 'service-available', False, update)
+            return
+
     if CONF.image_feature_enabled.api_v1 != contains_version('v1.', versions):
         print_and_or_update('api_v1', 'image-feature-enabled',
                             not CONF.image_feature_enabled.api_v1, update)
@@ -92,10 +112,15 @@
 
 
 def _get_api_versions(os, service):
+    # Clients are used to obtain the base_url. Each client applies the
+    # appropriate filters to the catalog to extract a base_url which
+    # matches the configured region and endpoint_type.
+    # The base URL is used to obtain the list of versions available.
     client_dict = {
-        'nova': os.servers_client,
-        'keystone': os.identity_client,
-        'cinder': os.volumes_client_latest,
+        'nova': os.compute.ServersClient(),
+        'keystone': os.identity_v3.IdentityClient(
+            endpoint_type=CONF.identity.v3_endpoint_type),
+        'cinder': os.volume_v3.VolumesClient(),
     }
     if service != 'keystone' and service != 'cinder':
         # Since keystone and cinder may be listening on a path,
@@ -166,14 +191,15 @@
 
 
 def get_extension_client(os, service):
+    params = config.service_client_config('object-storage')
     extensions_client = {
-        'nova': os.extensions_client,
-        'neutron': os.network_extensions_client,
-        'swift': os.capabilities_client,
+        'nova': os.compute.ExtensionsClient(),
+        'neutron': os.network.ExtensionsClient(),
+        'swift': object_storage.CapabilitiesClient(os.auth_provider, **params),
         # NOTE: Cinder v3 API is current and v2 and v1 are deprecated.
         # V3 extension API is the same as v2, so we reuse the v2 client
         # for v3 API also.
-        'cinder': os.volumes_v2_extension_client,
+        'cinder': os.volume_v2.ExtensionsClient(),
     }
 
     if service not in extensions_client:
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 1415111..810f9e5 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -16,9 +16,13 @@
 import mock
 from oslo_serialization import jsonutils as json
 
+from tempest import clients
 from tempest.cmd import verify_tempest_config
+from tempest.common import credentials_factory
 from tempest import config
+from tempest.lib.common import rest_client
 from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
 from tempest.tests import base
 from tempest.tests import fake_config
 
@@ -234,10 +238,15 @@
         print_mock.assert_not_called()
 
     def test_verify_glance_version_no_v2_with_v1_1(self):
-        def fake_get_versions():
-            return (None, ['v1.1'])
+        # This test verifies that wrong config api_v2 = True is detected
+        class FakeClient(object):
+            def get_versions(self):
+                return (None, ['v1.0'])
+
         fake_os = mock.MagicMock()
-        fake_os.image_client.get_versions = fake_get_versions
+        fake_module = mock.MagicMock()
+        fake_module.ImagesClient = FakeClient
+        fake_os.image_v1 = fake_module
         with mock.patch.object(verify_tempest_config,
                                'print_and_or_update') as print_mock:
             verify_tempest_config.verify_glance_api_versions(fake_os, True)
@@ -245,10 +254,15 @@
                                            False, True)
 
     def test_verify_glance_version_no_v2_with_v1_0(self):
-        def fake_get_versions():
-            return (None, ['v1.0'])
+        # This test verifies that wrong config api_v2 = True is detected
+        class FakeClient(object):
+            def get_versions(self):
+                return (None, ['v1.0'])
+
         fake_os = mock.MagicMock()
-        fake_os.image_client.get_versions = fake_get_versions
+        fake_module = mock.MagicMock()
+        fake_module.ImagesClient = FakeClient
+        fake_os.image_v1 = fake_module
         with mock.patch.object(verify_tempest_config,
                                'print_and_or_update') as print_mock:
             verify_tempest_config.verify_glance_api_versions(fake_os, True)
@@ -256,24 +270,59 @@
                                            False, True)
 
     def test_verify_glance_version_no_v1(self):
-        def fake_get_versions():
-            return (None, ['v2.0'])
+        # This test verifies that wrong config api_v1 = True is detected
+        class FakeClient(object):
+            def get_versions(self):
+                raise lib_exc.NotFound()
+
+            def list_versions(self):
+                return {'versions': [{'id': 'v2.0'}]}
+
         fake_os = mock.MagicMock()
-        fake_os.image_client.get_versions = fake_get_versions
+        fake_module = mock.MagicMock()
+        fake_module.ImagesClient = FakeClient
+        fake_module.VersionsClient = FakeClient
+        fake_os.image_v1 = fake_module
+        fake_os.image_v2 = fake_module
         with mock.patch.object(verify_tempest_config,
                                'print_and_or_update') as print_mock:
             verify_tempest_config.verify_glance_api_versions(fake_os, True)
         print_mock.assert_called_once_with('api_v1', 'image-feature-enabled',
                                            False, True)
 
+    def test_verify_glance_version_no_version(self):
+        # This test verifies that wrong config api_v1 = True is detected
+        class FakeClient(object):
+            def get_versions(self):
+                raise lib_exc.NotFound()
+
+            def list_versions(self):
+                raise lib_exc.NotFound()
+
+        fake_os = mock.MagicMock()
+        fake_module = mock.MagicMock()
+        fake_module.ImagesClient = FakeClient
+        fake_module.VersionsClient = FakeClient
+        fake_os.image_v1 = fake_module
+        fake_os.image_v2 = fake_module
+        with mock.patch.object(verify_tempest_config,
+                               'print_and_or_update') as print_mock:
+            verify_tempest_config.verify_glance_api_versions(fake_os, True)
+        print_mock.assert_called_once_with('glance',
+                                           'service-available',
+                                           False, True)
+
     def test_verify_extensions_neutron(self):
         def fake_list_extensions():
             return {'extensions': [{'alias': 'fake1'},
                                    {'alias': 'fake2'},
                                    {'alias': 'not_fake'}]}
         fake_os = mock.MagicMock()
-        fake_os.network_extensions_client.list_extensions = (
-            fake_list_extensions)
+        fake_client = mock.MagicMock()
+        fake_client.list_extensions = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
@@ -295,8 +344,11 @@
                                    {'alias': 'fake2'},
                                    {'alias': 'not_fake'}]}
         fake_os = mock.MagicMock()
-        fake_os.network_extensions_client.list_extensions = (
-            fake_list_extensions)
+        fake_client = mock.MagicMock()
+        fake_client.list_extensions = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
@@ -313,15 +365,17 @@
                                    {'alias': 'fake2'},
                                    {'alias': 'not_fake'}]}
         fake_os = mock.MagicMock()
-        # NOTE (e0ne): mock both v1 and v2 APIs
-        fake_os.volumes_extension_client.list_extensions = fake_list_extensions
-        fake_os.volumes_v2_extension_client.list_extensions = (
-            fake_list_extensions)
+        fake_client = mock.MagicMock()
+        fake_client.list_extensions = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
         results = verify_tempest_config.verify_extensions(fake_os,
                                                           'cinder', {})
+
         self.assertIn('cinder', results)
         self.assertIn('fake1', results['cinder'])
         self.assertTrue(results['cinder']['fake1'])
@@ -338,10 +392,11 @@
                                    {'alias': 'fake2'},
                                    {'alias': 'not_fake'}]}
         fake_os = mock.MagicMock()
-        # NOTE (e0ne): mock both v1 and v2 APIs
-        fake_os.volumes_extension_client.list_extensions = fake_list_extensions
-        fake_os.volumes_v2_extension_client.list_extensions = (
-            fake_list_extensions)
+        fake_client = mock.MagicMock()
+        fake_client.list_extensions = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
@@ -357,7 +412,11 @@
             return ([{'alias': 'fake1'}, {'alias': 'fake2'},
                      {'alias': 'not_fake'}])
         fake_os = mock.MagicMock()
-        fake_os.extensions_client.list_extensions = fake_list_extensions
+        fake_client = mock.MagicMock()
+        fake_client.list_extensions = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
@@ -379,7 +438,11 @@
                                     {'alias': 'fake2'},
                                     {'alias': 'not_fake'}]})
         fake_os = mock.MagicMock()
-        fake_os.extensions_client.list_extensions = fake_list_extensions
+        fake_client = mock.MagicMock()
+        fake_client.list_extensions = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
@@ -397,7 +460,11 @@
                     'not_fake': 'metadata',
                     'swift': 'metadata'}
         fake_os = mock.MagicMock()
-        fake_os.capabilities_client.list_capabilities = fake_list_extensions
+        fake_client = mock.MagicMock()
+        fake_client.list_capabilities = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['fake1', 'fake2', 'fake3'])))
@@ -419,7 +486,11 @@
                     'not_fake': 'metadata',
                     'swift': 'metadata'}
         fake_os = mock.MagicMock()
-        fake_os.capabilities_client.list_capabilities = fake_list_extensions
+        fake_client = mock.MagicMock()
+        fake_client.list_capabilities = fake_list_extensions
+        self.useFixture(fixtures.MockPatchObject(
+            verify_tempest_config, 'get_extension_client',
+            return_value=fake_client))
         self.useFixture(fixtures.MockPatchObject(
             verify_tempest_config, 'get_enabled_extensions',
             return_value=(['all'])))
@@ -429,3 +500,13 @@
         self.assertIn('extensions', results['swift'])
         self.assertEqual(sorted(['not_fake', 'fake1', 'fake2']),
                          sorted(results['swift']['extensions']))
+
+    def test_get_extension_client(self):
+        creds = credentials_factory.get_credentials(
+            fill_in=False, username='fake_user', project_name='fake_project',
+            password='fake_password')
+        os = clients.Manager(creds)
+        for service in ['nova', 'neutron', 'swift', 'cinder']:
+            extensions_client = verify_tempest_config.get_extension_client(
+                os, service)
+            self.assertIsInstance(extensions_client, rest_client.RestClient)