Fixed neutron endpoint override

The network_api endpoint code would never
actually use the manually configured endpoints.

This patch changes that by first checking if
custom endpoints were configured, and if that
isn't the case it will use the service_catalog
instead.

In addition we introduce full testing on
this code path to make sure it behaves
as we expect.

Change-Id: I2e9f1485fce401336ab8a4a8b1aa1f971292168f
This commit is contained in:
Erik Olof Gunnar Andersson 2019-09-27 23:54:17 -07:00
parent a12d2d32d3
commit 14429136db
3 changed files with 324 additions and 30 deletions

View File

@ -14,14 +14,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import eventlet.patcher
import six
from oslo_config import cfg
from oslo_log import log as logging
import six
from designate import exceptions
from designate.plugin import DriverPlugin
LOG = logging.getLogger(__name__)
# NOTE(kiall): This is a workaround for bug #1424621, a broken reimplementation
# of eventlet's 0.17.0 monkey patching of dnspython.
@ -38,49 +37,82 @@ class NetworkAPI(DriverPlugin):
def _endpoints(self, service_catalog=None, service_type=None,
endpoint_type='publicURL', config_section=None,
region=None):
if service_catalog is not None and len(service_catalog):
endpoints = self._endpoints_from_catalog(
configured_endpoints = self.get_configured_endpoints(config_section)
if configured_endpoints:
endpoints = self.endpoints_from_config(
configured_endpoints,
region=region,
)
elif service_catalog:
endpoints = self.endpoints_from_catalog(
service_catalog, service_type, endpoint_type,
region=region)
elif config_section is not None:
endpoints = []
for u in cfg.CONF[config_section].endpoints:
e_region, e = u.split('|')
# Filter if region is given
if (e_region and region) and e_region != region:
continue
endpoints.append((e, e_region))
if not endpoints:
msg = 'Endpoints are not configured'
raise exceptions.ConfigurationError(msg)
region=region,
)
else:
msg = 'No service_catalog and no configured endpoints'
raise exceptions.ConfigurationError(msg)
raise exceptions.ConfigurationError(
'No service_catalog and no configured endpoints'
)
LOG.debug('Returning endpoints: %s', endpoints)
return endpoints
def _endpoints_from_catalog(self, service_catalog, service_type,
endpoint_type, region=None):
@staticmethod
def endpoints_from_config(configured_endpoints, region=None):
"""
Return the endpoints for the given service from the configuration.
return [('http://endpoint', 'region')]
"""
endpoints = []
for endpoint_data in configured_endpoints:
if not endpoint_data:
continue
endpoint_region, endpoint = endpoint_data.split('|')
if region and endpoint_region != region:
continue
endpoints.append((endpoint, endpoint_region))
if not endpoints:
raise exceptions.ConfigurationError(
'Endpoints are not correctly configured'
)
return endpoints
@staticmethod
def endpoints_from_catalog(service_catalog, service_type, endpoint_type,
region=None):
"""
Return the endpoints for the given service from the context's sc
or lookup towards the configured keystone.
return [('http://endpoint', 'region')]
"""
urls = []
endpoints = []
for svc in service_catalog:
if svc['type'] != service_type:
continue
for url in svc['endpoints']:
if endpoint_type in url:
if region is not None and url['region'] != region:
continue
urls.append((url[endpoint_type], url['region']))
if not urls:
raise exceptions.NetworkEndpointNotFound
return urls
for endpoint_data in svc['endpoints']:
if endpoint_type not in endpoint_data:
continue
endpoint = endpoint_data[endpoint_type]
endpoint_region = endpoint_data['region']
if region and endpoint_region != region:
continue
endpoints.append((endpoint, endpoint_region))
if not endpoints:
raise exceptions.NetworkEndpointNotFound()
return endpoints
@staticmethod
def get_configured_endpoints(config_section):
"""
Returns endpoints from a specific section in the configuration.
return ['region|http://endpoint']
"""
if not config_section:
return None
cfg_group = cfg.CONF[config_section]
return cfg_group.endpoints
def list_floatingips(self, context, region=None):
"""

View File

@ -0,0 +1,262 @@
# 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.mport threading
import designate.exceptions
from designate.network_api import base
from oslo_config import cfg
from oslo_config import fixture as cfg_fixture
import oslotest.base
CONF = cfg.CONF
SERVICE_CATALOG = [
{
'endpoints': [
{
'adminURL': 'admin1',
'region': 'RegionOne',
'internalURL': 'internal1',
'publicURL': 'public1'
}
],
'type': 'dns',
'name': 'foo1'
},
{
'endpoints': [
{
'adminURL': 'admin2',
'region': 'RegionTwo',
'internalURL': 'internal2',
'publicURL': 'public2'
}
],
'type': 'dns',
'name': 'foo2'
},
{
'endpoints': [
{
'adminURL': 'admin3',
'region': 'RegionTwo',
'internalURL': 'internal3',
'publicURL': 'public3'
}
],
'type': 'network',
'name': 'foo2'
},
]
class NetworkEndpointsTest(oslotest.base.BaseTestCase):
def setUp(self):
super(NetworkEndpointsTest, self).setUp()
self.useFixture(cfg_fixture.Config(CONF))
self.base = base.NetworkAPI()
def test_endpoints_from_config(self):
CONF.set_override(
'endpoints', ['RegionThree|public3', 'RegionFour|public4'],
'network_api:neutron'
)
result = self.base._endpoints(
service_catalog=SERVICE_CATALOG,
service_type='dns',
endpoint_type='publicURL',
config_section='network_api:neutron',
)
self.assertEqual(
[('public3', 'RegionThree'), ('public4', 'RegionFour')], result
)
def test_endpoints_from_config_with_region(self):
CONF.set_override(
'endpoints', ['RegionThree|public3', 'RegionFour|public4'],
'network_api:neutron'
)
result = self.base._endpoints(
service_catalog=SERVICE_CATALOG,
service_type='dns',
endpoint_type='publicURL',
region='RegionFour',
config_section='network_api:neutron',
)
self.assertEqual(
[('public4', 'RegionFour')], result
)
def test_endpoints_from_catalog(self):
result = self.base._endpoints(
service_catalog=SERVICE_CATALOG,
service_type='dns',
endpoint_type='publicURL',
config_section='network_api:neutron',
)
self.assertEqual(
[('public1', 'RegionOne'), ('public2', 'RegionTwo')], result
)
def test_endpoints_from_catalog_with_region(self):
result = self.base._endpoints(
service_catalog=SERVICE_CATALOG,
service_type='dns',
endpoint_type='publicURL',
region='RegionOne',
config_section='network_api:neutron',
)
self.assertEqual(
[('public1', 'RegionOne')], result
)
def test_no_endpoints_or_service_catalog_available(self):
self.assertRaisesRegex(
designate.exceptions.ConfigurationError,
'No service_catalog and no configured endpoints',
self.base._endpoints,
service_catalog=None,
service_type='dns',
endpoint_type='publicURL',
config_section='network_api:neutron',
)
class NetworkEndpointsFromConfigTest(oslotest.base.BaseTestCase):
def setUp(self):
super(NetworkEndpointsFromConfigTest, self).setUp()
self.useFixture(cfg_fixture.Config(CONF))
self.base = base.NetworkAPI()
def test_endpoint(self):
CONF.set_override(
'endpoints', ['RegionThree|public3'], 'network_api:neutron'
)
result = self.base.endpoints_from_config(
cfg.CONF['network_api:neutron'].endpoints,
)
self.assertEqual(
[('public3', 'RegionThree')], result
)
def test_endpoints(self):
CONF.set_override(
'endpoints', ['RegionThree|public3', 'RegionFour|public4'],
'network_api:neutron'
)
result = self.base.endpoints_from_config(
cfg.CONF['network_api:neutron'].endpoints,
)
self.assertEqual(
[('public3', 'RegionThree'), ('public4', 'RegionFour')], result
)
def test_endpoint_from_region(self):
CONF.set_override(
'endpoints', ['RegionThree|public3', 'RegionFour|public4'],
'network_api:neutron'
)
result = self.base.endpoints_from_config(
cfg.CONF['network_api:neutron'].endpoints,
region='RegionFour',
)
self.assertEqual(
[('public4', 'RegionFour')], result
)
def test_endpoint_from_region_not_found(self):
CONF.set_override(
'endpoints', ['RegionThree|public3', 'RegionThree|public4'],
'network_api:neutron'
)
self.assertRaisesRegex(
designate.exceptions.ConfigurationError,
'Endpoints are not correctly configured',
self.base.endpoints_from_config,
cfg.CONF['network_api:neutron'].endpoints,
region='RegionFive',
)
def test_endpoint_empty_list(self):
CONF.set_override(
'endpoints', [],
'network_api:neutron'
)
self.assertRaisesRegex(
designate.exceptions.ConfigurationError,
'Endpoints are not correctly configured',
self.base.endpoints_from_config,
cfg.CONF['network_api:neutron'].endpoints,
)
class NetworkEndpointsFromCatalogTest(oslotest.base.BaseTestCase):
def setUp(self):
super(NetworkEndpointsFromCatalogTest, self).setUp()
self.base = base.NetworkAPI()
def test_endpoints(self):
result = self.base.endpoints_from_catalog(
service_catalog=SERVICE_CATALOG,
service_type='dns',
endpoint_type='publicURL',
)
self.assertEqual(
[('public1', 'RegionOne'), ('public2', 'RegionTwo')], result
)
def test_endpoint_from_region(self):
result = self.base.endpoints_from_catalog(
service_catalog=SERVICE_CATALOG,
service_type='dns',
endpoint_type='publicURL',
region='RegionTwo',
)
self.assertEqual(
[('public2', 'RegionTwo')], result
)
def test_endpoint_region_not_found(self):
self.assertRaises(
designate.exceptions.NetworkEndpointNotFound,
self.base.endpoints_from_catalog,
service_type='dns',
endpoint_type='publicURL',
region='RegionSix',
service_catalog=SERVICE_CATALOG,
)
def test_no_endpoints_found(self):
self.assertRaises(
designate.exceptions.NetworkEndpointNotFound,
self.base.endpoints_from_catalog,
service_type='compute',
endpoint_type='publicURL',
service_catalog=SERVICE_CATALOG,
)