Merge "Use get_service_clients framework with basic Secure RBAC"
diff --git a/ironic_tempest_plugin/config.py b/ironic_tempest_plugin/config.py
index 7354ef7..de517dc 100644
--- a/ironic_tempest_plugin/config.py
+++ b/ironic_tempest_plugin/config.py
@@ -18,6 +18,8 @@
 from tempest import config  # noqa
 
 
+# NOTE(TheJulia): The following options are loaded into a tempest
+# plugin configuration option via plugin.py.
 ironic_service_option = cfg.BoolOpt('ironic',
                                     default=False,
                                     help='Whether or not ironic is expected '
@@ -28,6 +30,18 @@
                                        help="Whether or not ironic-inspector "
                                        "is expected to be available")
 
+ironic_scope_enforcement = cfg.BoolOpt('ironic',
+                                       default=False,
+                                       help='Wheter or not ironic is '
+                                            'exepcted to enforce auth '
+                                            'scope.')
+
+inspector_scope_enforcement = cfg.BoolOpt('ironic_inspector',
+                                          default=False,
+                                          help='Whether or not '
+                                               'ironic-inspector is expected '
+                                               'to enforce auth scope.')
+
 baremetal_group = cfg.OptGroup(name='baremetal',
                                title='Baremetal provisioning service options',
                                help='When enabling baremetal tests, Nova '
@@ -38,6 +52,8 @@
                                     'live_migration, pause, rescue, resize, '
                                     'shelve, snapshot, and suspend')
 
+# The bulk of the embedded configuration is below.
+
 baremetal_introspection_group = cfg.OptGroup(
     name="baremetal_introspection",
     title="Baremetal introspection service options",
diff --git a/ironic_tempest_plugin/manager.py b/ironic_tempest_plugin/manager.py
index 2977740..95fe207 100644
--- a/ironic_tempest_plugin/manager.py
+++ b/ironic_tempest_plugin/manager.py
@@ -42,7 +42,7 @@
 class ScenarioTest(tempest.test.BaseTestCase):
     """Base class for scenario tests. Uses tempest own clients. """
 
-    credentials = ['primary']
+    credentials = ['primary', 'admin', 'system_admin']
 
     @classmethod
     def setup_clients(cls):
@@ -92,7 +92,7 @@
     def _create_port(self, network_id, client=None, namestart='port-quotatest',
                      **kwargs):
         if not client:
-            client = self.ports_client
+            client = self.os_primary.ports_client
         name = data_utils.rand_name(namestart)
         result = client.create_port(
             name=name,
@@ -106,7 +106,7 @@
 
     def create_keypair(self, client=None):
         if not client:
-            client = self.keypairs_client
+            client = self.os_primary.keypairs_client
         name = data_utils.rand_name(self.__class__.__name__)
         # We don't need to create a keypair by pubkey in scenario
         body = client.create_keypair(name=name)
@@ -254,12 +254,13 @@
         if not CONF.compute_feature_enabled.console_output:
             LOG.debug('Console output not supported, cannot log')
             return
+        client = self.os_primary.servers_client
         if not servers:
-            servers = self.servers_client.list_servers()
+            servers = client.list_servers()
             servers = servers['servers']
         for server in servers:
             try:
-                console_output = self.servers_client.get_console_output(
+                console_output = client.get_console_output(
                     server['id'])['output']
                 LOG.debug('Console output for %s\nbody=\n%s',
                           server['id'], console_output)
@@ -277,12 +278,12 @@
 
         LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
                   server_id, image, preserve_ephemeral)
-        self.servers_client.rebuild_server(
+        self.os_primary.servers_client.rebuild_server(
             server_id=server_id, image_ref=image,
             preserve_ephemeral=preserve_ephemeral,
             **rebuild_kwargs)
         if wait:
-            waiters.wait_for_server_status(self.servers_client,
+            waiters.wait_for_server_status(self.os_primary.servers_client,
                                            server_id, 'ACTIVE')
 
     def ping_ip_address(self, ip_address, should_succeed=True,
@@ -357,12 +358,13 @@
 
         if not pool_name:
             pool_name = CONF.network.floating_network_name
-        floating_ip = (self.compute_floating_ips_client.
+        client = self.os_primary.compute_floating_ips_client
+        floating_ip = (client.
                        create_floating_ip(pool=pool_name)['floating_ip'])
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.compute_floating_ips_client.delete_floating_ip,
+                        client.delete_floating_ip,
                         floating_ip['id'])
-        self.compute_floating_ips_client.associate_floating_ip_to_server(
+        client.associate_floating_ip_to_server(
             floating_ip['ip'], thing['id'])
         return floating_ip
 
@@ -423,7 +425,7 @@
         routes traffic to the public network.
         """
         if not client:
-            client = self.routers_client
+            client = self.os_primary.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         router_id = CONF.network.public_router_id
@@ -443,7 +445,7 @@
     def _create_router(self, client=None, tenant_id=None,
                        namestart='router-smoke'):
         if not client:
-            client = self.routers_client
+            client = self.os_primary.routers_client
         if not tenant_id:
             tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
@@ -470,7 +472,7 @@
 
     """
 
-    credentials = ['primary', 'admin']
+    credentials = ['primary', 'admin', 'system_admin']
 
     @classmethod
     def skip_checks(cls):
@@ -483,9 +485,9 @@
                         namestart='network-smoke-',
                         port_security_enabled=True):
         if not networks_client:
-            networks_client = self.networks_client
+            networks_client = self.os_primary.networks_client
         if not tenant_id:
-            tenant_id = networks_client.tenant_id
+            tenant_id = self.os_primary.networks_client.tenant_id
         name = data_utils.rand_name(namestart)
         network_kwargs = dict(name=name, tenant_id=tenant_id)
         # Neutron disables port security by default so we have to check the
@@ -542,7 +544,7 @@
         if not external_network_id:
             external_network_id = CONF.network.public_network_id
         if not client:
-            client = self.floating_ips_client
+            client = self.os_primary.floating_ips_client
         if not port_id:
             port_id, ip4 = self._get_server_port_id_and_ip4(thing)
         else:
diff --git a/ironic_tempest_plugin/plugin.py b/ironic_tempest_plugin/plugin.py
index 43b2052..546509b 100644
--- a/ironic_tempest_plugin/plugin.py
+++ b/ironic_tempest_plugin/plugin.py
@@ -43,8 +43,43 @@
                           group='service_available')
         conf.register_opt(project_config.inspector_service_option,
                           group='service_available')
+        conf.register_opt(project_config.ironic_scope_enforcement,
+                          group='enforce_scope')
+        conf.register_opt(project_config.inspector_scope_enforcement,
+                          group='enforce_scope')
         for group, option in _opts:
             config.register_opt_group(conf, group, option)
 
     def get_opt_lists(self):
         return [(group.name, option) for group, option in _opts]
+
+    def get_service_clients(self):
+        ironic_config = config.service_client_config(
+            project_config.baremetal_group.name
+        )
+        baremetal_client = {
+            'name': 'baremetal',
+            'service_version': 'baremetal.v1',
+            'module_path': 'ironic_tempest_plugin.services.baremetal.v1.'
+                           'json.baremetal_client',
+            'client_names': [
+                'BaremetalClient',
+            ],
+        }
+        baremetal_client.update(ironic_config)
+
+        inspector_config = config.service_client_config(
+            project_config.baremetal_introspection_group.name
+        )
+        inspector_client = {
+            'name': 'introspection',
+            'service_version': 'baremetal_introspection.v1',
+            'module_path': 'ironic_tempest_plugin.services.'
+                           'introspection_client',
+            'client_names': [
+                'BaremetalIntrospectionClient',
+            ],
+        }
+        inspector_client.update(inspector_config)
+
+        return [baremetal_client, inspector_client]
diff --git a/ironic_tempest_plugin/tests/api/admin/base.py b/ironic_tempest_plugin/tests/api/admin/base.py
index 8cc8aec..d78f74a 100644
--- a/ironic_tempest_plugin/tests/api/admin/base.py
+++ b/ironic_tempest_plugin/tests/api/admin/base.py
@@ -17,7 +17,6 @@
 from tempest.lib import exceptions as lib_exc
 from tempest import test
 
-from ironic_tempest_plugin import clients
 from ironic_tempest_plugin.common import waiters
 from ironic_tempest_plugin.services.baremetal import base
 from ironic_tempest_plugin.tests.api.admin import api_microversion_fixture
@@ -58,7 +57,7 @@
                         test.BaseTestCase):
     """Base class for Baremetal API tests."""
 
-    credentials = ['admin']
+    credentials = ['admin', 'system_admin']
 
     @classmethod
     def skip_checks(cls):
@@ -86,12 +85,16 @@
                 CONF.baremetal.min_microversion))
         cls.services_microversion = {
             CONF.baremetal.catalog_type: cls.request_microversion}
+
         super(BaseBaremetalTest, cls).setup_credentials()
 
     @classmethod
     def setup_clients(cls):
         super(BaseBaremetalTest, cls).setup_clients()
-        cls.client = clients.Manager().baremetal_client
+        if CONF.enforce_scope.ironic:
+            cls.client = cls.os_system_admin.baremetal.BaremetalClient()
+        else:
+            cls.client = cls.os_admin.baremetal.BaremetalClient()
 
     @classmethod
     def resource_setup(cls):
diff --git a/ironic_tempest_plugin/tests/scenario/baremetal_manager.py b/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
index db0d200..4820c64 100644
--- a/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
+++ b/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
@@ -22,7 +22,6 @@
 from tempest.lib.common.utils.linux import remote_client
 from tempest.lib import exceptions as lib_exc
 
-from ironic_tempest_plugin import clients
 from ironic_tempest_plugin.common import utils
 from ironic_tempest_plugin.common import waiters as ironic_waiters
 from ironic_tempest_plugin import manager
@@ -74,7 +73,7 @@
 
 class BaremetalScenarioTest(manager.ScenarioTest):
 
-    credentials = ['primary', 'admin']
+    credentials = ['primary', 'admin', 'system_admin']
     min_microversion = None
     max_microversion = api_version_utils.LATEST_MICROVERSION
 
@@ -93,8 +92,11 @@
     @classmethod
     def setup_clients(cls):
         super(BaremetalScenarioTest, cls).setup_clients()
-
-        cls.baremetal_client = clients.Manager().baremetal_client
+        if CONF.enforce_scope.ironic:
+            client = cls.os_system_admin.baremetal.BaremetalClient()
+        else:
+            client = cls.os_admin.baremetal.BaremetalClient()
+        cls.baremetal_client = client
 
     @classmethod
     def resource_setup(cls):
@@ -172,7 +174,7 @@
     def boot_instance(self, clients=None, keypair=None,
                       net_id=None, fixed_ip=None, **create_kwargs):
         if clients is None:
-            servers_client = self.servers_client
+            servers_client = self.os_primary.servers_client
         else:
             servers_client = clients.servers_client
         if keypair is None:
@@ -222,7 +224,7 @@
 
     def terminate_instance(self, instance, servers_client=None):
         if servers_client is None:
-            servers_client = self.servers_client
+            servers_client = self.os_primary.servers_client
 
         node = self.get_node(instance_id=instance['id'])
         servers_client.delete_server(instance['id'])
@@ -239,7 +241,7 @@
                         servers_client=None):
         """Rescue the instance, verify we can ping and SSH."""
         if servers_client is None:
-            servers_client = self.servers_client
+            servers_client = self.os_primary.servers_client
 
         rescuing_instance = servers_client.rescue_server(instance['id'])
         rescue_password = rescuing_instance['adminPass']
@@ -265,8 +267,8 @@
     def unrescue_instance(self, instance, node, server_ip,
                           servers_client=None):
         if servers_client is None:
-            servers_client = self.servers_client
-        self.servers_client.unrescue_server(instance['id'])
+            servers_client = self.os_primary.servers_client
+        self.os_primary.servers_client.unrescue_server(instance['id'])
         self.wait_provisioning_state(
             node['uuid'],
             BaremetalProvisionStates.ACTIVE,
diff --git a/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py b/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py
index 10a83a6..176f912 100644
--- a/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py
+++ b/ironic_tempest_plugin/tests/scenario/baremetal_standalone_manager.py
@@ -31,7 +31,7 @@
 class BaremetalStandaloneManager(bm.BaremetalScenarioTest,
                                  manager.NetworkScenarioTest):
 
-    credentials = ['primary', 'admin']
+    credentials = ['primary', 'admin', 'system_admin']
     # NOTE(vsaienko): Standalone tests are using v1/node/<node_ident>/vifs to
     # attach VIF to a node.
     min_microversion = '1.28'
diff --git a/ironic_tempest_plugin/tests/scenario/introspection_manager.py b/ironic_tempest_plugin/tests/scenario/introspection_manager.py
index 71fa001..199bab1 100644
--- a/ironic_tempest_plugin/tests/scenario/introspection_manager.py
+++ b/ironic_tempest_plugin/tests/scenario/introspection_manager.py
@@ -23,7 +23,6 @@
 
 import ironic_tempest_plugin
 from ironic_tempest_plugin import exceptions
-from ironic_tempest_plugin.services import introspection_client
 from ironic_tempest_plugin.tests.api.admin.api_microversion_fixture import \
     APIMicroversionFixture as IronicMicroversionFixture
 from ironic_tempest_plugin.tests.scenario.baremetal_manager import \
@@ -40,7 +39,7 @@
 
     wait_provisioning_state_interval = 15
 
-    credentials = ['primary', 'admin']
+    credentials = ['admin', 'system_admin', 'primary']
 
     ironic_api_version = LATEST_MICROVERSION
 
@@ -53,8 +52,11 @@
     @classmethod
     def setup_clients(cls):
         super(InspectorScenarioTest, cls).setup_clients()
-        inspector_manager = introspection_client.Manager()
-        cls.introspection_client = inspector_manager.introspection_client
+        if CONF.enforce_scope.ironic_inspector:
+            oscli = cls.os_system_admin.introspection
+        else:
+            oscli = cls.os_admin.introspection
+        cls.introspection_client = oscli.BaremetalIntrospectionClient()
 
     def setUp(self):
         super(InspectorScenarioTest, self).setUp()
diff --git a/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py b/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
index e3c1929..d4e8ae3 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
@@ -45,7 +45,7 @@
           expected state transitions
     """
 
-    credentials = ['primary', 'admin']
+    credentials = ['primary', 'admin', 'system_admin']
 
     TEST_RESCUE_MODE = False
     image_ref = None
diff --git a/ironic_tempest_plugin/tests/scenario/test_baremetal_boot_from_volume.py b/ironic_tempest_plugin/tests/scenario/test_baremetal_boot_from_volume.py
index 9908270..154fc96 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_boot_from_volume.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_boot_from_volume.py
@@ -34,7 +34,7 @@
     * Delete instance
     """
 
-    credentials = ['primary', 'admin']
+    credentials = ['primary', 'admin', 'system_admin']
 
     min_microversion = '1.32'
 
diff --git a/ironic_tempest_plugin/tests/scenario/test_baremetal_multitenancy.py b/ironic_tempest_plugin/tests/scenario/test_baremetal_multitenancy.py
index 60c3ed9..fc4c513 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_multitenancy.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_multitenancy.py
@@ -36,7 +36,7 @@
     * Delete both instances
     """
 
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ['primary', 'alt', 'admin', 'system_admin']
 
     @classmethod
     def skip_checks(cls):
diff --git a/ironic_tempest_plugin/tests/scenario/test_baremetal_single_tenant.py b/ironic_tempest_plugin/tests/scenario/test_baremetal_single_tenant.py
index a873471..e06d43a 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_single_tenant.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_single_tenant.py
@@ -36,7 +36,7 @@
     * Delete both instances
     """
 
-    credentials = ['primary', 'alt', 'admin']
+    credentials = ['primary', 'alt', 'admin', 'system_admin']
 
     @classmethod
     def skip_checks(cls):