Don't use name of a service as a key

Name of a service shouldn't be used as a key in structures as the name is
a user-facing name and it's not intended to be machine-parseable:
https://docs.openstack.org/keystone/stein/contributor/service-catalog.html#services

Story: 2006892
Task: 37526

Change-Id: I9621aee957e8a043f6ac251b96abafd80ef167f1
This commit is contained in:
Martin Kopec 2019-11-19 07:49:55 +00:00
parent b84544cf0a
commit 6a616e5db2
25 changed files with 96 additions and 87 deletions

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class AlarmingService(Service):
@staticmethod
def get_service_name():
return ['aodh']
def get_service_type():
return ['alarming']
@staticmethod
def get_codename():

View File

@ -22,7 +22,7 @@ class Ec2Service(Service):
conf.set('aws', 'ec2_url', self.service_url)
@staticmethod
def get_service_name():
def get_service_type():
return ['ec2']
@ -32,5 +32,5 @@ class S3Service(Service):
conf.set('aws', 's3_url', self.service_url)
@staticmethod
def get_service_name():
def get_service_type():
return ['s3']

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class BaremetalService(Service):
@staticmethod
def get_service_name():
return ['ironic']
def get_service_type():
return ['baremetal']
@staticmethod
def get_codename():

View File

@ -89,11 +89,11 @@ class Service(object):
return self.extensions
@staticmethod
def get_service_name():
"""Return the service name.
def get_service_type():
"""Return the service type.
This returns a list because you can have different services for the
same type, like volume, volumev2, volumev3
This returns a list because you can have services with more types,
like volume, volumev2, volumev3.
"""
return []

View File

@ -34,8 +34,8 @@ class MeteringService(Service):
conf.set('service_available', 'ceilometer', 'True')
@staticmethod
def get_service_name():
return ['ceilometer']
def get_service_type():
return ['metering']
@staticmethod
def get_codename():

View File

@ -62,8 +62,8 @@ class ComputeService(VersionedService):
str(is_service(**{'type': 'key-manager'})))
@staticmethod
def get_service_name():
return ['nova']
def get_service_type():
return ['compute']
@staticmethod
def get_codename():

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class DataProcessingService(Service):
@staticmethod
def get_service_name():
return ['sahara']
def get_service_type():
return ['data-processing']
@staticmethod
def get_codename():

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class DatabaseService(Service):
@staticmethod
def get_service_name():
return ['trove']
def get_service_type():
return ['database']
@staticmethod
def get_codename():

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class DnsService(Service):
@staticmethod
def get_service_name():
return ['designate']
def get_service_type():
return ['dns']
@staticmethod
def get_codename():

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class EventService(Service):
@staticmethod
def get_service_name():
return ['panko']
def get_service_type():
return ['event']
@staticmethod
def get_codename():

View File

@ -61,8 +61,8 @@ class IdentityService(VersionedService):
return ['v2', 'v3']
@staticmethod
def get_service_name():
return ['keystone']
def get_service_type():
return ['identity']
def set_identity_v3_extensions(self):
"""Returns discovered identity v3 extensions

View File

@ -74,8 +74,8 @@ class ImageService(VersionedService):
return ['v1', 'v2']
@staticmethod
def get_service_name():
return ['glance']
def get_service_type():
return ['image']
@staticmethod
def get_codename():

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class MessagingService(Service):
@staticmethod
def get_service_name():
return ['zaqar']
def get_service_type():
return ['messaging']
@staticmethod
def get_codename():

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class MetricService(Service):
@staticmethod
def get_service_name():
return ['gnocchi']
def get_service_type():
return ['metric']
@staticmethod
def get_codename():

View File

@ -93,8 +93,8 @@ class NetworkService(VersionedService):
'discovered and must be specified')
@staticmethod
def get_service_name():
return ['neutron']
def get_service_type():
return ['network']
@staticmethod
def get_codename():

View File

@ -106,8 +106,8 @@ class ObjectStorageService(Service):
self.list_create_roles(conf, self.client.roles)
@staticmethod
def get_service_name():
return ['swift']
def get_service_type():
return ['object-store']
@staticmethod
def get_codename():

View File

@ -28,8 +28,8 @@ class LoadBalancerService(VersionedService):
conf.set('load_balancer', 'RBAC_test_type', 'owner_or_admin')
@staticmethod
def get_service_name():
return ['octavia']
def get_service_type():
return ['load-balancer']
@staticmethod
def get_codename():

View File

@ -22,8 +22,8 @@ from config_tempest.services.base import Service
class OrchestrationService(Service):
@staticmethod
def get_service_name():
return ['heat']
def get_service_type():
return ['orchestration']
@staticmethod
def get_codename():

View File

@ -64,39 +64,50 @@ class Services(object):
def get_available_services(self):
try:
services = self._clients.service_client.list_services()['services']
return {s['name']: s['type'] for s in services}
except exceptions.Forbidden:
C.LOG.warning("User has no permissions to list services, using "
"catalog. Services without endpoint will not be "
"discovered.")
token, auth_data = self._clients.auth_provider.get_auth()
return {s['name']: s['type'] for s
in auth_data[self.service_catalog]}
services = self.catalog
return services
def get_service_data(self, s_name, s_type):
for s in self.catalog:
if s['name'] == s_name and s['type'] == s_type:
return s
return None
def discover(self):
token, auth_data = self._clients.auth_provider.get_auth()
auth_entries = {e['type']: e for e in auth_data[self.service_catalog]}
# We loop through the classes we have for each service, and if we find
# a class that match a service enabled, we add it in our services list.
# some services doesn't have endpoints, so we need to check first
for s_class in self.service_classes:
s_names = s_class.get_service_name()
for s_name in s_names:
s_type = self.available_services.get(s_name, None)
if s_type:
endpoint_data = auth_entries.get(s_type, None)
s_types = s_class.get_service_type()
for s_type in s_types:
s_name = [t['name'] for t in self.available_services
if t['type'] == s_type]
if s_name:
# In the general case, there should only be one service in
# a deployment per service type
# https://docs.openstack.org/keystone/latest/contributor/
# service-catalog.html#services
if len(s_name) > 1:
C.LOG.warning("There are more service names ('%s') for"
" '%s' service type, which is undefined"
" behavior. Continuing with '%s'.",
str(s_name), s_type, s_name[0])
s_name = s_name[0]
service_data = self.get_service_data(s_name, s_type)
url = None
if not endpoint_data:
C.LOG.Warning('No endpoint data found for {}'.format(
if not service_data:
C.LOG.warning('No endpoint data found for {}'.format(
s_name))
else:
url = self.parse_endpoints(self.get_endpoints(
endpoint_data), s_type)
service_data), s_type)
# Create the service class and add it to services list
service = s_class(s_name, s_type, url, token,
service = s_class(s_name, s_type, url, self.token,
self._ssl_validation,
self._clients.get_service_client(
s_type))
@ -153,11 +164,13 @@ class Services(object):
def set_catalog_and_url(self):
if self._creds.api_version == 3:
self.service_catalog = 'catalog'
service_catalog = 'catalog'
self.public_url = 'url'
else:
self.service_catalog = 'serviceCatalog'
service_catalog = 'serviceCatalog'
self.public_url = 'publicURL'
self.token, auth_data = self._clients.auth_provider.get_auth()
self.catalog = auth_data[service_catalog]
def parse_endpoints(self, ep, name):
"""Parse an endpoint(s).
@ -214,15 +227,16 @@ class Services(object):
:param kwargs: Search parameters (accepts service name or type)
:rtype: boolean
"""
a_s = self.available_services
if kwargs.get('name'):
if kwargs.get('name') not in self.available_services.keys():
return False
return True
if [s for s in a_s if s['name'] == kwargs.get('name')]:
return True
return False
if kwargs.get('type'):
if kwargs.get('type') not in self.available_services.values():
return False
return True
if [s for s in a_s if s['type'] == kwargs.get('type')]:
return True
return False
return False
def post_configuration(self):

View File

@ -35,5 +35,5 @@ class ShareService(VersionedService):
return 'share'
@staticmethod
def get_service_name():
return ['manila', 'manilav2']
def get_service_type():
return ['share', 'sharev2']

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class TelemetryService(Service):
@staticmethod
def get_service_name():
return ['ceilometer']
def get_service_type():
return ['telemetry']
@staticmethod
def get_codename():

View File

@ -56,8 +56,8 @@ class VolumeService(VersionedService):
return 'volume'
@staticmethod
def get_service_name():
return ['cinderv2', 'cinderv3']
def get_service_type():
return ['volumev2', 'volumev3']
def post_configuration(self, conf, is_service):
# Verify if the cinder backup service is enabled

View File

@ -19,8 +19,8 @@ from config_tempest.services.base import Service
class Workflowv2Service(Service):
@staticmethod
def get_service_name():
return ['mistral']
def get_service_type():
return ['workflow']
@staticmethod
def get_codename():

View File

@ -26,9 +26,11 @@ class TestEc2Service(BaseConfigTempestTest):
FAKE_URL = "http://10.200.16.10:8774/"
@mock.patch('config_tempest.services.services.Services.discover')
@mock.patch('config_tempest.services.services.Services.'
'set_catalog_and_url')
@mock.patch('config_tempest.services.services.Services.'
'get_available_services')
def setUp(self, mock_set_avail, mock_discover):
def setUp(self, mock_set_avail, mock_catalog, mock_discover):
super(TestEc2Service, self).setUp()
conf = self._get_conf('v2', 'v3')
self.clients = self._get_clients(conf)
@ -46,9 +48,11 @@ class TestS3Service(BaseConfigTempestTest):
FAKE_URL = "http://10.200.16.10:8774/"
@mock.patch('config_tempest.services.services.Services.discover')
@mock.patch('config_tempest.services.services.Services.'
'set_catalog_and_url')
@mock.patch('config_tempest.services.services.Services.'
'get_available_services')
def setUp(self, mock_set_avail, mock_discover):
def setUp(self, mock_set_avail, mock_catalog, mock_discover):
super(TestS3Service, self).setUp()
conf = self._get_conf('v2', 'v3')
self.clients = self._get_clients(conf)

View File

@ -37,10 +37,13 @@ class TestServices(BaseConfigTempestTest):
super(TestServices, self).setUp()
@mock.patch('config_tempest.services.services.Services.discover')
@mock.patch('config_tempest.services.services.Services.'
'set_catalog_and_url')
@mock.patch('config_tempest.services.services.Services.'
'get_available_services')
def _create_services_instance(self, mock_avail, mock_discover, v2=False):
mock_avail.return_value = {'my_service': 'my_type'}
def _create_services_instance(self, mock_avail, mock_catalog,
mock_discover, v2=False):
mock_avail.return_value = [{'name': 'my_service', 'type': 'my_type'}]
conf = self._get_conf('v2', 'v3')
creds = self._get_creds(conf, v2=v2)
clients = mock.Mock()
@ -74,18 +77,6 @@ class TestServices(BaseConfigTempestTest):
resp = services.get_endpoints({'endpoints': []})
self.assertEqual(resp, [])
def test_set_catalog_and_url(self):
# api version = 2
services = self._create_services_instance(v2=True)
services.set_catalog_and_url()
self.assertEqual(services.service_catalog, 'serviceCatalog')
self.assertEqual(services.public_url, 'publicURL')
# api version = 3
services = self._create_services_instance()
services.set_catalog_and_url()
self.assertEqual(services.service_catalog, 'catalog')
self.assertEqual(services.public_url, 'url')
def test_parse_endpoints_empty(self):
services = self._create_services_instance()
services.public_url = "url"