Important changes for service filtering

Some important changes for service filtering to support resources:
* Support the notion of ANY service_type in the service filter for
  user preferences.
* Create a join method in ServiceFilter to join a resource
  filter with a user preference.
* Support service filter preference in session.

For example if a user wanted to use region='East' they would create
a service filter preference in their session with that region and
use that session with any resource.

Change-Id: I13fc2838b66ec85bdd0191c78b27b3cd685a8322
This commit is contained in:
Terry Howe
2014-06-11 13:26:44 -06:00
parent 34084339c8
commit c6bb1fa352
7 changed files with 85 additions and 40 deletions

View File

@@ -106,6 +106,11 @@ def option_parser():
default=env('OS_PASSWORD'),
help='Authentication password (Env: OS_PASSWORD)',
)
parser.add_argument(
'--os-region',
metavar='<region>',
default=env('OS_REGION'),
help='Service region (Env: OS_REGION)')
parser.add_argument(
'--os-cacert',
metavar='<ca-bundle-file>',

View File

@@ -20,9 +20,11 @@ from openstack import session
def make_session(opts):
region = opts.os_region
preference = service_filter.ServiceFilter(region=region)
xport = transport.make_transport(opts)
auth = authenticate.make_authenticate(opts)
return session.Session(xport, auth)
return session.Session(xport, auth, preference=preference)
def run_session(opts):
@@ -30,7 +32,7 @@ def run_session(opts):
if argument is None:
raise Exception("A path argument must be specified")
sess = make_session(opts)
filtration = service_filter.ServiceFilter('Identity')
filtration = service_filter.ServiceFilter(service_type='Identity')
print("Session: %s" % sess)
print(sess.get(argument, service=filtration).text)
return

View File

@@ -16,12 +16,13 @@ from openstack import exceptions
class ServiceFilter(object):
"""The basic structure of an authentication plugin."""
ANY = 'any'
PUBLIC = 'public'
INTERNAL = 'internal'
ADMIN = 'admin'
VISIBILITY = [PUBLIC, INTERNAL, ADMIN]
def __init__(self, service_type, visibility=PUBLIC, region=None,
def __init__(self, service_type=ANY, visibility=PUBLIC, region=None,
service_name=None):
"""" Create a service identifier.
@@ -31,9 +32,6 @@ class ServiceFilter(object):
:param string region: The desired region (optional).
:param string service_name: Name of the service
"""
if not service_type:
msg = "Service type must be specified to locate service"
raise exceptions.SDKException(msg)
self.service_type = service_type.lower()
if not visibility:
msg = "Visibility must be specified to locate service"
@@ -55,7 +53,15 @@ class ServiceFilter(object):
ret += ",service_name=%s" % self.service_name
return ret
def join(self, default):
return ServiceFilter(service_type=default.service_type,
visibility=default.visibility,
region=self.region,
service_name=self.service_name)
def match_service_type(self, service_type):
if self.service_type == self.ANY:
return True
return self.service_type == service_type
def match_service_name(self, service_name):

View File

@@ -20,7 +20,7 @@ _logger = logging.getLogger(__name__)
class Session(object):
def __init__(self, transport, authenticator):
def __init__(self, transport, authenticator, preference=None):
"""Maintains client communication session.
Session layer which uses the transport for communication. The
@@ -28,9 +28,12 @@ class Session(object):
:param transport: A transport layer for the session.
:param authenticator: An authenticator to authenticate the session.
:param ServiceFilter preference: Service filter preference.
:type preference: :class:`openstack.auth.service_filter.ServiceFilter`
"""
self.transport = transport
self.authenticator = authenticator
self.preference = preference
def _request(self, path, method, service=None, authenticate=True,
**kwargs):
@@ -55,6 +58,8 @@ class Session(object):
token = self.authenticator.get_token(self.transport)
if token:
headers['X-Auth-Token'] = token
if service and self.preference:
service = self.preference.join(service)
endpoint = self.authenticator.get_endpoint(self.transport, service)
url = utils.urljoin(endpoint, path)

View File

@@ -20,37 +20,44 @@ from openstack.tests.auth import common
class TestServiceCatalog(testtools.TestCase):
def get_urls(self, sot):
sf = service_filter.ServiceFilter('compute')
sf = service_filter.ServiceFilter(service_type='compute')
exp = ["http://compute.region2.public/",
"http://compute.region1.public/"]
self.assertEqual(exp, sot.get_urls(sf))
sf = service_filter.ServiceFilter('image')
sf = service_filter.ServiceFilter(service_type='image')
self.assertEqual(["http://image.region1.public/"], sot.get_urls(sf))
sf = service_filter.ServiceFilter('identity')
sf = service_filter.ServiceFilter(service_type='identity')
self.assertEqual(["http://identity.region1.public/"], sot.get_urls(sf))
sf = service_filter.ServiceFilter('object-store')
sf = service_filter.ServiceFilter(service_type='object-store')
self.assertEqual(["http://object-store.region1.public/"],
sot.get_urls(sf))
def get_urls_name(self, sot):
sf = service_filter.ServiceFilter('compute', service_name='nova')
sf = service_filter.ServiceFilter(service_type='compute',
service_name='nova')
self.assertEqual(["http://compute.region1.public/"], sot.get_urls(sf))
sf = service_filter.ServiceFilter('compute', service_name='nova2')
sf = service_filter.ServiceFilter(service_type='compute',
service_name='nova2')
self.assertEqual(["http://compute.region2.public/"], sot.get_urls(sf))
def get_urls_region(self, sot):
sf = service_filter.ServiceFilter('compute', region='RegionTwo')
sf = service_filter.ServiceFilter(service_type='compute',
region='RegionTwo')
self.assertEqual(["http://compute.region2.public/"], sot.get_urls(sf))
sf = service_filter.ServiceFilter('compute', region='RegionOne')
sf = service_filter.ServiceFilter(service_type='compute',
region='RegionOne')
self.assertEqual(["http://compute.region1.public/"], sot.get_urls(sf))
def get_urls_visibility(self, sot):
sf = service_filter.ServiceFilter('identity', visibility='admin')
sf = service_filter.ServiceFilter(service_type='identity',
visibility='admin')
self.assertEqual(["http://identity.region1.admin/"], sot.get_urls(sf))
sf = service_filter.ServiceFilter('identity', visibility='internal')
sf = service_filter.ServiceFilter(service_type='identity',
visibility='internal')
self.assertEqual(["http://identity.region1.internal/"],
sot.get_urls(sf))
sf = service_filter.ServiceFilter('identity', visibility='public')
sf = service_filter.ServiceFilter(service_type='identity',
visibility='public')
self.assertEqual(["http://identity.region1.public/"], sot.get_urls(sf))

View File

@@ -19,69 +19,89 @@ from openstack import exceptions
class TestServiceFilter(testtools.TestCase):
def test_minimum(self):
sot = filt.ServiceFilter('identity')
self.assertEqual("service_type=identity,visibility=public",
sot = filt.ServiceFilter()
self.assertEqual("service_type=any,visibility=public",
six.text_type(sot))
def test_maximum(self):
sot = filt.ServiceFilter('compute', visibility='admin', region='b',
service_name='c')
sot = filt.ServiceFilter(service_type='compute', visibility='admin',
region='b', service_name='c')
exp = "service_type=compute,visibility=admin,region=b,service_name=c"
self.assertEqual(exp, six.text_type(sot))
def test_visibility(self):
sot = filt.ServiceFilter('identity', visibility='public')
sot = filt.ServiceFilter(service_type='identity', visibility='public')
self.assertEqual("service_type=identity,visibility=public",
six.text_type(sot))
sot = filt.ServiceFilter('identity', visibility='internal')
sot = filt.ServiceFilter(service_type='identity',
visibility='internal')
self.assertEqual("service_type=identity,visibility=internal",
six.text_type(sot))
sot = filt.ServiceFilter('identity', visibility='admin')
sot = filt.ServiceFilter(service_type='identity', visibility='admin')
self.assertEqual("service_type=identity,visibility=admin",
six.text_type(sot))
sot = filt.ServiceFilter('identity', visibility='publicURL')
sot = filt.ServiceFilter(service_type='identity',
visibility='publicURL')
self.assertEqual("service_type=identity,visibility=public",
six.text_type(sot))
sot = filt.ServiceFilter('identity', visibility='internalURL')
sot = filt.ServiceFilter(service_type='identity',
visibility='internalURL')
self.assertEqual("service_type=identity,visibility=internal",
six.text_type(sot))
sot = filt.ServiceFilter('identity', visibility='adminURL')
sot = filt.ServiceFilter(service_type='identity',
visibility='adminURL')
self.assertEqual("service_type=identity,visibility=admin",
six.text_type(sot))
self.assertRaises(exceptions.SDKException,
filt.ServiceFilter, 'identity', visibility='b')
self.assertRaises(exceptions.SDKException, filt.ServiceFilter,
'identity', visibility=None)
self.assertRaises(exceptions.SDKException, filt.ServiceFilter, None)
self.assertRaises(exceptions.SDKException, filt.ServiceFilter, None)
service_type='identity', visibility='b')
self.assertRaises(exceptions.SDKException, filt.ServiceFilter,
service_type='identity', visibility=None)
def test_match_service_type(self):
sot = filt.ServiceFilter('identity')
sot = filt.ServiceFilter(service_type='identity')
self.assertTrue(sot.match_service_type('identity'))
self.assertFalse(sot.match_service_type('compute'))
def test_match_service_type_any(self):
sot = filt.ServiceFilter()
self.assertTrue(sot.match_service_type('identity'))
self.assertTrue(sot.match_service_type('compute'))
def test_match_service_name(self):
sot = filt.ServiceFilter('identity')
sot = filt.ServiceFilter(service_type='identity')
self.assertTrue(sot.match_service_name('keystone'))
self.assertTrue(sot.match_service_name('ldap'))
self.assertTrue(sot.match_service_name(None))
sot = filt.ServiceFilter('identity', service_name='keystone')
sot = filt.ServiceFilter(service_type='identity',
service_name='keystone')
self.assertTrue(sot.match_service_name('keystone'))
self.assertFalse(sot.match_service_name('ldap'))
self.assertFalse(sot.match_service_name(None))
def test_match_region(self):
sot = filt.ServiceFilter('identity')
sot = filt.ServiceFilter(service_type='identity')
self.assertTrue(sot.match_region('East'))
self.assertTrue(sot.match_region('West'))
self.assertTrue(sot.match_region(None))
sot = filt.ServiceFilter('identity', region='East')
sot = filt.ServiceFilter(service_type='identity', region='East')
self.assertTrue(sot.match_region('East'))
self.assertFalse(sot.match_region('West'))
self.assertFalse(sot.match_region(None))
def test_match_visibility(self):
sot = filt.ServiceFilter('identity', visibility='internal')
sot = filt.ServiceFilter(service_type='identity',
visibility='internal')
self.assertFalse(sot.match_visibility('admin'))
self.assertTrue(sot.match_visibility('internal'))
self.assertFalse(sot.match_visibility('public'))
def test_join(self):
a = filt.ServiceFilter(region='east')
b = filt.ServiceFilter(service_type='identity')
result = a.join(b)
self.assertEqual("service_type=identity,visibility=public,region=east",
six.text_type(result))
self.assertEqual("service_type=any,visibility=public,region=east",
six.text_type(a))
self.assertEqual("service_type=identity,visibility=public",
six.text_type(b))

View File

@@ -24,7 +24,7 @@ class TestSession(base.TestCase):
super(TestSession, self).setUp()
self.xport = fakes.FakeTransport()
self.auth = fakes.FakeAuthenticator()
self.serv = service_filter.ServiceFilter('identity')
self.serv = service_filter.ServiceFilter(service_type='identity')
self.sess = session.Session(self.xport, self.auth)
self.expected = {'headers': {'X-Auth-Token': self.auth.TOKEN}}