diff --git a/ironic/common/neutron.py b/ironic/common/neutron.py index d05cf72496..5b5fffae4c 100644 --- a/ironic/common/neutron.py +++ b/ironic/common/neutron.py @@ -238,6 +238,11 @@ def add_ports_to_network(task, network_uuid, security_groups=None): failures = [] portmap = get_node_portmap(task) pxe_enabled_ports = [p for p in task.ports if p.pxe_enabled] + + if not pxe_enabled_ports: + raise exception.NetworkError(_( + "No available PXE-enabled port on node %s.") % node.uuid) + for ironic_port in pxe_enabled_ports: # Skip ports that are missing required information for deploy. if not validate_port_info(node, ironic_port): @@ -278,9 +283,9 @@ def add_ports_to_network(task, network_uuid, security_groups=None): "the following ports: %(ports)s.", {'node': node.uuid, 'ports': failures}) else: - LOG.info('Successfully created ports for node %(node_uuid)s in ' - 'network %(net)s.', - {'node_uuid': node.uuid, 'net': network_uuid}) + LOG.info('For node %(node_uuid)s in network %(net)s, successfully ', + 'created ports (ironic ID: neutron ID): %(ports)s.', + {'node_uuid': node.uuid, 'net': network_uuid, 'ports': ports}) return ports diff --git a/ironic/tests/unit/common/test_neutron.py b/ironic/tests/unit/common/test_neutron.py index 9efb9d8cdb..87e3088056 100644 --- a/ironic/tests/unit/common/test_neutron.py +++ b/ironic/tests/unit/common/test_neutron.py @@ -392,6 +392,27 @@ class TestNeutronNetworkActions(db_base.DbTestCase): self.assertIn("Some errors were encountered when updating", log_mock.warning.call_args_list[1][0][0]) + def test_add_network_no_port(self): + # No port registered + node = object_utils.create_test_node(self.context, + uuid=uuidutils.generate_uuid()) + with task_manager.acquire(self.context, node.uuid) as task: + self.assertEqual([], task.ports) + self.assertRaisesRegex(exception.NetworkError, 'No available', + neutron.add_ports_to_network, + task, self.network_uuid) + + def test_add_network_no_pxe_enabled_ports(self): + # Have port but no PXE enabled + port = self.ports[0] + port.pxe_enabled = False + port.save() + with task_manager.acquire(self.context, self.node.uuid) as task: + self.assertFalse(task.ports[0].pxe_enabled) + self.assertRaisesRegex(exception.NetworkError, 'No available', + neutron.add_ports_to_network, + task, self.network_uuid) + @mock.patch.object(neutron, 'remove_neutron_ports', autospec=True) def test_remove_ports_from_network(self, remove_mock): with task_manager.acquire(self.context, self.node.uuid) as task: diff --git a/releasenotes/notes/pxe-enabled-ports-check-c1736215dce76e97.yaml b/releasenotes/notes/pxe-enabled-ports-check-c1736215dce76e97.yaml new file mode 100644 index 0000000000..ad0abb5d7e --- /dev/null +++ b/releasenotes/notes/pxe-enabled-ports-check-c1736215dce76e97.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + When creating a neutron port for booting a ramdisk, an error is raised if + there are no PXE-enabled ports available for the node. See `bug 2001811 + `_ for more details.