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:
parent
a12d2d32d3
commit
14429136db
|
@ -14,14 +14,13 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
import eventlet.patcher
|
import eventlet.patcher
|
||||||
import six
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
import six
|
||||||
|
|
||||||
from designate import exceptions
|
from designate import exceptions
|
||||||
from designate.plugin import DriverPlugin
|
from designate.plugin import DriverPlugin
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
# NOTE(kiall): This is a workaround for bug #1424621, a broken reimplementation
|
# NOTE(kiall): This is a workaround for bug #1424621, a broken reimplementation
|
||||||
# of eventlet's 0.17.0 monkey patching of dnspython.
|
# 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,
|
def _endpoints(self, service_catalog=None, service_type=None,
|
||||||
endpoint_type='publicURL', config_section=None,
|
endpoint_type='publicURL', config_section=None,
|
||||||
region=None):
|
region=None):
|
||||||
if service_catalog is not None and len(service_catalog):
|
configured_endpoints = self.get_configured_endpoints(config_section)
|
||||||
endpoints = self._endpoints_from_catalog(
|
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,
|
service_catalog, service_type, endpoint_type,
|
||||||
region=region)
|
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)
|
|
||||||
else:
|
else:
|
||||||
msg = 'No service_catalog and no configured endpoints'
|
raise exceptions.ConfigurationError(
|
||||||
raise exceptions.ConfigurationError(msg)
|
'No service_catalog and no configured endpoints'
|
||||||
|
)
|
||||||
|
|
||||||
LOG.debug('Returning endpoints: %s', endpoints)
|
LOG.debug('Returning endpoints: %s', endpoints)
|
||||||
return endpoints
|
return endpoints
|
||||||
|
|
||||||
def _endpoints_from_catalog(self, service_catalog, service_type,
|
@staticmethod
|
||||||
endpoint_type, region=None):
|
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
|
Return the endpoints for the given service from the context's sc
|
||||||
or lookup towards the configured keystone.
|
or lookup towards the configured keystone.
|
||||||
|
|
||||||
return [('http://endpoint', 'region')]
|
return [('http://endpoint', 'region')]
|
||||||
"""
|
"""
|
||||||
urls = []
|
endpoints = []
|
||||||
for svc in service_catalog:
|
for svc in service_catalog:
|
||||||
if svc['type'] != service_type:
|
if svc['type'] != service_type:
|
||||||
continue
|
continue
|
||||||
for url in svc['endpoints']:
|
for endpoint_data in svc['endpoints']:
|
||||||
if endpoint_type in url:
|
if endpoint_type not in endpoint_data:
|
||||||
if region is not None and url['region'] != region:
|
continue
|
||||||
continue
|
endpoint = endpoint_data[endpoint_type]
|
||||||
urls.append((url[endpoint_type], url['region']))
|
endpoint_region = endpoint_data['region']
|
||||||
if not urls:
|
if region and endpoint_region != region:
|
||||||
raise exceptions.NetworkEndpointNotFound
|
continue
|
||||||
return urls
|
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):
|
def list_floatingips(self, context, region=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
Loading…
Reference in New Issue