Added support for SSL connection in mistra-api server
Change-Id: I4e114a11191821f4ef9dec967fb76b0a34179119 Implements: blueprint mistral-api-server-https
This commit is contained in:
parent
3a7e91df4a
commit
4adc3cfb56
55
mistral/api/service.py
Normal file
55
mistral/api/service.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Copyright 2016 NEC Corporation. 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.
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_service import service
|
||||
from oslo_service import wsgi
|
||||
|
||||
from mistral.api import app
|
||||
|
||||
|
||||
class WSGIService(service.ServiceBase):
|
||||
"""Provides ability to launch Mistral API from wsgi app."""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.app = app.setup_app()
|
||||
self.workers = (cfg.CONF.api.api_workers or
|
||||
processutils.get_worker_count())
|
||||
|
||||
self.server = wsgi.Server(
|
||||
cfg.CONF,
|
||||
name,
|
||||
self.app,
|
||||
host=cfg.CONF.api.host,
|
||||
port=cfg.CONF.api.port,
|
||||
use_ssl=cfg.CONF.api.enable_ssl_api
|
||||
)
|
||||
|
||||
def start(self):
|
||||
self.server.start()
|
||||
|
||||
def stop(self):
|
||||
self.server.stop()
|
||||
|
||||
def wait(self):
|
||||
self.server.wait()
|
||||
|
||||
def reset(self):
|
||||
self.server.reset()
|
||||
|
||||
|
||||
def process_launcher():
|
||||
return service.ProcessLauncher(cfg.CONF)
|
@ -27,7 +27,6 @@ eventlet.monkey_patch(
|
||||
|
||||
|
||||
import os
|
||||
import six
|
||||
|
||||
|
||||
# If ../mistral/__init__.py exists, add ../ to Python search path, so that
|
||||
@ -41,15 +40,7 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'mistral', '__init__.py')):
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
if six.PY3 is True:
|
||||
import socketserver
|
||||
else:
|
||||
import SocketServer as socketserver
|
||||
|
||||
from wsgiref import simple_server
|
||||
from wsgiref.simple_server import WSGIServer
|
||||
|
||||
from mistral.api import app
|
||||
from mistral.api import service as mistral_service
|
||||
from mistral import config
|
||||
from mistral.db.v2 import api as db_api
|
||||
from mistral.engine import default_engine as def_eng
|
||||
@ -139,25 +130,11 @@ def launch_event_engine():
|
||||
print("Stopping event_engine service...")
|
||||
|
||||
|
||||
class ThreadingWSGIServer(socketserver.ThreadingMixIn, WSGIServer):
|
||||
pass
|
||||
|
||||
|
||||
def launch_api():
|
||||
host = cfg.CONF.api.host
|
||||
port = cfg.CONF.api.port
|
||||
|
||||
api_server = simple_server.make_server(
|
||||
host,
|
||||
port,
|
||||
app.setup_app(),
|
||||
ThreadingWSGIServer
|
||||
)
|
||||
|
||||
LOG.info("Mistral API is serving on http://%s:%s (PID=%s)" %
|
||||
(host, port, os.getpid()))
|
||||
|
||||
api_server.serve_forever()
|
||||
launcher = mistral_service.process_launcher()
|
||||
server = mistral_service.WSGIService('mistral_api')
|
||||
launcher.launch_service(server, workers=server.workers)
|
||||
launcher.wait()
|
||||
|
||||
|
||||
def launch_any(options):
|
||||
|
@ -65,6 +65,18 @@ api_opts = [
|
||||
default=False,
|
||||
help='Enables the ability to delete action_execution which '
|
||||
'has no relationship with workflows.'
|
||||
),
|
||||
cfg.BoolOpt(
|
||||
'enable_ssl_api',
|
||||
default=False,
|
||||
help='Enable the integrated stand-alone API to service requests'
|
||||
'via HTTPS instead of HTTP.'
|
||||
),
|
||||
cfg.IntOpt(
|
||||
'api_workers',
|
||||
help='Number of workers for Mistral API service '
|
||||
'default is equal to the number of CPUs available if that can '
|
||||
'be determined, else a default worker count of 1 is returned.'
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -32,7 +32,7 @@ class TestCORSMiddleware(base.APITest):
|
||||
cfg.CONF.register_opts(cors_middleware.CORS_OPTS, 'cors')
|
||||
|
||||
# Load up our valid domain values before the application is created.
|
||||
cfg.CONF.set_override(
|
||||
self.override_config(
|
||||
"allowed_origin",
|
||||
"http://valid.example.com",
|
||||
group='cors'
|
||||
|
109
mistral/tests/unit/api/test_service.py
Normal file
109
mistral/tests/unit/api/test_service.py
Normal file
@ -0,0 +1,109 @@
|
||||
# Copyright 2016 NEC Corporation. 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
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
import pecan
|
||||
|
||||
from mistral.api import service
|
||||
from mistral.tests.unit import base
|
||||
|
||||
|
||||
class TestWSGIService(base.BaseTest):
|
||||
@mock.patch('mistral.api.app.setup_app')
|
||||
@mock.patch.object(service.wsgi, 'Server')
|
||||
def test_workers_set_default(self, wsgi_server, mock_app):
|
||||
service_name = "mistral_api"
|
||||
mock_app.return_value = pecan.testing.load_test_app({
|
||||
'app': {
|
||||
'root': cfg.CONF.pecan.root,
|
||||
'modules': cfg.CONF.pecan.modules,
|
||||
'debug': cfg.CONF.pecan.debug,
|
||||
'auth_enable': cfg.CONF.pecan.auth_enable,
|
||||
'disable_cron_trigger_thread': True
|
||||
}
|
||||
})
|
||||
test_service = service.WSGIService(service_name)
|
||||
|
||||
wsgi_server.assert_called_once_with(
|
||||
cfg.CONF,
|
||||
service_name,
|
||||
test_service.app,
|
||||
host='0.0.0.0',
|
||||
port=8989,
|
||||
use_ssl=False
|
||||
)
|
||||
|
||||
@mock.patch('mistral.api.app.setup_app')
|
||||
@mock.patch.object(service.wsgi, 'Server')
|
||||
def test_workers_set_correct_setting(self, wsgi_server, mock_app):
|
||||
self.override_config('api_workers', 8, group='api')
|
||||
|
||||
mock_app.return_value = pecan.testing.load_test_app({
|
||||
'app': {
|
||||
'root': cfg.CONF.pecan.root,
|
||||
'modules': cfg.CONF.pecan.modules,
|
||||
'debug': cfg.CONF.pecan.debug,
|
||||
'auth_enable': cfg.CONF.pecan.auth_enable,
|
||||
'disable_cron_trigger_thread': True
|
||||
}
|
||||
})
|
||||
test_service = service.WSGIService("mistral_api")
|
||||
|
||||
self.assertEqual(8, test_service.workers)
|
||||
|
||||
@mock.patch('mistral.api.app.setup_app')
|
||||
@mock.patch.object(service.wsgi, 'Server')
|
||||
def test_workers_set_zero_setting(self, wsgi_server, mock_app):
|
||||
self.override_config('api_workers', 0, group='api')
|
||||
|
||||
mock_app.return_value = pecan.testing.load_test_app({
|
||||
'app': {
|
||||
'root': cfg.CONF.pecan.root,
|
||||
'modules': cfg.CONF.pecan.modules,
|
||||
'debug': cfg.CONF.pecan.debug,
|
||||
'auth_enable': cfg.CONF.pecan.auth_enable,
|
||||
'disable_cron_trigger_thread': True
|
||||
}
|
||||
})
|
||||
test_service = service.WSGIService("mistral_api")
|
||||
|
||||
self.assertEqual(processutils.get_worker_count(), test_service.workers)
|
||||
|
||||
@mock.patch('mistral.api.app.setup_app')
|
||||
@mock.patch.object(service.wsgi, 'Server')
|
||||
def test_wsgi_service_with_ssl_enabled(self, wsgi_server, mock_app):
|
||||
self.override_config('enable_ssl_api', True, group='api')
|
||||
|
||||
mock_app.return_value = pecan.testing.load_test_app({
|
||||
'app': {
|
||||
'root': cfg.CONF.pecan.root,
|
||||
'modules': cfg.CONF.pecan.modules,
|
||||
'debug': cfg.CONF.pecan.debug,
|
||||
'auth_enable': cfg.CONF.pecan.auth_enable,
|
||||
'disable_cron_trigger_thread': True
|
||||
}
|
||||
})
|
||||
service_name = 'mistral_api'
|
||||
srv = service.WSGIService(service_name)
|
||||
|
||||
wsgi_server.assert_called_once_with(
|
||||
cfg.CONF,
|
||||
service_name,
|
||||
srv.app,
|
||||
host='0.0.0.0',
|
||||
port=8989,
|
||||
use_ssl=True
|
||||
)
|
@ -202,6 +202,11 @@ class BaseTest(base.BaseTestCase):
|
||||
def _sleep(self, seconds):
|
||||
time.sleep(seconds)
|
||||
|
||||
def override_config(self, name, override, group=None):
|
||||
"""Cleanly override CONF variables."""
|
||||
cfg.CONF.set_override(name, override, group)
|
||||
self.addCleanup(cfg.CONF.clear_override, name, group)
|
||||
|
||||
|
||||
class DbTestCase(BaseTest):
|
||||
is_heavy_init_called = False
|
||||
|
@ -7,3 +7,4 @@ namespace = keystonemiddleware.auth_token
|
||||
namespace = periodic.config
|
||||
namespace = oslo.log
|
||||
namespace = oslo.policy
|
||||
namespace = oslo.service.sslutils
|
||||
|
Loading…
Reference in New Issue
Block a user