1# Copyright 2018 Red Hat, Inc. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# not use this file except in compliance with the License. You may obtain 5# a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations 13# under the License. 14 15import importlib 16import warnings 17 18import os_service_types 19 20from openstack import _log 21from openstack import service_description 22 23_logger = _log.setup_logging('openstack') 24_service_type_manager = os_service_types.ServiceTypes() 25 26 27def make_names(): 28 imports = ['from openstack import service_description'] 29 services = [] 30 31 for service in _service_type_manager.services: 32 service_type = service['service_type'] 33 if service_type == 'ec2-api': 34 # NOTE(mordred) It doesn't make any sense to use ec2-api 35 # from openstacksdk. The credentials API calls are all calls 36 # on identity endpoints. 37 continue 38 desc_class = _find_service_description_class(service_type) 39 40 st = service_type.replace('-', '_') 41 42 if desc_class.__module__ != 'openstack.service_description': 43 base_mod, dm = desc_class.__module__.rsplit('.', 1) 44 imports.append( 45 'from {base_mod} import {dm}'.format( 46 base_mod=base_mod, 47 dm=dm)) 48 else: 49 dm = 'service_description' 50 51 dc = desc_class.__name__ 52 services.append( 53 "{st} = {dm}.{dc}(service_type='{service_type}')".format( 54 st=st, dm=dm, dc=dc, service_type=service_type), 55 ) 56 57 # Register the descriptor class with every known alias. Don't 58 # add doc strings though - although they are supported, we don't 59 # want to give anybody any bad ideas. Making a second descriptor 60 # does not introduce runtime cost as the descriptors all use 61 # the same _proxies dict on the instance. 62 for alias_name in _get_aliases(st): 63 if alias_name[-1].isdigit(): 64 continue 65 services.append( 66 '{alias_name} = {st}'.format( 67 alias_name=alias_name, 68 st=st)) 69 services.append('') 70 print("# Generated file, to change, run tools/print-services.py") 71 for imp in sorted(imports): 72 print(imp) 73 print('\n') 74 print("class ServicesMixin:\n") 75 for service in services: 76 if service: 77 print(" {service}".format(service=service)) 78 else: 79 print() 80 81 82def _get_aliases(service_type, aliases=None): 83 # We make connection attributes for all official real type names 84 # and aliases. Three services have names they were called by in 85 # openstacksdk that are not covered by Service Types Authority aliases. 86 # Include them here - but take heed, no additional values should ever 87 # be added to this list. 88 # that were only used in openstacksdk resource naming. 89 LOCAL_ALIASES = { 90 'baremetal': 'bare_metal', 91 'block_storage': 'block_store', 92 'clustering': 'cluster', 93 } 94 all_types = set(_service_type_manager.get_aliases(service_type)) 95 if aliases: 96 all_types.update(aliases) 97 if service_type in LOCAL_ALIASES: 98 all_types.add(LOCAL_ALIASES[service_type]) 99 all_aliases = set() 100 for alias in all_types: 101 all_aliases.add(alias.replace('-', '_')) 102 return all_aliases 103 104 105def _find_service_description_class(service_type): 106 package_name = 'openstack.{service_type}'.format( 107 service_type=service_type).replace('-', '_') 108 module_name = service_type.replace('-', '_') + '_service' 109 class_name = ''.join( 110 [part.capitalize() for part in module_name.split('_')]) 111 try: 112 import_name = '.'.join([package_name, module_name]) 113 service_description_module = importlib.import_module(import_name) 114 except ImportError as e: 115 # ImportWarning is ignored by default. This warning is here 116 # as an opt-in for people trying to figure out why something 117 # didn't work. 118 warnings.warn( 119 "Could not import {service_type} service description: {e}".format( 120 service_type=service_type, e=str(e)), 121 ImportWarning) 122 return service_description.ServiceDescription 123 # There are no cases in which we should have a module but not the class 124 # inside it. 125 service_description_class = getattr(service_description_module, class_name) 126 return service_description_class 127 128 129make_names() 130