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 40aa1d072a..0a35a3df59 100644 --- a/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py +++ b/ironic_tempest_plugin/services/baremetal/v1/json/baremetal_client.py @@ -195,6 +195,10 @@ class BaremetalClient(base.BaremetalClient): :param address: MAC address of the port. :param extra: Meta data of the port. Default: {'foo': 'bar'}. :param uuid: UUID of the port. + :param portgroup_uuid: The UUID of a portgroup of which this port is a + member. + :param physical_network: The physical network to which the port is + attached. :return: A tuple with the server response and the created port. """ @@ -204,8 +208,9 @@ class BaremetalClient(base.BaremetalClient): if node_id is not None: port['node_uuid'] = node_id - if kwargs['address'] is not None: - port['address'] = kwargs['address'] + for key in ('address', 'physical_network', 'portgroup_uuid'): + if kwargs.get(key) is not None: + port[key] = kwargs[key] return self._create_request('ports', port) diff --git a/ironic_tempest_plugin/tests/api/admin/base.py b/ironic_tempest_plugin/tests/api/admin/base.py index 9577f83fa3..ff51c86f1e 100644 --- a/ironic_tempest_plugin/tests/api/admin/base.py +++ b/ironic_tempest_plugin/tests/api/admin/base.py @@ -185,7 +185,8 @@ class BaseBaremetalTest(api_version_utils.BaseMicroversionTest, @classmethod @creates('port') - def create_port(cls, node_id, address, extra=None, uuid=None): + def create_port(cls, node_id, address, extra=None, uuid=None, + portgroup_uuid=None, physical_network=None): """Wrapper utility for creating test ports. :param node_id: The unique identifier of the node. @@ -193,12 +194,18 @@ class BaseBaremetalTest(api_version_utils.BaseMicroversionTest, :param extra: Meta data of the port. If not supplied, an empty dictionary will be created. :param uuid: UUID of the port. + :param portgroup_uuid: The UUID of a portgroup of which this port is a + member. + :param physical_network: The physical network to which the port is + attached. :return: A tuple with the server response and the created port. """ extra = extra or {} resp, body = cls.client.create_port(address=address, node_id=node_id, - extra=extra, uuid=uuid) + extra=extra, uuid=uuid, + portgroup_uuid=portgroup_uuid, + physical_network=physical_network) return resp, body diff --git a/ironic_tempest_plugin/tests/api/admin/test_ports.py b/ironic_tempest_plugin/tests/api/admin/test_ports.py index fe10573884..a4aea4f268 100644 --- a/ironic_tempest_plugin/tests/api/admin/test_ports.py +++ b/ironic_tempest_plugin/tests/api/admin/test_ports.py @@ -14,6 +14,7 @@ from tempest.lib.common.utils import data_utils from tempest.lib import decorators from tempest.lib import exceptions as lib_exc +from ironic_tempest_plugin.tests.api.admin import api_microversion_fixture from ironic_tempest_plugin.tests.api.admin import base @@ -256,3 +257,120 @@ class TestPorts(base.BaseBaremetalTest): _, body = self.client.show_port(port['uuid']) self.assertEqual(new_address, body['address']) self.assertEqual(new_extra, body['extra']) + + +class TestPortsWithPhysicalNetwork(base.BaseBaremetalTest): + """Tests for ports with physical network information.""" + + min_microversion = '1.34' + + def setUp(self): + super(TestPortsWithPhysicalNetwork, self).setUp() + + self.useFixture( + api_microversion_fixture.APIMicroversionFixture( + TestPortsWithPhysicalNetwork.min_microversion) + ) + _, self.chassis = self.create_chassis() + _, self.node = self.create_node(self.chassis['uuid']) + + @decorators.idempotent_id('f1a5d279-c456-4311-ad31-fea09f61c22b') + def test_create_port_with_physical_network(self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, port = self.create_port(node_id=node_id, address=address, + physical_network='physnet1') + + _, body = self.client.show_port(port['uuid']) + + self._assertExpected(port, body) + self.assertEqual('physnet1', port['physical_network']) + + @decorators.idempotent_id('9c26298b-1bcb-47b7-9b9e-8bdd6e3c4aba') + def test_update_port_replace_physical_network(self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, port = self.create_port(node_id=node_id, address=address, + physical_network='physnet1') + + new_physnet = 'physnet2' + + patch = [{'path': '/physical_network', + 'op': 'replace', + 'value': new_physnet}] + + self.client.update_port(port['uuid'], patch) + + _, body = self.client.show_port(port['uuid']) + self.assertEqual(new_physnet, body['physical_network']) + + @decorators.idempotent_id('6503309c-b2c7-4f59-b15a-0d92b5de9210') + def test_update_port_remove_physical_network(self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, port = self.create_port(node_id=node_id, address=address, + physical_network='physnet1') + + patch = [{'path': '/physical_network', + 'op': 'remove'}] + + self.client.update_port(port['uuid'], patch) + + _, body = self.client.show_port(port['uuid']) + self.assertIsNone(body['physical_network']) + + @decorators.idempotent_id('4155c24d-8474-4b53-a320-aee475f85a68') + def test_create_ports_in_portgroup_with_physical_network(self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, portgroup = self.create_portgroup(node_id, address=address) + + _, port1 = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + address = data_utils.rand_mac_address() + _, port2 = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + _, body = self.client.show_port(port1['uuid']) + self.assertEqual('physnet1', body['physical_network']) + self.assertEqual(portgroup['uuid'], body['portgroup_uuid']) + + _, body = self.client.show_port(port2['uuid']) + self.assertEqual('physnet1', body['physical_network']) + self.assertEqual(portgroup['uuid'], body['portgroup_uuid']) + + @decorators.idempotent_id('cf05a3ef-3bc4-4db7-bb4c-4eb871eb9f81') + def test_update_ports_in_portgroup_with_physical_network(self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, portgroup = self.create_portgroup(node_id, address=address) + + _, port1 = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + address = data_utils.rand_mac_address() + _, port2 = self.create_port(node_id=node_id, address=address, + physical_network='physnet1') + + patch = [{'path': '/portgroup_uuid', + 'op': 'replace', + 'value': portgroup['uuid']}] + + self.client.update_port(port2['uuid'], patch) + + _, body = self.client.show_port(port1['uuid']) + self.assertEqual('physnet1', body['physical_network']) + self.assertEqual(portgroup['uuid'], body['portgroup_uuid']) + + _, body = self.client.show_port(port2['uuid']) + self.assertEqual('physnet1', body['physical_network']) + self.assertEqual(portgroup['uuid'], body['portgroup_uuid']) 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 91ba7fd16e..86a0ce6b19 100644 --- a/ironic_tempest_plugin/tests/api/admin/test_ports_negative.py +++ b/ironic_tempest_plugin/tests/api/admin/test_ports_negative.py @@ -14,6 +14,7 @@ from tempest.lib.common.utils import data_utils from tempest.lib import decorators from tempest.lib import exceptions as lib_exc +from ironic_tempest_plugin.tests.api.admin import api_microversion_fixture from ironic_tempest_plugin.tests.api.admin import base @@ -337,3 +338,128 @@ class TestPortsNegative(base.BaseBaremetalTest): _, body = self.client.show_port(port_id) self.assertEqual(address, body['address']) self.assertEqual(extra, body['extra']) + + +class TestPortsWithPhysicalNetworkOldAPI(base.BaseBaremetalTest): + """Negative tests for ports with physical network information.""" + + old_microversion = '1.33' + + def setUp(self): + super(TestPortsWithPhysicalNetworkOldAPI, self).setUp() + + self.useFixture( + api_microversion_fixture.APIMicroversionFixture( + TestPortsWithPhysicalNetworkOldAPI.old_microversion) + ) + _, self.chassis = self.create_chassis() + _, self.node = self.create_node(self.chassis['uuid']) + + @decorators.idempotent_id('307e57e9-082f-4830-9480-91affcbfda08') + def test_create_port_with_physical_network_old_api(self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + self.assertRaises(lib_exc.UnexpectedResponseCode, + self.create_port, + node_id=node_id, address=address, + physical_network='physnet1') + + @decorators.idempotent_id('0b278c0a-d334-424e-a5c5-b6d001c2a715') + def test_update_port_replace_physical_network_old_api(self): + _, port = self.create_port(self.node['uuid'], + data_utils.rand_mac_address()) + + new_physnet = 'physnet1' + + patch = [{'path': '/physical_network', + 'op': 'replace', + 'value': new_physnet}] + + self.assertRaises(lib_exc.UnexpectedResponseCode, + self.client.update_port, + port['uuid'], patch) + + +class TestPortsNegativeWithPhysicalNetwork(base.BaseBaremetalTest): + """Negative tests for ports with physical network information.""" + + min_microversion = '1.34' + + def setUp(self): + super(TestPortsNegativeWithPhysicalNetwork, self).setUp() + + self.useFixture( + api_microversion_fixture.APIMicroversionFixture( + TestPortsNegativeWithPhysicalNetwork.min_microversion) + ) + _, self.chassis = self.create_chassis() + _, self.node = self.create_node(self.chassis['uuid']) + + @decorators.idempotent_id('e20156fb-956b-4d5b-89a4-f379044a1d3c') + def test_create_ports_in_portgroup_with_inconsistent_physical_network( + self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, portgroup = self.create_portgroup(node_id, address=address) + + _, _ = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + address = data_utils.rand_mac_address() + self.assertRaises(lib_exc.Conflict, + self.create_port, + node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet2') + + @decorators.idempotent_id('050e792c-22c9-4e4a-ae89-dfbfc52ad00d') + def test_update_ports_in_portgroup_with_inconsistent_physical_network( + self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, portgroup = self.create_portgroup(node_id, address=address) + + _, _ = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + address = data_utils.rand_mac_address() + _, port2 = self.create_port(node_id=node_id, address=address, + physical_network='physnet2') + + patch = [{'path': '/portgroup_uuid', + 'op': 'replace', + 'value': portgroup['uuid']}] + + self.assertRaises(lib_exc.Conflict, + self.client.update_port, + port2['uuid'], patch) + + @decorators.idempotent_id('3cd1c8ec-57d1-40cb-922b-dd02431beea3') + def test_update_ports_in_portgroup_with_inconsistent_physical_network_2( + self): + node_id = self.node['uuid'] + address = data_utils.rand_mac_address() + + _, portgroup = self.create_portgroup(node_id, address=address) + + _, _ = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + address = data_utils.rand_mac_address() + _, port2 = self.create_port(node_id=node_id, address=address, + portgroup_uuid=portgroup['uuid'], + physical_network='physnet1') + + patch = [{'path': '/physical_network', + 'op': 'replace', + 'value': 'physnet2'}] + + self.assertRaises(lib_exc.Conflict, + self.client.update_port, + port2['uuid'], patch)