diff --git a/esi/lib/networks.py b/esi/lib/networks.py index 92412fb..1b29fdb 100644 --- a/esi/lib/networks.py +++ b/esi/lib/networks.py @@ -112,3 +112,26 @@ def get_networks_from_port(connection, port, networks_dict={}, floating_ips_dict floating_network = connection.network.get_network(floating_network_id) return parent_network, trunk_networks, trunk_ports, floating_network + + +def create_port(connection, node_name, network): + """ + Creates a port on the specified network using the network object. + + :param connection: An OpenStack connection object used to interact with OpenStack services. + :param node_name: The name of the node associated with the port. + :param network: The network object where the port should be created. + This object must have 'id' and 'name' attributes. + + :return: The created port object, or an existing port if a matching one was found. + """ + + port_name = 'esi-{0}-{1}'.format(node_name, network.name) + existing_ports = list(connection.network.ports(name=port_name, status='DOWN')) + + if existing_ports: + network_port = existing_ports[0] + else: + network_port = connection.network.create_port(name=port_name, network_id=network.id, device_owner='baremetal:none') + + return network_port diff --git a/esi/lib/nodes.py b/esi/lib/nodes.py index 9b238e7..3fd0eae 100644 --- a/esi/lib/nodes.py +++ b/esi/lib/nodes.py @@ -209,14 +209,7 @@ def network_attach(connection, node, attach_info): raise exceptions.ResourceFailure('Node {0} has no free ports'.format(node.name)) if network: - port_name = 'esi-{0}-{1}'.format(node.name, parent_network.name) - network_ports = list(connection.network.ports(name=port_name, status='DOWN')) - if len(network_ports) > 0: - network_port = network_ports[0] - else: - network_port = connection.network.create_port(name=port_name, - network_id=parent_network.id, - device_owner='baremetal:none') + network_port = networks.create_port(connection, node.name, parent_network) elif trunk: network_port = connection.network.find_port(trunk_network.port_id, ignore_missing=False) diff --git a/esi/tests/unit/lib/test_networks.py b/esi/tests/unit/lib/test_networks.py index 621288f..378fc18 100644 --- a/esi/tests/unit/lib/test_networks.py +++ b/esi/tests/unit/lib/test_networks.py @@ -389,3 +389,40 @@ def test_get_networks_from_port_trunk(self): ) self.assertEqual(actual, expected) + + +class TestCreatePort(TestCase): + + def setUp(self): + super(TestCreatePort, self).setUp() + self.connection = mock.Mock() + self.network = test_utils.create_mock_object({ + "id": "network_uuid", + "name": "test_network" + }) + self.port = test_utils.create_mock_object({ + "id": "port_uuid", + "network_id": "network_uuid", + "name": "esi-port-test_network", + }) + + def test_create_port_with_defaults(self): + self.connection.network.ports.return_value = [] + self.connection.network.create_port.return_value = self.port + actual_port = networks.create_port(self.connection, "node_name", self.network) + self.connection.network.ports.assert_called_once_with( + name='esi-node_name-test_network', status='DOWN' + ) + self.connection.network.create_port.assert_called_once_with( + name='esi-node_name-test_network', network_id="network_uuid", device_owner="baremetal:none" + ) + self.assertEqual(actual_port, self.port) + + def test_create_port_with_existing_port(self): + self.connection.network.ports.return_value = [self.port] + actual_port = networks.create_port(self.connection, "node_name", self.network) + self.connection.network.ports.assert_called_once_with( + name='esi-node_name-test_network', status='DOWN' + ) + self.connection.network.create_port.assert_not_called() + self.assertEqual(actual_port, self.port)