Merge "Add API microversion support"

This commit is contained in:
Jenkins
2016-08-04 13:56:25 +00:00
committed by Gerrit Code Review
6 changed files with 97 additions and 4 deletions

View File

@@ -186,6 +186,14 @@ class Profile(object):
"""
self._get_filter(service).version = version
def set_api_version(self, service, api_version):
"""Set the desired API micro-version for the specified service.
:param str service: Service type.
:param str api_version: Desired service API micro-version.
"""
self._setter(service, "api_version", api_version)
def set_interface(self, service, interface):
"""Set the desired interface for the specified service.

View File

@@ -72,7 +72,7 @@ class ServiceFilter(dict):
valid_versions = []
def __init__(self, service_type, interface=PUBLIC, region=None,
service_name=None, version=None):
service_name=None, version=None, api_version=None):
"""Create a service identifier.
:param string service_type: The desired type of service.
@@ -81,12 +81,14 @@ class ServiceFilter(dict):
:param string region: The desired region (optional).
:param string service_name: Name of the service
:param string version: Version of service to use.
:param string api_version: Microversion of service supported.
"""
self['service_type'] = service_type.lower()
self['interface'] = interface
self['region_name'] = region
self['service_name'] = service_name
self['version'] = version
self['api_version'] = api_version
@property
def service_type(self):
@@ -124,6 +126,14 @@ class ServiceFilter(dict):
def version(self, value):
self['version'] = value
@property
def api_version(self):
return self['api_version']
@api_version.setter
def api_version(self, value):
self['api_version'] = value
@property
def path(self):
return self['path']

View File

@@ -28,6 +28,7 @@ from six.moves.urllib import parse
DEFAULT_USER_AGENT = "openstacksdk/%s" % openstack_version.__version__
VERSION_PATTERN = re.compile('/v\d[\d.]*')
API_REQUEST_HEADER = "openstack-api-version"
def parse_url(filt, url):
@@ -89,9 +90,33 @@ class Session(_session.Session):
self.user_agent = "%s %s" % (user_agent, DEFAULT_USER_AGENT)
else:
self.user_agent = DEFAULT_USER_AGENT
super(Session, self).__init__(user_agent=self.user_agent, **kwargs)
self.profile = profile
api_version_header = self._get_api_requests()
super(Session, self).__init__(user_agent=self.user_agent,
additional_headers=api_version_header,
**kwargs)
def _get_api_requests(self):
"""Get API micro-version requests.
:param profile: A profile object that contains customizations about
service name, region, version, interface or
api_version.
:return: A standard header string if there is any specialization in
API microversion, or None if no such request exists.
"""
if self.profile is None:
return None
req = []
for svc in self.profile.get_services():
if svc.service_type and svc.api_version:
req.append(" ".join([svc.service_type, svc.api_version]))
if req:
return {API_REQUEST_HEADER: ",".join(req)}
return None
def get_endpoint(self, auth=None, interface=None, **kwargs):
"""Override get endpoint to automate endpoint filtering"""

View File

@@ -60,6 +60,16 @@ class TestProfile(base.TestCase):
self.assertRaises(exceptions.SDKException, prof.set_version, 'bogus',
'v2')
def test_set_api_version(self):
# This tests that api_version is effective after explicit setting, or
# else it defaults to None.
prof = profile.Profile()
prof.set_api_version('clustering', '1.2')
svc = prof.get_filter('clustering')
self.assertEqual('1.2', svc.api_version)
svc = prof.get_filter('compute')
self.assertIsNone(svc.api_version)
def test_set_all(self):
prof = profile.Profile()
prof.set_name(prof.ALL, 'fee')

View File

@@ -24,6 +24,16 @@ class TestValidVersion(testtools.TestCase):
class TestServiceFilter(testtools.TestCase):
def test_init(self):
sot = service_filter.ServiceFilter(
'ServiceType', region='REGION1', service_name='ServiceName',
version='1', api_version='1.23')
self.assertEqual('servicetype', sot.service_type)
self.assertEqual('REGION1', sot.region)
self.assertEqual('ServiceName', sot.service_name)
self.assertEqual('1', sot.version)
self.assertEqual('1.23', sot.api_version)
def test_get_module(self):
sot = identity_service.IdentityService()
self.assertEqual('openstack.identity.v3', sot.get_module())

View File

@@ -17,6 +17,7 @@ from keystoneauth1 import exceptions as _exceptions
from openstack import exceptions
from openstack.image import image_service
from openstack import profile
from openstack import session
@@ -41,14 +42,43 @@ class TestSession(testtools.TestCase):
"http://127.0.0.1:9292/wot/v1/mytenant",
session.parse_url(filt, "http://127.0.0.1:9292/wot/v2.0/mytenant"))
def test_user_agent_none(self):
def test_init_user_agent_none(self):
sot = session.Session(None)
self.assertTrue(sot.user_agent.startswith("openstacksdk"))
def test_user_agent_set(self):
def test_init_user_agent_set(self):
sot = session.Session(None, user_agent="testing/123")
self.assertTrue(sot.user_agent.startswith("testing/123 openstacksdk"))
def test_init_with_single_api_request(self):
prof = profile.Profile()
prof.set_api_version('clustering', '1.2')
sot = session.Session(prof)
# The assertion acutally tests the property assigned in parent class
self.assertEqual({'openstack-api-version': 'clustering 1.2'},
sot.additional_headers)
def test_init_with_multi_api_requests(self):
prof = profile.Profile()
prof.set_api_version('clustering', '1.2')
prof.set_api_version('compute', '2.15')
sot = session.Session(prof)
versions = sot.additional_headers['openstack-api-version']
requests = [req.strip() for req in versions.split(',')]
self.assertIn('clustering 1.2', requests)
self.assertIn('compute 2.15', requests)
def test_init_with_no_api_requests(self):
prof = profile.Profile()
sot = session.Session(prof)
self.assertEqual({}, sot.additional_headers)
def test_map_exceptions_not_found_exception(self):
ksa_exc = _exceptions.HttpError(message="test", http_status=404)
func = mock.Mock(side_effect=ksa_exc)