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
changes/43/255443/10
Kanagaraj Manickam 7 years ago
parent 6c893e2e02
commit 00d3677615
  1. 4
      heat/common/exception.py
  2. 7
      heat/engine/clients/__init__.py
  3. 47
      heat/engine/clients/client_plugin.py
  4. 4
      heat/engine/resource.py
  5. 2
      heat/tests/clients/test_barbican_client.py
  6. 2
      heat/tests/clients/test_cinder_client.py
  7. 7
      heat/tests/clients/test_clients.py
  8. 2
      heat/tests/clients/test_glance_client.py
  9. 2
      heat/tests/clients/test_manila_client.py
  10. 2
      heat/tests/clients/test_neutron_client.py
  11. 4
      heat/tests/clients/test_nova_client.py
  12. 2
      heat/tests/clients/test_sahara_client.py
  13. 2
      heat/tests/clients/test_swift_client.py

@ -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…
Cancel
Save