From 9e4b769055d0d4ca136afa0b1865930cc2cec6d7 Mon Sep 17 00:00:00 2001
From: Robert Li <baoli@cisco.com>
Date: Thu, 14 Jan 2016 07:54:29 -0500
Subject: [PATCH] Build socket list right before select call

This will make sure the socket list and the interface list are
always in sync, and the select call is on the right list of
sockets.

Co-Authored-By: Dmitry Tantsur <dtantsur@redhat.com>
Closes-Bug: #1533892
Change-Id: Id6710f4648203b7d476a2a16ea647224baca1bb9
---
 ironic_python_agent/netutils.py                    | 3 +--
 ironic_python_agent/tests/unit/test_netutils.py    | 9 ++++++++-
 releasenotes/notes/lldp-loop-fdfa584caf33d847.yaml | 4 ++++
 3 files changed, 13 insertions(+), 3 deletions(-)
 create mode 100644 releasenotes/notes/lldp-loop-fdfa584caf33d847.yaml

diff --git a/ironic_python_agent/netutils.py b/ironic_python_agent/netutils.py
index ccf73c147..801833a39 100644
--- a/ironic_python_agent/netutils.py
+++ b/ironic_python_agent/netutils.py
@@ -162,13 +162,12 @@ def _get_lldp_info(interfaces):
     if not interfaces:
         return {}
 
-    socks = [interface[1] for interface in interfaces]
-
     while interfaces:
         LOG.info('Waiting on LLDP info for interfaces: %(interfaces)s, '
                  'timeout: %(timeout)s', {'interfaces': interfaces,
                                           'timeout': CONF.lldp_timeout})
 
+        socks = [interface[1] for interface in interfaces]
         # rlist is a list of sockets ready for reading
         rlist, _, _ = select.select(socks, [], [], CONF.lldp_timeout)
         if not rlist:
diff --git a/ironic_python_agent/tests/unit/test_netutils.py b/ironic_python_agent/tests/unit/test_netutils.py
index 2bafff4f7..257a556e4 100644
--- a/ironic_python_agent/tests/unit/test_netutils.py
+++ b/ironic_python_agent/tests/unit/test_netutils.py
@@ -113,7 +113,8 @@ class TestNetutils(test_base.BaseTestCase):
         sock_mock.side_effect = [sock1, sock2]
 
         select_mock.side_effect = [
-            ([sock1, sock2], [], []),
+            ([sock1], [], []),
+            ([sock2], [], []),
         ]
 
         lldp_info = netutils.get_lldp_info(interface_names)
@@ -131,6 +132,12 @@ class TestNetutils(test_base.BaseTestCase):
         # 2 interfaces, 2 calls to enter promiscuous mode, 1 to leave
         self.assertEqual(6, fcntl_mock.call_count)
 
+        expected_calls = [
+            mock.call([sock1, sock2], [], [], cfg.CONF.lldp_timeout),
+            mock.call([sock2], [], [], cfg.CONF.lldp_timeout),
+        ]
+        self.assertEqual(expected_calls, select_mock.call_args_list)
+
     @mock.patch('fcntl.ioctl')
     @mock.patch('select.select')
     @mock.patch('socket.socket')
diff --git a/releasenotes/notes/lldp-loop-fdfa584caf33d847.yaml b/releasenotes/notes/lldp-loop-fdfa584caf33d847.yaml
new file mode 100644
index 000000000..343f29bd4
--- /dev/null
+++ b/releasenotes/notes/lldp-loop-fdfa584caf33d847.yaml
@@ -0,0 +1,4 @@
+---
+fixes:
+  - Fixed incorrect invocation of "select" which could cause LLDP collection
+    to hang under certain conditions.