Calculate name in CloudRegion

We calculate a name from the auth_url in the from_session factory
function, but it should really be a fundamental piece of logic for
CloudRegion about what to do with name not being present since we've
added in several paths for people to make a Connection that have nothing
to do with named clouds in clouds.yaml.

Change-Id: Ib4cdcde6be50295e214e7cd4ca8c65b7da431529
This commit is contained in:
Monty Taylor 2018-02-04 12:00:00 -06:00
parent a61b5d25de
commit ebe5fde830
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
6 changed files with 57 additions and 35 deletions

View File

@ -318,7 +318,9 @@ class OpenStackCloud(_normalize.Normalizer):
def session_constructor(*args, **kwargs):
# We need to pass our current keystone session to the Session
# Constructor, otherwise the new auth plugin doesn't get used.
return keystoneauth1.session.Session(session=self.session)
return keystoneauth1.session.Session(
session=self.session,
discovery_cache=self.config._discovery_cache)
# Use cloud='defaults' so that we overlay settings properly
cloud_config = config.get_one(
@ -326,7 +328,7 @@ class OpenStackCloud(_normalize.Normalizer):
session_constructor=session_constructor,
**params)
# Override the cloud name so that logging/location work right
cloud_config.name = self.name
cloud_config._name = self.name
cloud_config.config['profile'] = self.name
# Use self.__class__ so that we return whatever this if, like if it's
# a subclass in the case of shade wrapping sdk.

View File

@ -60,9 +60,6 @@ def from_session(session, name=None, region_name=None,
:param kwargs:
Config settings for this cloud region.
"""
# If someone is constructing one of these from a Session, then they are
# not using a named config. Use the hostname of their auth_url instead.
name = name or urllib.parse.urlparse(session.auth.auth_url).hostname
config_dict = config_defaults.get_defaults()
config_dict.update(**kwargs)
return CloudRegion(
@ -77,11 +74,13 @@ class CloudRegion(object):
A CloudRegion encapsulates the config information needed for connections
to all of the services in a Region of a Cloud.
"""
def __init__(self, name, region_name=None, config=None,
def __init__(self, name=None, region_name=None, config=None,
force_ipv4=False, auth_plugin=None,
openstack_config=None, session_constructor=None,
app_name=None, app_version=None, session=None):
self.name = name
app_name=None, app_version=None, session=None,
discovery_cache=None):
self._name = name
self.region_name = region_name
self.config = config
self.log = _log.setup_logging('openstack.config')
@ -92,6 +91,7 @@ class CloudRegion(object):
self._session_constructor = session_constructor or ks_session.Session
self._app_name = app_name
self._app_version = app_version
self._discovery_cache = discovery_cache or None
def __getattr__(self, key):
"""Return arbitrary attributes."""
@ -116,6 +116,32 @@ class CloudRegion(object):
def __ne__(self, other):
return not self == other
@property
def name(self):
if self._name is None:
try:
self._name = urllib.parse.urlparse(
self.get_session().auth.auth_url).hostname
except Exception:
self._name = self._app_name or ''
return self._name
@property
def full_name(self):
"""Return a string that can be used as an identifier.
Always returns a valid string. It will have name and region_name
or just one of the two if only one is set, or else 'unknown'.
"""
if self.name and self.region_name:
return ":".join([self.name, self.region_name])
elif self.name and not self.region_name:
return self.name
elif not self.name and self.region_name:
return self.region_name
else:
return 'unknown'
def set_session_constructor(self, session_constructor):
"""Sets the Session constructor."""
self._session_constructor = session_constructor
@ -128,9 +154,10 @@ class CloudRegion(object):
verify = self.config['verify']
if self.config['cacert']:
warnings.warn(
"You are specifying a cacert for the cloud {0} but "
"also to ignore the host verification. The host SSL cert "
"will not be verified.".format(self.name))
"You are specifying a cacert for the cloud {full_name}"
" but also to ignore the host verification. The host SSL"
" cert will not be verified.".format(
full_name=self.full_name))
cert = self.config.get('cert', None)
if cert:
@ -216,15 +243,15 @@ class CloudRegion(object):
# cert verification
if not verify:
self.log.debug(
"Turning off SSL warnings for {cloud}:{region}"
" since verify=False".format(
cloud=self.name, region=self.region_name))
"Turning off SSL warnings for {full_name}"
" since verify=False".format(full_name=self.full_name))
requestsexceptions.squelch_warnings(insecure_requests=not verify)
self._keystone_session = self._session_constructor(
auth=self._auth,
verify=verify,
cert=cert,
timeout=self.config['api_timeout'])
timeout=self.config['api_timeout'],
discovery_cache=self._discovery_cache)
if hasattr(self._keystone_session, 'additional_user_agent'):
self._keystone_session.additional_user_agent.append(
('openstacksdk', openstack_version.__version__))

View File

@ -295,18 +295,7 @@ class Connection(six.with_metaclass(_meta.ConnectionMeta,
load_envvars=cloud is not None,
**kwargs)
if self.config.name:
tm_name = ':'.join([
self.config.name,
self.config.region_name or 'unknown'])
else:
tm_name = self.config.region_name or 'unknown'
self.task_manager = task_manager.TaskManager(name=tm_name)
if session:
# TODO(mordred) Expose constructor option for this in OCC
self.config._keystone_session = session
self.task_manager = task_manager.TaskManager(self.config.full_name)
self._session = None
self._proxies = {}

View File

@ -16,7 +16,6 @@
"""
import copy
from six.moves import urllib
from openstack import _log
from openstack.config import cloud_region
@ -45,9 +44,6 @@ def _get_config_from_profile(profile, authenticator, **kwargs):
# TODO(shade) Remove this once we've shifted python-openstackclient
# to not use the profile interface.
# We don't have a cloud name. Make one up from the auth_url hostname
# so that log messages work.
name = urllib.parse.urlparse(authenticator.auth_url).hostname
region_name = None
for service in profile.get_services():
if service.region:
@ -66,7 +62,7 @@ def _get_config_from_profile(profile, authenticator, **kwargs):
config_kwargs = config_defaults.get_defaults()
config_kwargs.update(kwargs)
config = cloud_region.CloudRegion(
name=name, region_name=region_name, config=config_kwargs)
region_name=region_name, config=config_kwargs)
config._auth = authenticator
return config

View File

@ -54,6 +54,14 @@ class TestShade(base.RequestsMockTestCase):
def test_openstack_cloud(self):
self.assertIsInstance(self.cloud, openstack.cloud.OpenStackCloud)
def test_connect_as(self):
# Do initial auth/catalog steps
# TODO(mordred) This only tests the constructor steps. Discovery
# cache sharing is broken. We need to get discovery_cache option
# plumbed through
# keystoneauth1.loading.base.BaseLoader.load_from_options
self.cloud.connect_as(project_name='test_project')
@mock.patch.object(openstack.cloud.OpenStackCloud, 'search_images')
def test_get_images(self, mock_search):
image1 = dict(id='123', name='mickey')

View File

@ -192,7 +192,7 @@ class TestCloudRegion(base.TestCase):
cc.get_session()
mock_session.assert_called_with(
auth=mock.ANY,
verify=True, cert=None, timeout=None)
verify=True, cert=None, timeout=None, discovery_cache=None)
self.assertEqual(
fake_session.additional_user_agent,
[('openstacksdk', openstack_version.__version__)])
@ -212,7 +212,7 @@ class TestCloudRegion(base.TestCase):
cc.get_session()
mock_session.assert_called_with(
auth=mock.ANY,
verify=True, cert=None, timeout=None)
verify=True, cert=None, timeout=None, discovery_cache=None)
self.assertEqual(fake_session.app_name, "test_app")
self.assertEqual(fake_session.app_version, "test_version")
self.assertEqual(
@ -232,7 +232,7 @@ class TestCloudRegion(base.TestCase):
cc.get_session()
mock_session.assert_called_with(
auth=mock.ANY,
verify=True, cert=None, timeout=9)
verify=True, cert=None, timeout=9, discovery_cache=None)
self.assertEqual(
fake_session.additional_user_agent,
[('openstacksdk', openstack_version.__version__)])