Merge "Enable client plugin to support dynamic api version"

This commit is contained in:
Jenkins 2016-05-11 11:42:36 +00:00 committed by Gerrit Code Review
commit 0105e8f153
13 changed files with 58 additions and 29 deletions

View File

@ -500,3 +500,7 @@ class SIGHUPInterrupt(HeatException):
class NoActionRequired(Exception):
pass
class InvalidServiceVersion(HeatException):
msg_fmt = _("Invalid service %(service)s version %(version)s")

View File

@ -64,10 +64,13 @@ class OpenStackClients(object):
self._client_plugins[name] = client_plugin
return client_plugin
def client(self, name):
def client(self, name, version=None):
client_plugin = self.client_plugin(name)
if client_plugin:
return client_plugin.client()
if version:
return client_plugin.client(version=version)
else:
return client_plugin.client()
if name in self._clients:
return self._clients[name]

View File

@ -26,6 +26,7 @@ import requests
import six
from heat.common import config
from heat.common import exception as heat_exception
from heat.common.i18n import _
cfg.CONF.import_opt('client_retry_limit', 'heat.common.config')
@ -99,10 +100,15 @@ class ClientPlugin(object):
# types, so its used in list format
service_types = []
# To make the backward compatibility with existing resource plugins
default_version = None
supported_versions = []
def __init__(self, context):
self._context = weakref.ref(context)
self._clients = weakref.ref(context.clients)
self._client = None
self.invalidate()
self._keystone_session_obj = None
@property
@ -135,23 +141,38 @@ class ClientPlugin(object):
def invalidate(self):
"""Invalidate/clear any cached client."""
self._client = None
self._client_instances = {}
def client(self):
if not self._client:
self._client = self._create()
elif (cfg.CONF.reauthentication_auth_method == 'trusts'
def client(self, version=None):
if not version:
version = self.default_version
if version in self._client_instances:
if (cfg.CONF.reauthentication_auth_method == 'trusts'
and self.context.auth_plugin.auth_ref.will_expire_soon(
cfg.CONF.stale_token_duration)):
# If the token is near expiry, force creating a new client,
# which will get a new token via another call to auth_token
# We also have to invalidate all other cached clients
self.clients.invalidate_plugins()
self._client = self._create()
return self._client
# If the token is near expiry, force creating a new client,
# which will get a new token via another call to auth_token
# We also have to invalidate all other cached clients
self.clients.invalidate_plugins()
else:
return self._client_instances[version]
# Back-ward compatibility
if version is None:
self._client_instances[version] = self._create()
else:
if version not in self.supported_versions:
raise heat_exception.InvalidServiceVersion(
version=version,
service=self._get_service_name())
self._client_instances[version] = self._create(version=version)
return self._client_instances[version]
@abc.abstractmethod
def _create(self):
def _create(self, version=None):
"""Return a newly created client."""
pass

View File

@ -609,10 +609,10 @@ class Resource(object):
"""
return [r.name for r in self.stack.dependencies.required_by(self)]
def client(self, name=None):
def client(self, name=None, version=None):
client_name = name or self.default_client_name
assert client_name, "Must specify client name"
return self.stack.clients.client(client_name)
return self.stack.clients.client(client_name, version)
def client_plugin(self, name=None):
client_name = name or self.default_client_name

View File

@ -30,7 +30,7 @@ class BarbicanClientPluginTest(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.barbican_plugin = c.client_plugin('barbican')
self.barbican_plugin._client = self.barbican_client
self.barbican_plugin.client = lambda: self.barbican_client
def test_create(self):
context = utils.dummy_context()

View File

@ -31,7 +31,7 @@ class CinderClientPluginTest(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.cinder_plugin = c.client_plugin('cinder')
self.cinder_plugin._client = self.cinder_client
self.cinder_plugin.client = lambda: self.cinder_client
def test_get_volume(self):
"""Tests the get_volume function."""

View File

@ -155,7 +155,6 @@ class ClientsTest(common.HeatTestCase):
obj.get_heat_url.return_value = None
obj.url_for = mock.Mock(name="url_for")
obj.url_for.return_value = "url_from_keystone"
obj._client = None
heat = obj.client()
heat_cached = obj.client()
self.assertEqual(heat, heat_cached)
@ -414,7 +413,7 @@ class TestClientPluginsInitialise(common.HeatTestCase):
self.assertIsNotNone(plugin)
self.assertEqual(c, plugin.clients)
self.assertEqual(con, plugin.context)
self.assertIsNone(plugin._client)
self.assertEqual({}, plugin._client_instances)
self.assertTrue(clients.has_client(plugin_name))
self.assertIsInstance(plugin.service_types, list)
self.assertTrue(len(plugin.service_types) >= 1,
@ -430,7 +429,9 @@ class TestClientPluginsInitialise(common.HeatTestCase):
plugin = c.client_plugin(plugin_name)
self.assertIsNotNone(plugin)
c.invalidate_plugins()
self.assertEqual(len(plugin_types), mock_invalidate.call_count)
# while client plugin is initialized and while client is invoked
# its being invalidated, so the count will be doubled
self.assertEqual(len(plugin_types) * 2, mock_invalidate.call_count)
class TestIsNotFound(common.HeatTestCase):

View File

@ -31,7 +31,7 @@ class GlanceUtilsTest(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.glance_plugin = c.client_plugin('glance')
self.glance_plugin._client = self.glance_client
self.glance_plugin.client = lambda: self.glance_client
self.my_image = mock.MagicMock()
def test_find_image_by_name_or_id(self):

View File

@ -43,7 +43,7 @@ class ManilaClientPluginTest(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.manila_plugin = c.client_plugin('manila')
self.manila_plugin._client = self.manila_client
self.manila_plugin.client = lambda: self.manila_client
# prepare list of items to test search
Item = collections.namedtuple('Item', ['id', 'name'])
self.item_list = [

View File

@ -32,7 +32,7 @@ class NeutronClientPluginTestCase(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.neutron_plugin = c.client_plugin('neutron')
self.neutron_plugin._client = self.neutron_client
self.neutron_plugin.client = lambda: self.neutron_client
class NeutronClientPluginTest(NeutronClientPluginTestCase):

View File

@ -38,7 +38,7 @@ class NovaClientPluginTestCase(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.nova_plugin = c.client_plugin('nova')
self.nova_plugin._client = self.nova_client
self.nova_plugin.client = lambda: self.nova_client
class NovaClientPluginTest(NovaClientPluginTestCase):
@ -628,7 +628,7 @@ class ConsoleUrlsTest(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.nova_plugin = c.client_plugin('nova')
self.nova_plugin._client = self.nova_client
self.nova_plugin.client = lambda: self.nova_client
self.server = mock.Mock()
self.console_method = getattr(self.server,
'get_%s_console' % self.srv_method)

View File

@ -32,7 +32,7 @@ class SaharaUtilsTest(common.HeatTestCase):
con = utils.dummy_context()
c = con.clients
self.sahara_plugin = c.client_plugin('sahara')
self.sahara_plugin._client = self.sahara_client
self.sahara_plugin.client = lambda: self.sahara_client
self.my_image = mock.MagicMock()
self.my_plugin = mock.MagicMock()

View File

@ -30,7 +30,7 @@ class SwiftClientPluginTestCase(common.HeatTestCase):
self.context.tenant_id = "demo"
c = self.context.clients
self.swift_plugin = c.client_plugin('swift')
self.swift_plugin._client = self.swift_client
self.swift_plugin.client = lambda: self.swift_client
class SwiftUtilsTest(SwiftClientPluginTestCase):