Handle old status-less placement service
Older versions of placement didn't include the status field in their version discovery documents. This was fixed in placement in https://review.opendev.org/575117, but there are clouds out there in the wild running this version and SDK bombs out trying to talk to them. Change-Id: I152f0c626b358328cedd404c8fc8d0bee46d2991
This commit is contained in:
parent
f34d399f52
commit
6f80554807
@ -321,6 +321,10 @@ class CloudRegion(object):
|
|||||||
else:
|
else:
|
||||||
return 'unknown'
|
return 'unknown'
|
||||||
|
|
||||||
|
def set_service_value(self, key, service_type, value):
|
||||||
|
key = _make_key(key, service_type)
|
||||||
|
self.config[key] = value
|
||||||
|
|
||||||
def set_session_constructor(self, session_constructor):
|
def set_session_constructor(self, session_constructor):
|
||||||
"""Sets the Session constructor."""
|
"""Sets the Session constructor."""
|
||||||
self._session_constructor = session_constructor
|
self._session_constructor = session_constructor
|
||||||
@ -645,7 +649,7 @@ class CloudRegion(object):
|
|||||||
self.get_interface(service_type), {})
|
self.get_interface(service_type), {})
|
||||||
return interface_versions.get(service_type, [])
|
return interface_versions.get(service_type, [])
|
||||||
|
|
||||||
def _get_hardcoded_endpoint(self, service_type, constructor):
|
def _get_endpoint_from_catalog(self, service_type, constructor):
|
||||||
adapter = constructor(
|
adapter = constructor(
|
||||||
session=self.get_session(),
|
session=self.get_session(),
|
||||||
service_type=self.get_service_type(service_type),
|
service_type=self.get_service_type(service_type),
|
||||||
@ -653,7 +657,11 @@ class CloudRegion(object):
|
|||||||
interface=self.get_interface(service_type),
|
interface=self.get_interface(service_type),
|
||||||
region_name=self.get_region_name(service_type),
|
region_name=self.get_region_name(service_type),
|
||||||
)
|
)
|
||||||
endpoint = adapter.get_endpoint()
|
return adapter.get_endpoint()
|
||||||
|
|
||||||
|
def _get_hardcoded_endpoint(self, service_type, constructor):
|
||||||
|
endpoint = self._get_endpoint_from_catalog(
|
||||||
|
service_type, constructor)
|
||||||
if not endpoint.rstrip().rsplit('/')[-1] == 'v2.0':
|
if not endpoint.rstrip().rsplit('/')[-1] == 'v2.0':
|
||||||
if not endpoint.endswith('/'):
|
if not endpoint.endswith('/'):
|
||||||
endpoint += '/'
|
endpoint += '/'
|
||||||
|
@ -89,6 +89,20 @@ class ServiceDescription(object):
|
|||||||
# The keystone proxy has a method called get_endpoint
|
# The keystone proxy has a method called get_endpoint
|
||||||
# that is about managing keystone endpoints. This is
|
# that is about managing keystone endpoints. This is
|
||||||
# unfortunate.
|
# unfortunate.
|
||||||
|
try:
|
||||||
|
endpoint = proxy_mod.Proxy.get_endpoint(proxy)
|
||||||
|
except IndexError:
|
||||||
|
# It's best not to look to closely here. This is
|
||||||
|
# to support old placement.
|
||||||
|
# There was a time when it had no status entry
|
||||||
|
# in its version discovery doc (OY) In this case,
|
||||||
|
# no endpoints get through version discovery
|
||||||
|
# filtering. In order to deal with that, catch
|
||||||
|
# the IndexError thrown by keystoneauth and
|
||||||
|
# set an endpoint_override for the user to the
|
||||||
|
# url in the catalog and try again.
|
||||||
|
self._set_override_from_catalog(instance.config)
|
||||||
|
proxy = self._make_proxy(instance)
|
||||||
endpoint = proxy_mod.Proxy.get_endpoint(proxy)
|
endpoint = proxy_mod.Proxy.get_endpoint(proxy)
|
||||||
if instance._strict_proxies:
|
if instance._strict_proxies:
|
||||||
self._validate_proxy(proxy, endpoint)
|
self._validate_proxy(proxy, endpoint)
|
||||||
@ -96,6 +110,17 @@ class ServiceDescription(object):
|
|||||||
instance._proxies[self.service_type] = proxy
|
instance._proxies[self.service_type] = proxy
|
||||||
return instance._proxies[self.service_type]
|
return instance._proxies[self.service_type]
|
||||||
|
|
||||||
|
def _set_override_from_catalog(self, config):
|
||||||
|
override = config._get_endpoint_from_catalog(
|
||||||
|
self.service_type,
|
||||||
|
proxy_mod.Proxy,
|
||||||
|
)
|
||||||
|
config.set_service_value(
|
||||||
|
'endpoint_override',
|
||||||
|
self.service_type,
|
||||||
|
override,
|
||||||
|
)
|
||||||
|
|
||||||
def _validate_proxy(self, proxy, endpoint):
|
def _validate_proxy(self, proxy, endpoint):
|
||||||
exc = None
|
exc = None
|
||||||
service_url = getattr(proxy, 'skip_discovery', None)
|
service_url = getattr(proxy, 'skip_discovery', None)
|
||||||
|
@ -532,9 +532,10 @@ class TestCase(base.TestCase):
|
|||||||
uri=compute_discovery_url,
|
uri=compute_discovery_url,
|
||||||
text=open(discovery_fixture, 'r').read())
|
text=open(discovery_fixture, 'r').read())
|
||||||
|
|
||||||
def get_placement_discovery_mock_dict(self):
|
def get_placement_discovery_mock_dict(
|
||||||
|
self, discovery_fixture='placement.json'):
|
||||||
discovery_fixture = os.path.join(
|
discovery_fixture = os.path.join(
|
||||||
self.fixtures_directory, "placement.json")
|
self.fixtures_directory, discovery_fixture)
|
||||||
return dict(method='GET', uri="https://placement.example.com/",
|
return dict(method='GET', uri="https://placement.example.com/",
|
||||||
text=open(discovery_fixture, 'r').read())
|
text=open(discovery_fixture, 'r').read())
|
||||||
|
|
||||||
@ -580,9 +581,9 @@ class TestCase(base.TestCase):
|
|||||||
self.__do_register_uris([
|
self.__do_register_uris([
|
||||||
self.get_cinder_discovery_mock_dict()])
|
self.get_cinder_discovery_mock_dict()])
|
||||||
|
|
||||||
def use_placement(self):
|
def use_placement(self, **kwargs):
|
||||||
self.__do_register_uris([
|
self.__do_register_uris([
|
||||||
self.get_placement_discovery_mock_dict()])
|
self.get_placement_discovery_mock_dict(**kwargs)])
|
||||||
|
|
||||||
def use_designate(self):
|
def use_designate(self):
|
||||||
# NOTE(slaweq): This method is only meant to be used in "setUp"
|
# NOTE(slaweq): This method is only meant to be used in "setUp"
|
||||||
|
10
openstack/tests/unit/fixtures/bad-placement.json
Normal file
10
openstack/tests/unit/fixtures/bad-placement.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"versions": [
|
||||||
|
{
|
||||||
|
"id": "v1.0",
|
||||||
|
"links": [{"href": "", "rel": "self"}],
|
||||||
|
"max_version": "1.17",
|
||||||
|
"min_version": "1.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -69,3 +69,35 @@ class TestPlacementRest(base.TestCase):
|
|||||||
(1, 17),
|
(1, 17),
|
||||||
self.cloud.placement.get_endpoint_data().max_microversion)
|
self.cloud.placement.get_endpoint_data().max_microversion)
|
||||||
self.assert_calls()
|
self.assert_calls()
|
||||||
|
|
||||||
|
|
||||||
|
class TestBadPlacementRest(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestBadPlacementRest, self).setUp()
|
||||||
|
# The bad-placement.json is for older placement that was
|
||||||
|
# missing the status field from its discovery doc. This
|
||||||
|
# lets us show that we can talk to such a placement.
|
||||||
|
self.use_placement(discovery_fixture='bad-placement.json')
|
||||||
|
|
||||||
|
def _register_uris(self, status_code=None):
|
||||||
|
uri = dict(
|
||||||
|
method='GET',
|
||||||
|
uri=self.get_mock_url(
|
||||||
|
'placement', 'public', append=['allocation_candidates']),
|
||||||
|
json={})
|
||||||
|
if status_code is not None:
|
||||||
|
uri['status_code'] = status_code
|
||||||
|
self.register_uris([uri])
|
||||||
|
|
||||||
|
def _validate_resp(self, resp, status_code):
|
||||||
|
self.assertEqual(status_code, resp.status_code)
|
||||||
|
self.assertEqual(
|
||||||
|
'https://placement.example.com/allocation_candidates',
|
||||||
|
resp.url)
|
||||||
|
self.assert_calls()
|
||||||
|
|
||||||
|
def test_discovery(self):
|
||||||
|
self._register_uris()
|
||||||
|
rs = self.cloud.placement.get('/allocation_candidates')
|
||||||
|
self._validate_resp(rs, 200)
|
||||||
|
6
releasenotes/notes/old-placement-4b3c34abb8fe7b81.yaml
Normal file
6
releasenotes/notes/old-placement-4b3c34abb8fe7b81.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Workaround an issue using openstacksdk with older versions of
|
||||||
|
the placement service that are missing a status field in
|
||||||
|
their version discovery doc.
|
Loading…
x
Reference in New Issue
Block a user