diff --git a/examples/common.py b/examples/common.py index 7749893f..c950f3b3 100755 --- a/examples/common.py +++ b/examples/common.py @@ -106,6 +106,11 @@ def option_parser(): default=env('OS_PASSWORD'), help='Authentication password (Env: OS_PASSWORD)', ) + parser.add_argument( + '--os-region', + metavar='', + default=env('OS_REGION'), + help='Service region (Env: OS_REGION)') parser.add_argument( '--os-cacert', metavar='', diff --git a/examples/session.py b/examples/session.py index c45c800a..6683e2b7 100644 --- a/examples/session.py +++ b/examples/session.py @@ -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 diff --git a/openstack/auth/service_filter.py b/openstack/auth/service_filter.py index 7d1d2a32..b191c654 100644 --- a/openstack/auth/service_filter.py +++ b/openstack/auth/service_filter.py @@ -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): diff --git a/openstack/session.py b/openstack/session.py index 9634e474..268155b2 100644 --- a/openstack/session.py +++ b/openstack/session.py @@ -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) diff --git a/openstack/tests/auth/test_service_catalog.py b/openstack/tests/auth/test_service_catalog.py index 215d94b1..73d905ce 100644 --- a/openstack/tests/auth/test_service_catalog.py +++ b/openstack/tests/auth/test_service_catalog.py @@ -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)) diff --git a/openstack/tests/auth/test_service_filter.py b/openstack/tests/auth/test_service_filter.py index 128ad354..44105a76 100644 --- a/openstack/tests/auth/test_service_filter.py +++ b/openstack/tests/auth/test_service_filter.py @@ -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)) diff --git a/openstack/tests/test_session.py b/openstack/tests/test_session.py index bd223d23..aeeb15e8 100644 --- a/openstack/tests/test_session.py +++ b/openstack/tests/test_session.py @@ -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}}