Enable client plugin to support dynamic api version
It helps client plugin to create client based on the required api version given at run time instead of hard-coded version. implements blueprint enable-client-plugin-to-use-a-given-service-api-version Change-Id: I1cf3cdf498b7a97b6aa262eb3012edda8ad2aaaf
This commit is contained in:
parent
6c893e2e02
commit
00d3677615
@ -500,3 +500,7 @@ class SIGHUPInterrupt(HeatException):
|
||||
|
||||
class NoActionRequired(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidServiceVersion(HeatException):
|
||||
msg_fmt = _("Invalid service %(service)s version %(version)s")
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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."""
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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 = [
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user