Merge registry context with common context

Pull the extra methods defined in glance.registry.context:RequestContext into
glance.common.context:RequestContext. This is necessary as the new v2 API
implementation talks directly to the database.

* Partially implements bp api-2

Change-Id: Ia8c1fde511bdca69be0dcf61ce12976ace5f7dc3
This commit is contained in:
Brian Waldon 2012-04-24 20:35:41 -07:00
parent ba939295e3
commit bd305fa07b
13 changed files with 95 additions and 145 deletions

View File

@ -47,12 +47,6 @@ information. In order to configure Glance to use Keystone, the
Keystone distribution). The ``authtoken`` middleware performs the Keystone
token validation, which is the heart of Keystone authentication.
It is important to note that the Glance API and the Glance Registry
use two different context classes; this is because the registry needs
advanced methods that are not available in the default context class.
The implications of this will be obvious in the below example for
configuring the Glance Registry.
Configuring Glance API to use Keystone
--------------------------------------

View File

@ -15,7 +15,6 @@ paste.app_factory = glance.common.wsgi:app_factory
glance.app_factory = glance.registry.api.v1:API
[filter:context]
context_class = glance.registry.context.RequestContext
paste.filter_factory = glance.common.wsgi:filter_factory
glance.filter_factory = glance.common.context:ContextMiddleware

View File

@ -19,6 +19,7 @@ from glance.common import cfg
from glance.common import exception
from glance.common import utils
from glance.common import wsgi
from glance.registry.db import api as db_api
class RequestContext(object):
@ -51,6 +52,79 @@ class RequestContext(object):
return True
return False
def is_image_visible(self, image):
"""Return True if the image is visible in this context."""
# Is admin == image visible
if self.is_admin:
return True
# No owner == image visible
if image.owner is None:
return True
# Image is_public == image visible
if image.is_public:
return True
# Perform tests based on whether we have an owner
if self.owner is not None:
if self.owner == image.owner:
return True
# Figure out if this image is shared with that tenant
try:
tmp = db_api.image_member_find(self, image.id, self.owner)
return not tmp['deleted']
except exception.NotFound:
pass
# Private image
return False
def is_image_mutable(self, image):
"""Return True if the image is mutable in this context."""
# Is admin == image mutable
if self.is_admin:
return True
# No owner == image not mutable
if image.owner is None or self.owner is None:
return False
# Image only mutable by its owner
return image.owner == self.owner
def is_image_sharable(self, image, **kwargs):
"""Return True if the image can be shared to others in this context."""
# Only allow sharing if we have an owner
if self.owner is None:
return False
# Is admin == image sharable
if self.is_admin:
return True
# If we own the image, we can share it
if self.owner == image.owner:
return True
# Let's get the membership association
if 'membership' in kwargs:
membership = kwargs['membership']
if membership is None:
# Not shared with us anyway
return False
else:
try:
membership = db_api.image_member_find(self, image.id,
self.owner)
except exception.NotFound:
# Not shared with us anyway
return False
# It's the can_share attribute we're now interested in
return membership.can_share
class ContextMiddleware(wsgi.Middleware):
@ -62,12 +136,6 @@ class ContextMiddleware(wsgi.Middleware):
def __init__(self, app, conf, **local_conf):
self.conf = conf
self.conf.register_opts(self.opts)
# Determine the context class to use
self.ctxcls = RequestContext
if 'context_class' in local_conf:
self.ctxcls = utils.import_class(local_conf['context_class'])
super(ContextMiddleware, self).__init__(app)
def make_context(self, *args, **kwargs):
@ -76,7 +144,7 @@ class ContextMiddleware(wsgi.Middleware):
"""
kwargs.setdefault('owner_is_tenant', self.conf.owner_is_tenant)
return self.ctxcls(*args, **kwargs)
return RequestContext(*args, **kwargs)
def process_request(self, req):
"""

View File

@ -23,10 +23,10 @@ import logging
import eventlet
from glance.common import context
from glance.common import exception
from glance.image_cache import ImageCache
from glance import registry
from glance.registry import context
import glance.store
import glance.store.filesystem
import glance.store.http

View File

@ -23,10 +23,10 @@ import logging
import eventlet
from glance.common import context
from glance.common import exception
from glance.image_cache import ImageCache
from glance import registry
from glance.registry import context
logger = logging.getLogger(__name__)

View File

@ -1,101 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# 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.
from glance.common import context
from glance.common import exception
from glance.registry.db import api as db_api
class RequestContext(context.RequestContext):
"""
Stores information about the security context under which the user
accesses the system, as well as additional request information.
Also provides tests for image visibility and sharability.
"""
def is_image_visible(self, image):
"""Return True if the image is visible in this context."""
# Is admin == image visible
if self.is_admin:
return True
# No owner == image visible
if image.owner is None:
return True
# Image is_public == image visible
if image.is_public:
return True
# Perform tests based on whether we have an owner
if self.owner is not None:
if self.owner == image.owner:
return True
# Figure out if this image is shared with that tenant
try:
tmp = db_api.image_member_find(self, image.id, self.owner)
return not tmp['deleted']
except exception.NotFound:
pass
# Private image
return False
def is_image_mutable(self, image):
"""Return True if the image is mutable in this context."""
# Is admin == image mutable
if self.is_admin:
return True
# No owner == image not mutable
if image.owner is None or self.owner is None:
return False
# Image only mutable by its owner
return image.owner == self.owner
def is_image_sharable(self, image, **kwargs):
"""Return True if the image can be shared to others in this context."""
# Only allow sharing if we have an owner
if self.owner is None:
return False
# Is admin == image sharable
if self.is_admin:
return True
# If we own the image, we can share it
if self.owner == image.owner:
return True
# Let's get the membership association
if 'membership' in kwargs:
membership = kwargs['membership']
if membership is None:
# Not shared with us anyway
return False
else:
try:
membership = db_api.image_member_find(self, image.id,
self.owner)
except exception.NotFound:
# Not shared with us anyway
return False
# It's the can_share attribute we're now interested in
return membership.can_share

View File

@ -347,7 +347,6 @@ paste.app_factory = glance.common.wsgi:app_factory
glance.app_factory = glance.registry.api.v1:API
[filter:context]
context_class = glance.registry.context.RequestContext
paste.filter_factory = glance.common.wsgi:filter_factory
glance.filter_factory = glance.common.context:ContextMiddleware

View File

@ -67,14 +67,12 @@ def stub_out_registry_and_store_server(stubs, base_dir):
def getresponse(self):
sql_connection = os.environ.get('GLANCE_SQL_CONNECTION',
"sqlite://")
context_class = 'glance.registry.context.RequestContext'
conf = utils.TestConfigOpts({
'sql_connection': sql_connection,
'verbose': VERBOSE,
'debug': DEBUG
})
api = context.ContextMiddleware(rserver.API(conf),
conf, context_class=context_class)
api = context.ContextMiddleware(rserver.API(conf), conf)
res = self.req.get_response(api)
# httplib.Response has a read() method...fake it out
@ -237,14 +235,12 @@ def stub_out_registry_server(stubs, **kwargs):
def getresponse(self):
sql_connection = kwargs.get('sql_connection', "sqlite:///")
context_class = 'glance.registry.context.RequestContext'
conf = utils.TestConfigOpts({
'sql_connection': sql_connection,
'verbose': VERBOSE,
'debug': DEBUG
})
api = context.ContextMiddleware(rserver.API(conf),
conf, context_class=context_class)
api = context.ContextMiddleware(rserver.API(conf), conf)
res = self.req.get_response(api)
# httplib.Response has a read() method...fake it out

View File

@ -22,12 +22,12 @@ import unittest
from glance import client
from glance.common import client as base_client
from glance.common import context
from glance.common import exception
from glance.common import utils
from glance.registry.db import api as db_api
from glance.registry.db import models as db_models
from glance.registry import client as rclient
from glance.registry import context as rcontext
from glance.tests.unit import base
from glance.tests import utils as test_utils
@ -149,7 +149,7 @@ class TestRegistryClient(base.IsolatedUnitTest):
"""Establish a clean test environment"""
super(TestRegistryClient, self).setUp()
db_api.configure_db(self.conf)
self.context = rcontext.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=True)
self.FIXTURES = [
{'id': UUID1,
'name': 'fake image #1',
@ -1228,7 +1228,7 @@ class TestClient(base.IsolatedUnitTest):
'size': 19,
'location': "file:///%s/%s" % (self.test_dir, UUID2),
'properties': {}}]
self.context = rcontext.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=True)
self.destroy_fixtures()
self.create_fixtures()

View File

@ -17,7 +17,7 @@
import unittest
from glance.registry import context
from glance.common import context
class FakeImage(object):

View File

@ -19,9 +19,9 @@
import datetime
import random
from glance.common import context
from glance.common import exception
from glance.common import utils
from glance.registry import context as rcontext
from glance.registry.db import api as db_api
from glance.registry.db import models as db_models
from glance.tests.unit import base
@ -90,8 +90,8 @@ class TestRegistryDb(base.IsolatedUnitTest):
"""Establish a clean test environment"""
super(TestRegistryDb, self).setUp()
conf = test_utils.TestConfigOpts(CONF)
self.adm_context = rcontext.RequestContext(is_admin=True)
self.context = rcontext.RequestContext(is_admin=False)
self.adm_context = context.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=False)
db_api.configure_db(conf)
self.destroy_fixtures()
self.create_fixtures()
@ -186,8 +186,8 @@ class TestPagingOrder(base.IsolatedUnitTest):
"""Establish a clean test environment"""
super(TestPagingOrder, self).setUp()
conf = test_utils.TestConfigOpts(CONF)
self.adm_context = rcontext.RequestContext(is_admin=True)
self.context = rcontext.RequestContext(is_admin=False)
self.adm_context = context.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=False)
db_api.configure_db(conf)
self.destroy_fixtures()
self.create_fixtures()

View File

@ -29,7 +29,6 @@ from glance.api.v1 import images
from glance.api.v1 import router
from glance.common import context
from glance.common import utils
from glance.registry import context as rcontext
from glance.registry.api import v1 as rserver
from glance.registry.db import api as db_api
from glance.registry.db import models as db_models
@ -94,10 +93,7 @@ class TestRegistryAPI(base.IsolatedUnitTest):
def setUp(self):
"""Establish a clean test environment"""
super(TestRegistryAPI, self).setUp()
context_class = 'glance.registry.context.RequestContext'
self.api = context.ContextMiddleware(rserver.API(self.conf),
self.conf,
context_class=context_class)
self.api = context.ContextMiddleware(rserver.API(self.conf), self.conf)
self.FIXTURES = [
{'id': UUID1,
'name': 'fake image #1',
@ -131,7 +127,7 @@ class TestRegistryAPI(base.IsolatedUnitTest):
'size': 19,
'location': "file:///%s/%s" % (self.test_dir, UUID2),
'properties': {}}]
self.context = rcontext.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=True)
db_api.configure_db(self.conf)
self.destroy_fixtures()
self.create_fixtures()
@ -1989,7 +1985,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
'size': 19,
'location': "file:///%s/%s" % (self.test_dir, UUID2),
'properties': {}}]
self.context = rcontext.RequestContext(is_admin=True)
self.context = context.RequestContext(is_admin=True)
db_api.configure_db(self.conf)
self.destroy_fixtures()
self.create_fixtures()
@ -2991,9 +2987,9 @@ class TestImageSerializer(base.IsolatedUnitTest):
super(TestImageSerializer, self).setUp()
self.receiving_user = 'fake_user'
self.receiving_tenant = 2
self.context = rcontext.RequestContext(is_admin=True,
user=self.receiving_user,
tenant=self.receiving_tenant)
self.context = context.RequestContext(is_admin=True,
user=self.receiving_user,
tenant=self.receiving_tenant)
self.serializer = images.ImageSerializer(self.conf)
def image_iter():

View File

@ -7,7 +7,6 @@ import keystoneclient.v2_0.client
import glance.common.context
import glance.common.cfg
import glance.registry.context
import glance.registry.db.api as db_api
@ -77,7 +76,7 @@ if __name__ == "__main__":
db_api.configure_db(config)
context = glance.registry.context.RequestContext(is_admin=True)
context = glance.common.context.RequestContext(is_admin=True)
auth_uri = config.keystone_auth_uri
admin_tenant_name = config.keystone_admin_tenant_name