Let os-client-config handle session creation
More things than shade need consistent Session creation, so we moved a copy of the shade code into os-client-config to allow python-*client to consume the same logic. Now that it's there, consume it in shade and remove the need for shade to know/duplicate the logic. Depends-On: Ide4c613cc143a0b8a3f36130989b57e808b2530f Change-Id: I86cdb3cdd2710ef302520184ccfcb1605384f706
This commit is contained in:
parent
9df40b00dc
commit
f7ca875777
@ -4,7 +4,7 @@ munch
|
||||
decorator
|
||||
jsonpatch
|
||||
ipaddress
|
||||
os-client-config>=1.9.0
|
||||
os-client-config>=1.10.1
|
||||
requestsexceptions>=1.1.1
|
||||
six
|
||||
|
||||
|
@ -26,15 +26,11 @@ import requestsexceptions
|
||||
from cinderclient.v1 import client as cinder_client
|
||||
import glanceclient
|
||||
import glanceclient.exc
|
||||
from glanceclient.common import utils as glance_utils
|
||||
from heatclient import client as heat_client
|
||||
from heatclient.common import template_utils
|
||||
import keystoneauth1.exceptions
|
||||
from keystoneauth1 import plugin as ksa_plugin
|
||||
from keystoneauth1 import session as ksa_session
|
||||
from keystoneclient.v2_0 import client as k2_client
|
||||
from keystoneclient.v3 import client as k3_client
|
||||
from neutronclient.v2_0 import client as neutron_client
|
||||
from keystoneclient import client as keystone_client
|
||||
from neutronclient.neutron import client as neutron_client
|
||||
from novaclient import client as nova_client
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
import swiftclient.client as swift_client
|
||||
@ -209,8 +205,10 @@ class OpenStackCloud(object):
|
||||
|
||||
# If server expiration time is set explicitly, use that. Otherwise
|
||||
# fall back to whatever it was before
|
||||
self._SERVER_LIST_AGE = cache_expiration.get(
|
||||
'server', self._SERVER_LIST_AGE)
|
||||
# TODO(mordred) replace with get_cache_resource_expiration once
|
||||
# it has a release with default value
|
||||
self._SERVER_LIST_AGE = int(cache_expiration.get(
|
||||
'server', self._SERVER_LIST_AGE))
|
||||
|
||||
self._container_cache = dict()
|
||||
self._file_hash_cache = dict()
|
||||
@ -250,23 +248,13 @@ class OpenStackCloud(object):
|
||||
return generate_key
|
||||
|
||||
def _get_client(
|
||||
self, service_key, client_class, interface_key='endpoint_type',
|
||||
self, service_key, client_class, interface_key=None,
|
||||
pass_version_arg=True, **kwargs):
|
||||
try:
|
||||
interface = self.cloud_config.get_interface(service_key)
|
||||
# trigger exception on lack of service
|
||||
self.get_session_endpoint(service_key)
|
||||
constructor_args = dict(
|
||||
session=self.keystone_session,
|
||||
service_name=self.cloud_config.get_service_name(service_key),
|
||||
service_type=self.cloud_config.get_service_type(service_key),
|
||||
region_name=self.region_name)
|
||||
constructor_args.update(kwargs)
|
||||
constructor_args[interface_key] = interface
|
||||
if pass_version_arg:
|
||||
version = self.cloud_config.get_api_version(service_key)
|
||||
constructor_args['version'] = version
|
||||
client = client_class(**constructor_args)
|
||||
client = self.cloud_config.get_legacy_client(
|
||||
service_key=service_key, client_class=client_class,
|
||||
interface_key=interface_key, pass_version_arg=pass_version_arg,
|
||||
**kwargs)
|
||||
except Exception:
|
||||
self.log.debug(
|
||||
"Couldn't construct {service} object".format(
|
||||
@ -286,31 +274,11 @@ class OpenStackCloud(object):
|
||||
'compute', nova_client.Client)
|
||||
return self._nova_client
|
||||
|
||||
def _get_identity_client_class(self):
|
||||
if self.cloud_config.get_api_version('identity') == '3':
|
||||
return k3_client.Client
|
||||
elif self.cloud_config.get_api_version('identity') in ('2', '2.0'):
|
||||
return k2_client.Client
|
||||
raise OpenStackCloudException(
|
||||
"Unknown identity API version: {version}".format(
|
||||
version=self.cloud_config.get_api_version('identity')))
|
||||
|
||||
@property
|
||||
def keystone_session(self):
|
||||
if self._keystone_session is None:
|
||||
|
||||
try:
|
||||
keystone_auth = self.cloud_config.get_auth()
|
||||
if not keystone_auth:
|
||||
raise OpenStackCloudException(
|
||||
"Problem with auth parameters")
|
||||
self._keystone_session = ksa_session.Session(
|
||||
auth=keystone_auth,
|
||||
verify=self.verify,
|
||||
cert=self.cert,
|
||||
timeout=self.api_timeout)
|
||||
except OpenStackCloudException:
|
||||
raise
|
||||
self._keystone_session = self.cloud_config.get_session()
|
||||
except Exception as e:
|
||||
raise OpenStackCloudException(
|
||||
"Error authenticating to keystone: %s " % str(e))
|
||||
@ -320,7 +288,7 @@ class OpenStackCloud(object):
|
||||
def keystone_client(self):
|
||||
if self._keystone_client is None:
|
||||
self._keystone_client = self._get_client(
|
||||
'identity', self._get_identity_client_class())
|
||||
'identity', keystone_client.Client)
|
||||
return self._keystone_client
|
||||
|
||||
@property
|
||||
@ -614,13 +582,8 @@ class OpenStackCloud(object):
|
||||
@property
|
||||
def glance_client(self):
|
||||
if self._glance_client is None:
|
||||
endpoint, version = glance_utils.strip_version(
|
||||
self.get_session_endpoint(service_key='image'))
|
||||
# TODO(mordred): Put check detected vs. configured version
|
||||
# and warn if they're different.
|
||||
self._glance_client = self._get_client(
|
||||
'image', glanceclient.Client, interface_key='interface',
|
||||
endpoint=endpoint)
|
||||
'image', glanceclient.Client)
|
||||
return self._glance_client
|
||||
|
||||
@property
|
||||
@ -644,25 +607,8 @@ class OpenStackCloud(object):
|
||||
@property
|
||||
def swift_client(self):
|
||||
if self._swift_client is None:
|
||||
try:
|
||||
token = self.keystone_session.get_token()
|
||||
endpoint = self.get_session_endpoint(
|
||||
service_key='object-store')
|
||||
self._swift_client = swift_client.Connection(
|
||||
preauthurl=endpoint,
|
||||
preauthtoken=token,
|
||||
auth_version=self.cloud_config.get_api_version('identity'),
|
||||
os_options=dict(
|
||||
auth_token=token,
|
||||
object_storage_url=endpoint,
|
||||
region_name=self.region_name),
|
||||
timeout=self.api_timeout,
|
||||
)
|
||||
except OpenStackCloudException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise OpenStackCloudException(
|
||||
"Error constructing swift client: %s", str(e))
|
||||
self._swift_client = self._get_client(
|
||||
'object-store', swift_client.Connection)
|
||||
return self._swift_client
|
||||
|
||||
@property
|
||||
@ -694,21 +640,6 @@ class OpenStackCloud(object):
|
||||
@property
|
||||
def trove_client(self):
|
||||
if self._trove_client is None:
|
||||
self.get_session_endpoint(service_key='database')
|
||||
# Make the connection - can't use keystone session until there
|
||||
# is one
|
||||
self._trove_client = trove_client.Client(
|
||||
self.cloud_config.get_api_version('database'),
|
||||
session=self.keystone_session,
|
||||
region_name=self.region_name,
|
||||
service_type=self.cloud_config.get_service_type('database'),
|
||||
)
|
||||
|
||||
if self._trove_client is None:
|
||||
raise OpenStackCloudException(
|
||||
"Failed to instantiate Trove client."
|
||||
" This could mean that your credentials are wrong.")
|
||||
|
||||
self._trove_client = self._get_client(
|
||||
'database', trove_client.Client)
|
||||
return self._trove_client
|
||||
@ -717,7 +648,7 @@ class OpenStackCloud(object):
|
||||
def neutron_client(self):
|
||||
if self._neutron_client is None:
|
||||
self._neutron_client = self._get_client(
|
||||
'network', neutron_client.Client, pass_version_arg=False)
|
||||
'network', neutron_client.Client)
|
||||
return self._neutron_client
|
||||
|
||||
def create_stack(
|
||||
@ -808,22 +739,8 @@ class OpenStackCloud(object):
|
||||
ram=ram, include=include))
|
||||
|
||||
def get_session_endpoint(self, service_key):
|
||||
override_endpoint = self.cloud_config.get_endpoint(service_key)
|
||||
if override_endpoint:
|
||||
return override_endpoint
|
||||
try:
|
||||
# keystone is a special case in keystone, because what?
|
||||
if service_key == 'identity':
|
||||
endpoint = self.keystone_session.get_endpoint(
|
||||
interface=ksa_plugin.AUTH_INTERFACE)
|
||||
else:
|
||||
endpoint = self.keystone_session.get_endpoint(
|
||||
service_type=self.cloud_config.get_service_type(
|
||||
service_key),
|
||||
service_name=self.cloud_config.get_service_name(
|
||||
service_key),
|
||||
interface=self.cloud_config.get_interface(service_key),
|
||||
region_name=self.region_name)
|
||||
return self.cloud_config.get_session_endpoint(service_key)
|
||||
except keystoneauth1.exceptions.catalog.EndpointNotFound as e:
|
||||
self.log.debug(
|
||||
"Endpoint not found in %s cloud: %s", self.name, str(e))
|
||||
@ -843,7 +760,7 @@ class OpenStackCloud(object):
|
||||
def has_service(self, service_key):
|
||||
if not self.cloud_config.config.get('has_%s' % service_key, True):
|
||||
self.log.debug(
|
||||
"Overriding {service_key} entry in catalog per config".format(
|
||||
"Disabling {service_key} entry in catalog per config".format(
|
||||
service_key=service_key))
|
||||
return False
|
||||
try:
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
import mock
|
||||
import os_client_config
|
||||
from os_client_config import cloud_config
|
||||
from swiftclient import client as swift_client
|
||||
from swiftclient import service as swift_service
|
||||
from swiftclient import exceptions as swift_exc
|
||||
@ -35,15 +36,13 @@ class TestObject(base.TestCase):
|
||||
cloud_config=config.get_one_cloud(validate=False))
|
||||
|
||||
@mock.patch.object(swift_client, 'Connection')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session',
|
||||
new_callable=mock.PropertyMock)
|
||||
@mock.patch.object(shade.OpenStackCloud, 'get_session_endpoint')
|
||||
def test_swift_client(self, endpoint_mock, session_mock, swift_mock):
|
||||
endpoint_mock.return_value = 'danzig'
|
||||
session = mock.MagicMock()
|
||||
session.get_token = mock.MagicMock()
|
||||
session.get_token.return_value = 'yankee'
|
||||
session_mock.return_value = session
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_swift_client(self, get_session_mock, swift_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = 'danzig'
|
||||
session_mock.get_token.return_value = 'yankee'
|
||||
get_session_mock.return_value = session_mock
|
||||
|
||||
self.cloud.swift_client
|
||||
swift_mock.assert_called_with(
|
||||
preauthurl='danzig',
|
||||
@ -55,15 +54,15 @@ class TestObject(base.TestCase):
|
||||
auth_token='yankee',
|
||||
region_name=''))
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session',
|
||||
new_callable=mock.PropertyMock)
|
||||
@mock.patch.object(shade.OpenStackCloud, 'get_session_endpoint')
|
||||
def test_swift_client_no_endpoint(self, endpoint_mock, session_mock):
|
||||
endpoint_mock.side_effect = KeyError
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_swift_client_no_endpoint(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = None
|
||||
get_session_mock.return_value = session_mock
|
||||
e = self.assertRaises(
|
||||
exc.OpenStackCloudException, lambda: self.cloud.swift_client)
|
||||
self.assertIn(
|
||||
'Error constructing swift client', str(e))
|
||||
'Failed to instantiate object-store client.', str(e))
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'auth_token')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'get_session_endpoint')
|
||||
|
@ -15,6 +15,7 @@
|
||||
import mock
|
||||
|
||||
import ironicclient
|
||||
from os_client_config import cloud_config
|
||||
import shade
|
||||
from shade.tests import base
|
||||
|
||||
@ -35,12 +36,10 @@ class TestShadeOperatorNoAuth(base.TestCase):
|
||||
validate=False,
|
||||
)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session',
|
||||
new_callable=mock.PropertyMock)
|
||||
@mock.patch.object(shade.OperatorCloud, 'get_session_endpoint')
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
@mock.patch.object(ironicclient.client, 'Client')
|
||||
def test_ironic_noauth_selection_using_a_task(
|
||||
self, mock_client, mock_endpoint, session_mock):
|
||||
self, mock_client, get_session_mock):
|
||||
"""Test noauth selection for Ironic in OperatorCloud
|
||||
|
||||
Utilize a task to trigger the client connection attempt
|
||||
@ -50,10 +49,11 @@ class TestShadeOperatorNoAuth(base.TestCase):
|
||||
We want session_endpoint to be called because we're storing the
|
||||
endpoint in a noauth token Session object now.
|
||||
"""
|
||||
session = mock.MagicMock()
|
||||
session.get_token = mock.MagicMock()
|
||||
session.get_token.return_value = 'yankee'
|
||||
session_mock.return_value = session
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = None
|
||||
session_mock.get_token.return_value = 'yankee'
|
||||
get_session_mock.return_value = session_mock
|
||||
|
||||
self.cloud_noauth.patch_machine('name', {})
|
||||
self.assertTrue(mock_endpoint.called)
|
||||
self.assertTrue(get_session_mock.called)
|
||||
self.assertTrue(mock_client.called)
|
||||
|
@ -17,11 +17,9 @@ import munch
|
||||
|
||||
import glanceclient
|
||||
from heatclient import client as heat_client
|
||||
from keystoneclient.v2_0 import client as k2_client
|
||||
from keystoneclient.v3 import client as k3_client
|
||||
from neutronclient.common import exceptions as n_exc
|
||||
|
||||
import os_client_config.cloud_config
|
||||
from os_client_config import cloud_config
|
||||
import shade
|
||||
from shade import exc
|
||||
from shade import meta
|
||||
@ -37,33 +35,6 @@ class TestShade(base.TestCase):
|
||||
def test_openstack_cloud(self):
|
||||
self.assertIsInstance(self.cloud, shade.OpenStackCloud)
|
||||
|
||||
@mock.patch.object(
|
||||
os_client_config.cloud_config.CloudConfig, 'get_api_version')
|
||||
def test_get_client_v2(self, mock_api_version):
|
||||
mock_api_version.return_value = '2'
|
||||
|
||||
self.assertIs(
|
||||
self.cloud._get_identity_client_class(),
|
||||
k2_client.Client)
|
||||
|
||||
@mock.patch.object(
|
||||
os_client_config.cloud_config.CloudConfig, 'get_api_version')
|
||||
def test_get_client_v3(self, mock_api_version):
|
||||
mock_api_version.return_value = '3'
|
||||
|
||||
self.assertIs(
|
||||
self.cloud._get_identity_client_class(),
|
||||
k3_client.Client)
|
||||
|
||||
@mock.patch.object(
|
||||
os_client_config.cloud_config.CloudConfig, 'get_api_version')
|
||||
def test_get_client_v4(self, mock_api_version):
|
||||
mock_api_version.return_value = '4'
|
||||
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.cloud._get_identity_client_class)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'search_images')
|
||||
def test_get_images(self, mock_search):
|
||||
image1 = dict(id='123', name='mickey')
|
||||
@ -98,33 +69,35 @@ class TestShade(base.TestCase):
|
||||
self.assertRaises(exc.OpenStackCloudException,
|
||||
self.cloud.list_servers)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'get_session_endpoint')
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
@mock.patch.object(glanceclient, 'Client')
|
||||
def test_glance_args(
|
||||
self, mock_client, mock_keystone_session, mock_endpoint):
|
||||
mock_keystone_session.return_value = None
|
||||
mock_endpoint.return_value = 'http://example.com/v2'
|
||||
self, mock_client, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = 'http://example.com/v2'
|
||||
get_session_mock.return_value = session_mock
|
||||
self.cloud.glance_client
|
||||
mock_client.assert_called_with(
|
||||
'2',
|
||||
endpoint='http://example.com',
|
||||
version='2', region_name='', service_name=None,
|
||||
region_name='', service_name=None,
|
||||
interface='public',
|
||||
service_type='image', session=mock.ANY,
|
||||
)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
@mock.patch.object(heat_client, 'Client')
|
||||
def test_heat_args(self, mock_client, mock_keystone_session):
|
||||
mock_keystone_session.return_value = None
|
||||
def test_heat_args(self, mock_client, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
get_session_mock.return_value = session_mock
|
||||
self.cloud.heat_client
|
||||
mock_client.assert_called_with(
|
||||
'1',
|
||||
endpoint_type='public',
|
||||
region_name='',
|
||||
service_name=None,
|
||||
service_type='orchestration',
|
||||
session=mock.ANY,
|
||||
version='1'
|
||||
)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'search_subnets')
|
||||
|
@ -12,12 +12,12 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from keystoneauth1 import plugin as ksc_plugin
|
||||
from keystoneauth1 import plugin as ksa_plugin
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
import os_client_config.cloud_config
|
||||
from os_client_config import cloud_config
|
||||
import shade
|
||||
import munch
|
||||
from shade import exc
|
||||
@ -992,27 +992,30 @@ class TestShadeOperator(base.TestCase):
|
||||
self.assertEqual('22', self.cloud.get_image_id('22'))
|
||||
self.assertEqual('22', self.cloud.get_image_id('22 name'))
|
||||
|
||||
@mock.patch.object(
|
||||
os_client_config.cloud_config.CloudConfig, 'get_endpoint')
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_endpoint')
|
||||
def test_get_session_endpoint_provided(self, fake_get_endpoint):
|
||||
fake_get_endpoint.return_value = 'http://fake.url'
|
||||
self.assertEqual(
|
||||
'http://fake.url', self.cloud.get_session_endpoint('image'))
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
def test_get_session_endpoint_session(self, session_mock):
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_session(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = 'http://fake.url'
|
||||
get_session_mock.return_value = session_mock
|
||||
self.assertEqual(
|
||||
'http://fake.url', self.cloud.get_session_endpoint('image'))
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
def test_get_session_endpoint_exception(self, session_mock):
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_exception(self, get_session_mock):
|
||||
class FakeException(Exception):
|
||||
pass
|
||||
|
||||
def side_effect(*args, **kwargs):
|
||||
raise FakeException("No service")
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.side_effect = side_effect
|
||||
get_session_mock.return_value = session_mock
|
||||
self.cloud.name = 'testcloud'
|
||||
self.cloud.region_name = 'testregion'
|
||||
with testtools.ExpectedException(
|
||||
@ -1021,26 +1024,34 @@ class TestShadeOperator(base.TestCase):
|
||||
" No service"):
|
||||
self.cloud.get_session_endpoint("image")
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
def test_get_session_endpoint_unavailable(self, session_mock):
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_unavailable(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = None
|
||||
get_session_mock.return_value = session_mock
|
||||
image_endpoint = self.cloud.get_session_endpoint("image")
|
||||
self.assertIsNone(image_endpoint)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
def test_get_session_endpoint_identity(self, session_mock):
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_get_session_endpoint_identity(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
get_session_mock.return_value = session_mock
|
||||
self.cloud.get_session_endpoint('identity')
|
||||
session_mock.get_endpoint.assert_called_with(
|
||||
interface=ksc_plugin.AUTH_INTERFACE)
|
||||
interface=ksa_plugin.AUTH_INTERFACE)
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
def test_has_service_no(self, session_mock):
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_has_service_no(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = None
|
||||
get_session_mock.return_value = session_mock
|
||||
self.assertFalse(self.cloud.has_service("image"))
|
||||
|
||||
@mock.patch.object(shade.OpenStackCloud, 'keystone_session')
|
||||
def test_has_service_yes(self, session_mock):
|
||||
@mock.patch.object(cloud_config.CloudConfig, 'get_session')
|
||||
def test_has_service_yes(self, get_session_mock):
|
||||
session_mock = mock.Mock()
|
||||
session_mock.get_endpoint.return_value = 'http://fake.url'
|
||||
get_session_mock.return_value = session_mock
|
||||
self.assertTrue(self.cloud.has_service("image"))
|
||||
|
||||
@mock.patch.object(shade._tasks.HypervisorList, 'main')
|
||||
|
Loading…
Reference in New Issue
Block a user