Debian: Remove sysinv references from sw-patch
sysinv files were being imported to provide authentication features like policy enforcement and request contexts. Those are now replaced with oslo imports. Test Plan: (Debian) PASS: AIO-DX bootstrap/unlock PASS: CLI upload/apply/host-install RR patch PASS: Horizon patching operations work PASS: NFV patching operations work PASS: no (new) errors in patching logs Story: 2009969 Task: 45998 Signed-off-by: Al Bailey <al.bailey@windriver.com> Change-Id: I15d80441201755673f827529469a7f4feaa7f0ee
This commit is contained in:
parent
0cada3c8ba
commit
a4906a4f57
@ -1,5 +1,2 @@
|
|||||||
{
|
{
|
||||||
"admin": "role:admin or role:administrator",
|
|
||||||
"admin_api": "is_admin:True",
|
|
||||||
"default": "rule:admin_api"
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
"""
|
#
|
||||||
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
# Copyright (c) 2014-2022 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
"""
|
|
||||||
|
|
||||||
|
"""Access Control Lists (ACL's) control access the API server."""
|
||||||
from cgcs_patch.authapi import auth_token
|
from cgcs_patch.authapi import auth_token
|
||||||
|
|
||||||
OPT_GROUP_NAME = 'keystone_authtoken'
|
OPT_GROUP_NAME = 'keystone_authtoken'
|
||||||
|
OPT_GROUP_PROVIDER = 'keystonemiddleware.auth_token'
|
||||||
|
|
||||||
"""Access Control Lists (ACL's) control access the API server."""
|
|
||||||
|
|
||||||
|
|
||||||
def install(app, conf, public_routes):
|
def install(app, conf, public_routes):
|
||||||
@ -23,8 +21,7 @@ def install(app, conf, public_routes):
|
|||||||
:return: The same WSGI application with ACL installed.
|
:return: The same WSGI application with ACL installed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
keystone_config = dict(conf.get(OPT_GROUP_NAME))
|
||||||
keystone_config = dict(conf.items(OPT_GROUP_NAME))
|
|
||||||
return auth_token.AuthTokenMiddleware(app,
|
return auth_token.AuthTokenMiddleware(app,
|
||||||
conf=keystone_config,
|
conf=keystone_config,
|
||||||
public_api_routes=public_routes)
|
public_api_routes=public_routes)
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
Copyright (c) 2014-2022 Wind River Systems, Inc.
|
||||||
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import configparser
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
import pecan
|
import pecan
|
||||||
|
|
||||||
@ -14,7 +13,6 @@ from cgcs_patch.authapi import config
|
|||||||
from cgcs_patch.authapi import hooks
|
from cgcs_patch.authapi import hooks
|
||||||
from cgcs_patch.authapi import policy
|
from cgcs_patch.authapi import policy
|
||||||
|
|
||||||
|
|
||||||
auth_opts = [
|
auth_opts = [
|
||||||
cfg.StrOpt('auth_strategy',
|
cfg.StrOpt('auth_strategy',
|
||||||
default='keystone',
|
default='keystone',
|
||||||
@ -32,9 +30,6 @@ def get_pecan_config():
|
|||||||
|
|
||||||
|
|
||||||
def setup_app(pecan_config=None, extra_hooks=None):
|
def setup_app(pecan_config=None, extra_hooks=None):
|
||||||
config_parser = configparser.RawConfigParser()
|
|
||||||
config_parser.read('/etc/patching/patching.conf')
|
|
||||||
|
|
||||||
policy.init()
|
policy.init()
|
||||||
|
|
||||||
app_hooks = [hooks.ConfigHook(),
|
app_hooks = [hooks.ConfigHook(),
|
||||||
@ -47,7 +42,7 @@ def setup_app(pecan_config=None, extra_hooks=None):
|
|||||||
pecan_config = get_pecan_config()
|
pecan_config = get_pecan_config()
|
||||||
|
|
||||||
if pecan_config.app.enable_acl:
|
if pecan_config.app.enable_acl:
|
||||||
app_hooks.append(hooks.AdminAuthHook())
|
app_hooks.append(hooks.AccessPolicyHook())
|
||||||
|
|
||||||
pecan.configuration.set_config(dict(pecan_config), overwrite=True)
|
pecan.configuration.set_config(dict(pecan_config), overwrite=True)
|
||||||
|
|
||||||
@ -61,8 +56,10 @@ def setup_app(pecan_config=None, extra_hooks=None):
|
|||||||
guess_content_type_from_ext=False, # Avoid mime-type lookup
|
guess_content_type_from_ext=False, # Avoid mime-type lookup
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# config_parser must contain the keystone_auth
|
||||||
if pecan_config.app.enable_acl:
|
if pecan_config.app.enable_acl:
|
||||||
return acl.install(app, config_parser, pecan_config.app.acl_public_routes)
|
CONF.import_group(acl.OPT_GROUP_NAME, acl.OPT_GROUP_PROVIDER)
|
||||||
|
return acl.install(app, CONF, pecan_config.app.acl_public_routes)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
39
sw-patch/cgcs-patch/cgcs_patch/authapi/context.py
Normal file
39
sw-patch/cgcs-patch/cgcs_patch/authapi/context.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2022 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from oslo_context import context
|
||||||
|
|
||||||
|
|
||||||
|
# Patching calls into fault. so only FM service type
|
||||||
|
# needs to be preserved in the service catalog
|
||||||
|
REQUIRED_SERVICE_TYPES = ('faultmanagement',)
|
||||||
|
|
||||||
|
|
||||||
|
class RequestContext(context.RequestContext):
|
||||||
|
"""Extends security contexts from the OpenStack common library."""
|
||||||
|
|
||||||
|
def __init__(self, is_public_api=False, service_catalog=None, **kwargs):
|
||||||
|
"""Stores several additional request parameters:
|
||||||
|
"""
|
||||||
|
super(RequestContext, self).__init__(**kwargs)
|
||||||
|
self.is_public_api = is_public_api
|
||||||
|
if service_catalog:
|
||||||
|
# Only include required parts of service_catalog
|
||||||
|
self.service_catalog = [s for s in service_catalog
|
||||||
|
if s.get('type') in REQUIRED_SERVICE_TYPES]
|
||||||
|
else:
|
||||||
|
# if list is empty or none
|
||||||
|
self.service_catalog = []
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
value = super(RequestContext, self).to_dict()
|
||||||
|
value.update({'is_public_api': self.is_public_api,
|
||||||
|
'service_catalog': self.service_catalog})
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def make_context(*args, **kwargs):
|
||||||
|
return RequestContext(*args, **kwargs)
|
@ -21,12 +21,12 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
from pecan import hooks
|
from pecan import hooks
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
from sysinv.common import context
|
from cgcs_patch.authapi.context import RequestContext
|
||||||
from sysinv.openstack.common import policy
|
from cgcs_patch.authapi import policy
|
||||||
|
|
||||||
from cgcs_patch import utils
|
from cgcs_patch import utils
|
||||||
|
|
||||||
|
|
||||||
@ -56,6 +56,9 @@ class ContextHook(hooks.PecanHook):
|
|||||||
The flag is set to True, if X-Roles contains either an administrator
|
The flag is set to True, if X-Roles contains either an administrator
|
||||||
or admin substring. Otherwise it is set to False.
|
or admin substring. Otherwise it is set to False.
|
||||||
|
|
||||||
|
X-Project-Name:
|
||||||
|
Used for context.project_name.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, public_api_routes):
|
def __init__(self, public_api_routes):
|
||||||
self.public_api_routes = public_api_routes
|
self.public_api_routes = public_api_routes
|
||||||
@ -66,36 +69,54 @@ class ContextHook(hooks.PecanHook):
|
|||||||
user_id = state.request.headers.get('X-User', user_id)
|
user_id = state.request.headers.get('X-User', user_id)
|
||||||
tenant = state.request.headers.get('X-Tenant-Id')
|
tenant = state.request.headers.get('X-Tenant-Id')
|
||||||
tenant = state.request.headers.get('X-Tenant', tenant)
|
tenant = state.request.headers.get('X-Tenant', tenant)
|
||||||
|
project_name = state.request.headers.get('X-Project-Name')
|
||||||
domain_id = state.request.headers.get('X-User-Domain-Id')
|
domain_id = state.request.headers.get('X-User-Domain-Id')
|
||||||
domain_name = state.request.headers.get('X-User-Domain-Name')
|
domain_name = state.request.headers.get('X-User-Domain-Name')
|
||||||
auth_token = state.request.headers.get('X-Auth-Token', None)
|
auth_token = state.request.headers.get('X-Auth-Token', None)
|
||||||
creds = {'roles': state.request.headers.get('X-Roles', '').split(',')}
|
creds = {'roles': state.request.headers.get('X-Roles', '').split(',')}
|
||||||
|
catalog_header = state.request.headers.get('X-Service-Catalog')
|
||||||
|
service_catalog = None
|
||||||
|
if catalog_header:
|
||||||
|
try:
|
||||||
|
service_catalog = jsonutils.loads(catalog_header)
|
||||||
|
except ValueError:
|
||||||
|
raise exc.HTTPInternalServerError(
|
||||||
|
'Invalid service catalog json.')
|
||||||
|
|
||||||
is_admin = policy.check('admin', state.request.headers, creds)
|
is_admin = policy.authorize('admin_api', {}, creds, do_raise=False)
|
||||||
|
|
||||||
path = utils.safe_rstrip(state.request.path, '/')
|
path = utils.safe_rstrip(state.request.path, '/')
|
||||||
is_public_api = path in self.public_api_routes
|
is_public_api = path in self.public_api_routes
|
||||||
|
|
||||||
state.request.context = context.RequestContext(
|
state.request.context = RequestContext(
|
||||||
auth_token=auth_token,
|
auth_token=auth_token,
|
||||||
user=user_id,
|
user=user_id,
|
||||||
tenant=tenant,
|
tenant=tenant,
|
||||||
domain_id=domain_id,
|
domain_id=domain_id,
|
||||||
domain_name=domain_name,
|
domain_name=domain_name,
|
||||||
is_admin=is_admin,
|
is_admin=is_admin,
|
||||||
is_public_api=is_public_api)
|
is_public_api=is_public_api,
|
||||||
|
project_name=project_name,
|
||||||
|
roles=creds['roles'],
|
||||||
|
service_catalog=service_catalog)
|
||||||
|
|
||||||
|
|
||||||
class AdminAuthHook(hooks.PecanHook):
|
class AccessPolicyHook(hooks.PecanHook):
|
||||||
"""Verify that the user has admin rights.
|
"""Verify that the user has the needed credentials
|
||||||
|
to execute the action.
|
||||||
Checks whether the request context is an admin context and
|
|
||||||
rejects the request otherwise.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def before(self, state):
|
def before(self, state):
|
||||||
ctx = state.request.context
|
controller = state.controller.__self__
|
||||||
is_admin_api = policy.check('admin_api', {}, ctx.to_dict())
|
if hasattr(controller, 'enforce_policy'):
|
||||||
|
controller_method = state.controller.__name__
|
||||||
if not is_admin_api and not ctx.is_public_api:
|
controller.enforce_policy(controller_method,
|
||||||
raise exc.HTTPForbidden()
|
state.request)
|
||||||
|
else:
|
||||||
|
context = state.request.context
|
||||||
|
is_admin_api = policy.authorize(
|
||||||
|
'admin_api',
|
||||||
|
{},
|
||||||
|
context.to_dict(),
|
||||||
|
do_raise=False)
|
||||||
|
if not is_admin_api and not context.is_public_api:
|
||||||
|
raise exc.HTTPForbidden()
|
||||||
|
@ -16,104 +16,76 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2014-2022 Wind River Systems, Inc.
|
# Copyright (c) 2014-2022 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
"""Policy Engine For Patching."""
|
"""Policy Engine For Patching."""
|
||||||
|
|
||||||
import os.path
|
from oslo_config import cfg
|
||||||
|
from oslo_policy import policy
|
||||||
from sysinv.common import exception
|
|
||||||
from sysinv.openstack.common import policy
|
|
||||||
|
|
||||||
from cgcs_patch import utils
|
|
||||||
|
|
||||||
|
|
||||||
_POLICY_PATH = None
|
base_rules = [
|
||||||
_POLICY_CACHE = {}
|
policy.RuleDefault('admin_required', 'role:admin or is_admin:1',
|
||||||
|
description='Who is considered an admin'),
|
||||||
|
policy.RuleDefault('admin_api', 'rule:admin_required',
|
||||||
|
description='admin API requirement'),
|
||||||
|
policy.RuleDefault('default', 'rule:admin_api',
|
||||||
|
description='default rule'),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
_ENFORCER = None
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def init(policy_file=None, rules=None,
|
||||||
global _POLICY_PATH
|
default_rule=None, use_conf=True, overwrite=True):
|
||||||
global _POLICY_CACHE
|
"""Init an Enforcer class.
|
||||||
_POLICY_PATH = None
|
|
||||||
_POLICY_CACHE = {}
|
|
||||||
policy.reset()
|
|
||||||
|
|
||||||
|
oslo policy supports change policy rule dynamically.
|
||||||
|
policy.enforce will reload the policy rules if it detects
|
||||||
|
the policy files have been touched.
|
||||||
|
|
||||||
def init():
|
:param policy_file: Custom policy file to use, if none is
|
||||||
global _POLICY_PATH
|
specified, ``conf.policy_file`` will be
|
||||||
global _POLICY_CACHE
|
used.
|
||||||
if not _POLICY_PATH:
|
:param rules: Default dictionary / Rules to use. It will be
|
||||||
_POLICY_PATH = '/etc/patching/policy.json'
|
considered just in the first instantiation. If
|
||||||
if not os.path.exists(_POLICY_PATH):
|
:meth:`load_rules` with ``force_reload=True``,
|
||||||
raise exception.ConfigNotFound(message='/etc/patching/policy.json')
|
:meth:`clear` or :meth:`set_rules` with
|
||||||
utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE,
|
``overwrite=True`` is called this will be overwritten.
|
||||||
reload_func=_set_rules)
|
:param default_rule: Default rule to use, conf.default_rule will
|
||||||
|
be used if none is specified.
|
||||||
|
:param use_conf: Whether to load rules from cache or config file.
|
||||||
def _set_rules(data):
|
:param overwrite: Whether to overwrite existing rules when reload rules
|
||||||
default_rule = "rule:admin_api"
|
from config file.
|
||||||
rules = policy.Rules.load_rules(data, default_rule, [])
|
|
||||||
policy.set_rules(rules)
|
|
||||||
|
|
||||||
|
|
||||||
def enforce(context, action, target, do_raise=True):
|
|
||||||
"""Verifies that the action is valid on the target in this context.
|
|
||||||
|
|
||||||
:param context: sysinv context
|
|
||||||
:param action: string representing the action to be checked
|
|
||||||
this should be colon separated for clarity.
|
|
||||||
i.e. ``compute:create_instance``,
|
|
||||||
``compute:attach_volume``,
|
|
||||||
``volume:attach_volume``
|
|
||||||
:param target: dictionary representing the object of the action
|
|
||||||
for object creation this should be a dictionary representing the
|
|
||||||
location of the object e.g. ``{'project_id': context.project_id}``
|
|
||||||
:param do_raise: if True (the default), raises PolicyNotAuthorized;
|
|
||||||
if False, returns False
|
|
||||||
|
|
||||||
:raises sysinv.exception.PolicyNotAuthorized: if verification fails
|
|
||||||
and do_raise is True.
|
|
||||||
|
|
||||||
:return: returns a non-False value (not necessarily "True") if
|
|
||||||
authorized, and the exact value False if not authorized and
|
|
||||||
do_raise is False.
|
|
||||||
"""
|
"""
|
||||||
|
global _ENFORCER
|
||||||
|
if not _ENFORCER:
|
||||||
|
# https://docs.openstack.org/oslo.policy/latest/user/usage.html
|
||||||
|
_ENFORCER = policy.Enforcer(CONF,
|
||||||
|
policy_file=policy_file,
|
||||||
|
rules=rules,
|
||||||
|
default_rule=default_rule,
|
||||||
|
use_conf=use_conf,
|
||||||
|
overwrite=overwrite)
|
||||||
|
_ENFORCER.register_defaults(base_rules)
|
||||||
|
return _ENFORCER
|
||||||
|
|
||||||
|
|
||||||
|
def authorize(rule, target, creds, do_raise=True):
|
||||||
|
"""A wrapper around 'authorize' from 'oslo_policy.policy'."""
|
||||||
init()
|
init()
|
||||||
|
return _ENFORCER.authorize(rule, target, creds, do_raise=do_raise)
|
||||||
|
|
||||||
credentials = context.to_dict()
|
|
||||||
|
|
||||||
# Add the exception arguments if asked to do a raise
|
def default_target(context):
|
||||||
extra = {}
|
return {'project_id': context.project_id, 'user_id': context.user_id}
|
||||||
if do_raise:
|
|
||||||
extra.update(exc=exception.PolicyNotAuthorized, action=action)
|
|
||||||
|
|
||||||
return policy.check(action, target, credentials, **extra)
|
|
||||||
|
|
||||||
|
|
||||||
def check_is_admin(context):
|
def check_is_admin(context):
|
||||||
"""Whether or not role contains 'admin' role according to policy setting.
|
"""Whether or not roles contains 'admin' role according to policy setting.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
init()
|
return authorize('context_is_admin', # rule
|
||||||
|
default_target(context), # target
|
||||||
credentials = context.to_dict()
|
context) # creds
|
||||||
target = credentials
|
|
||||||
|
|
||||||
return policy.check('context_is_admin', target, credentials)
|
|
||||||
|
|
||||||
|
|
||||||
@policy.register('context_is_admin')
|
|
||||||
class IsAdminCheck(policy.Check):
|
|
||||||
"""An explicit check for is_admin."""
|
|
||||||
|
|
||||||
def __init__(self, kind, match):
|
|
||||||
"""Initialize the check."""
|
|
||||||
|
|
||||||
self.expected = (match.lower() == 'true')
|
|
||||||
|
|
||||||
super(IsAdminCheck, self).__init__(kind, str(self.expected))
|
|
||||||
|
|
||||||
def __call__(self, target, creds):
|
|
||||||
"""Determine whether is_admin matches the requested value."""
|
|
||||||
|
|
||||||
return creds['is_admin'] == self.expected
|
|
||||||
|
@ -2588,6 +2588,13 @@ class PatchControllerMainThread(threading.Thread):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
# The following call to CONF is to ensure the oslo config
|
||||||
|
# has been called to specify a valid config dir.
|
||||||
|
# Otherwise oslo_policy will fail when it looks for its files.
|
||||||
|
CONF(
|
||||||
|
(), # Required to load an anonymous configuration
|
||||||
|
default_config_files=['/etc/patching/patching.conf', ]
|
||||||
|
)
|
||||||
configure_logging()
|
configure_logging()
|
||||||
|
|
||||||
cfg.read_config()
|
cfg.read_config()
|
||||||
|
23
sw-patch/cgcs-patch/cgcs_patch/tests/api/auth_config.py
Normal file
23
sw-patch/cgcs-patch/cgcs_patch/tests/api/auth_config.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
Copyright (c) 2022 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Server Specific Configurations
|
||||||
|
server = {
|
||||||
|
'port': '5487',
|
||||||
|
'host': '127.0.0.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pecan Application Configurations
|
||||||
|
app = {
|
||||||
|
'root': 'cgcs_patch.api.controllers.root.RootController',
|
||||||
|
'modules': ['cgcs_patch.authapi'],
|
||||||
|
'static_root': '%(confdir)s/public',
|
||||||
|
'template_path': '%(confdir)s/../templates',
|
||||||
|
'debug': False,
|
||||||
|
'enable_acl': True,
|
||||||
|
'acl_public_routes': [],
|
||||||
|
}
|
23
sw-patch/cgcs-patch/cgcs_patch/tests/api/config.py
Normal file
23
sw-patch/cgcs-patch/cgcs_patch/tests/api/config.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
Copyright (c) 2022 Wind River Systems, Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Server Specific Configurations
|
||||||
|
server = {
|
||||||
|
'port': '5487',
|
||||||
|
'host': '127.0.0.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pecan Application Configurations
|
||||||
|
app = {
|
||||||
|
'root': 'cgcs_patch.api.controllers.root.RootController',
|
||||||
|
'modules': ['cgcs_patch.authapi'],
|
||||||
|
'static_root': '%(confdir)s/public',
|
||||||
|
'template_path': '%(confdir)s/../templates',
|
||||||
|
'debug': False,
|
||||||
|
'enable_acl': False,
|
||||||
|
'acl_public_routes': [],
|
||||||
|
}
|
1
sw-patch/cgcs-patch/cgcs_patch/tests/api/patching.conf
Normal file
1
sw-patch/cgcs-patch/cgcs_patch/tests/api/patching.conf
Normal file
@ -0,0 +1 @@
|
|||||||
|
[DEFAULT]
|
42
sw-patch/cgcs-patch/cgcs_patch/tests/api/test_api.py
Normal file
42
sw-patch/cgcs-patch/cgcs_patch/tests/api/test_api.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2022 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
from oslo_config import cfg
|
||||||
|
from pecan import set_config
|
||||||
|
from pecan.testing import load_test_app
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class SWPatchAPITest(TestCase):
|
||||||
|
"""API Tests for sw-patch"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# trigger oslo_config to load a config file
|
||||||
|
# so that it can co-locate a policy file
|
||||||
|
config_file = os.path.join(os.path.dirname(__file__),
|
||||||
|
'patching.conf')
|
||||||
|
cfg.CONF((),
|
||||||
|
default_config_files=[config_file, ])
|
||||||
|
# config.py sets acl to False
|
||||||
|
self.app = load_test_app(os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'config.py'
|
||||||
|
))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
set_config({}, overwrite=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRootController(SWPatchAPITest):
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
response = self.app.get('/')
|
||||||
|
assert response.status_int == 200
|
||||||
|
|
||||||
|
def test_get_not_found(self):
|
||||||
|
response = self.app.get('/a/bogus/url', expect_errors=True)
|
||||||
|
assert response.status_int == 404
|
43
sw-patch/cgcs-patch/cgcs_patch/tests/api/test_authapi.py
Normal file
43
sw-patch/cgcs-patch/cgcs_patch/tests/api/test_authapi.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2022 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
from oslo_config import cfg
|
||||||
|
from pecan import set_config
|
||||||
|
from pecan.testing import load_test_app
|
||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class SWPatchAuthAPITest(TestCase):
|
||||||
|
"""Auth API Tests for sw-patch"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# trigger oslo_config to load a config file
|
||||||
|
# so that it can co-locate a policy file
|
||||||
|
config_file = os.path.join(os.path.dirname(__file__),
|
||||||
|
'patching.conf')
|
||||||
|
cfg.CONF((),
|
||||||
|
default_config_files=[config_file, ])
|
||||||
|
# auth_config.py sets acl to True
|
||||||
|
self.app = load_test_app(os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'auth_config.py'
|
||||||
|
))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
set_config({}, overwrite=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRootControllerNoAuth(SWPatchAuthAPITest):
|
||||||
|
"""We are not authenticated. Commands return 401"""
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
response = self.app.get('/', expect_errors=True)
|
||||||
|
assert response.status_int == 401
|
||||||
|
|
||||||
|
def test_get_not_found(self):
|
||||||
|
response = self.app.get('/a/bogus/url', expect_errors=True)
|
||||||
|
assert response.status_int == 401
|
@ -2,11 +2,15 @@
|
|||||||
# of appearance. Changing the order has an impact on the overall integration
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
|
|
||||||
|
keystoneauth1
|
||||||
keystonemiddleware
|
keystonemiddleware
|
||||||
lxml
|
lxml
|
||||||
oslo.config
|
oslo.config
|
||||||
|
oslo.policy
|
||||||
|
oslo.serialization
|
||||||
netaddr
|
netaddr
|
||||||
pecan
|
pecan
|
||||||
pycryptodomex
|
pycryptodomex
|
||||||
requests_toolbelt
|
requests_toolbelt
|
||||||
sh
|
sh
|
||||||
|
WebOb
|
||||||
|
@ -17,7 +17,6 @@ basepython = python3
|
|||||||
deps = -r{toxinidir}/requirements.txt
|
deps = -r{toxinidir}/requirements.txt
|
||||||
-r{toxinidir}/test-requirements.txt
|
-r{toxinidir}/test-requirements.txt
|
||||||
-e{[tox]stxdir}/fault/fm-api/source
|
-e{[tox]stxdir}/fault/fm-api/source
|
||||||
-e{[tox]stxdir}/config/sysinv/sysinv/sysinv
|
|
||||||
-e{[tox]stxdir}/config/tsconfig/tsconfig
|
-e{[tox]stxdir}/config/tsconfig/tsconfig
|
||||||
|
|
||||||
install_command = pip install \
|
install_command = pip install \
|
||||||
|
Loading…
Reference in New Issue
Block a user