Enable running under wsgi container

When running the rest api under wsgi container you need to pass the
app callable to uwsgi directly. However, the DB connection
initialization was previously done in the main() function which also
called app.run() which would conflict with running under a wsgi
container. This commit breaks the initialization out into the module
level before the app creation. This ensures that the DB initialization
bits are always run regardless of running under uwsgi, gunicorn,
mod_wsgi, or something else. Additionally, the readme is updated to
document how to run the service under uwsgi standalone.

Change-Id: If53b3a1e6fdecd403ebca44809c767caacbde7fe
This commit is contained in:
Matthew Treinish 2015-10-02 11:35:00 -04:00
parent 91fa7babb7
commit 5ac0e82075
No known key found for this signature in database
GPG Key ID: FD12A0F214C9E177
4 changed files with 29 additions and 19 deletions

View File

@ -55,8 +55,14 @@ API
---
The rest api is a flask application so any of the methods for deploying a
flask application can be used. The standalone entrypoint used for development
isn't suitable for production because it's single threaded. For example you
can use something like uwsgi or mod_wsgi to deploy it for real.
isn't suitable for production because it's single threaded. You should use
a wsgi container, something like uwsgi, gunicorn, or mod_wsgi to deploy it
for real. For example, running the API with uwsgi standalone you can do
something like::
$ uwsgi -s /tmp/uwsgi.sock --module openstack_health.api --callable app --pyargv config_file --http :5000
That will startup a uwsgi server running the rest api on port 5000.
Frontend
--------

View File

@ -28,6 +28,16 @@ engine = None
Session = None
@app.before_first_request
def setup():
config = ConfigParser.ConfigParser()
config.read(sys.argv[1])
global engine
engine = create_engine(config.get('default', 'db_uri'))
global Session
Session = sessionmaker(bind=engine)
@app.route('/build_name/<string:build_name>/runs', methods=['GET'])
def get_runs_from_build_name(build_name):
global Session
@ -143,12 +153,6 @@ def get_test_runs():
def main():
config = ConfigParser.ConfigParser()
config.read(sys.argv[1])
global engine
engine = create_engine(config.get('default', 'db_uri'))
global Session
Session = sessionmaker(bind=engine)
app.run(debug=True)

View File

@ -30,13 +30,20 @@ class TestRestAPI(base.TestCase):
super(TestRestAPI, self).setUp()
api.app.config['TESTING'] = True
self.app = api.app.test_client()
# NOTE(mtreinish): This is mocking the flask function which calls
# whatever uses the .before_first_request decorator, simply mocking
# out the setup function was insufficient
setup_mock = mock.patch(
'flask.app.Flask.try_trigger_before_first_request_functions')
setup_mock.start()
self.addCleanup(setup_mock.stop)
api.Session = mock.MagicMock()
@mock.patch('subunit2sql.db.api.get_all_tests',
return_value=[models.Test(
id='fake_id', test_id='test.id', run_count=4, success=2,
failure=2, run_time=21.2)])
def test_get_tests(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/tests')
self.assertEqual(200, res.status_code)
expected_response = {'tests': [
@ -55,7 +62,6 @@ class TestRestAPI(base.TestCase):
artifacts='fake_url.com',
run_at=timestamp_a)])
def test_get_runs(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/runs')
self.assertEqual(200, res.status_code)
format_time = timestamp_a.strftime('%a, %d %b %Y %H:%M:%S GMT')
@ -76,7 +82,6 @@ class TestRestAPI(base.TestCase):
status='success', start_time=timestamp_a,
stop_time=timestamp_b)])
def test_get_test_runs(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/test_runs')
self.assertEqual(200, res.status_code)
format_time_a = timestamp_a.strftime('%a, %d %b %Y %H:%M:%S GMT')
@ -97,7 +102,6 @@ class TestRestAPI(base.TestCase):
artifacts='fake_url.com',
run_at=timestamp_a)])
def test_get_runs_from_build_name(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/build_name/test_build_name/runs')
self.assertEqual(200, res.status_code)
format_time = timestamp_a.strftime('%a, %d %b %Y %H:%M:%S GMT')
@ -117,7 +121,6 @@ class TestRestAPI(base.TestCase):
id='fake_id', test_id='test.id', run_count=4, success=2,
failure=2, run_time=21.2)])
def test_get_tests_from_run(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/run/fake_id/tests')
self.assertEqual(200, res.status_code)
expected_response = {'tests': [
@ -142,7 +145,6 @@ class TestRestAPI(base.TestCase):
}
})
def test_get_run_test_runs(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/run/test_run_id/test_runs')
self.assertEqual(200, res.status_code)
format_time_a = timestamp_a.strftime('%a, %d %b %Y %H:%M:%S GMT')
@ -163,7 +165,6 @@ class TestRestAPI(base.TestCase):
timestamp_a: [{'pass': 2, 'fail': 3, 'skip': 1}]
})
def test_get_runs_by_date(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/runs/group_by/project')
self.assertEqual(200, res.status_code)
expected_response = {u'runs': {
@ -180,7 +181,6 @@ class TestRestAPI(base.TestCase):
timestamp_a: [{'pass': 2, 'fail': 3, 'skip': 1}]
})
def test_get_runs_by_date_min_res(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/runs/group_by/project?datetime_resolution=min')
self.assertEqual(200, res.status_code)
expected_response = {u'runs': {
@ -197,7 +197,6 @@ class TestRestAPI(base.TestCase):
timestamp_a: [{'pass': 2, 'fail': 3, 'skip': 1}]
})
def test_get_runs_by_date_hour_res(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('/runs/group_by/projects?datetime_resolution=hour')
self.assertEqual(200, res.status_code)
expected_response = {u'runs': {
@ -222,7 +221,6 @@ class TestRestAPI(base.TestCase):
'skip': 0}]}
})
def test_get_runs_by_date_day_res(self, api_mock):
api.Session = mock.MagicMock()
res = self.app.get('runs/group_by/projects?datetime_resolution=day')
self.assertEqual(200, res.status_code)
date = unicode(timestamp_a.date().isoformat())
@ -279,7 +277,6 @@ class TestRestAPI(base.TestCase):
api_mock.assert_called_once_with('project', None, None, api.Session())
def test_get_runs_by_date_invalid_resolution(self):
api.Session = mock.MagicMock()
res = self.app.get(
'/runs/group_by/projects?datetime_resolution=century')
self.assertEqual(res.status_code, 400)

View File

@ -26,6 +26,9 @@ packages =
console_scripts =
openstack-health-api = openstack_health.api:main
wsgi_scripts =
openstack-health = openstack_health.api:app
[build_sphinx]
all_files = 1
build-dir = doc/build