Use oslo context instead of the native context implementation

Change-Id: I9abd709b3a1d038bd1819eafa1dac6712b1a4cbb
This commit is contained in:
liusheng 2016-12-06 14:15:43 +08:00
parent 79d808f9e3
commit b9f4a5bfe1
20 changed files with 49 additions and 270 deletions

View File

@ -94,7 +94,7 @@ function configure_nimble {
iniset ${NIMBLE_CONF_FILE} oslo_policy policy_file ${NIMBLE_POLICY_FILE}
if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
setup_colorized_logging ${NIMBLE_CONF_FILE} DEFAULT "project_id" "user_id"
setup_colorized_logging ${NIMBLE_CONF_FILE} DEFAULT tenant user
fi
}

View File

@ -15,10 +15,10 @@
# under the License.
from oslo_config import cfg
from oslo_context import context
from pecan import hooks
from six.moves import http_client
from nimble.common import context
from nimble.common import policy
from nimble.db import api as dbapi
@ -43,7 +43,7 @@ class ContextHook(hooks.PecanHook):
The following HTTP request headers are used:
X-User-Id or X-User:
Used for context.user_id.
Used for context.user.
X-Tenant-Id or X-Tenant:
Used for context.tenant.
@ -64,22 +64,20 @@ class ContextHook(hooks.PecanHook):
def before(self, state):
headers = state.request.headers
is_public_api = state.request.environ.get('is_public_api', False)
creds = {
'user_name': headers.get('X-User-Name'),
'user_id': headers.get('X-User-Id'),
'user': headers.get('X-User-Id'),
'project_name': headers.get('X-Project-Name'),
'project_id': headers.get('X-Project-Id'),
'domain_id': headers.get('X-User-Domain-Id'),
'tenant': headers.get('X-Project-Id'),
'domain': headers.get('X-User-Domain-Id'),
'domain_name': headers.get('X-User-Domain-Name'),
'auth_token': headers.get('X-Auth-Token'),
'roles': headers.get('X-Roles', '').split(','),
'is_public_api': is_public_api,
}
is_admin = policy.check('is_admin', creds, creds)
state.request.context = context.get_context(is_admin=is_admin, **creds)
state.request.context = context.RequestContext(
is_admin=is_admin, **creds)
def after(self, state):
if state.request.context == {}:

View File

@ -1,110 +0,0 @@
# -*- encoding: utf-8 -*-
#
# 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_context import context
class RequestContext(context.RequestContext):
"""Extends security contexts from the oslo.context library."""
def __init__(self, auth_token=None, domain_id=None, domain_name=None,
user_name=None, user_id=None, project_name=None,
project_id=None, is_admin=False, is_public_api=False,
read_only=False, request_id=None, roles=None,
show_password=True, overwrite=True, **kwargs):
"""Initialize the RequestContext
:param auth_token: The authentication token of the current request.
:param domain_id: The ID of the domain.
:param domain_name: The name of the domain.
:param user: The name of the user.
:param tenant: The name of the tenant.
:param is_admin: Indicates if the request context is an administrator
context.
:param is_public_api: Specifies whether the request should be processed
without authentication.
:param request_id: The UUID of the request.
:param roles: List of user's roles if any.
:param show_password: Specifies whether passwords should be masked
before sending back to API call.
:param overwrite: Set to False to ensure that the greenthread local
copy of the index is not overwritten.
"""
super(RequestContext, self).__init__(auth_token=auth_token,
user=user_name,
tenant=project_name,
is_admin=is_admin,
read_only=read_only,
request_id=request_id,
overwrite=overwrite)
self.user_id = user_id
self.user_name = user_name
self.project_name = project_name
self.project_id = project_id
self.is_public_api = is_public_api
self.domain_id = domain_id
self.domain_name = domain_name
self.show_password = show_password
# NOTE(dims): roles was added in context.RequestContext recently.
# we should pass roles in __init__ above instead of setting the
# value here once the minimum version of oslo.context is updated.
self.roles = roles or []
def to_dict(self):
value = super(RequestContext, self).to_dict()
value.update({'auth_token': self.auth_token,
'user_name': self.user_name,
'user_id': self.user_id,
'project_name': self.project_name,
'project_id': self.project_id,
'is_admin': self.is_admin,
'read_only': self.read_only,
'request_id': self.request_id,
'domain_id': self.domain_id,
'roles': self.roles,
'domain_name': self.domain_name,
'show_password': self.show_password,
'is_public_api': self.is_public_api})
return value
@classmethod
def from_dict(cls, values):
return cls(**values)
def ensure_thread_contain_context(self):
"""Ensure threading contains context
For async/periodic tasks, the context of local thread is missing.
Set it with request context and this is useful to log the request_id
in log messages.
"""
if context.get_current():
return
self.update_store()
def get_context(*args, **kwargs):
return RequestContext(*args, **kwargs)
def get_admin_context():
"""Create an administrator context."""
context = RequestContext(None,
project_id=None,
is_admin=True,
overwrite=False)
return context

View File

@ -204,7 +204,8 @@ def authorize_wsgi(api_name, act=None, need_target=True):
@functools.wraps(fn)
def handle(self, *args, **kwargs):
context = pecan.request.context
credentials = context.to_dict()
credentials = context.to_policy_values()
credentials['is_admin'] = context.is_admin
target = {}
# maybe we can pass "_get_resource" to authorize_wsgi
if need_target and hasattr(self, "_get_resource"):
@ -227,8 +228,8 @@ def authorize_wsgi(api_name, act=None, need_target=True):
else:
# for create method, before resource exsites, we can check the
# the credentials with itself.
target = {'project_id': context.project_id,
'user_id': context.user_id}
target = {'project_id': context.tenant,
'user_id': context.user}
try:
authorize(action, target, credentials)
except Exception:

View File

@ -14,9 +14,9 @@
# under the License.
from oslo_config import cfg
from oslo_context import context as nimble_context
import oslo_messaging as messaging
from nimble.common import context as nimble_context
from nimble.common import exception

View File

@ -13,6 +13,7 @@
# under the License.
from oslo_concurrency import processutils
from oslo_context import context
from oslo_log import log
import oslo_messaging as messaging
from oslo_service import service
@ -21,7 +22,6 @@ from oslo_utils import importutils
from nimble.api import app
from nimble.common import config
from nimble.common import context
from nimble.common import exception
from nimble.common.i18n import _
from nimble.common.i18n import _LE

View File

@ -64,7 +64,7 @@ def model_query(context, model, *args, **kwargs):
"""
if kwargs.pop("project_only", False):
kwargs["project_id"] = context.project_id
kwargs["project_id"] = context.tenant
with _session_for_read() as session:
query = sqlalchemyutils.model_query(

View File

@ -44,8 +44,8 @@ class API(object):
base_options = {
'image_uuid': image_uuid,
'status': status.BUILDING,
'user_id': context.user_id,
'project_id': context.project_id,
'user_id': context.user,
'project_id': context.tenant,
'instance_type_uuid': instance_type['uuid'],
'name': name,
'description': description,

View File

@ -18,6 +18,7 @@ import os
from oslo_config import cfg
from oslo_config import fixture as config_fixture
from oslo_context import context
from oslo_db import options
from oslo_log import log
from oslotest import base
@ -25,7 +26,6 @@ import pecan
import testscenarios
from nimble.common import config as nimble_config
from nimble.common import context as nimble_context
from nimble.tests import policy_fixture
@ -50,7 +50,7 @@ class TestCase(base.BaseTestCase):
def setUp(self):
super(TestCase, self).setUp()
self.context = nimble_context.get_admin_context()
self.context = context.get_admin_context()
self._set_config()

View File

@ -223,10 +223,10 @@ class BaseApiTest(base.DbTestCase):
headers = {
'X-User-Name': ct.get("user_name") or "user",
'X-User-Id':
ct.get("user_id") or "8abcdef1-2345-6789-abcd-ef123456abc0",
ct.get("user") or "8abcdef1-2345-6789-abcd-ef123456abc0",
'X-Project-Name': ct.get("project_name") or "project",
'X-Project-Id':
ct.get("project_id") or "1abcdef1-2345-6789-abcd-ef123456abe0",
ct.get("tenant") or "1abcdef1-2345-6789-abcd-ef123456abe0",
'X-User-Domain-Id':
ct.get("domain_id") or "9abcdef1-2345-6789-abcd-ef123456abc0",
'X-User-Domain-Name': ct.get("domain_name") or "no_domain",

View File

@ -17,9 +17,9 @@
import mock
from oslo_config import cfg
from oslo_context import context
from nimble.api import hooks
from nimble.common import context
from nimble.tests import base
@ -100,14 +100,13 @@ class TestContextHook(base.TestCase):
context_hook.before(reqstate)
mock_ctx.assert_called_with(
auth_token=headers['X-Auth-Token'],
user_id=headers['X-User-Id'],
user=headers['X-User-Id'],
user_name=headers['X-User-Name'],
project_id=headers['X-Project-Id'],
tenant=headers['X-Project-Id'],
project_name=headers['X-Project-Name'],
domain_id=headers['X-User-Domain-Id'],
domain=headers['X-User-Domain-Id'],
domain_name=headers['X-User-Domain-Name'],
is_admin=True,
is_public_api=False,
roles=headers['X-Roles'].split(','))
@mock.patch.object(context, 'RequestContext')
@ -119,14 +118,13 @@ class TestContextHook(base.TestCase):
context_hook.before(reqstate)
mock_ctx.assert_called_with(
auth_token=headers['X-Auth-Token'],
user_id=headers['X-User-Id'],
user=headers['X-User-Id'],
user_name=headers['X-User-Name'],
project_id=headers['X-Project-Id'],
tenant=headers['X-Project-Id'],
project_name=headers['X-Project-Name'],
domain_id=headers['X-User-Domain-Id'],
domain=headers['X-User-Domain-Id'],
domain_name=headers['X-User-Domain-Name'],
is_admin=True,
is_public_api=True,
roles=headers['X-Roles'].split(','))
@mock.patch.object(context, 'RequestContext')

View File

@ -66,7 +66,7 @@ class TestInstanceAuthorization(v1_test.APITestV1):
self.context.roles = "no-admin"
# we can not prevent the evil tenant, quota will limite him.
# Note(Shaohe): quota is in plan
self.context.project_id = self.evil_project
self.context.tenant = self.evil_project
headers = self.gen_headers(self.context)
self.post_json('/instances', body, headers=headers, status=201)
@ -74,23 +74,21 @@ class TestInstanceAuthorization(v1_test.APITestV1):
def test_instance_get_one_by_owner(self, mock_get_node):
mock_get_node.return_value = {'power_state': 'power on'}
# not admin but the owner
self.context.project_id = self.instance1.project_id
self.context.tenant = self.instance1.project_id
headers = self.gen_headers(self.context, roles="no-admin")
self.get_json('/instances/%s' % self.instance1.uuid, headers=headers)
@mock.patch('nimble.engine.api.API.get_ironic_node')
def test_instance_get_one_by_admin(self, mock_get_node):
mock_get_node.return_value = {'power_state': 'power on'}
# admin but the owner
self.context.project_id = self.instance1.project_id
# when the evil tenant is admin, he can do everything.
self.context.project_id = self.evil_project
self.context.tenant = self.evil_project
headers = self.gen_headers(self.context, roles="admin")
self.get_json('/instances/%s' % self.instance1.uuid, headers=headers)
def test_instance_get_one_unauthorized(self):
# not admin and not the owner
self.context.project_id = self.evil_project
self.context.tenant = self.evil_project
headers = self.gen_headers(self.context, roles="no-admin")
resp = self.get_json('/instances/%s' % self.instance1.uuid,
True, headers=headers)
@ -104,7 +102,7 @@ class TestPatch(v1_test.APITestV1):
def setUp(self):
super(TestPatch, self).setUp()
self.instance = utils.create_test_instance(name="patch_instance")
self.context.project_id = self.instance.project_id
self.context.tenant = self.instance.project_id
self.headers = self.gen_headers(self.context, roles="no-admin")
def test_update_not_found(self):

View File

@ -1,107 +0,0 @@
# 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_context import context as oslo_context
from nimble.common import context
from nimble.tests import base as tests_base
class RequestContextTestCase(tests_base.TestCase):
def setUp(self):
super(RequestContextTestCase, self).setUp()
@mock.patch.object(oslo_context.RequestContext, "__init__")
def test_create_context(self, context_mock):
test_context = context.RequestContext()
context_mock.assert_called_once_with(
auth_token=None, user=None, tenant=None, is_admin=False,
read_only=False, request_id=None, overwrite=True)
self.assertFalse(test_context.is_public_api)
self.assertIsNone(test_context.domain_id)
self.assertIsNone(test_context.domain_name)
self.assertEqual([], test_context.roles)
def test_from_dict(self):
dict = {
"user_name": "user1",
"project_name": "tenant1",
"is_public_api": True,
"domain_id": "domain_id1",
"domain_name": "domain_name1",
"roles": None
}
ctx = context.RequestContext.from_dict(dict)
self.assertTrue(ctx.is_public_api)
self.assertEqual("domain_id1", ctx.domain_id)
self.assertEqual("domain_name1", ctx.domain_name)
self.assertEqual("user1", ctx.user_name)
self.assertEqual("tenant1", ctx.project_name)
self.assertEqual([], ctx.roles)
def test_to_dict(self):
values = {
'auth_token': 'auth_token1',
"user_name": "user1",
"project_name": "tenant1",
'is_admin': True,
'read_only': True,
'request_id': 'id1',
"is_public_api": True,
"domain_id": "domain_id1",
"domain_name": "domain_name1",
"roles": None,
"overwrite": True
}
ctx = context.RequestContext(**values)
ctx_dict = ctx.to_dict()
self.assertIn('auth_token', ctx_dict)
self.assertIn('user', ctx_dict)
self.assertIn('tenant', ctx_dict)
self.assertIn('is_admin', ctx_dict)
self.assertIn('read_only', ctx_dict)
self.assertIn('request_id', ctx_dict)
self.assertIn('domain_id', ctx_dict)
self.assertIn('roles', ctx_dict)
self.assertIn('domain_name', ctx_dict)
self.assertIn('is_public_api', ctx_dict)
self.assertNotIn('overwrite', ctx_dict)
self.assertEqual('auth_token1', ctx_dict['auth_token'])
self.assertEqual('user1', ctx_dict['user_name'])
self.assertEqual('tenant1', ctx_dict['project_name'])
self.assertTrue(ctx_dict['is_admin'])
self.assertTrue(ctx_dict['read_only'])
self.assertEqual('id1', ctx_dict['request_id'])
self.assertTrue(ctx_dict['is_public_api'])
self.assertEqual('domain_id1', ctx_dict['domain_id'])
self.assertEqual('domain_name1', ctx_dict['domain_name'])
self.assertEqual([], ctx_dict['roles'])
def test_get_admin_context(self):
admin_context = context.get_admin_context()
self.assertTrue(admin_context.is_admin)
@mock.patch.object(oslo_context, 'get_current')
def test_thread_without_context(self, context_get_mock):
self.context.update_store = mock.Mock()
context_get_mock.return_value = None
self.context.ensure_thread_contain_context()
self.context.update_store.assert_called_once_with()
@mock.patch.object(oslo_context, 'get_current')
def test_thread_with_context(self, context_get_mock):
self.context.update_store = mock.Mock()
context_get_mock.return_value = self.context
self.context.ensure_thread_contain_context()
self.assertFalse(self.context.update_store.called)

View File

@ -11,10 +11,11 @@
# under the License.
import mock
from oslo_config import cfg
from oslo_context import context as nimble_context
import oslo_messaging as messaging
from nimble.common import context as nimble_context
from nimble.common import rpc
from nimble.tests import base
@ -116,5 +117,5 @@ class TestRequestContextSerializer(base.TestCase):
new_context = self.serializer.deserialize_context(serialize_values)
# Nimble RequestContext from_dict will pop 'user' and 'tenant' and
# initialize to None.
self.assertIsNone(new_context.user)
self.assertIsNone(new_context.tenant)
self.assertEqual('fake-user', new_context.user)
self.assertEqual('fake-tenant', new_context.tenant)

View File

@ -73,14 +73,14 @@ class DbInstanceTestCase(base.DbTestCase):
# Set project_only to True
# get instances from current project (project_1)
self.context.project_id = 'project_1'
self.context.tenant = 'project_1'
res = self.dbapi.instance_get_all(self.context, project_only=True)
res_uuids = [r.uuid for r in res]
six.assertCountEqual(self, uuids_project_1, res_uuids)
# Set project_only to True
# get instances from current project (project_2)
self.context.project_id = 'project_2'
self.context.tenant = 'project_2'
res = self.dbapi.instance_get_all(self.context, project_only=True)
res_uuids = [r.uuid for r in res]
six.assertCountEqual(self, uuids_project_2, res_uuids)

View File

@ -15,9 +15,9 @@
""" Tests for create_instance TaskFlow """
import mock
from oslo_context import context
from oslo_utils import uuidutils
from nimble.common import context
from nimble.engine.baremetal import ironic
from nimble.engine.flows import create_instance
from nimble.engine.scheduler import filter_scheduler as scheduler

View File

@ -16,8 +16,8 @@
"""Unit tests for engine API."""
import mock
from oslo_context import context
from nimble.common import context
from nimble.engine import api as engine_api
from nimble.engine import rpcapi as engine_rpcapi
from nimble.engine import status
@ -32,8 +32,8 @@ class ComputeAPIUnitTest(base.DbTestCase):
self.user_id = 'fake-user'
self.project_id = 'fake-project'
self.engine_api = engine_api.API()
self.context = context.RequestContext(user_id=self.user_id,
project_id=self.project_id)
self.context = context.RequestContext(user=self.user_id,
tenant=self.project_id)
def _create_instance_type(self):
inst_type = db_utils.get_test_instance_type()

View File

@ -14,8 +14,8 @@
# under the License.
import mock
from oslo_context import context
from nimble.common import context
from nimble import objects
from nimble.tests.unit.db import base
from nimble.tests.unit.db import utils

View File

@ -12,8 +12,8 @@
# under the License.
import mock
from oslo_context import context
from nimble.common import context
from nimble.common import exception
from nimble import objects
from nimble.tests.unit.db import base

View File

@ -17,12 +17,12 @@ import gettext
import iso8601
import mock
from oslo_context import context
from oslo_versionedobjects import base as object_base
from oslo_versionedobjects import exception as object_exception
from oslo_versionedobjects import fixture as object_fixture
import six
from nimble.common import context
from nimble.objects import base
from nimble.objects import fields
from nimble.tests import base as test_base
@ -55,8 +55,8 @@ class MyObj(base.NimbleObject, object_base.VersionedObjectDictCompat):
return 'polo'
@object_base.remotable
def update_test(self, context=None):
if context and context.tenant == 'alternate':
def update_test(self, ctxt=None):
if ctxt and ctxt.tenant == 'alternate':
self.bar = 'alternate-context'
else:
self.bar = 'updated'
@ -384,7 +384,7 @@ class _TestObject(object):
expected_object_fingerprints = {
'Instance': '1.0-b861be9748601f713458a7a709eafd6b',
'InstanceType': '1.0-589b096651fcdb30898ff50f748dd948',
'MyObj': '1.1-4f5efe8f0fcaf182bbe1c7fe3ba858db',
'MyObj': '1.1-aad62eedc5a5cc8bcaf2982c285e753f',
'FakeNode': '1.0-295d1b08ce3048535926c47dedd27211',
}