Merge "Support multiple API and mDNS listen address pairs"

This commit is contained in:
Jenkins 2016-05-04 17:22:11 +00:00 committed by Gerrit Code Review
commit 20b5c13fca
10 changed files with 141 additions and 56 deletions

View File

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

View File

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

View File

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

View File

@ -27,10 +27,17 @@ OPTS = [
help='Number of mdns worker processes to spawn'), help='Number of mdns worker processes to spawn'),
cfg.IntOpt('threads', default=1000, cfg.IntOpt('threads', default=1000,
help='Number of mdns greenthreads to spawn'), help='Number of mdns greenthreads to spawn'),
cfg.IPOpt('host', default='0.0.0.0', cfg.IPOpt('host',
deprecated_for_removal=True,
deprecated_reason="Replaced by 'listen' option",
help='mDNS Bind Host'), help='mDNS Bind Host'),
cfg.PortOpt('port', default=5354, cfg.PortOpt('port',
deprecated_for_removal=True,
deprecated_reason="Replaced by 'listen' option",
help='mDNS Port Number'), help='mDNS Port Number'),
cfg.ListOpt('listen',
default=['0.0.0.0:5354'],
help='mDNS host:port pairs to listen on'),
cfg.IntOpt('tcp-backlog', default=100, cfg.IntOpt('tcp-backlog', default=100,
help='mDNS TCP Backlog'), help='mDNS TCP Backlog'),
cfg.FloatOpt('tcp-recv-timeout', default=0.5, cfg.FloatOpt('tcp-recv-timeout', default=0.5,

View File

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

View File

@ -97,6 +97,43 @@ class Service(service.Service):
super(Service, self).stop() super(Service, self).stop()
def _get_listen_on_addresses(self, default_port):
"""
Helper Method to handle migration from singular host/port to
multiple binds
"""
try:
# The API service uses "api_host", and "api_port", others use
# just host and port.
host = self._service_config.api_host
port = self._service_config.api_port
except cfg.NoSuchOptError:
host = self._service_config.host
port = self._service_config.port
if host or port:
LOG.warning(_LW("host and port config options used, the 'listen' "
"option has been ignored"))
host = host or "0.0.0.0"
port = port or default_port
return [(host, port)]
else:
def _split_host_port(l):
try:
host, port = l.split(':', 1)
return host, int(port)
except ValueError:
LOG.exception(_LE('Invalid ip:port pair: %s'), l)
raise
# Convert listen pair list to a set, to remove accidental
# duplicates.
return map(_split_host_port, set(self._service_config.listen))
class RPCService(object): class RPCService(object):
""" """
@ -180,6 +217,8 @@ class WSGIService(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(WSGIService, self).__init__(*args, **kwargs) super(WSGIService, self).__init__(*args, **kwargs)
self._wsgi_socks = []
@abc.abstractproperty @abc.abstractproperty
def _wsgi_application(self): def _wsgi_application(self):
pass pass
@ -187,23 +226,28 @@ class WSGIService(object):
def start(self): def start(self):
super(WSGIService, self).start() super(WSGIService, self).start()
self._wsgi_sock = utils.bind_tcp( addresses = self._get_listen_on_addresses(9001)
self._service_config.api_host,
self._service_config.api_port, for address in addresses:
CONF.backlog, self._start(address[0], address[1])
CONF.tcp_keepidle)
def _start(self, host, port):
wsgi_sock = utils.bind_tcp(
host, port, CONF.backlog, CONF.tcp_keepidle)
if sslutils.is_enabled(CONF): if sslutils.is_enabled(CONF):
self._wsgi_sock = sslutils.wrap(CONF, self._wsgi_sock) wsgi_sock = sslutils.wrap(CONF, wsgi_sock)
self.tg.add_thread(self._wsgi_handle) self._wsgi_socks.append(wsgi_sock)
def _wsgi_handle(self): self.tg.add_thread(self._wsgi_handle, wsgi_sock)
def _wsgi_handle(self, wsgi_sock):
logger = logging.getLogger('eventlet.wsgi') logger = logging.getLogger('eventlet.wsgi')
# Adjust wsgi MAX_HEADER_LINE to accept large tokens. # Adjust wsgi MAX_HEADER_LINE to accept large tokens.
eventlet.wsgi.MAX_HEADER_LINE = self._service_config.max_header_line eventlet.wsgi.MAX_HEADER_LINE = self._service_config.max_header_line
eventlet.wsgi.server(self._wsgi_sock, eventlet.wsgi.server(wsgi_sock,
self._wsgi_application, self._wsgi_application,
custom_pool=self.tg.pool, custom_pool=self.tg.pool,
log=logger) log=logger)
@ -221,6 +265,9 @@ class DNSService(object):
# reading/writing to the UDP socket at once. Disable this warning. # reading/writing to the UDP socket at once. Disable this warning.
eventlet.debug.hub_prevent_multiple_readers(False) eventlet.debug.hub_prevent_multiple_readers(False)
self._dns_socks_tcp = []
self._dns_socks_udp = []
@abc.abstractproperty @abc.abstractproperty
def _dns_application(self): def _dns_application(self):
pass pass
@ -228,17 +275,23 @@ class DNSService(object):
def start(self): def start(self):
super(DNSService, self).start() super(DNSService, self).start()
self._dns_sock_tcp = utils.bind_tcp( addresses = self._get_listen_on_addresses(self._dns_default_port)
self._service_config.host,
self._service_config.port,
self._service_config.tcp_backlog)
self._dns_sock_udp = utils.bind_udp( for address in addresses:
self._service_config.host, self._start(address[0], address[1])
self._service_config.port)
self.tg.add_thread(self._dns_handle_tcp) def _start(self, host, port):
self.tg.add_thread(self._dns_handle_udp) sock_tcp = utils.bind_tcp(
host, port, self._service_config.tcp_backlog)
sock_udp = utils.bind_udp(
host, port)
self._dns_socks_tcp.append(sock_tcp)
self._dns_socks_udp.append(sock_udp)
self.tg.add_thread(self._dns_handle_tcp, sock_tcp)
self.tg.add_thread(self._dns_handle_udp, sock_udp)
def wait(self): def wait(self):
super(DNSService, self).wait() super(DNSService, self).wait()
@ -248,18 +301,18 @@ class DNSService(object):
# _handle_udp are stopped too. # _handle_udp are stopped too.
super(DNSService, self).stop() super(DNSService, self).stop()
if hasattr(self, '_dns_sock_tcp'): for sock_tcp in self._dns_socks_tcp:
self._dns_sock_tcp.close() sock_tcp.close()
if hasattr(self, '_dns_sock_udp'): for sock_udp in self._dns_socks_udp:
self._dns_sock_udp.close() sock_udp.close()
def _dns_handle_tcp(self): def _dns_handle_tcp(self, sock_tcp):
LOG.info(_LI("_handle_tcp thread started")) LOG.info(_LI("_handle_tcp thread started"))
while True: while True:
try: try:
client, addr = self._dns_sock_tcp.accept() client, addr = sock_tcp.accept()
if self._service_config.tcp_recv_timeout: if self._service_config.tcp_recv_timeout:
client.settimeout(self._service_config.tcp_recv_timeout) client.settimeout(self._service_config.tcp_recv_timeout)
@ -312,20 +365,21 @@ class DNSService(object):
self.tg.add_thread(self._dns_handle, addr, payload, self.tg.add_thread(self._dns_handle, addr, payload,
client=client) client=client)
def _dns_handle_udp(self): def _dns_handle_udp(self, sock_udp):
LOG.info(_LI("_handle_udp thread started")) LOG.info(_LI("_handle_udp thread started"))
while True: while True:
try: try:
# TODO(kiall): Determine the appropriate default value for # TODO(kiall): Determine the appropriate default value for
# UDP recvfrom. # UDP recvfrom.
payload, addr = self._dns_sock_udp.recvfrom(8192) payload, addr = sock_udp.recvfrom(8192)
LOG.debug("Handling UDP Request from: %(host)s:%(port)d" % LOG.debug("Handling UDP Request from: %(host)s:%(port)d" %
{'host': addr[0], 'port': addr[1]}) {'host': addr[0], 'port': addr[1]})
# Dispatch a thread to handle the query # Dispatch a thread to handle the query
self.tg.add_thread(self._dns_handle, addr, payload) self.tg.add_thread(self._dns_handle, addr, payload,
sock_udp=sock_udp)
except socket.error as e: except socket.error as e:
errname = errno.errorcode[e.args[0]] errname = errno.errorcode[e.args[0]]
@ -338,7 +392,7 @@ class DNSService(object):
"from: %(host)s:%(port)d") % "from: %(host)s:%(port)d") %
{'host': addr[0], 'port': addr[1]}) {'host': addr[0], 'port': addr[1]})
def _dns_handle(self, addr, payload, client=None): def _dns_handle(self, addr, payload, client=None, sock_udp=None):
""" """
Handle a DNS Query Handle a DNS Query
@ -360,7 +414,7 @@ class DNSService(object):
client.sendall(tcp_response) client.sendall(tcp_response)
else: else:
# Handle UDP Responses # Handle UDP Responses
self._dns_sock_udp.sendto(response, addr) sock_udp.sendto(response, addr)
except Exception: except Exception:
LOG.exception(_LE("Unhandled exception while processing request " LOG.exception(_LE("Unhandled exception while processing request "

View File

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

View File

@ -82,15 +82,13 @@ function configure_designate {
iniset $DESIGNATE_CONF service:api enabled_extensions_v1 $DESIGNATE_ENABLED_EXTENSIONS_V1 iniset $DESIGNATE_CONF service:api enabled_extensions_v1 $DESIGNATE_ENABLED_EXTENSIONS_V1
iniset $DESIGNATE_CONF service:api enabled_extensions_v2 $DESIGNATE_ENABLED_EXTENSIONS_V2 iniset $DESIGNATE_CONF service:api enabled_extensions_v2 $DESIGNATE_ENABLED_EXTENSIONS_V2
iniset $DESIGNATE_CONF service:api enabled_extensions_admin $DESIGNATE_ENABLED_EXTENSIONS_ADMIN iniset $DESIGNATE_CONF service:api enabled_extensions_admin $DESIGNATE_ENABLED_EXTENSIONS_ADMIN
iniset $DESIGNATE_CONF service:api api_host $DESIGNATE_SERVICE_HOST
iniset $DESIGNATE_CONF service:api api_base_uri $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/ iniset $DESIGNATE_CONF service:api api_base_uri $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/
iniset $DESIGNATE_CONF service:api enable_api_v1 $DESIGNATE_ENABLE_API_V1 iniset $DESIGNATE_CONF service:api enable_api_v1 $DESIGNATE_ENABLE_API_V1
iniset $DESIGNATE_CONF service:api enable_api_v2 $DESIGNATE_ENABLE_API_V2 iniset $DESIGNATE_CONF service:api enable_api_v2 $DESIGNATE_ENABLE_API_V2
iniset $DESIGNATE_CONF service:api enable_api_admin $DESIGNATE_ENABLE_API_ADMIN iniset $DESIGNATE_CONF service:api enable_api_admin $DESIGNATE_ENABLE_API_ADMIN
# mDNS Configuration # mDNS Configuration
iniset $DESIGNATE_CONF service:mdns host $DESIGNATE_SERVICE_HOST iniset $DESIGNATE_CONF service:mdns listen ${DESIGNATE_SERVICE_HOST}:${DESIGNATE_SERVICE_PORT_MDNS}
iniset $DESIGNATE_CONF service:mdns port $DESIGNATE_SERVICE_PORT_MDNS
# Set up Notifications/Ceilometer Integration # Set up Notifications/Ceilometer Integration
iniset $DESIGNATE_CONF DEFAULT notification_driver "$DESIGNATE_NOTIFICATION_DRIVER" iniset $DESIGNATE_CONF DEFAULT notification_driver "$DESIGNATE_NOTIFICATION_DRIVER"
@ -114,9 +112,9 @@ function configure_designate {
# TLS Proxy Configuration # TLS Proxy Configuration
if is_service_enabled tls-proxy; then if is_service_enabled tls-proxy; then
# Set the service port for a proxy to take the original # Set the service port for a proxy to take the original
iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT_INT iniset $DESIGNATE_CONF service:api listen ${DESIGNATE_SERVICE_HOST}:${DESIGNATE_SERVICE_PORT_INT}
else else
iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT iniset $DESIGNATE_CONF service:api listen ${DESIGNATE_SERVICE_HOST}:${DESIGNATE_SERVICE_PORT}
fi fi
# Setup the Keystone Integration # Setup the Keystone Integration

View File

@ -100,11 +100,8 @@ debug = False
# The base uri used in responses # The base uri used in responses
#api_base_uri = 'http://127.0.0.1:9001/' #api_base_uri = 'http://127.0.0.1:9001/'
# Address to bind the API server # API bind host+port pairs, comma separated
#api_host = 0.0.0.0 #listen = 0.0.0.0:9001
# Port the bind the API server to
#api_port = 9001
# Maximum line size of message headers to be accepted. max_header_line may # Maximum line size of message headers to be accepted. max_header_line may
# need to be increased when using large tokens (typically those generated by # need to be increased when using large tokens (typically those generated by
@ -238,11 +235,8 @@ debug = False
# Number of mdns greenthreads to spawn # Number of mdns greenthreads to spawn
#threads = 1000 #threads = 1000
# mDNS Bind Host # mDNS bind host+port pairs, comma separated
#host = 0.0.0.0 #listen = 0.0.0.0:5354
# mDNS Port Number
#port = 5354
# mDNS TCP Backlog # mDNS TCP Backlog
#tcp_backlog = 100 #tcp_backlog = 100
@ -264,8 +258,7 @@ debug = False
#----------------------- #-----------------------
[service:agent] [service:agent]
#workers = None #workers = None
#host = 0.0.0.0 #listen = 0.0.0.0:5358
#port = 5358
#tcp_backlog = 100 #tcp_backlog = 100
#allow_notify = 127.0.0.1 #allow_notify = 127.0.0.1
#masters = 127.0.0.1:5354 #masters = 127.0.0.1:5354

View File

@ -0,0 +1,15 @@
---
features:
- designate-mdns, designate-agent and designate-api can now bind to multiple
host:port pairs via the new "listen" configuration arguments for eacg
service.
deprecations:
- designate-api's api_host and api_port configuration options have been
deprecated, please use the new combined "listen" argument in place of
these.
- designate-mdns's host and port configuration options have been
deprecated, please use the new combined "listen" argument in place of
these.
- designate-agents's host and port configuration options have been
deprecated, please use the new combined "listen" argument in place of
these.