From 804349e9be514bc3f0f76f9a2acb48ef7fed3023 Mon Sep 17 00:00:00 2001 From: Zachary Date: Fri, 5 Jan 2018 14:58:21 +0800 Subject: [PATCH] Check for PXE-enabled ports when creating neutron ports The function "add_ports_to_network" will create neutron ports for each PXE-enabled port on task.node to boot the ramdisk. But there is no check to see if there are any PXE-enabled ports. If there aren't, no neutron ports will be created and things will fail further down the pipeline. To fail sooner with an appropriate message, we raise an exception if there are no PXE-enabled ports for the node. Story: 2001811 Task: 12546 Co-Authored-By: Ruby Loo Change-Id: I96c21e7d842ad929161a0d298a342fdf4a1275e2 --- ironic/common/neutron.py | 11 +++++++--- ironic/tests/unit/common/test_neutron.py | 21 +++++++++++++++++++ ...-enabled-ports-check-c1736215dce76e97.yaml | 6 ++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/pxe-enabled-ports-check-c1736215dce76e97.yaml 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.