Validate network data for portgroups

Check that network_data.json from configdrive contains
all required information to build a bond according to
node porgroup configuration.

Related-Bug: #1718481
Related-Prod: PRODX-49717
Change-Id: I0f06f01fdfcd6665e1e493dcebd26747aef6dd3a
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 5715609..6613d1c 100644
--- a/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
+++ b/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py
@@ -59,14 +59,24 @@
         return self._list_request('/chassis/%s/nodes' % chassis_uuid)
 
     @base.handle_errors
-    def list_ports(self, **kwargs):
-        """List all existing ports."""
-        return self._list_request('ports', **kwargs)
+    def list_ports(self, api_version=None, **kwargs):
+        """List all existing ports.
+
+        :param api_version: Ironic API version to use.
+        """
+        extra_headers, headers = self._get_headers(api_version)
+        return self._list_request('ports', headers=headers,
+                                  extra_headers=headers, **kwargs)
 
     @base.handle_errors
-    def list_portgroups(self, **kwargs):
-        """List all existing port groups."""
-        return self._list_request('portgroups', **kwargs)
+    def list_portgroups(self, api_version=None, **kwargs):
+        """List all existing port groups.
+
+        :param api_version: Ironic API version to use.
+        """
+        extra_headers, headers = self._get_headers(api_version)
+        return self._list_request('portgroups', headers=headers,
+                                  extra_headers=extra_headers, **kwargs)
 
     @base.handle_errors
     def list_volume_connectors(self, **kwargs):
@@ -168,13 +178,17 @@
         return self._show_request('ports', uuid)
 
     @base.handle_errors
-    def show_portgroup(self, portgroup_ident):
+    def show_portgroup(self, portgroup_ident, api_version=None):
         """Gets a specific port group.
 
         :param portgroup_ident: Name or UUID of the port group.
+        :param api_version: Ironic API version to use.
         :return: Serialized port group as a dictionary.
         """
-        return self._show_request('portgroups', portgroup_ident)
+        extra_headers, headers = self._get_headers(api_version)
+        return self._show_request('portgroups', portgroup_ident,
+                                  headers=headers,
+                                  extra_headers=extra_headers)
 
     @base.handle_errors
     def show_volume_connector(self, volume_connector_ident):
diff --git a/ironic_tempest_plugin/tests/scenario/baremetal_manager.py b/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
index 27b3c9d..9a7287a 100644
--- a/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
+++ b/ironic_tempest_plugin/tests/scenario/baremetal_manager.py
@@ -146,6 +146,16 @@
             ports.append(p)
         return ports
 
+    def get_portgroups(self, node_uuid):
+        portgroups = []
+        _, body = self.baremetal_client.list_portgroups(
+            node=node_uuid, api_version='1.23')
+        for portgroup in body['portgroups']:
+            _, p = self.baremetal_client.show_portgroup(
+                portgroup['uuid'], api_version='1.23')
+            portgroups.append(p)
+        return portgroups
+
     def get_node_vifs(self, node_uuid, api_version='1.28'):
         _, body = self.baremetal_client.vif_list(node_uuid,
                                                  api_version=api_version)
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 b5513c7..473d088 100644
--- a/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
+++ b/ironic_tempest_plugin/tests/scenario/test_baremetal_basic_ops.py
@@ -13,6 +13,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import json
 import re
 
 from oslo_log import log as logging
@@ -228,6 +229,38 @@
         output = client.exec_command(cmd).rstrip()
         self.assertEqual(success_string, output)
 
+    def validate_network_data(self, ssh_client):
+        portgroups = self.get_portgroups(self.node["uuid"])
+        if not portgroups:
+            return
+
+        ssh_client.mount_config_drive()
+        cmd_md = 'sudo cat /mnt/openstack/latest/network_data.json'
+        result = ssh_client.exec_command(cmd_md)
+        ssh_client.unmount_config_drive()
+        result = json.loads(result)
+
+        self.assertIn('links', result)
+        bond_seen = False
+        modes_to_check = []
+        expected_links_count = 0
+
+        for pg in portgroups:
+            modes_to_check.append(pg['mode'])
+            expected_links_count += 1
+            _, body = self.baremetal_client.list_ports(
+                portgroup=pg['uuid'], api_version='1.28')
+            expected_links_count += len(body['ports'])
+
+        for link in result["links"]:
+            if link["type"] == "bond":
+                bond_seen = True
+                self.assertIn('bond_mode', link)
+                self.assertIn('bond_mode', link)
+                self.assertIn(link['bond_mode'], modes_to_check)
+        self.assertEqual(len(result['links']), expected_links_count)
+        self.assertTrue(bond_seen)
+
     def baremetal_server_ops(self):
         self.add_keypair()
         self.instance, self.node = self.boot_instance(image_id=self.image_ref)
@@ -250,6 +283,8 @@
         if CONF.baremetal.boot_mode == "uefi":
             self.validate_uefi(vm_client)
 
+        self.validate_network_data(vm_client)
+
         # Test rescue mode
         if self.TEST_RESCUE_MODE:
             self.rescue_instance(self.instance, self.node, ip_address)