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:
parent
91fa7babb7
commit
5ac0e82075
10
README.rst
10
README.rst
|
@ -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
|
||||
--------
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue