Browse Source

Avoid eventlet_backdoor listing on same port

Oslo.service is binding to same port when we provide a port range
as eventlet is internally setting SO_REUSEPORT flag (starting from
eventlet version v0.20). And there is a flag (reuse_port)
introduced in v0.22 to give control to user to avoid SO_REUSEPORT.
In this patch, first we try passing reuse_port=False, if this fails
then directly open socket and listen instead of eventlist.listen.

Closes-Bug: #1810280
Change-Id: Idc842acc7e430199c76fe12785b0bf0e7a58e121
venkata anil 3 months ago
parent
commit
811650783d
2 changed files with 25 additions and 4 deletions
  1. 17
    4
      oslo_service/eventlet_backdoor.py
  2. 8
    0
      oslo_service/tests/test_eventlet_backdoor.py

+ 17
- 4
oslo_service/eventlet_backdoor.py View File

@@ -21,13 +21,13 @@ import gc
21 21
 import logging
22 22
 import os
23 23
 import pprint
24
-import socket
25 24
 import sys
26 25
 import traceback
27 26
 
28 27
 import eventlet.backdoor
29 28
 import greenlet
30 29
 
30
+from eventlet.green import socket
31 31
 from oslo_service._i18n import _
32 32
 from oslo_service import _options
33 33
 
@@ -121,11 +121,24 @@ def _parse_port_range(port_range):
121 121
             port_range, ex, _options.help_for_backdoor_port)
122 122
 
123 123
 
124
-def _listen(host, start_port, end_port, listen_func):
124
+def _listen_func(host, port):
125
+    # eventlet is setting SO_REUSEPORT by default from v0.20.
126
+    # But we can configure it by passing reuse_port argument
127
+    # from v0.22
128
+    try:
129
+        return eventlet.listen((host, port), reuse_port=False)
130
+    except TypeError:
131
+        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
132
+        sock.bind((host, port))
133
+        sock.listen(50)
134
+        return sock
135
+
136
+
137
+def _listen(host, start_port, end_port):
125 138
     try_port = start_port
126 139
     while True:
127 140
         try:
128
-            return listen_func((host, try_port))
141
+            return _listen_func(host, try_port)
129 142
         except socket.error as exc:
130 143
             if (exc.errno != errno.EADDRINUSE or
131 144
                try_port >= end_port):
@@ -169,7 +182,7 @@ def _initialize_if_enabled(conf):
169 182
 
170 183
     if conf.backdoor_socket is None:
171 184
         start_port, end_port = _parse_port_range(str(conf.backdoor_port))
172
-        sock = _listen('localhost', start_port, end_port, eventlet.listen)
185
+        sock = _listen('localhost', start_port, end_port)
173 186
         # In the case of backdoor port being zero, a port number is assigned by
174 187
         # listen().  In any case, pull the port number out here.
175 188
         where_running = sock.getsockname()[1]

+ 8
- 0
oslo_service/tests/test_eventlet_backdoor.py View File

@@ -105,6 +105,14 @@ class BackdoorPortTest(base.ServiceBaseTestCase):
105 105
         self.assertRaises(socket.error,
106 106
                           eventlet_backdoor.initialize_if_enabled, self.conf)
107 107
 
108
+    @mock.patch.object(eventlet, 'spawn')
109
+    def test_backdoor_port_range_inuse(self, spawn_mock):
110
+        self.config(backdoor_port='8800:8801')
111
+        port = eventlet_backdoor.initialize_if_enabled(self.conf)
112
+        self.assertEqual(8800, port)
113
+        port = eventlet_backdoor.initialize_if_enabled(self.conf)
114
+        self.assertEqual(8801, port)
115
+
108 116
     @mock.patch.object(eventlet, 'spawn')
109 117
     @mock.patch.object(eventlet, 'listen')
110 118
     def test_backdoor_port_range(self, listen_mock, spawn_mock):

Loading…
Cancel
Save