Merge "Add API tests for the reset_interfaces parameter"
diff --git a/ironic_tempest_plugin/config.py b/ironic_tempest_plugin/config.py
index 3594b5b..c4fb185 100644
--- a/ironic_tempest_plugin/config.py
+++ b/ironic_tempest_plugin/config.py
@@ -129,6 +129,8 @@
     cfg.ListOpt('enabled_rescue_interfaces',
                 default=['no-rescue'],
                 help="List of Ironic enabled rescue interfaces."),
+    cfg.StrOpt('default_rescue_interface',
+               help="Ironic default rescue interface."),
     cfg.IntOpt('adjusted_root_disk_size_gb',
                min=0,
                help="Ironic adjusted disk size to use in the standalone tests "
diff --git a/ironic_tempest_plugin/tests/api/admin/base.py b/ironic_tempest_plugin/tests/api/admin/base.py
index c589461..8850c55 100644
--- a/ironic_tempest_plugin/tests/api/admin/base.py
+++ b/ironic_tempest_plugin/tests/api/admin/base.py
@@ -162,12 +162,12 @@
 
     @classmethod
     @creates('node')
-    def create_node(cls, chassis_id, cpu_arch='x86', cpus=8, local_gb=10,
+    def create_node(cls, chassis_id, cpu_arch='x86_64', cpus=8, local_gb=10,
                     memory_mb=4096, resource_class=None):
         """Wrapper utility for creating test baremetal nodes.
 
         :param chassis_id: The unique identifier of the chassis.
-        :param cpu_arch: CPU architecture of the node. Default: x86.
+        :param cpu_arch: CPU architecture of the node. Default: x86_64.
         :param cpus: Number of CPUs. Default: 8.
         :param local_gb: Disk size. Default: 10.
         :param memory_mb: Available RAM. Default: 4096.
diff --git a/ironic_tempest_plugin/tests/api/admin/test_nodes.py b/ironic_tempest_plugin/tests/api/admin/test_nodes.py
index 1e97954..8c1343f 100644
--- a/ironic_tempest_plugin/tests/api/admin/test_nodes.py
+++ b/ironic_tempest_plugin/tests/api/admin/test_nodes.py
@@ -111,7 +111,7 @@
 
         _, node = self.create_node(self.chassis['uuid'], **props)
 
-        new_p = {'cpu_arch': 'x86',
+        new_p = {'cpu_arch': 'arm64',
                  'cpus': '1',
                  'local_gb': '10000',
                  'memory_mb': '12300'}
diff --git a/ironic_tempest_plugin/tests/scenario/baremetal_manager.py b/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
index c220619..6d7d55b 100644
--- a/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
+++ b/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
@@ -19,6 +19,7 @@
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common import api_version_utils
+from tempest.lib.common.utils.linux import remote_client
 from tempest.lib import exceptions as lib_exc
 
 from ironic_tempest_plugin import clients
@@ -232,3 +233,44 @@
              BaremetalProvisionStates.AVAILABLE],
             timeout=CONF.baremetal.unprovision_timeout,
             interval=30)
+
+    def rescue_instance(self, instance, node, server_ip,
+                        servers_client=None):
+        """Rescue the instance, verify we can ping and SSH."""
+        if servers_client is None:
+            servers_client = self.servers_client
+
+        rescuing_instance = servers_client.rescue_server(instance['id'])
+        rescue_password = rescuing_instance['adminPass']
+
+        self.wait_provisioning_state(
+            node['uuid'],
+            BaremetalProvisionStates.RESCUE,
+            timeout=CONF.baremetal.rescue_timeout)
+        waiters.wait_for_server_status(servers_client,
+                                       instance['id'], 'RESCUE')
+        # Ping server ip
+        self.assertTrue(self.ping_ip_address(server_ip))
+        # Open ssh connection to server
+        linux_client = remote_client.RemoteClient(
+            server_ip,
+            'rescue',
+            password=rescue_password,
+            server=self.instance,
+            servers_client=servers_client,
+            ssh_timeout=CONF.baremetal.rescue_timeout)
+        linux_client.validate_authentication()
+
+    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'])
+        self.wait_provisioning_state(
+            node['uuid'],
+            BaremetalProvisionStates.ACTIVE,
+            timeout=CONF.baremetal.unrescue_timeout)
+        waiters.wait_for_server_status(servers_client,
+                                       instance['id'], 'ACTIVE')
+        # Verify server connection
+        self.get_remote_client(server_ip)
diff --git a/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py b/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py
index 5ea83b1..e30b9ef 100644
--- a/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py
+++ b/ironic_tempest_plugin/tests/scenario/ironic_standalone/test_cleaning.py
@@ -18,7 +18,6 @@
 from tempest import config
 from tempest.lib import decorators
 
-from ironic_tempest_plugin.services.baremetal import base
 from ironic_tempest_plugin.tests.scenario import \
     baremetal_standalone_manager as bsm
 
@@ -33,11 +32,11 @@
     image_ref = CONF.baremetal.whole_disk_image_ref
     wholedisk_image = True
     delete_node = False
+    api_microversion = '1.28'
 
     @decorators.idempotent_id('0d82cedd-9697-4cf7-8e4a-80d510f53615')
     @utils.services('image', 'network')
     def test_manual_cleaning(self):
-        base.set_baremetal_api_microversion('1.28')
         self.check_manual_partition_cleaning(self.node)
 
 
@@ -48,11 +47,11 @@
     image_ref = CONF.baremetal.whole_disk_image_ref
     wholedisk_image = True
     delete_node = False
+    api_microversion = '1.28'
 
     @decorators.idempotent_id('fb03abfa-cdfc-41ec-aaa8-c70402786a85')
     @utils.services('image', 'network')
     def test_manual_cleaning(self):
-        base.set_baremetal_api_microversion('1.28')
         self.check_manual_partition_cleaning(self.node)
 
 
@@ -63,9 +62,10 @@
     image_ref = CONF.baremetal.whole_disk_image_ref
     wholedisk_image = True
     delete_node = False
+    deploy_interface = 'iscsi'
+    api_microversion = '1.31'
 
     @decorators.idempotent_id('065238db-1b6d-4d75-a9da-c240f8cbd956')
     @utils.services('image', 'network')
     def test_manual_cleaning(self):
-        base.set_baremetal_api_microversion('1.28')
         self.check_manual_partition_cleaning(self.node)
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 f78155d..61e5323 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
@@ -45,6 +45,26 @@
           expected state transitions
     """
 
+    TEST_RESCUE_MODE = False
+
+    @classmethod
+    def skip_checks(cls):
+        super(BaremetalBasicOps, cls).skip_checks()
+
+        # If default rescue interface is configured to test the rescue
+        # feature, then skips this test and let the test derived class
+        # to be executed.
+        rescue_if = CONF.baremetal.default_rescue_interface
+        if cls.TEST_RESCUE_MODE:
+            if not rescue_if or rescue_if == 'no-rescue':
+                msg = 'Node rescue interface is not enabled.'
+                raise cls.skipException(msg)
+        else:
+            if rescue_if and rescue_if != 'no-rescue':
+                msg = ('Node rescue interface is enabled, but %s class '
+                       'cannot test rescue operations.' % cls.__name__)
+                raise cls.skipException(msg)
+
     @staticmethod
     def _is_version_supported(version):
         """Return whether an API microversion is supported."""
@@ -193,7 +213,6 @@
         self.validate_ports()
         self.validate_scheduling()
         ip_address = self.get_server_ip(self.instance)
-        self.get_remote_client(ip_address).validate_authentication()
         vm_client = self.get_remote_client(ip_address)
 
         # We expect the ephemeral partition to be mounted on /mnt and to have
@@ -205,4 +224,15 @@
             self.create_timestamp(
                 ip_address, private_key=self.keypair['private_key'])
 
+        # Test rescue mode
+        if self.TEST_RESCUE_MODE:
+            self.rescue_instance(self.instance, self.node, ip_address)
+            self.unrescue_instance(self.instance, self.node, ip_address)
+
         self.terminate_instance(self.instance)
+
+
+class BaremetalBasicOpsAndRescue(BaremetalBasicOps):
+    """This test includes rescue/unrescue ops."""
+
+    TEST_RESCUE_MODE = True
diff --git a/tox.ini b/tox.ini
index d7cf22d..6b0e1ae 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 minversion = 2.0
-envlist = py34,py27,pypy,pep8
+envlist = py3,py27,pep8
 skipsdist = True
 
 [testenv]