diff --git a/ironic/cmd/ironic_deploy_helper.py b/ironic/cmd/ironic_deploy_helper.py index 5c23ab1ee4..20205c8685 100644 --- a/ironic/cmd/ironic_deploy_helper.py +++ b/ironic/cmd/ironic_deploy_helper.py @@ -31,11 +31,11 @@ import stat from wsgiref import simple_server from ironic.common import config -from ironic.common import context as ironic_context from ironic.common import exception from ironic.common import states from ironic.common import utils from ironic import db +from ironic.openstack.common import context as ironic_context from ironic.openstack.common import excutils from ironic.openstack.common import log as logging diff --git a/ironic/common/context.py b/ironic/common/context.py deleted file mode 100644 index c393079de9..0000000000 --- a/ironic/common/context.py +++ /dev/null @@ -1,228 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 OpenStack Foundation -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# 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. - -"""RequestContext: context for requests that persist through all of nova.""" - -import copy -import uuid - -from ironic.common import exception -from ironic.common import policy -from ironic.openstack.common import local -from ironic.openstack.common import log as logging -from ironic.openstack.common import timeutils - - -LOG = logging.getLogger(__name__) - - -def generate_request_id(): - return 'req-' + str(uuid.uuid4()) - - -class RequestContext(object): - """Security context and request information. - - Represents the user taking a given action within the system. - - """ - - def __init__(self, user_id, project_id, is_admin=None, read_deleted="no", - roles=None, remote_address=None, timestamp=None, - request_id=None, auth_token=None, overwrite=True, - quota_class=None, user_name=None, project_name=None, - service_catalog=None, instance_lock_checked=False, **kwargs): - """Initialize this RequestContext. - - :param read_deleted: 'no' indicates deleted records are hidden, 'yes' - indicates deleted records are visible, 'only' indicates that - *only* deleted records are visible. - - :param overwrite: Set to False to ensure that the greenthread local - copy of the index is not overwritten. - - :param kwargs: Extra arguments that might be present, but we ignore - because they possibly came in from older rpc messages. - """ - if kwargs: - LOG.warn(_('Arguments dropped when creating context: %s') % - str(kwargs)) - - self.user_id = user_id - self.project_id = project_id - self.roles = roles or [] - self.read_deleted = read_deleted - self.remote_address = remote_address - if not timestamp: - timestamp = timeutils.utcnow() - if isinstance(timestamp, basestring): - timestamp = timeutils.parse_strtime(timestamp) - self.timestamp = timestamp - if not request_id: - request_id = generate_request_id() - self.request_id = request_id - self.auth_token = auth_token - - if service_catalog: - # Only include required parts of service_catalog - self.service_catalog = [s for s in service_catalog - if s.get('type') in ('volume')] - else: - # if list is empty or none - self.service_catalog = [] - - self.instance_lock_checked = instance_lock_checked - - # NOTE(markmc): this attribute is currently only used by the - # rs_limits turnstile pre-processor. - # See https://lists.launchpad.net/openstack/msg12200.html - self.quota_class = quota_class - self.user_name = user_name - self.project_name = project_name - self.is_admin = is_admin - if self.is_admin is None: - self.is_admin = policy.check_is_admin(self) - if overwrite or not hasattr(local.store, 'context'): - self.update_store() - - def _get_read_deleted(self): - return self._read_deleted - - def _set_read_deleted(self, read_deleted): - if read_deleted not in ('no', 'yes', 'only'): - raise ValueError(_("read_deleted can only be one of 'no', " - "'yes' or 'only', not %r") % read_deleted) - self._read_deleted = read_deleted - - def _del_read_deleted(self): - del self._read_deleted - - read_deleted = property(_get_read_deleted, _set_read_deleted, - _del_read_deleted) - - def update_store(self): - local.store.context = self - - def to_dict(self): - return {'user_id': self.user_id, - 'project_id': self.project_id, - 'is_admin': self.is_admin, - 'read_deleted': self.read_deleted, - 'roles': self.roles, - 'remote_address': self.remote_address, - 'timestamp': timeutils.strtime(self.timestamp), - 'request_id': self.request_id, - 'auth_token': self.auth_token, - 'quota_class': self.quota_class, - 'user_name': self.user_name, - 'service_catalog': self.service_catalog, - 'project_name': self.project_name, - 'instance_lock_checked': self.instance_lock_checked, - 'tenant': self.tenant, - 'user': self.user} - - @classmethod - def from_dict(cls, values): - return cls(**values) - - def elevated(self, read_deleted=None, overwrite=False): - """Return a version of this context with admin flag set.""" - context = copy.copy(self) - context.is_admin = True - - if 'admin' not in context.roles: - context.roles.append('admin') - - if read_deleted is not None: - context.read_deleted = read_deleted - - return context - - # NOTE(sirp): the openstack/common version of RequestContext uses - # tenant/user whereas the Nova version uses project_id/user_id. We need - # this shim in order to use context-aware code from openstack/common, like - # logging, until we make the switch to using openstack/common's version of - # RequestContext. - @property - def tenant(self): - return self.project_id - - @property - def user(self): - return self.user_id - - -def get_admin_context(read_deleted="no"): - return RequestContext(user_id=None, - project_id=None, - is_admin=True, - read_deleted=read_deleted, - overwrite=False) - - -def is_user_context(context): - """Indicates if the request context is a normal user.""" - if not context: - return False - if context.is_admin: - return False - if not context.user_id or not context.project_id: - return False - return True - - -def require_admin_context(ctxt): - """Raise exception.AdminRequired() if context is an admin context.""" - if not ctxt.is_admin: - raise exception.AdminRequired() - - -def require_context(ctxt): - """Raise exception.NotAuthorized() if context is not a user or an - admin context. - """ - if not ctxt.is_admin and not is_user_context(ctxt): - raise exception.NotAuthorized() - - -def authorize_project_context(context, project_id): - """Ensures a request has permission to access the given project.""" - if is_user_context(context): - if not context.project_id: - raise exception.NotAuthorized() - elif context.project_id != project_id: - raise exception.NotAuthorized() - - -def authorize_user_context(context, user_id): - """Ensures a request has permission to access the given user.""" - if is_user_context(context): - if not context.user_id: - raise exception.NotAuthorized() - elif context.user_id != user_id: - raise exception.NotAuthorized() - - -def authorize_quota_class_context(context, class_name): - """Ensures a request has permission to access the given quota class.""" - if is_user_context(context): - if not context.quota_class: - raise exception.NotAuthorized() - elif context.quota_class != class_name: - raise exception.NotAuthorized() diff --git a/ironic/tests/api/test_nodes.py b/ironic/tests/api/test_nodes.py index 2a78c2f322..cd005c8371 100644 --- a/ironic/tests/api/test_nodes.py +++ b/ironic/tests/api/test_nodes.py @@ -18,7 +18,6 @@ Tests for the API /nodes/ methods. import mox -from ironic.common import context from ironic.common import exception from ironic.conductor import rpcapi from ironic.tests.api import base @@ -52,7 +51,6 @@ class TestPatch(base.FunctionalTest): def setUp(self): super(TestPatch, self).setUp() ndict = dbutils.get_test_node() - self.context = context.get_admin_context() self.node = self.dbapi.create_node(ndict) self.mox.StubOutWithMock(rpcapi.ConductorAPI, 'update_node') self.mox.StubOutWithMock(rpcapi.ConductorAPI, 'start_state_change') diff --git a/ironic/tests/db/base.py b/ironic/tests/db/base.py index 5dbe120e52..bea001abdd 100644 --- a/ironic/tests/db/base.py +++ b/ironic/tests/db/base.py @@ -15,7 +15,7 @@ """Ironic DB test base class.""" -from ironic.common import context as ironic_context +from ironic.openstack.common import context as ironic_context from ironic.tests import base diff --git a/ironic/tests/objects/test_chassis.py b/ironic/tests/objects/test_chassis.py index 725f428bb1..1045e72194 100644 --- a/ironic/tests/objects/test_chassis.py +++ b/ironic/tests/objects/test_chassis.py @@ -14,7 +14,6 @@ # License for the specific language governing permissions and limitations # under the License. -from ironic.common import context from ironic.db import api as db_api from ironic.db.sqlalchemy import models from ironic import objects @@ -29,7 +28,6 @@ class TestChassisObject(base.DbTestCase): super(TestChassisObject, self).setUp() self.fake_chassis = utils.get_test_chassis() self.dbapi = db_api.get_instance() - self.ctxt = context.get_admin_context() def test_load(self): uuid = self.fake_chassis['uuid'] @@ -38,7 +36,7 @@ class TestChassisObject(base.DbTestCase): self.dbapi.get_chassis(uuid).AndReturn(self.fake_chassis) self.mox.ReplayAll() - objects.Chassis.get_by_uuid(self.ctxt, uuid) + objects.Chassis.get_by_uuid(self.context, uuid) self.mox.VerifyAll() def test_save(self): @@ -51,7 +49,7 @@ class TestChassisObject(base.DbTestCase): self.dbapi.update_chassis(uuid, {'extra': {"test": 123}}) self.mox.ReplayAll() - c = objects.Chassis.get_by_uuid(self.ctxt, uuid) + c = objects.Chassis.get_by_uuid(self.context, uuid) c.extra = {"test": 123} c.save() self.mox.VerifyAll() @@ -68,7 +66,7 @@ class TestChassisObject(base.DbTestCase): dict(self.fake_chassis, uuid=new_uuid)) self.mox.ReplayAll() - c = objects.Chassis.get_by_uuid(self.ctxt, uuid) + c = objects.Chassis.get_by_uuid(self.context, uuid) self.assertEqual(c.uuid, uuid) c.refresh() self.assertEqual(c.uuid, new_uuid) diff --git a/ironic/tests/objects/test_node.py b/ironic/tests/objects/test_node.py index ff5d11cb62..3377543313 100644 --- a/ironic/tests/objects/test_node.py +++ b/ironic/tests/objects/test_node.py @@ -14,7 +14,6 @@ # License for the specific language governing permissions and limitations # under the License. -from ironic.common import context from ironic.db import api as db_api from ironic.db.sqlalchemy import models from ironic import objects @@ -30,20 +29,18 @@ class TestNodeObject(base.DbTestCase): self.dbapi = db_api.get_instance() def test_load(self): - ctxt = context.get_admin_context() uuid = self.fake_node['uuid'] self.mox.StubOutWithMock(self.dbapi, 'get_node') self.dbapi.get_node(uuid).AndReturn(self.fake_node) self.mox.ReplayAll() - objects.Node.get_by_uuid(ctxt, uuid) + objects.Node.get_by_uuid(self.context, uuid) self.mox.VerifyAll() # TODO(deva): add tests for load-on-demand info, eg. ports, # once Port objects are created def test_save(self): - ctxt = context.get_admin_context() uuid = self.fake_node['uuid'] self.mox.StubOutWithMock(self.dbapi, 'get_node') self.mox.StubOutWithMock(self.dbapi, 'update_node') @@ -52,13 +49,12 @@ class TestNodeObject(base.DbTestCase): self.dbapi.update_node(uuid, {'properties': {"fake": "property"}}) self.mox.ReplayAll() - n = objects.Node.get_by_uuid(ctxt, uuid) + n = objects.Node.get_by_uuid(self.context, uuid) n.properties = {"fake": "property"} n.save() self.mox.VerifyAll() def test_refresh(self): - ctxt = context.get_admin_context() uuid = self.fake_node['uuid'] self.mox.StubOutWithMock(self.dbapi, 'get_node') @@ -68,7 +64,7 @@ class TestNodeObject(base.DbTestCase): dict(self.fake_node, properties={"fake": "second"})) self.mox.ReplayAll() - n = objects.Node.get_by_uuid(ctxt, uuid) + n = objects.Node.get_by_uuid(self.context, uuid) self.assertEqual(n.properties, {"fake": "first"}) n.refresh() self.assertEqual(n.properties, {"fake": "second"}) diff --git a/ironic/tests/objects/test_port.py b/ironic/tests/objects/test_port.py index 786b415afe..2cd179c5a5 100644 --- a/ironic/tests/objects/test_port.py +++ b/ironic/tests/objects/test_port.py @@ -14,7 +14,7 @@ # License for the specific language governing permissions and limitations # under the License. -from ironic.common import context + from ironic.db import api as db_api from ironic.db.sqlalchemy import models from ironic import objects @@ -30,18 +30,16 @@ class TestPortObject(base.DbTestCase): self.dbapi = db_api.get_instance() def test_load(self): - ctxt = context.get_admin_context() uuid = self.fake_port['uuid'] self.mox.StubOutWithMock(self.dbapi, 'get_port') self.dbapi.get_port(uuid).AndReturn(self.fake_port) self.mox.ReplayAll() - objects.Port.get_by_uuid(ctxt, uuid) + objects.Port.get_by_uuid(self.context, uuid) self.mox.VerifyAll() def test_save(self): - ctxt = context.get_admin_context() uuid = self.fake_port['uuid'] self.mox.StubOutWithMock(self.dbapi, 'get_port') self.mox.StubOutWithMock(self.dbapi, 'update_port') @@ -50,13 +48,12 @@ class TestPortObject(base.DbTestCase): self.dbapi.update_port(uuid, {'address': "b2:54:00:cf:2d:40"}) self.mox.ReplayAll() - p = objects.Port.get_by_uuid(ctxt, uuid) + p = objects.Port.get_by_uuid(self.context, uuid) p.address = "b2:54:00:cf:2d:40" p.save() self.mox.VerifyAll() def test_refresh(self): - ctxt = context.get_admin_context() uuid = self.fake_port['uuid'] self.mox.StubOutWithMock(self.dbapi, 'get_port') @@ -66,7 +63,7 @@ class TestPortObject(base.DbTestCase): self.mox.ReplayAll() - p = objects.Port.get_by_uuid(ctxt, uuid) + p = objects.Port.get_by_uuid(self.context, uuid) self.assertEqual(p.address, "52:54:00:cf:2d:31") p.refresh()