Merge "add no authentication for vitrage"

This commit is contained in:
Jenkins 2017-07-03 09:22:42 +00:00 committed by Gerrit Code Review
commit 40fb89d4bf
8 changed files with 235 additions and 90 deletions

View File

@ -1,14 +1,41 @@
# Remove keystone_authtoken from the pipeline if you don't want to use keystone authentication
[pipeline:main]
pipeline = cors keystone_authtoken vitrage
[composite:vitrage+noauth]
use = egg:Paste#urlmap
/ = vitrageversions_pipeline
/v1 = vitragev1_noauth_pipeline
[app:vitrage]
[composite:vitrage+keystone]
use = egg:Paste#urlmap
/ = vitrageversions_pipeline
/v1 = vitragev1_keystone_pipeline
[pipeline:vitrageversions_pipeline]
pipeline = cors http_proxy_to_wsgi vitrageversions
[app:vitrageversions]
paste.app_factory = vitrage.api.app:app_factory
root = vitrage.api.controllers.root.VersionsController
[filter:keystone_authtoken]
[pipeline:vitragev1_keystone_pipeline]
pipeline = cors http_proxy_to_wsgi request_id authtoken vitragev1
[pipeline:vitragev1_noauth_pipeline]
pipeline = cors http_proxy_to_wsgi request_id vitragev1
[app:vitragev1]
paste.app_factory = vitrage.api.app:app_factory
root = vitrage.api.controllers.v1.root.V1Controller
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
oslo_config_project = vitrage
[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = vitrage
oslo_config_project = vitrage
[filter:http_proxy_to_wsgi]
paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
oslo_config_project = vitrage

View File

@ -17,21 +17,16 @@ from oslo_config import cfg
# Register options for the service
OPTS = [
cfg.PortOpt('port',
default=8999,
help='The port for the vitrage API server.',
),
cfg.StrOpt('host',
default='0.0.0.0',
help='The listen IP for the vitrage API server.',
),
cfg.PortOpt('port', default=8999,
help='The port for the vitrage API server.',),
cfg.StrOpt('host', default='0.0.0.0',
help='The listen IP for the vitrage API server.',),
cfg.StrOpt('paste_config', default='api-paste.ini',
help='Configuration file for WSGI definition of API.'),
cfg.IntOpt('workers', default=1,
min=1,
cfg.IntOpt('workers', default=1, min=1,
help='Number of workers for vitrage API server.'),
cfg.BoolOpt('pecan_debug', default=False,
help='Toggle Pecan Debug Middleware.'),
cfg.StrOpt('auth_mode', default='keystone', choices={'keystone', 'noauth'},
help='Authentication mode to use.'),
]

View File

@ -11,6 +11,8 @@
# under the License.
import os
import uuid
import pecan
from oslo_config import cfg
@ -20,36 +22,27 @@ from paste import deploy
from werkzeug import serving
from vitrage.api import hooks
from vitrage import service
LOG = log.getLogger(__name__)
PECAN_CONFIG = {
'app': {
'root': 'vitrage.api.controllers.root.RootController',
'modules': ['vitrage.api'],
},
}
# NOTE(sileht): pastedeploy uses ConfigParser to handle
# global_conf, since python 3 ConfigParser doesn't
# allow storing object as config value, only strings are
# permit, so to be able to pass an object created before paste load
# the app, we store them into a global var. But the each loaded app
# store it's configuration in unique key to be concurrency safe.
global APPCONFIGS
APPCONFIGS = {}
def setup_app(pecan_config=PECAN_CONFIG, conf=None):
if conf is None:
raise RuntimeError('Config is actually mandatory')
def setup_app(root, conf=None):
app_hooks = [hooks.ConfigHook(conf),
hooks.TranslationHook(),
hooks.RPCHook(conf),
hooks.ContextHook()]
pecan.configuration.set_config(dict(pecan_config), overwrite=True)
pecan_debug = conf.api.pecan_debug
if conf.api.workers != 1 and pecan_debug:
pecan_debug = False
LOG.warning('pecan_debug cannot be enabled, if workers is > 1, '
'the value is overridden with False')
app = pecan.make_app(
pecan_config['app']['root'],
debug=pecan_debug,
root,
hooks=app_hooks,
guess_content_type_from_ext=False
)
@ -58,18 +51,25 @@ def setup_app(pecan_config=PECAN_CONFIG, conf=None):
def load_app(conf):
global APPCONFIGS
# Build the WSGI app
cfg_file = None
cfg_path = conf.api.paste_config
if not os.path.isabs(cfg_path):
cfg_file = conf.find_file(cfg_path)
elif os.path.exists(cfg_path):
cfg_file = cfg_path
cfg_path = conf.find_file(cfg_path)
if not cfg_file:
if cfg_path is None or not os.path.exists(cfg_path):
raise cfg.ConfigFilesNotFoundError([conf.api.paste_config])
LOG.info('Full WSGI config used: %s', cfg_file)
return deploy.loadapp("config:" + cfg_file)
config = dict(conf=conf)
configkey = str(uuid.uuid4())
APPCONFIGS[configkey] = config
LOG.info('Full WSGI config used: %s', cfg_path)
appname = "vitrage+" + conf.api.auth_mode
return deploy.loadapp("config:" + cfg_path, name=appname,
global_conf={'configkey': configkey})
def build_server(conf):
@ -93,10 +93,7 @@ def build_server(conf):
app, processes=conf.api.workers)
def _app():
conf = service.prepare_service()
return setup_app(conf=conf)
def app_factory(global_config, **local_conf):
return _app()
global APPCONFIGS
appconfig = APPCONFIGS.get(global_config.get('configkey'))
return setup_app(root=local_conf.get('root'), **appconfig)

View File

@ -11,11 +11,9 @@
# under the License.
import pecan as pecan
from vitrage.api.controllers.v1 import root as v1
class RootController(object):
v1 = v1.V1Controller()
class VersionsController(object):
@staticmethod
@pecan.expose('json')

View File

@ -16,12 +16,13 @@
# under the License.
"""Base classes for API tests.
"""
import os
import pecan
import pecan.testing
from oslo_config import fixture as fixture_config
import sys
import webtest
from vitrage.api import app
from vitrage import service
from vitrage.tests import base
@ -40,29 +41,24 @@ class FunctionalTest(base.BaseTest):
def setUp(self):
super(FunctionalTest, self).setUp()
conf = service.prepare_service(args=[], config_files=[])
self.conf = self.useFixture(fixture_config.Config(conf)).conf
self.CONF = self.useFixture(fixture_config.Config(conf)).conf
self.conf.set_override('policy_file',
os.path.abspath('etc/vitrage/policy.json'),
group='oslo_policy')
self.app = self._make_app()
vitrage_init_file = sys.modules['vitrage'].__file__
vitrage_root = os.path.abspath(
os.path.join(os.path.dirname(vitrage_init_file), '..', ))
def _make_app(self):
self.config = {
'app': {
'root': 'vitrage.api.controllers.root.RootController',
'modules': ['vitrage.api'],
},
'wsme': {
'debug': True,
},
}
self.CONF.set_override('policy_file', os.path.join(vitrage_root,
'etc', 'vitrage',
'policy.json'),
group='oslo_policy', enforce_type=True)
return pecan.testing.load_test_app(self.config, conf=self.conf)
self.CONF.set_override('paste_config', os.path.join(vitrage_root,
'etc', 'vitrage',
'api-paste.ini'),
group='api', enforce_type=True)
def tearDown(self):
super(FunctionalTest, self).tearDown()
pecan.set_config({}, overwrite=True)
self.CONF.set_override('auth_mode', self.auth, group='api')
self.app = webtest.TestApp(app.load_app(self.CONF))
def put_json(self, path, params, expect_errors=False, headers=None,
extra_environ=None, status=None):

View File

@ -26,6 +26,11 @@ VERSIONS_RESPONSE = {u'versions': [{u'id': u'v1.0',
class TestVersions(api.FunctionalTest):
def __init__(self, *args, **kwds):
super(TestVersions, self).__init__(*args, **kwds)
self.auth = 'keystone'
def test_versions(self):
data = self.get_json('/')
self.assertEqual(VERSIONS_RESPONSE, data)

View File

@ -15,23 +15,15 @@
# limitations under the License.
# noinspection PyPackageRequirements
import mock
import webtest
from vitrage.api import app
from vitrage.tests.functional.api.v1 import FunctionalTest
class TestAuthentications(FunctionalTest):
def _make_app(self):
file_name = self.path_get('etc/vitrage/api-paste.ini')
self.conf.set_override("paste_config", file_name, "api")
# We need the other call to prepare_service in app.py to return the
# same tweaked conf object.
with mock.patch('vitrage.service.prepare_service') as ps:
ps.return_value = self.conf
return webtest.TestApp(app.load_app(conf=self.conf))
class AuthTest(FunctionalTest):
def test_not_authenticated(self):
def __init__(self, *args, **kwds):
super(AuthTest, self).__init__(*args, **kwds)
self.auth = 'keystone'
def test_in_keystone_mode_not_authenticated(self):
resp = self.post_json('/topology/', params=None, expect_errors=True)
self.assertEqual(401, resp.status_int)
self.assertEqual('401 Unauthorized', resp.status)

View File

@ -0,0 +1,135 @@
# Copyright 2016 - Nokia Corporation
# Copyright 2014 OpenStack Foundation
#
# 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 datetime import datetime
# noinspection PyPackageRequirements
from mock import mock
from vitrage.tests.functional.api.v1 import FunctionalTest
class NoAuthTest(FunctionalTest):
def __init__(self, *args, **kwds):
super(NoAuthTest, self).__init__(*args, **kwds)
self.auth = 'noauth'
def test_noauth_mode_post_event(self):
with mock.patch('pecan.request') as request:
details = {
'hostname': 'host123',
'source': 'sample_monitor',
'cause': 'another alarm',
'severity': 'critical',
'status': 'down',
'monitor_id': 'sample monitor',
'monitor_event_id': '456',
}
event_time = datetime.now().isoformat()
event_type = 'compute.host.down'
resp = self.post_json('/event/', params={'time': event_time,
'type': event_type,
'details': details})
self.assertEqual(1, request.client.call.call_count)
self.assertEqual('200 OK', resp.status)
def test_noauth_mode_get_topology(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{}'
params = dict(depth=None, graph_type='graph', query=None,
root=None,
all_tenants=False)
resp = self.post_json('/topology/', params=params)
self.assertEqual(1, request.client.call.call_count)
self.assertEqual('200 OK', resp.status)
self.assertEqual({}, resp.json)
def test_noauth_mode_list_alarms(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{"alarms": []}'
params = dict(vitrage_id='all', all_tenants=False)
resp = self.post_json('/alarm/', params=params)
self.assertEqual(1, request.client.call.call_count)
self.assertEqual('200 OK', resp.status)
self.assertEqual([], resp.json)
def test_noauth_mode_list_resources(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{"resources": []}'
params = dict(resource_type='all', all_tenants=False)
data = self.get_json('/resources/', params=params)
self.assertEqual(1, request.client.call.call_count)
self.assertEqual([], data)
def test_noauth_mode_show_resource(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{}'
params = dict(resource_type='all', all_tenants=False)
data = self.get_json('/resources/1234', params=params)
self.assertEqual(1, request.client.call.call_count)
self.assertEqual({}, data)
def test_noauth_mode_list_templates(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{"templates_details": []}'
data = self.get_json('/template/')
self.assertEqual(1, request.client.call.call_count)
self.assertEqual([], data)
def test_noauth_mode_show_template(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{}'
data = self.get_json('/template/1234')
self.assertEqual(1, request.client.call.call_count)
self.assertEqual({}, data)
def test_noauth_mode_validate_template(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{}'
params = {"templates": {}}
resp = self.post_json('/template/', params=params)
self.assertEqual(1, request.client.call.call_count)
self.assertEqual('200 OK', resp.status)
self.assertEqual({}, resp.json)
def test_noauth_mode_get_rca(self):
with mock.patch('pecan.request') as request:
request.client.call.return_value = '{}'
params = dict(all_tenants=False)
data = self.get_json('/rca/1234/', params=params)
self.assertEqual(1, request.client.call.call_count)
self.assertEqual({}, data)