Browse Source

Merge "Support multiple API and mDNS listen address pairs"

Jenkins 3 years ago
parent
commit
20b5c13fca

+ 11
- 4
designate/agent/__init__.py View File

@@ -24,10 +24,17 @@ OPTS = [
24 24
                help='Number of agent worker processes to spawn'),
25 25
     cfg.IntOpt('threads', default=1000,
26 26
                help='Number of agent greenthreads to spawn'),
27
-    cfg.IPOpt('host', default='0.0.0.0',
28
-              help='The host for the Agent to bind to'),
29
-    cfg.PortOpt('port', default=5358,
30
-                help='The port for the Agent to bind to'),
27
+    cfg.IPOpt('host',
28
+              deprecated_for_removal=True,
29
+              deprecated_reason="Replaced by 'listen' option",
30
+              help='Agent Bind Host'),
31
+    cfg.PortOpt('port',
32
+                deprecated_for_removal=True,
33
+                deprecated_reason="Replaced by 'listen' option",
34
+                help='Agent Port Number'),
35
+    cfg.ListOpt('listen',
36
+                default=['0.0.0.0:5358'],
37
+                help='Agent host:port pairs to listen on'),
31 38
     cfg.IntOpt('tcp-backlog', default=100,
32 39
                help='The Agent TCP Backlog'),
33 40
     cfg.FloatOpt('tcp-recv-timeout', default=0.5,

+ 1
- 0
designate/agent/service.py View File

@@ -37,6 +37,7 @@ CONF = cfg.CONF
37 37
 
38 38
 
39 39
 class Service(service.DNSService, service.Service):
40
+    _dns_default_port = 5358
40 41
 
41 42
     def __init__(self, threads=None):
42 43
         super(Service, self).__init__(threads=threads)

+ 10
- 3
designate/api/__init__.py View File

@@ -28,10 +28,17 @@ cfg.CONF.register_opts([
28 28
     cfg.BoolOpt('enable-host-header', default=False,
29 29
                help='Enable host request headers'),
30 30
     cfg.StrOpt('api-base-uri', default='http://127.0.0.1:9001/'),
31
-    cfg.IPOpt('api_host', default='0.0.0.0',
32
-              help='API Host'),
33
-    cfg.PortOpt('api_port', default=9001,
31
+    cfg.IPOpt('api_host',
32
+              deprecated_for_removal=True,
33
+              deprecated_reason="Replaced by 'listen' option",
34
+              help='API Bind Host'),
35
+    cfg.PortOpt('api_port',
36
+                deprecated_for_removal=True,
37
+                deprecated_reason="Replaced by 'listen' option",
34 38
                 help='API Port Number'),
39
+    cfg.ListOpt('listen',
40
+                default=['0.0.0.0:9001'],
41
+                help='API host:port pairs to listen on'),
35 42
     cfg.StrOpt('api_paste_config', default='api-paste.ini',
36 43
                help='File name for the paste.deploy config for designate-api'),
37 44
     cfg.StrOpt('auth_strategy', default='keystone',

+ 9
- 2
designate/mdns/__init__.py View File

@@ -27,10 +27,17 @@ OPTS = [
27 27
                help='Number of mdns worker processes to spawn'),
28 28
     cfg.IntOpt('threads', default=1000,
29 29
                help='Number of mdns greenthreads to spawn'),
30
-    cfg.IPOpt('host', default='0.0.0.0',
30
+    cfg.IPOpt('host',
31
+              deprecated_for_removal=True,
32
+              deprecated_reason="Replaced by 'listen' option",
31 33
               help='mDNS Bind Host'),
32
-    cfg.PortOpt('port', default=5354,
34
+    cfg.PortOpt('port',
35
+                deprecated_for_removal=True,
36
+                deprecated_reason="Replaced by 'listen' option",
33 37
                 help='mDNS Port Number'),
38
+    cfg.ListOpt('listen',
39
+                default=['0.0.0.0:5354'],
40
+                help='mDNS host:port pairs to listen on'),
34 41
     cfg.IntOpt('tcp-backlog', default=100,
35 42
                help='mDNS TCP Backlog'),
36 43
     cfg.FloatOpt('tcp-recv-timeout', default=0.5,

+ 1
- 0
designate/mdns/service.py View File

@@ -29,6 +29,7 @@ CONF = cfg.CONF
29 29
 
30 30
 
31 31
 class Service(service.DNSService, service.RPCService, service.Service):
32
+    _dns_default_port = 5354
32 33
 
33 34
     @property
34 35
     def storage(self):

+ 83
- 29
designate/service.py View File

@@ -97,6 +97,43 @@ class Service(service.Service):
97 97
 
98 98
         super(Service, self).stop()
99 99
 
100
+    def _get_listen_on_addresses(self, default_port):
101
+        """
102
+        Helper Method to handle migration from singular host/port to
103
+        multiple binds
104
+        """
105
+        try:
106
+            # The API service uses "api_host", and "api_port", others use
107
+            # just host and port.
108
+            host = self._service_config.api_host
109
+            port = self._service_config.api_port
110
+
111
+        except cfg.NoSuchOptError:
112
+            host = self._service_config.host
113
+            port = self._service_config.port
114
+
115
+        if host or port:
116
+            LOG.warning(_LW("host and port config options used, the 'listen' "
117
+                            "option has been ignored"))
118
+
119
+            host = host or "0.0.0.0"
120
+            port = port or default_port
121
+
122
+            return [(host, port)]
123
+
124
+        else:
125
+            def _split_host_port(l):
126
+                try:
127
+                    host, port = l.split(':', 1)
128
+                    return host, int(port)
129
+                except ValueError:
130
+                    LOG.exception(_LE('Invalid ip:port pair: %s'), l)
131
+                    raise
132
+
133
+            # Convert listen pair list to a set, to remove accidental
134
+            # duplicates.
135
+            return map(_split_host_port, set(self._service_config.listen))
136
+
100 137
 
101 138
 class RPCService(object):
102 139
     """
@@ -180,6 +217,8 @@ class WSGIService(object):
180 217
     def __init__(self, *args, **kwargs):
181 218
         super(WSGIService, self).__init__(*args, **kwargs)
182 219
 
220
+        self._wsgi_socks = []
221
+
183 222
     @abc.abstractproperty
184 223
     def _wsgi_application(self):
185 224
         pass
@@ -187,23 +226,28 @@ class WSGIService(object):
187 226
     def start(self):
188 227
         super(WSGIService, self).start()
189 228
 
190
-        self._wsgi_sock = utils.bind_tcp(
191
-            self._service_config.api_host,
192
-            self._service_config.api_port,
193
-            CONF.backlog,
194
-            CONF.tcp_keepidle)
229
+        addresses = self._get_listen_on_addresses(9001)
230
+
231
+        for address in addresses:
232
+            self._start(address[0], address[1])
233
+
234
+    def _start(self, host, port):
235
+        wsgi_sock = utils.bind_tcp(
236
+            host, port, CONF.backlog, CONF.tcp_keepidle)
195 237
 
196 238
         if sslutils.is_enabled(CONF):
197
-            self._wsgi_sock = sslutils.wrap(CONF, self._wsgi_sock)
239
+            wsgi_sock = sslutils.wrap(CONF, wsgi_sock)
198 240
 
199
-        self.tg.add_thread(self._wsgi_handle)
241
+        self._wsgi_socks.append(wsgi_sock)
200 242
 
201
-    def _wsgi_handle(self):
243
+        self.tg.add_thread(self._wsgi_handle, wsgi_sock)
244
+
245
+    def _wsgi_handle(self, wsgi_sock):
202 246
         logger = logging.getLogger('eventlet.wsgi')
203 247
         # Adjust wsgi MAX_HEADER_LINE to accept large tokens.
204 248
         eventlet.wsgi.MAX_HEADER_LINE = self._service_config.max_header_line
205 249
 
206
-        eventlet.wsgi.server(self._wsgi_sock,
250
+        eventlet.wsgi.server(wsgi_sock,
207 251
                              self._wsgi_application,
208 252
                              custom_pool=self.tg.pool,
209 253
                              log=logger)
@@ -221,6 +265,9 @@ class DNSService(object):
221 265
         # reading/writing to the UDP socket at once. Disable this warning.
222 266
         eventlet.debug.hub_prevent_multiple_readers(False)
223 267
 
268
+        self._dns_socks_tcp = []
269
+        self._dns_socks_udp = []
270
+
224 271
     @abc.abstractproperty
225 272
     def _dns_application(self):
226 273
         pass
@@ -228,17 +275,23 @@ class DNSService(object):
228 275
     def start(self):
229 276
         super(DNSService, self).start()
230 277
 
231
-        self._dns_sock_tcp = utils.bind_tcp(
232
-            self._service_config.host,
233
-            self._service_config.port,
234
-            self._service_config.tcp_backlog)
278
+        addresses = self._get_listen_on_addresses(self._dns_default_port)
235 279
 
236
-        self._dns_sock_udp = utils.bind_udp(
237
-            self._service_config.host,
238
-            self._service_config.port)
280
+        for address in addresses:
281
+            self._start(address[0], address[1])
239 282
 
240
-        self.tg.add_thread(self._dns_handle_tcp)
241
-        self.tg.add_thread(self._dns_handle_udp)
283
+    def _start(self, host, port):
284
+        sock_tcp = utils.bind_tcp(
285
+            host, port, self._service_config.tcp_backlog)
286
+
287
+        sock_udp = utils.bind_udp(
288
+            host, port)
289
+
290
+        self._dns_socks_tcp.append(sock_tcp)
291
+        self._dns_socks_udp.append(sock_udp)
292
+
293
+        self.tg.add_thread(self._dns_handle_tcp, sock_tcp)
294
+        self.tg.add_thread(self._dns_handle_udp, sock_udp)
242 295
 
243 296
     def wait(self):
244 297
         super(DNSService, self).wait()
@@ -248,18 +301,18 @@ class DNSService(object):
248 301
         # _handle_udp are stopped too.
249 302
         super(DNSService, self).stop()
250 303
 
251
-        if hasattr(self, '_dns_sock_tcp'):
252
-            self._dns_sock_tcp.close()
304
+        for sock_tcp in self._dns_socks_tcp:
305
+            sock_tcp.close()
253 306
 
254
-        if hasattr(self, '_dns_sock_udp'):
255
-            self._dns_sock_udp.close()
307
+        for sock_udp in self._dns_socks_udp:
308
+            sock_udp.close()
256 309
 
257
-    def _dns_handle_tcp(self):
310
+    def _dns_handle_tcp(self, sock_tcp):
258 311
         LOG.info(_LI("_handle_tcp thread started"))
259 312
 
260 313
         while True:
261 314
             try:
262
-                client, addr = self._dns_sock_tcp.accept()
315
+                client, addr = sock_tcp.accept()
263 316
 
264 317
                 if self._service_config.tcp_recv_timeout:
265 318
                     client.settimeout(self._service_config.tcp_recv_timeout)
@@ -312,20 +365,21 @@ class DNSService(object):
312 365
                 self.tg.add_thread(self._dns_handle, addr, payload,
313 366
                                    client=client)
314 367
 
315
-    def _dns_handle_udp(self):
368
+    def _dns_handle_udp(self, sock_udp):
316 369
         LOG.info(_LI("_handle_udp thread started"))
317 370
 
318 371
         while True:
319 372
             try:
320 373
                 # TODO(kiall): Determine the appropriate default value for
321 374
                 #              UDP recvfrom.
322
-                payload, addr = self._dns_sock_udp.recvfrom(8192)
375
+                payload, addr = sock_udp.recvfrom(8192)
323 376
 
324 377
                 LOG.debug("Handling UDP Request from: %(host)s:%(port)d" %
325 378
                          {'host': addr[0], 'port': addr[1]})
326 379
 
327 380
                 # Dispatch a thread to handle the query
328
-                self.tg.add_thread(self._dns_handle, addr, payload)
381
+                self.tg.add_thread(self._dns_handle, addr, payload,
382
+                                   sock_udp=sock_udp)
329 383
 
330 384
             except socket.error as e:
331 385
                 errname = errno.errorcode[e.args[0]]
@@ -338,7 +392,7 @@ class DNSService(object):
338 392
                                   "from: %(host)s:%(port)d") %
339 393
                               {'host': addr[0], 'port': addr[1]})
340 394
 
341
-    def _dns_handle(self, addr, payload, client=None):
395
+    def _dns_handle(self, addr, payload, client=None, sock_udp=None):
342 396
         """
343 397
         Handle a DNS Query
344 398
 
@@ -360,7 +414,7 @@ class DNSService(object):
360 414
                         client.sendall(tcp_response)
361 415
                     else:
362 416
                         # Handle UDP Responses
363
-                        self._dns_sock_udp.sendto(response, addr)
417
+                        sock_udp.sendto(response, addr)
364 418
 
365 419
         except Exception:
366 420
             LOG.exception(_LE("Unhandled exception while processing request "

+ 3
- 1
designate/tests/test_mdns/test_service.py View File

@@ -60,6 +60,8 @@ class MdnsServiceTest(MdnsTestCase):
60 60
         expected_response = (b"271289050001000000000000076578616d706c6503636f6"
61 61
                              b"d0000010001")
62 62
 
63
-        self.service._dns_handle(self.addr, binascii.a2b_hex(payload))
63
+        sock_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
64
+        self.service._dns_handle(self.addr, binascii.a2b_hex(payload),
65
+                                 sock_udp=sock_udp)
64 66
         sendto_mock.assert_called_once_with(
65 67
             binascii.a2b_hex(expected_response), self.addr)

+ 3
- 5
devstack/plugin.sh View File

@@ -82,15 +82,13 @@ function configure_designate {
82 82
     iniset $DESIGNATE_CONF service:api enabled_extensions_v1 $DESIGNATE_ENABLED_EXTENSIONS_V1
83 83
     iniset $DESIGNATE_CONF service:api enabled_extensions_v2 $DESIGNATE_ENABLED_EXTENSIONS_V2
84 84
     iniset $DESIGNATE_CONF service:api enabled_extensions_admin $DESIGNATE_ENABLED_EXTENSIONS_ADMIN
85
-    iniset $DESIGNATE_CONF service:api api_host $DESIGNATE_SERVICE_HOST
86 85
     iniset $DESIGNATE_CONF service:api api_base_uri $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/
87 86
     iniset $DESIGNATE_CONF service:api enable_api_v1 $DESIGNATE_ENABLE_API_V1
88 87
     iniset $DESIGNATE_CONF service:api enable_api_v2 $DESIGNATE_ENABLE_API_V2
89 88
     iniset $DESIGNATE_CONF service:api enable_api_admin $DESIGNATE_ENABLE_API_ADMIN
90 89
 
91 90
     # mDNS Configuration
92
-    iniset $DESIGNATE_CONF service:mdns host $DESIGNATE_SERVICE_HOST
93
-    iniset $DESIGNATE_CONF service:mdns port $DESIGNATE_SERVICE_PORT_MDNS
91
+    iniset $DESIGNATE_CONF service:mdns listen ${DESIGNATE_SERVICE_HOST}:${DESIGNATE_SERVICE_PORT_MDNS}
94 92
 
95 93
     # Set up Notifications/Ceilometer Integration
96 94
     iniset $DESIGNATE_CONF DEFAULT notification_driver "$DESIGNATE_NOTIFICATION_DRIVER"
@@ -114,9 +112,9 @@ function configure_designate {
114 112
     # TLS Proxy Configuration
115 113
     if is_service_enabled tls-proxy; then
116 114
         # Set the service port for a proxy to take the original
117
-        iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT_INT
115
+        iniset $DESIGNATE_CONF service:api listen ${DESIGNATE_SERVICE_HOST}:${DESIGNATE_SERVICE_PORT_INT}
118 116
     else
119
-        iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT
117
+        iniset $DESIGNATE_CONF service:api listen ${DESIGNATE_SERVICE_HOST}:${DESIGNATE_SERVICE_PORT}
120 118
     fi
121 119
 
122 120
     # Setup the Keystone Integration

+ 5
- 12
etc/designate/designate.conf.sample View File

@@ -100,11 +100,8 @@ debug = False
100 100
 # The base uri used in responses
101 101
 #api_base_uri = 'http://127.0.0.1:9001/'
102 102
 
103
-# Address to bind the API server
104
-#api_host = 0.0.0.0
105
-
106
-# Port the bind the API server to
107
-#api_port = 9001
103
+# API bind host+port pairs, comma separated
104
+#listen = 0.0.0.0:9001
108 105
 
109 106
 # Maximum line size of message headers to be accepted. max_header_line may
110 107
 # need to be increased when using large tokens (typically those generated by
@@ -238,11 +235,8 @@ debug = False
238 235
 # Number of mdns greenthreads to spawn
239 236
 #threads = 1000
240 237
 
241
-# mDNS Bind Host
242
-#host = 0.0.0.0
243
-
244
-# mDNS Port Number
245
-#port = 5354
238
+# mDNS bind host+port pairs, comma separated
239
+#listen = 0.0.0.0:5354
246 240
 
247 241
 # mDNS TCP Backlog
248 242
 #tcp_backlog = 100
@@ -264,8 +258,7 @@ debug = False
264 258
 #-----------------------
265 259
 [service:agent]
266 260
 #workers = None
267
-#host = 0.0.0.0
268
-#port = 5358
261
+#listen = 0.0.0.0:5358
269 262
 #tcp_backlog = 100
270 263
 #allow_notify = 127.0.0.1
271 264
 #masters = 127.0.0.1:5354

+ 15
- 0
releasenotes/notes/api-mdns-multiple-bind-c78853de46ee587d.yaml View File

@@ -0,0 +1,15 @@
1
+---
2
+features:
3
+  - designate-mdns, designate-agent and designate-api can now bind to multiple
4
+    host:port pairs via the new "listen" configuration arguments for eacg
5
+    service.
6
+deprecations:
7
+  - designate-api's api_host and api_port configuration options have been
8
+    deprecated, please use the new combined "listen" argument in place of
9
+    these.
10
+  - designate-mdns's host and port configuration options have been
11
+    deprecated, please use the new combined "listen" argument in place of
12
+    these.
13
+  - designate-agents's host and port configuration options have been
14
+    deprecated, please use the new combined "listen" argument in place of
15
+    these.

Loading…
Cancel
Save