Support for SSL in wsgi.Server
SSL are entirely optional. Support for SSL as well using code from glance. We have some new options for configuring the SSL support. There are tests for accessing a sample app w/o ipv6 or ssl, one with just ssl and one with ipv6 and ssl Fixes LP# 1101342 DocImpact Change-Id: I824acef4130d27828dcf199736b3ca668d6202d7
This commit is contained in:
parent
a30e7c10da
commit
a4faa98b99
@ -222,6 +222,33 @@ notification_topics = notifications
|
|||||||
# router_auto_schedule = True
|
# router_auto_schedule = True
|
||||||
# =========== end of items for agent scheduler extension =====
|
# =========== end of items for agent scheduler extension =====
|
||||||
|
|
||||||
|
# =========== WSGI parameters related to the API server ==============
|
||||||
|
# Sets the value of TCP_KEEPIDLE in seconds to use for each server socket when
|
||||||
|
# starting API server. Not supported on OS X.
|
||||||
|
#tcp_keepidle = 600
|
||||||
|
|
||||||
|
# Number of seconds to keep retrying to listen
|
||||||
|
#retry_until_window = 30
|
||||||
|
|
||||||
|
# Number of backlog requests to configure the socket with.
|
||||||
|
#backlog = 4096
|
||||||
|
|
||||||
|
# Enable SSL on the API server
|
||||||
|
#use_ssl = False
|
||||||
|
|
||||||
|
# Certificate file to use when starting API server securely
|
||||||
|
#ssl_cert_file = /path/to/certfile
|
||||||
|
|
||||||
|
# Private key file to use when starting API server securely
|
||||||
|
#ssl_key_file = /path/to/keyfile
|
||||||
|
|
||||||
|
# CA certificate file to use when starting API server securely to
|
||||||
|
# verify connecting clients. This is an optional parameter only required if
|
||||||
|
# API clients need to authenticate to the API server using SSL certificates
|
||||||
|
# signed by a trusted CA
|
||||||
|
#ssl_ca_file = /path/to/cafile
|
||||||
|
# ======== end of WSGI parameters related to the API server ==========
|
||||||
|
|
||||||
[QUOTAS]
|
[QUOTAS]
|
||||||
# resource name(s) that are supported in quota features
|
# resource name(s) that are supported in quota features
|
||||||
# quota_items = network,subnet,port
|
# quota_items = network,subnet,port
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
import urllib2
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
|
from oslo.config import cfg
|
||||||
import webob
|
import webob
|
||||||
import webob.exc
|
import webob.exc
|
||||||
|
|
||||||
@ -28,6 +31,11 @@ from quantum.common import exceptions as exception
|
|||||||
from quantum.tests import base
|
from quantum.tests import base
|
||||||
from quantum import wsgi
|
from quantum import wsgi
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
TEST_VAR_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||||
|
'..', 'var'))
|
||||||
|
|
||||||
|
|
||||||
class TestWSGIServer(base.BaseTestCase):
|
class TestWSGIServer(base.BaseTestCase):
|
||||||
"""WSGI server tests."""
|
"""WSGI server tests."""
|
||||||
@ -74,7 +82,7 @@ class TestWSGIServer(base.BaseTestCase):
|
|||||||
mock_listen.assert_called_once_with(
|
mock_listen.assert_called_once_with(
|
||||||
('fe80::204:acff:fe96:da87%eth0', 1234, 0, 2),
|
('fe80::204:acff:fe96:da87%eth0', 1234, 0, 2),
|
||||||
family=socket.AF_INET6,
|
family=socket.AF_INET6,
|
||||||
backlog=128
|
backlog=cfg.CONF.backlog
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_pool.spawn.assert_has_calls([
|
mock_pool.spawn.assert_has_calls([
|
||||||
@ -84,6 +92,25 @@ class TestWSGIServer(base.BaseTestCase):
|
|||||||
mock_listen.return_value)
|
mock_listen.return_value)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_app(self):
|
||||||
|
greetings = 'Hello, World!!!'
|
||||||
|
|
||||||
|
def hello_world(env, start_response):
|
||||||
|
if env['PATH_INFO'] != '/':
|
||||||
|
start_response('404 Not Found',
|
||||||
|
[('Content-Type', 'text/plain')])
|
||||||
|
return ['Not Found\r\n']
|
||||||
|
start_response('200 OK', [('Content-Type', 'text/plain')])
|
||||||
|
return [greetings]
|
||||||
|
|
||||||
|
server = wsgi.Server("test_app")
|
||||||
|
server.start(hello_world, 0, host="127.0.0.1")
|
||||||
|
|
||||||
|
response = urllib2.urlopen('http://127.0.0.1:%d/' % server.port)
|
||||||
|
self.assertEquals(greetings, response.read())
|
||||||
|
|
||||||
|
server.stop()
|
||||||
|
|
||||||
|
|
||||||
class SerializerTest(base.BaseTestCase):
|
class SerializerTest(base.BaseTestCase):
|
||||||
def test_serialize_unknown_content_type(self):
|
def test_serialize_unknown_content_type(self):
|
||||||
@ -1016,3 +1043,49 @@ class XMLDictSerializerTest(base.BaseTestCase):
|
|||||||
result = serializer(data)
|
result = serializer(data)
|
||||||
result = result.replace('\n', '').replace(' ', '')
|
result = result.replace('\n', '').replace(' ', '')
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
|
||||||
|
class TestWSGIServerWithSSL(base.BaseTestCase):
|
||||||
|
"""WSGI server tests."""
|
||||||
|
|
||||||
|
def test_app_using_ssl(self):
|
||||||
|
CONF.set_default('use_ssl', True)
|
||||||
|
CONF.set_default("ssl_cert_file",
|
||||||
|
os.path.join(TEST_VAR_DIR, 'certificate.crt'))
|
||||||
|
CONF.set_default("ssl_key_file",
|
||||||
|
os.path.join(TEST_VAR_DIR, 'privatekey.key'))
|
||||||
|
|
||||||
|
greetings = 'Hello, World!!!'
|
||||||
|
|
||||||
|
@webob.dec.wsgify
|
||||||
|
def hello_world(req):
|
||||||
|
return greetings
|
||||||
|
|
||||||
|
server = wsgi.Server("test_app")
|
||||||
|
server.start(hello_world, 0, host="127.0.0.1")
|
||||||
|
|
||||||
|
response = urllib2.urlopen('https://127.0.0.1:%d/' % server.port)
|
||||||
|
self.assertEquals(greetings, response.read())
|
||||||
|
|
||||||
|
server.stop()
|
||||||
|
|
||||||
|
def test_app_using_ipv6_and_ssl(self):
|
||||||
|
CONF.set_default('use_ssl', True)
|
||||||
|
CONF.set_default("ssl_cert_file",
|
||||||
|
os.path.join(TEST_VAR_DIR, 'certificate.crt'))
|
||||||
|
CONF.set_default("ssl_key_file",
|
||||||
|
os.path.join(TEST_VAR_DIR, 'privatekey.key'))
|
||||||
|
|
||||||
|
greetings = 'Hello, World!!!'
|
||||||
|
|
||||||
|
@webob.dec.wsgify
|
||||||
|
def hello_world(req):
|
||||||
|
return greetings
|
||||||
|
|
||||||
|
server = wsgi.Server("test_app")
|
||||||
|
server.start(hello_world, 0, host="::1")
|
||||||
|
|
||||||
|
response = urllib2.urlopen('https://[::1]:%d/' % server.port)
|
||||||
|
self.assertEquals(greetings, response.read())
|
||||||
|
|
||||||
|
server.stop()
|
||||||
|
35
quantum/tests/var/ca.crt
Normal file
35
quantum/tests/var/ca.crt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
WoRMgEwjGJWqzhJZUYpUAQ==
|
||||||
|
-----END CERTIFICATE-----
|
30
quantum/tests/var/certificate.crt
Normal file
30
quantum/tests/var/certificate.crt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
51
quantum/tests/var/privatekey.key
Normal file
51
quantum/tests/var/privatekey.key
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
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
|
||||||
|
-----END RSA PRIVATE KEY-----
|
121
quantum/wsgi.py
121
quantum/wsgi.py
@ -18,13 +18,18 @@
|
|||||||
"""
|
"""
|
||||||
Utility methods for working with WSGI servers
|
Utility methods for working with WSGI servers
|
||||||
"""
|
"""
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from xml.etree import ElementTree as etree
|
from xml.etree import ElementTree as etree
|
||||||
from xml.parsers import expat
|
from xml.parsers import expat
|
||||||
|
|
||||||
import eventlet.wsgi
|
import eventlet.wsgi
|
||||||
eventlet.patcher.monkey_patch(all=False, socket=True)
|
eventlet.patcher.monkey_patch(all=False, socket=True)
|
||||||
|
from oslo.config import cfg
|
||||||
import routes.middleware
|
import routes.middleware
|
||||||
import webob.dec
|
import webob.dec
|
||||||
import webob.exc
|
import webob.exc
|
||||||
@ -35,6 +40,38 @@ from quantum import context
|
|||||||
from quantum.openstack.common import jsonutils
|
from quantum.openstack.common import jsonutils
|
||||||
from quantum.openstack.common import log as logging
|
from quantum.openstack.common import log as logging
|
||||||
|
|
||||||
|
socket_opts = [
|
||||||
|
cfg.IntOpt('backlog',
|
||||||
|
default=4096,
|
||||||
|
help=_("Number of backlog requests to configure "
|
||||||
|
"the socket with")),
|
||||||
|
cfg.IntOpt('tcp_keepidle',
|
||||||
|
default=600,
|
||||||
|
help=_("Sets the value of TCP_KEEPIDLE in seconds for each "
|
||||||
|
"server socket. Not supported on OS X.")),
|
||||||
|
cfg.IntOpt('retry_until_window',
|
||||||
|
default=30,
|
||||||
|
help=_("Number of seconds to keep retrying to listen")),
|
||||||
|
cfg.BoolOpt('use_ssl',
|
||||||
|
default=False,
|
||||||
|
help=_('Enable SSL on the API server')),
|
||||||
|
cfg.StrOpt('ssl_ca_file',
|
||||||
|
default=None,
|
||||||
|
help=_("CA certificate file to use to verify "
|
||||||
|
"connecting clients")),
|
||||||
|
cfg.StrOpt('ssl_cert_file',
|
||||||
|
default=None,
|
||||||
|
help=_("Certificate file to use when starting "
|
||||||
|
"the server securely")),
|
||||||
|
cfg.StrOpt('ssl_key_file',
|
||||||
|
default=None,
|
||||||
|
help=_("Private key file to use when starting "
|
||||||
|
"the server securely")),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(socket_opts)
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -51,30 +88,92 @@ class Server(object):
|
|||||||
self.pool = eventlet.GreenPool(threads)
|
self.pool = eventlet.GreenPool(threads)
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def start(self, application, port, host='0.0.0.0', backlog=128):
|
def _get_socket(self, host, port, backlog):
|
||||||
"""Run a WSGI server with the given application."""
|
bind_addr = (host, port)
|
||||||
self._host = host
|
|
||||||
self._port = port
|
|
||||||
|
|
||||||
# TODO(dims): eventlet's green dns/socket module does not actually
|
# TODO(dims): eventlet's green dns/socket module does not actually
|
||||||
# support IPv6 in getaddrinfo(). We need to get around this in the
|
# support IPv6 in getaddrinfo(). We need to get around this in the
|
||||||
# future or monitor upstream for a fix
|
# future or monitor upstream for a fix
|
||||||
try:
|
try:
|
||||||
info = socket.getaddrinfo(self._host,
|
info = socket.getaddrinfo(bind_addr[0],
|
||||||
self._port,
|
bind_addr[1],
|
||||||
socket.AF_UNSPEC,
|
socket.AF_UNSPEC,
|
||||||
socket.SOCK_STREAM)[0]
|
socket.SOCK_STREAM)[0]
|
||||||
family = info[0]
|
family = info[0]
|
||||||
bind_addr = info[-1]
|
bind_addr = info[-1]
|
||||||
|
|
||||||
self._socket = eventlet.listen(bind_addr,
|
|
||||||
family=family,
|
|
||||||
backlog=backlog)
|
|
||||||
except:
|
except:
|
||||||
LOG.exception(_("Unable to listen on %(host)s:%(port)s") %
|
LOG.exception(_("Unable to listen on %(host)s:%(port)s") %
|
||||||
{'host': host, 'port': port})
|
{'host': host, 'port': port})
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if CONF.use_ssl:
|
||||||
|
if not os.path.exists(CONF.ssl_cert_file):
|
||||||
|
raise RuntimeError(_("Unable to find ssl_cert_file "
|
||||||
|
": %s") % CONF.ssl_cert_file)
|
||||||
|
|
||||||
|
if not os.path.exists(CONF.ssl_key_file):
|
||||||
|
raise RuntimeError(_("Unable to find "
|
||||||
|
"ssl_key_file : %s") % CONF.ssl_key_file)
|
||||||
|
|
||||||
|
# ssl_ca_file is optional
|
||||||
|
if CONF.ssl_ca_file and not os.path.exists(CONF.ssl_ca_file):
|
||||||
|
raise RuntimeError(_("Unable to find ssl_ca_file "
|
||||||
|
": %s") % CONF.ssl_ca_file)
|
||||||
|
|
||||||
|
def wrap_ssl(sock):
|
||||||
|
ssl_kwargs = {
|
||||||
|
'server_side': True,
|
||||||
|
'certfile': CONF.ssl_cert_file,
|
||||||
|
'keyfile': CONF.ssl_key_file,
|
||||||
|
'cert_reqs': ssl.CERT_NONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
if CONF.ssl_ca_file:
|
||||||
|
ssl_kwargs['ca_certs'] = CONF.ssl_ca_file
|
||||||
|
ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED
|
||||||
|
|
||||||
|
return ssl.wrap_socket(sock, **ssl_kwargs)
|
||||||
|
|
||||||
|
sock = None
|
||||||
|
retry_until = time.time() + CONF.retry_until_window
|
||||||
|
while not sock and time.time() < retry_until:
|
||||||
|
try:
|
||||||
|
sock = eventlet.listen(bind_addr,
|
||||||
|
backlog=backlog,
|
||||||
|
family=family)
|
||||||
|
if CONF.use_ssl:
|
||||||
|
sock = wrap_ssl(sock)
|
||||||
|
|
||||||
|
except socket.error as err:
|
||||||
|
if err.errno != errno.EADDRINUSE:
|
||||||
|
raise
|
||||||
|
eventlet.sleep(0.1)
|
||||||
|
if not sock:
|
||||||
|
raise RuntimeError(_("Could not bind to %(host)s:%(port)s "
|
||||||
|
"after trying for %(time)d seconds") %
|
||||||
|
{'host': host,
|
||||||
|
'port': port,
|
||||||
|
'time': CONF.retry_until_window})
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
# sockets can hang around forever without keepalive
|
||||||
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
|
|
||||||
|
# This option isn't available in the OS X version of eventlet
|
||||||
|
if hasattr(socket, 'TCP_KEEPIDLE'):
|
||||||
|
sock.setsockopt(socket.IPPROTO_TCP,
|
||||||
|
socket.TCP_KEEPIDLE,
|
||||||
|
CONF.tcp_keepidle)
|
||||||
|
|
||||||
|
return sock
|
||||||
|
|
||||||
|
def start(self, application, port, host='0.0.0.0'):
|
||||||
|
"""Run a WSGI server with the given application."""
|
||||||
|
self._host = host
|
||||||
|
self._port = port
|
||||||
|
backlog = CONF.backlog
|
||||||
|
|
||||||
|
self._socket = self._get_socket(self._host,
|
||||||
|
self._port,
|
||||||
|
backlog=backlog)
|
||||||
self._server = self.pool.spawn(self._run, application, self._socket)
|
self._server = self.pool.spawn(self._run, application, self._socket)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
Loading…
Reference in New Issue
Block a user