Merge "Single tenant tests: BM to BM and BM to VM"
diff --git a/.gitreview b/.gitreview
index 5977701..5226891 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,4 +1,4 @@
 [gerrit]
-host=review.openstack.org
+host=review.opendev.org
 port=29418
 project=openstack/ironic-tempest-plugin.git
diff --git a/README.rst b/README.rst
index 0f7ec06..e4e5a10 100644
--- a/README.rst
+++ b/README.rst
@@ -7,7 +7,7 @@
 
 * Free software: Apache license
 * Documentation: https://docs.openstack.org/ironic-tempest-plugin
-* Source: https://git.openstack.org/cgit/openstack/ironic-tempest-plugin
+* Source: https://opendev.org/openstack/ironic-tempest-plugin
 * Bugs: https://storyboard.openstack.org/#!/project/951
 
 .. _Tempest: https://docs.openstack.org/tempest/latest/
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 2156eb7..114d4b0 100755
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -22,10 +22,13 @@
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = [
     'sphinx.ext.autodoc',
-    #'sphinx.ext.intersphinx',
-    'oslosphinx'
+    'openstackdocstheme'
 ]
 
+# openstackdocstheme options
+repository_name = 'openstack/ironic-tempest-plugin'
+use_storyboard = True
+
 # autodoc generation is a bit aggressive and a nuisance when doing heavy
 # text edit cycles.
 # execute "export SPHINX_DEBUG=1" in your terminal to disable
@@ -55,8 +58,8 @@
 # The theme to use for HTML and HTML Help pages.  Major themes that come with
 # Sphinx are currently 'default' and 'sphinxdoc'.
 # html_theme_path = ["."]
-# html_theme = '_theme'
 # html_static_path = ['static']
+html_theme = 'openstackdocs'
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = '%sdoc' % project
diff --git a/ironic_tempest_plugin/config.py b/ironic_tempest_plugin/config.py
index a3b5019..79b6d18 100644
--- a/ironic_tempest_plugin/config.py
+++ b/ironic_tempest_plugin/config.py
@@ -198,4 +198,6 @@
     cfg.StrOpt('auto_discovery_target_driver',
                help="The driver to set on the newly discovered nodes. "
                     "Only has effect with auto_discovery_feature is True."),
+    cfg.StrOpt('data_store',
+               help="The storage backend for storing introspection data."),
 ]
diff --git a/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py b/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
index 08e15cd..b326e0d 100644
--- a/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
+++ b/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
@@ -846,7 +846,8 @@
         :return: A tuple with the server response and the created allocation.
 
         """
-        kwargs['resource_class'] = resource_class
+        if resource_class:
+            kwargs['resource_class'] = resource_class
         return self._create_request('allocations', kwargs)
 
     @base.handle_errors
diff --git a/ironic_tempest_plugin/tests/api/admin/base.py b/ironic_tempest_plugin/tests/api/admin/base.py
index 746eea6..8cc8aec 100644
--- a/ironic_tempest_plugin/tests/api/admin/base.py
+++ b/ironic_tempest_plugin/tests/api/admin/base.py
@@ -104,7 +104,7 @@
         cls.power_timeout = CONF.baremetal.power_timeout
         cls.unprovision_timeout = CONF.baremetal.unprovision_timeout
         cls.created_objects = {}
-        for resource in RESOURCE_TYPES:
+        for resource in RESOURCE_TYPES + ['allocation']:
             cls.created_objects[resource] = set()
         cls.deployed_nodes = set()
 
@@ -122,6 +122,14 @@
                 except lib_exc.BadRequest:
                     pass
 
+            # Delete allocations explicitly after unprovisioning instances, but
+            # before deleting nodes.
+            for allocation in cls.created_objects['allocation']:
+                try:
+                    cls.client.delete_allocation(allocation)
+                except lib_exc.NotFound:
+                    pass
+
             for node in cls.created_objects['node']:
                 try:
                     cls.client.update_node(node, instance_uuid=None)
@@ -452,3 +460,15 @@
                         res=resource,
                         uuid=uuid)
         self.assertEqual(expected_link, link)
+
+    @classmethod
+    @creates('allocation')
+    def create_allocation(cls, resource_class, **kwargs):
+        """Wrapper utility for creating test allocations.
+
+        :param resource_class: Resource class to request.
+        :param kwargs: Other fields to pass.
+        :return: A tuple with the server response and the created allocation.
+        """
+        resp, body = cls.client.create_allocation(resource_class, **kwargs)
+        return resp, body
diff --git a/ironic_tempest_plugin/tests/api/admin/test_allocations.py b/ironic_tempest_plugin/tests/api/admin/test_allocations.py
index a6e8e9c..972d864 100644
--- a/ironic_tempest_plugin/tests/api/admin/test_allocations.py
+++ b/ironic_tempest_plugin/tests/api/admin/test_allocations.py
@@ -21,18 +21,15 @@
 CONF = config.CONF
 
 
-class TestAllocations(base.BaseBaremetalTest):
-    """Tests for baremetal allocations."""
-
-    min_microversion = '1.52'
-
-    def provide_node(self, node_id, cleaning_timeout=None):
-        super(TestAllocations, self).provide_node(node_id, cleaning_timeout)
+class Base(base.BaseBaremetalTest):
+    @classmethod
+    def provide_and_power_off_node(cls, node_id, cleaning_timeout=None):
+        cls.provide_node(node_id, cleaning_timeout)
         # Force non-empty power state, otherwise allocation API won't pick it
-        self.client.set_node_power_state(node_id, 'power off')
+        cls.client.set_node_power_state(node_id, 'power off')
 
     def setUp(self):
-        super(TestAllocations, self).setUp()
+        super(Base, self).setUp()
 
         # Generate a resource class to prevent parallel tests from clashing
         # with each other.
@@ -41,12 +38,18 @@
         _, self.chassis = self.create_chassis()
         _, self.node = self.create_node(self.chassis['uuid'],
                                         resource_class=self.resource_class)
-        self.provide_node(self.node['uuid'])
+        self.provide_and_power_off_node(self.node['uuid'])
+
+
+class TestAllocations(Base):
+    """Tests for baremetal allocations."""
+
+    min_microversion = '1.52'
 
     @decorators.idempotent_id('9203ea28-3c61-4108-8498-22247b654ff6')
     def test_create_show_allocation(self):
         self.assertIsNone(self.node['allocation_uuid'])
-        _, body = self.client.create_allocation(self.resource_class)
+        _, body = self.create_allocation(self.resource_class)
         uuid = body['uuid']
 
         self.assertTrue(uuid)
@@ -72,10 +75,10 @@
         _, node2 = self.create_node(self.chassis['uuid'],
                                     resource_class=self.resource_class)
         self.client.set_node_traits(node2['uuid'], ['CUSTOM_MEOW'])
-        self.provide_node(node2['uuid'])
+        self.provide_and_power_off_node(node2['uuid'])
 
-        _, body = self.client.create_allocation(self.resource_class,
-                                                traits=['CUSTOM_MEOW'])
+        _, body = self.create_allocation(self.resource_class,
+                                         traits=['CUSTOM_MEOW'])
         uuid = body['uuid']
 
         self.assertTrue(uuid)
@@ -95,10 +98,10 @@
         _, node2 = self.create_node(self.chassis['uuid'],
                                     resource_class=self.resource_class,
                                     name=node_name)
-        self.provide_node(node2['uuid'])
+        self.provide_and_power_off_node(node2['uuid'])
 
-        _, body = self.client.create_allocation(self.resource_class,
-                                                candidate_nodes=[node_name])
+        _, body = self.create_allocation(self.resource_class,
+                                         candidate_nodes=[node_name])
         uuid = body['uuid']
 
         self.assertTrue(uuid)
@@ -114,23 +117,21 @@
 
     @decorators.idempotent_id('84eb3c21-4e16-4f33-9551-dce0f8689462')
     def test_delete_allocation(self):
-        _, body = self.client.create_allocation(self.resource_class)
+        _, body = self.create_allocation(self.resource_class)
         self.client.delete_allocation(body['uuid'])
         self.assertRaises(lib_exc.NotFound, self.client.show_allocation,
                           body['uuid'])
 
     @decorators.idempotent_id('5e30452d-ee92-4342-82c1-5eea5e55c937')
     def test_delete_allocation_by_name(self):
-        _, body = self.client.create_allocation(self.resource_class,
-                                                name='banana')
+        _, body = self.create_allocation(self.resource_class, name='banana')
         self.client.delete_allocation('banana')
         self.assertRaises(lib_exc.NotFound, self.client.show_allocation,
                           'banana')
 
     @decorators.idempotent_id('fbbc13bc-86da-438b-af01-d1bc1bab57d6')
     def test_show_by_name(self):
-        _, body = self.client.create_allocation(self.resource_class,
-                                                name='banana')
+        _, body = self.create_allocation(self.resource_class, name='banana')
         _, loaded_body = self.client.show_allocation('banana')
         # The allocation will likely have been processed by this time, so do
         # not compare the whole body.
@@ -139,7 +140,7 @@
 
     @decorators.idempotent_id('4ca123c4-160d-4d8d-a3f7-15feda812263')
     def test_list_allocations(self):
-        _, body = self.client.create_allocation(self.resource_class)
+        _, body = self.create_allocation(self.resource_class)
 
         _, listing = self.client.list_allocations()
         self.assertIn(body['uuid'],
@@ -152,8 +153,8 @@
 
     @decorators.idempotent_id('092b7148-9ff0-4107-be57-2cfcd21eb5d7')
     def test_list_allocations_by_state(self):
-        _, body = self.client.create_allocation(self.resource_class)
-        _, body2 = self.client.create_allocation(self.resource_class + 'foo2')
+        _, body = self.create_allocation(self.resource_class)
+        _, body2 = self.create_allocation(self.resource_class + 'foo2')
 
         waiters.wait_for_allocation(self.client, body['uuid'])
         waiters.wait_for_allocation(self.client, body2['uuid'],
@@ -177,7 +178,7 @@
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('bf7e1375-019a-466a-a294-9c1052827ada')
     def test_create_allocation_resource_class_mismatch(self):
-        _, body = self.client.create_allocation(self.resource_class + 'foo')
+        _, body = self.create_allocation(self.resource_class + 'foo')
 
         _, body = waiters.wait_for_allocation(self.client, body['uuid'],
                                               expect_error=True)
@@ -187,7 +188,7 @@
     @decorators.attr(type=['negative'])
     @decorators.idempotent_id('b4eeddee-ca34-44f9-908b-490b78b18486')
     def test_create_allocation_traits_mismatch(self):
-        _, body = self.client.create_allocation(
+        _, body = self.create_allocation(
             self.resource_class, traits=['CUSTOM_DOES_NOT_EXIST'])
 
         _, body = waiters.wait_for_allocation(self.client, body['uuid'],
@@ -201,10 +202,56 @@
         _, node2 = self.create_node(self.chassis['uuid'],
                                     resource_class=self.resource_class + 'alt')
         # Mismatch between the resource class and the candidate node
-        _, body = self.client.create_allocation(
+        _, body = self.create_allocation(
             self.resource_class, candidate_nodes=[node2['uuid']])
 
         _, body = waiters.wait_for_allocation(self.client, body['uuid'],
                                               expect_error=True)
         self.assertEqual('error', body['state'])
         self.assertTrue(body['last_error'])
+
+
+class TestBackfill(Base):
+    """Tests for backfilling baremetal allocations."""
+
+    min_microversion = '1.58'
+
+    @decorators.idempotent_id('10774c1d-6b79-453a-8e26-9bf04ab580a4')
+    def test_backfill_allocation(self):
+        self.deploy_node(self.node['uuid'])
+
+        _, body = self.client.create_allocation(self.resource_class,
+                                                node=self.node['uuid'])
+        uuid = body['uuid']
+        self.assertEqual(self.node['uuid'], body['node_uuid'])
+        self.assertEqual('active', body['state'])
+        self.assertIsNone(body['last_error'])
+
+        _, body2 = self.client.show_node_allocation(body['node_uuid'])
+        self.assertEqual(self.node['uuid'], body2['node_uuid'])
+        self.assertEqual('active', body2['state'])
+        self.assertIsNone(body2['last_error'])
+
+        _, node = self.client.show_node(self.node['uuid'])
+        self.assertEqual(uuid, node['allocation_uuid'])
+
+    @decorators.idempotent_id('c33d4b65-1232-4a3f-9aad-942e32f6f7b0')
+    def test_backfill_without_resource_class(self):
+        self.deploy_node(self.node['uuid'])
+
+        _, body = self.client.create_allocation(None, node=self.node['uuid'])
+        uuid = body['uuid']
+        self.assertEqual(self.node['uuid'], body['node_uuid'])
+        self.assertEqual('active', body['state'])
+        self.assertIsNone(body['last_error'])
+        # Resource class is copied from node
+        self.assertEqual(self.node['resource_class'], body['resource_class'])
+
+        _, body2 = self.client.show_node_allocation(body['node_uuid'])
+        self.assertEqual(self.node['uuid'], body2['node_uuid'])
+        self.assertEqual('active', body2['state'])
+        self.assertIsNone(body2['last_error'])
+        self.assertEqual(self.node['resource_class'], body2['resource_class'])
+
+        _, node = self.client.show_node(self.node['uuid'])
+        self.assertEqual(uuid, node['allocation_uuid'])
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 61e5323..4fa73ee 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
@@ -101,13 +101,13 @@
         LOG.info("Looking for partition %s mounted on %s", label, mount)
 
         # Validate we have a device with the given partition label
-        cmd = "/sbin/blkid | grep '%s' | cut -d':' -f1" % label
+        cmd = "/sbin/blkid -c /dev/null -l -o device -t LABEL=%s" % label
         device = client.exec_command(cmd).rstrip('\n')
         LOG.debug("Partition device is %s", device)
         self.assertNotEqual('', device)
 
         # Validate the mount point for the device
-        cmd = "mount | grep '%s' | cut -d' ' -f3" % device
+        cmd = "mount | grep -w '%s' | cut -d' ' -f3" % device
         actual_mount = client.exec_command(cmd).rstrip('\n')
         LOG.debug("Partition mount point is %s", actual_mount)
         self.assertEqual(actual_mount, mount)
diff --git a/ironic_tempest_plugin/tests/scenario/test_introspection_basic.py b/ironic_tempest_plugin/tests/scenario/test_introspection_basic.py
index f97316d..9823a88 100644
--- a/ironic_tempest_plugin/tests/scenario/test_introspection_basic.py
+++ b/ironic_tempest_plugin/tests/scenario/test_introspection_basic.py
@@ -94,7 +94,12 @@
         for node_id in self.node_ids:
             node = self.node_show(node_id)
             self.assertEqual('yes', node['extra']['rule_success'])
-            if CONF.service_available.swift:
+            data_store = CONF.baremetal_introspection.data_store
+            if data_store is None:
+                # Backward compatibility, the option is not set.
+                data_store = ('swift' if CONF.service_available.swift
+                              else 'none')
+            if data_store != 'none':
                 self.verify_node_introspection_data(node)
             self.verify_node_flavor(node)
 
diff --git a/ironic_tempest_plugin/tests/scenario/test_introspection_discovery.py b/ironic_tempest_plugin/tests/scenario/test_introspection_discovery.py
index c44844f..6f92d43 100644
--- a/ironic_tempest_plugin/tests/scenario/test_introspection_discovery.py
+++ b/ironic_tempest_plugin/tests/scenario/test_introspection_discovery.py
@@ -156,7 +156,12 @@
 
         inspected_node = self.node_show(self.node_info['name'])
         self.verify_node_flavor(inspected_node)
-        if CONF.service_available.swift:
+        data_store = CONF.baremetal_introspection.data_store
+        if data_store is None:
+            # Backward compatibility, the option is not set.
+            data_store = ('swift' if CONF.service_available.swift
+                          else 'none')
+        if data_store != 'none':
             self.verify_node_introspection_data(inspected_node)
         self.assertEqual(ProvisionStates.ENROLL,
                          inspected_node['provision_state'])
diff --git a/test-requirements.txt b/test-requirements.txt
index 1b68194..b5667d2 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -4,8 +4,8 @@
 
 hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
 
-sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
-oslosphinx>=4.7.0 # Apache-2.0
+sphinx!=1.6.6,!=1.6.7,>=1.6.2,<2.0.0;python_version=='2.7' # BSD
+sphinx!=1.6.6,!=1.6.7,>=1.6.2;python_version>='3.4' # BSD
+openstackdocstheme>=1.18.1 # Apache-2.0
 
-# releasenotes
 reno>=2.5.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 6b0e1ae..0cc29c7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,11 +5,12 @@
 
 [testenv]
 usedevelop = True
-install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
+install_command = pip install {opts} {packages}
 setenv =
    VIRTUAL_ENV={envdir}
    PYTHONWARNINGS=default::DeprecationWarning
-deps = -r{toxinidir}/test-requirements.txt
+deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+       -r{toxinidir}/test-requirements.txt
 commands = python setup.py test --slowest --testr-args='{posargs}'
 
 [testenv:pep8]
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 2c6dce8..bcedbc3 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -7,48 +7,46 @@
       jobs:
         # NOTE(dtantsur): keep N-3 and older non-voting for these jobs.
         - ironic-standalone
+        - ironic-standalone-stein
         - ironic-dsvm-standalone-rocky
-        # NOTE(iurygregory): we want to make voting again
         - ironic-dsvm-standalone-queens:
             voting: false
-        - ironic-dsvm-standalone-pike:
-            voting: false
         - ironic-tempest-functional-python3
+        - ironic-tempest-functional-python3-stein
         - ironic-tempest-dsvm-functional-python3-rocky
         - ironic-inspector-tempest
+        - ironic-inspector-tempest-stein
         - ironic-tempest-dsvm-ironic-inspector-rocky
-        - ironic-tempest-dsvm-ironic-inspector-queens
-        - ironic-tempest-dsvm-ironic-inspector-pike:
+        - ironic-tempest-dsvm-ironic-inspector-queens:
             voting: false
         # NOTE(dtantsur): these jobs cover rarely changed tests and are quite
         # unstable, so keep them non-voting on stable branches.
-        # NOTE(iurygregory):  debug rocky and queens
-        # since before was working, pike was broken before
+        # NOTE(iurygregory): debug rocky and queens since they used to pass
         - ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
+        - ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode-stein:
+            voting: false
         - ironic-tempest-dsvm-ipa-wholedisk-agent_ipmitool-tinyipa-multinode-rocky:
             voting: false
         - ironic-tempest-dsvm-ipa-wholedisk-agent_ipmitool-tinyipa-multinode-queens:
             voting: false
-        - ironic-tempest-dsvm-ipa-wholedisk-agent_ipmitool-tinyipa-multinode-pike:
-            voting: false
         - ironic-inspector-tempest-discovery
+        - ironic-inspector-tempest-discovery-stein:
+            voting: false
         - ironic-inspector-tempest-dsvm-discovery-rocky:
             voting: false
         - ironic-inspector-tempest-dsvm-discovery-queens:
             voting: false
-        # NOTE(iurygregory): we may want to debug why its failling since before was green
-        - ironic-inspector-tempest-dsvm-discovery-pike:
-            voting: false
     gate:
       queue: ironic
       jobs:
-        # NOTE(iurygregory): re add ironic-dsvm-standalone-queens when is green again
         - ironic-standalone
+        - ironic-standalone-stein
         - ironic-dsvm-standalone-rocky
         - ironic-tempest-functional-python3
+        - ironic-tempest-functional-python3-stein
         - ironic-tempest-dsvm-functional-python3-rocky
         - ironic-inspector-tempest
+        - ironic-inspector-tempest-stein
         - ironic-tempest-dsvm-ironic-inspector-rocky
-        - ironic-tempest-dsvm-ironic-inspector-queens
         - ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
         - ironic-inspector-tempest-discovery
diff --git a/zuul.d/stable-jobs.yaml b/zuul.d/stable-jobs.yaml
index e4cf069..f553787 100644
--- a/zuul.d/stable-jobs.yaml
+++ b/zuul.d/stable-jobs.yaml
@@ -1,4 +1,9 @@
 - job:
+    name: ironic-standalone-stein
+    parent: ironic-standalone
+    override-branch: stable/stein
+
+- job:
     name: ironic-dsvm-standalone-rocky
     parent: ironic-standalone
     override-branch: stable/rocky
@@ -15,12 +20,10 @@
         EBTABLES_RACE_FIX: True
         IRONIC_USE_MOD_WSGI: True
 
-
 - job:
-    name: ironic-dsvm-standalone-pike
-    parent: ironic-standalone
-    override-branch: stable/pike
-    nodeset: openstack-single-node-xenial
+    name: ironic-tempest-functional-python3-stein
+    parent: ironic-tempest-functional-python3
+    override-branch: stable/stein
 
 - job:
     name: ironic-tempest-dsvm-functional-python3-rocky
@@ -34,6 +37,11 @@
         rabbit: True
 
 - job:
+    name: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode-stein
+    parent: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
+    override-branch: stable/stein
+
+- job:
     name: ironic-tempest-dsvm-ipa-wholedisk-agent_ipmitool-tinyipa-multinode-rocky
     parent: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
     override-branch: stable/rocky
@@ -70,22 +78,13 @@
           OVS_BRIDGE_MAPPINGS: 'mynetwork:sub1brbm,public:br_ironic_vxlan'
 
 - job:
-    name: ironic-tempest-dsvm-ipa-wholedisk-agent_ipmitool-tinyipa-multinode-pike
-    parent: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
-    override-branch: stable/pike
-    nodeset: openstack-two-node-xenial
+    name: ironic-inspector-tempest-stein
+    parent: ironic-inspector-tempest
+    override-branch: stable/stein
     vars:
       devstack_localrc:
-        IRONIC_DEFAULT_BOOT_OPTION: netboot
         FIXED_NETWORK_SIZE: 4096
-        IRONIC_DEFAULT_RESCUE_INTERFACE: agent
         EBTABLES_RACE_FIX: True
-        PUBLIC_BRIDGE: br_ironic_vxlan
-        OVS_BRIDGE_MAPPINGS: 'mynetwork:brbm,public:br_ironic_vxlan'
-    group-vars:
-      subnode:
-        devstack_localrc:
-          OVS_BRIDGE_MAPPINGS: 'mynetwork:sub1brbm,public:br_ironic_vxlan'
 
 - job:
     name: ironic-tempest-dsvm-ironic-inspector-rocky
@@ -108,14 +107,9 @@
         EBTABLES_RACE_FIX: True
 
 - job:
-    name: ironic-tempest-dsvm-ironic-inspector-pike
-    parent: ironic-inspector-tempest
-    override-branch: stable/pike
-    nodeset: openstack-single-node-xenial
-    vars:
-      devstack_localrc:
-        FIXED_NETWORK_SIZE: 4096
-        EBTABLES_RACE_FIX: True
+    name: ironic-inspector-tempest-discovery-stein
+    parent: ironic-inspector-tempest-discovery
+    override-branch: stable/stein
 
 - job:
     name: ironic-inspector-tempest-dsvm-discovery-rocky
@@ -128,9 +122,3 @@
     parent: ironic-inspector-tempest-discovery
     override-branch: stable/queens
     nodeset: openstack-single-node-xenial
-
-- job:
-    name: ironic-inspector-tempest-dsvm-discovery-pike
-    parent: ironic-inspector-tempest-discovery
-    override-branch: stable/pike
-    nodeset: openstack-single-node-xenial