Merge "Use werkzeug to run Magnum API with SSL"
This commit is contained in:
commit
30194b55d6
@ -36,7 +36,17 @@ API_SERVICE_OPTS = [
|
||||
cfg.StrOpt('api_paste_config',
|
||||
default="api-paste.ini",
|
||||
help="Configuration file for WSGI definition of API."
|
||||
)
|
||||
),
|
||||
cfg.StrOpt('ssl_cert_file',
|
||||
help="This option allows setting path to the SSL certificate "
|
||||
"of API server. "),
|
||||
cfg.StrOpt('ssl_key_file',
|
||||
help="This option specifies the path to the file where SSL "
|
||||
"private key of API server is stored when SSL is in "
|
||||
"effect. "),
|
||||
cfg.BoolOpt('enabled_ssl',
|
||||
default=False,
|
||||
help='Enable SSL Magnum API service')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -16,22 +16,41 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from wsgiref import simple_server
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_reports import guru_meditation_report as gmr
|
||||
from werkzeug import serving
|
||||
|
||||
from magnum.api import app as api_app
|
||||
from magnum.common import service
|
||||
from magnum.i18n import _
|
||||
from magnum.i18n import _LI
|
||||
from magnum.objects import base
|
||||
from magnum import version
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_ssl_configs(use_ssl):
|
||||
if use_ssl:
|
||||
cert_file = CONF.api.ssl_cert_file
|
||||
key_file = CONF.api.ssl_key_file
|
||||
|
||||
if cert_file and not os.path.exists(cert_file):
|
||||
raise RuntimeError(
|
||||
_("Unable to find cert_file : %s") % cert_file)
|
||||
|
||||
if key_file and not os.path.exists(key_file):
|
||||
raise RuntimeError(
|
||||
_("Unable to find key_file : %s") % key_file)
|
||||
|
||||
return cert_file, key_file
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
service.prepare_service(sys.argv)
|
||||
|
||||
@ -42,15 +61,18 @@ def main():
|
||||
|
||||
app = api_app.load_app()
|
||||
|
||||
# SSL configuration
|
||||
use_ssl = CONF.api.enabled_ssl
|
||||
|
||||
# Create the WSGI server and start it
|
||||
host, port = cfg.CONF.api.host, cfg.CONF.api.port
|
||||
srv = simple_server.make_server(host, port, app)
|
||||
|
||||
LOG.info(_LI('Starting server in PID %s'), os.getpid())
|
||||
LOG.debug("Configuration:")
|
||||
cfg.CONF.log_opt_values(LOG, logging.DEBUG)
|
||||
|
||||
LOG.info(_LI('serving on http://%(host)s:%(port)s'),
|
||||
dict(host=host, port=port))
|
||||
LOG.info(_LI('Serving on %(proto)s://%(host)s:%(port)s'),
|
||||
dict(proto="https" if use_ssl else "http", host=host, port=port))
|
||||
|
||||
srv.serve_forever()
|
||||
serving.run_simple(host, port, app,
|
||||
ssl_context=_get_ssl_configs(use_ssl))
|
||||
|
@ -18,21 +18,79 @@ from magnum.cmd import api
|
||||
from magnum.tests import base
|
||||
|
||||
|
||||
# NOTE(hieulq): need to mock MagnumObject, otherwise other test cases
|
||||
# will be failed because of setting wrong ovo indirection api
|
||||
@mock.patch('magnum.objects.base.MagnumObject')
|
||||
class TestMagnumAPI(base.TestCase):
|
||||
|
||||
# NOTE(hieulq): need to mock MagnumObject, otherwise other test cases
|
||||
# will be failed because of setting wrong ovo indirection api
|
||||
@mock.patch('magnum.objects.base.MagnumObject')
|
||||
@mock.patch('wsgiref.simple_server.make_server')
|
||||
@mock.patch('werkzeug.serving.run_simple')
|
||||
@mock.patch.object(api, 'api_app')
|
||||
@mock.patch('magnum.common.service.prepare_service')
|
||||
def test_api(self, mock_prep, mock_app, mock_make, mock_base):
|
||||
def test_api_http(self, mock_prep, mock_app, mock_run, mock_base):
|
||||
api.main()
|
||||
|
||||
app = mock_app.load_app.return_value
|
||||
server = mock_make.return_value
|
||||
mock_prep.assert_called_once_with(mock.ANY)
|
||||
mock_app.load_app.assert_called_once_with()
|
||||
mock_make.assert_called_once_with(base.CONF.api.host,
|
||||
base.CONF.api.port, app)
|
||||
server.serve_forever.assert_called_once_with()
|
||||
mock_run.assert_called_once_with(base.CONF.api.host,
|
||||
base.CONF.api.port,
|
||||
app, ssl_context=None)
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('werkzeug.serving.run_simple')
|
||||
@mock.patch.object(api, 'api_app')
|
||||
@mock.patch('magnum.common.service.prepare_service')
|
||||
def test_api_https_no_cert(self, mock_prep, mock_app, mock_run,
|
||||
mock_exist, mock_base):
|
||||
self.config(enabled_ssl=True,
|
||||
ssl_cert_file='tmp_crt',
|
||||
group='api')
|
||||
mock_exist.return_value = False
|
||||
|
||||
self.assertRaises(RuntimeError, api.main)
|
||||
mock_prep.assert_called_once_with(mock.ANY)
|
||||
mock_app.load_app.assert_called_once_with()
|
||||
mock_run.assert_not_called()
|
||||
mock_exist.assert_called_once_with('tmp_crt')
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('werkzeug.serving.run_simple')
|
||||
@mock.patch.object(api, 'api_app')
|
||||
@mock.patch('magnum.common.service.prepare_service')
|
||||
def test_api_https_no_key(self, mock_prep, mock_app, mock_run,
|
||||
mock_exist, mock_base):
|
||||
self.config(enabled_ssl=True,
|
||||
ssl_cert_file='tmp_crt',
|
||||
ssl_key_file='tmp_key',
|
||||
group='api')
|
||||
mock_exist.side_effect = [True, False]
|
||||
|
||||
self.assertRaises(RuntimeError, api.main)
|
||||
mock_prep.assert_called_once_with(mock.ANY)
|
||||
mock_app.load_app.assert_called_once_with()
|
||||
mock_run.assert_not_called()
|
||||
mock_exist.assert_has_calls([mock.call('tmp_crt'),
|
||||
mock.call('tmp_key')])
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
@mock.patch('werkzeug.serving.run_simple')
|
||||
@mock.patch.object(api, 'api_app')
|
||||
@mock.patch('magnum.common.service.prepare_service')
|
||||
def test_api_https(self, mock_prep, mock_app, mock_run,
|
||||
mock_exist, mock_base):
|
||||
self.config(enabled_ssl=True,
|
||||
ssl_cert_file='tmp_crt',
|
||||
ssl_key_file='tmp_key',
|
||||
group='api')
|
||||
mock_exist.side_effect = [True, True]
|
||||
|
||||
api.main()
|
||||
|
||||
app = mock_app.load_app.return_value
|
||||
mock_prep.assert_called_once_with(mock.ANY)
|
||||
mock_app.load_app.assert_called_once_with()
|
||||
mock_exist.assert_has_calls([mock.call('tmp_crt'),
|
||||
mock.call('tmp_key')])
|
||||
mock_run.assert_called_once_with(base.CONF.api.host,
|
||||
base.CONF.api.port, app,
|
||||
ssl_context=('tmp_crt', 'tmp_key'))
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
upgrade:
|
||||
- Magnum now support SSL for API service. User can enable SSL for API
|
||||
via new 3 config options 'enabled_ssl', 'ssl_cert_file' and 'ssl_key_file'.
|
||||
- Change default API development service from wsgiref simple_server to
|
||||
werkzeug for better supporting SSL.
|
@ -55,3 +55,4 @@ stevedore>=1.16.0 # Apache-2.0
|
||||
taskflow>=1.26.0 # Apache-2.0
|
||||
cryptography!=1.3.0,>=1.0 # BSD/Apache-2.0
|
||||
urllib3>=1.15.1 # MIT
|
||||
Werkzeug>=0.7 # BSD License
|
||||
|
Loading…
Reference in New Issue
Block a user