Merge "Fix failure cases around test_ports"
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 b385c28..8461ebf 100644
--- a/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
+++ b/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
@@ -1024,3 +1024,11 @@
             uri=f'{self.uri_prefix}/nodes/{uuid}/inventory')
         self.expected_success(http_client.OK, resp.status)
         return body
+
+    @base.handle_errors
+    def get_shards(self, api_version='1.82'):
+        """Get all shards."""
+
+        extra_headers, headers = self._get_headers(api_version)
+        return self._list_request('shards', headers=headers,
+                                  extra_headers=extra_headers)
diff --git a/ironic_tempest_plugin/tests/api/admin/test_nodes.py b/ironic_tempest_plugin/tests/api/admin/test_nodes.py
index 6d63768..3da3f3e 100644
--- a/ironic_tempest_plugin/tests/api/admin/test_nodes.py
+++ b/ironic_tempest_plugin/tests/api/admin/test_nodes.py
@@ -372,7 +372,7 @@
     def test_create_node_resource_class_old_api(self):
         """Try to create a node with resource class using older api version."""
         resource_class = data_utils.arbitrary_string()
-        self.assertRaises(lib_exc.UnexpectedResponseCode, self.create_node,
+        self.assertRaises(lib_exc.NotAcceptable, self.create_node,
                           self.chassis['uuid'], resource_class=resource_class)
 
     @decorators.attr(type='negative')
@@ -380,7 +380,7 @@
     def test_update_node_resource_class_old_api(self):
         """Try to update a node with resource class using older api version."""
         resource_class = data_utils.arbitrary_string()
-        self.assertRaises(lib_exc.UnexpectedResponseCode,
+        self.assertRaises(lib_exc.NotAcceptable,
                           self.client.update_node,
                           self.node['uuid'], resource_class=resource_class)
 
@@ -390,10 +390,10 @@
         """Try to list nodes with resource class using older api version."""
         resource_class = data_utils.arbitrary_string()
         self.assertRaises(
-            lib_exc.UnexpectedResponseCode,
+            lib_exc.NotAcceptable,
             self.client.list_nodes, resource_class=resource_class)
         self.assertRaises(
-            lib_exc.UnexpectedResponseCode,
+            lib_exc.NotAcceptable,
             self.client.list_nodes_detail, resource_class=resource_class)
 
 
@@ -1043,10 +1043,9 @@
     @decorators.idempotent_id('5419af7b-4e27-4be4-88f6-e01c598a8102')
     def test_list_node_traits_old_api(self):
         """Try to list traits for a node using an older api version."""
-        exc = self.assertRaises(
-            lib_exc.UnexpectedResponseCode,
+        self.assertRaises(
+            lib_exc.NotAcceptable,
             self.client.list_node_traits, self.node['uuid'])
-        self.assertEqual(406, exc.resp.status)
 
     @decorators.attr(type='negative')
     @decorators.idempotent_id('a4353f3a-bedc-4579-9c7e-4bebcd95903d')
@@ -1096,10 +1095,9 @@
     @decorators.idempotent_id('eb75b3c8-ac9c-4399-90a2-c0030bfde7a6')
     def test_list_nodes_traits_field(self):
         """Try to list nodes' traits field using older api version."""
-        exc = self.assertRaises(
-            lib_exc.UnexpectedResponseCode,
+        self.assertRaises(
+            lib_exc.NotAcceptable,
             self.client.list_nodes, fields='traits')
-        self.assertEqual(406, exc.resp.status)
 
     @decorators.attr(type='negative')
     @decorators.idempotent_id('214ae7fc-149b-4657-b6bc-66353d49ade8')
diff --git a/ironic_tempest_plugin/tests/api/admin/test_ports_negative.py b/ironic_tempest_plugin/tests/api/admin/test_ports_negative.py
index 98a4747..fb1913c 100644
--- a/ironic_tempest_plugin/tests/api/admin/test_ports_negative.py
+++ b/ironic_tempest_plugin/tests/api/admin/test_ports_negative.py
@@ -364,7 +364,7 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        self.assertRaises((lib_exc.BadRequest, lib_exc.UnexpectedResponseCode),
+        self.assertRaises((lib_exc.BadRequest, lib_exc.NotAcceptable),
                           self.create_port,
                           node_id=node_id, address=address,
                           physical_network='physnet1')
@@ -381,7 +381,7 @@
                   'op': 'replace',
                   'value': new_physnet}]
 
-        self.assertRaises((lib_exc.BadRequest, lib_exc.UnexpectedResponseCode),
+        self.assertRaises((lib_exc.BadRequest, lib_exc.NotAcceptable),
                           self.client.update_port,
                           port['uuid'], patch)
 
diff --git a/ironic_tempest_plugin/tests/api/admin/test_shards.py b/ironic_tempest_plugin/tests/api/admin/test_shards.py
index ffe6914..8ad76c0 100644
--- a/ironic_tempest_plugin/tests/api/admin/test_shards.py
+++ b/ironic_tempest_plugin/tests/api/admin/test_shards.py
@@ -12,9 +12,12 @@
 
 from tempest import config
 from tempest.lib import decorators
+from tempest.lib import exceptions
 
+from ironic_tempest_plugin.tests.api.admin import api_microversion_fixture
 from ironic_tempest_plugin.tests.api import base
 
+
 CONF = config.CONF
 
 
@@ -126,3 +129,60 @@
 
         self.assertIn(self.none_node_id, fetched_node_ids)
         self.assertNotIn(self.bad_node_id, fetched_node_ids)
+
+    @decorators.idempotent_id('77e36b09-308a-4fdf-bdac-d31d3b4c7c23')
+    def test_only_show_requested_shard_wrong_microversions(self):
+        """Test get node on shard filter fails on bad microversions.
+
+        Test that we get the correct error when using microversions
+        below the minimum supported.
+        """
+        shard = "oneshardtest"
+        self._setup_nodes(shard)
+
+        for microversion in ["1.37", "1.81"]:
+            self.useFixture(
+                api_microversion_fixture.APIMicroversionFixture(microversion)
+            )
+
+            self.assertRaises(
+                exceptions.NotAcceptable,
+                self.client.list_nodes,
+                shard=shard,
+            )
+
+
+class TestGetAllShards(base.BaseBaremetalTest):
+    """Tests for baremetal shards."""
+
+    min_microversion = '1.82'
+
+    def setUp(self):
+        super(TestGetAllShards, self).setUp()
+        _, self.chassis = self.create_chassis()
+        self.shards = ["shard1", "shard2", "shard3"]
+        self.node_ids = []
+        for shard in self.shards:
+            _, node = self.create_node(self.chassis['uuid'], shard=shard)
+            self.node_ids.append(node['uuid'])
+
+    @decorators.idempotent_id('fc786196-63c7-4e0d-bd14-3e478d4d1e3e')
+    def test_get_all_shards(self):
+        _, fetched_shards = self.client.get_shards()
+        fetched_shards = [shard['name'] for shard in fetched_shards['shards']]
+
+        self.assertItemsEqual(self.shards, fetched_shards)
+
+    @decorators.idempotent_id('e9d5fd51-1419-4af2-9d6c-c317556c2096')
+    def test_get_shards_wrong_microversions(self):
+        """Test get shards fails on bad microversions.
+
+        Test that we get the correct error when using microversions
+        below the minimum supported.
+        """
+        for microversion in ["1.37", "1.81"]:
+            self.useFixture(
+                api_microversion_fixture.APIMicroversionFixture(microversion)
+            )
+            # Test microversion below minimum supported
+            self.assertRaises(exceptions.NotFound, self.client.get_shards)
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 1be91a6..4d9da27 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -11,8 +11,6 @@
         - ironic-standalone-2024.1
         - ironic-standalone-2023.2:
             voting: false
-        - ironic-standalone-2023.1:
-            voting: false
         - ironic-tempest-functional-python3
         - ironic-tempest-functional-python3-2024.2
         - ironic-tempest-functional-python3-2024.1
@@ -22,22 +20,16 @@
         - ironic-tempest-functional-rbac-scope-enforced-2024.1
         - ironic-tempest-functional-rbac-scope-enforced-2023.2:
             voting: false
-        - ironic-tempest-functional-rbac-scope-enforced-2023.1:
-            voting: false
         - ironic-standalone-anaconda
         - ironic-standalone-anaconda-2024.2
         - ironic-standalone-anaconda-2024.1
         - ironic-standalone-anaconda-2023.2:
             voting: false
-        - ironic-standalone-anaconda-2023.1:
-            voting: false
         - ironic-standalone-redfish
         - ironic-standalone-redfish-2024.2
         - ironic-standalone-redfish-2024.1
         - ironic-standalone-redfish-2023.2:
             voting: false
-        - ironic-standalone-redfish-2023.1:
-            voting: false
         # NOTE(dtantsur): inspector is deprecated and rarely sees any changes,
         # no point in running many jobs
         - ironic-inspector-tempest
@@ -56,8 +48,6 @@
             voting: false
         - ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode-2023.2:
             voting: false
-        - ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode-2023.1:
-            voting: false
         - ironic-inspector-tempest-discovery:
             voting: false
     gate:
diff --git a/zuul.d/stable-jobs.yaml b/zuul.d/stable-jobs.yaml
index 87c6a7f..c75f782 100644
--- a/zuul.d/stable-jobs.yaml
+++ b/zuul.d/stable-jobs.yaml
@@ -14,11 +14,6 @@
     override-checkout: stable/2023.2
 
 - job:
-    name: ironic-standalone-2023.1
-    parent: ironic-standalone
-    override-checkout: stable/2023.1
-
-- job:
     name: ironic-standalone-redfish-2024.2
     parent: ironic-standalone
     override-checkout: stable/2024.2
@@ -34,11 +29,6 @@
     override-checkout: stable/2023.2
 
 - job:
-    name: ironic-standalone-redfish-2023.1
-    parent: ironic-standalone
-    override-checkout: stable/2023.1
-
-- job:
     name: ironic-standalone-anaconda-2024.2
     parent: ironic-standalone-anaconda
     override-checkout: stable/2024.2
@@ -54,11 +44,6 @@
     override-checkout: stable/2023.2
 
 - job:
-    name: ironic-standalone-anaconda-2023.1
-    parent: ironic-standalone-anaconda
-    override-checkout: stable/2023.1
-
-- job:
     name: ironic-tempest-functional-python3-2024.2
     parent: ironic-tempest-functional-python3
     override-checkout: stable/2024.2
@@ -74,11 +59,6 @@
     override-checkout: stable/2023.2
 
 - job:
-    name: ironic-tempest-functional-python3-2023.1
-    parent: ironic-tempest-functional-python3
-    override-checkout: stable/2023.1
-
-- job:
     name: ironic-tempest-functional-rbac-scope-enforced-2024.2
     parent: ironic-tempest-functional-rbac-scope-enforced
     override-checkout: stable/2024.2
@@ -94,11 +74,6 @@
     override-checkout: stable/2023.2
 
 - job:
-    name: ironic-tempest-functional-rbac-scope-enforced-2023.1
-    parent: ironic-tempest-functional-rbac-scope-enforced
-    override-checkout: stable/2023.1
-
-- job:
     name: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode-2024.2
     parent: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
     override-checkout: stable/2024.2
@@ -114,11 +89,6 @@
     override-checkout: stable/2023.2
 
 - job:
-    name: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode-2023.1
-    parent: ironic-tempest-ipa-wholedisk-direct-tinyipa-multinode
-    override-checkout: stable/2023.1
-
-- job:
     name: ironic-inspector-tempest-2024.2
     parent: ironic-inspector-tempest
     override-checkout: stable/2024.2