Skip to content

Commit

Permalink
Enhance wsgi to listen on ipv6 address
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Davanum Srinivas committed Jan 22, 2013
1 parent 61a4bd7 commit 20314e0
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 2 deletions.
69 changes: 69 additions & 0 deletions quantum/tests/unit/test_wsgi.py
@@ -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)
])
37 changes: 35 additions & 2 deletions quantum/wsgi.py
Expand Up @@ -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
Expand Down Expand Up @@ -51,8 +52,40 @@ def __init__(self, name, threads=1000):

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."""
Expand Down

0 comments on commit 20314e0

Please sign in to comment.