Enhance wsgi to listen on ipv6 address

Check if the hostname is ipv6 and set the family appropriately.
Picked up the code snippet from glance to determine the address_family
per markmclain's comment
Picked up some code from nova as well to get the test case running
properly

Fixes LP# 1101341

Change-Id: I67166dc030e4ea0dd82888abfbc9db555747de27
This commit is contained in:
Davanum Srinivas 2013-01-10 11:26:25 -05:00
parent 61a4bd7124
commit 20314e0ba0
2 changed files with 104 additions and 2 deletions

View File

@ -0,0 +1,69 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import socket
import unittest2 as unittest
from quantum import wsgi
class TestWSGIServer(unittest.TestCase):
"""WSGI server tests."""
def test_start_random_port(self):
server = wsgi.Server("test_random_port")
server.start(None, 0, host="127.0.0.1")
self.assertNotEqual(0, server.port)
server.stop()
server.wait()
def test_start_random_port_with_ipv6(self):
server = wsgi.Server("test_random_port")
server.start(None, 0, host="::1")
self.assertEqual("::1", server.host)
self.assertNotEqual(0, server.port)
server.stop()
server.wait()
class TestWSGIServer2(unittest.TestCase):
def setUp(self):
self.eventlet_p = mock.patch.object(wsgi, 'eventlet')
self.eventlet = self.eventlet_p.start()
self.server = wsgi.Server("test_app")
def tearDown(self):
self.eventlet_p.stop()
def test_ipv6_with_link_local_start(self):
mock_app = mock.Mock()
with mock.patch.object(self.server, 'pool') as pool:
self.server.start(mock_app,
0,
host="fe80::204:acff:fe96:da87%eth0")
self.eventlet.assert_has_calls([
mock.call.listen(('fe80::204:acff:fe96:da87%eth0', 0, 0, 2),
backlog=128,
family=10)
])
pool.spawn.assert_has_calls([mock.call(
self.server._run,
mock_app,
self.eventlet.listen.mock_calls[0].return_value)
])

View File

@ -18,6 +18,7 @@
"""
Utility methods for working with WSGI servers
"""
import socket
import sys
from xml.dom import minidom
from xml.parsers import expat
@ -51,8 +52,40 @@ class Server(object):
def start(self, application, port, host='0.0.0.0', backlog=128):
"""Run a WSGI server with the given application."""
socket = eventlet.listen((host, port), backlog=backlog)
self.pool.spawn_n(self._run, application, socket)
self._host = host
self._port = port
# TODO(dims): eventlet's green dns/socket module does not actually
# support IPv6 in getaddrinfo(). We need to get around this in the
# future or monitor upstream for a fix
try:
info = socket.getaddrinfo(self._host,
self._port,
socket.AF_UNSPEC,
socket.SOCK_STREAM)[0]
family = info[0]
bind_addr = info[-1]
self._socket = eventlet.listen(bind_addr,
family=family,
backlog=backlog)
except:
LOG.exception(_("Unable to listen on %(host)s:%(port)s") %
{'host': host, 'port': port})
sys.exit(1)
self._server = self.pool.spawn(self._run, application, self._socket)
@property
def host(self):
return self._socket.getsockname()[0] if self._socket else self._host
@property
def port(self):
return self._socket.getsockname()[1] if self._socket else self._port
def stop(self):
self._server.kill()
def wait(self):
"""Wait until all servers have completed running."""