From 9eee2019786704a32b40c2a22b966f51b6255a6c Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 5 Jul 2016 15:35:53 -0400 Subject: [PATCH] Lazy load client classes This patch updates the openstack actions so that a missing python "client" class doesn't cause all actions to fail to load. The oslo.utils try_import function is used along with a new _get_client_class() function for each action. This makes it possible to use available openstack actions, which have suitable python client libraries installed, without having to install all the available client libraries. Previously, the mistral-db-manage populate would fail to load them unless all the required libraries were installed. Change-Id: Ic278f2e7ed29ada07617858502502887eb744242 --- mistral/actions/openstack/actions.py | 190 +++++++++++++++++---------- mistral/actions/openstack/base.py | 5 +- 2 files changed, 124 insertions(+), 71 deletions(-) diff --git a/mistral/actions/openstack/actions.py b/mistral/actions/openstack/actions.py index 5c63e28a..62808e66 100644 --- a/mistral/actions/openstack/actions.py +++ b/mistral/actions/openstack/actions.py @@ -14,28 +14,31 @@ import functools -from barbicanclient import client as barbicanclient -from ceilometerclient.v2 import client as ceilometerclient -from cinderclient.v2 import client as cinderclient -from designateclient import v1 as designateclient -from glanceclient.v2 import client as glanceclient -from heatclient.v1 import client as heatclient -from ironic_inspector_client import v1 as ironic_inspector_client -from ironicclient.v1 import client as ironicclient -from keystoneclient.auth import identity -from keystoneclient import httpclient -from keystoneclient.v3 import client as keystoneclient -from magnumclient.v1 import client as magnumclient -from mistralclient.api.v2 import client as mistralclient -from muranoclient.v1 import client as muranoclient -from neutronclient.v2_0 import client as neutronclient -from novaclient import client as novaclient from oslo_config import cfg from oslo_log import log -from swiftclient import client as swift_client -from tackerclient.v1_0 import client as tackerclient -from troveclient.v1 import client as troveclient -from zaqarclient.queues.v2 import client as zaqarclient +from oslo_utils import importutils + +from keystoneclient.auth import identity +from keystoneclient import httpclient + +barbicanclient = importutils.try_import('barbicanclient.client') +ceilometerclient = importutils.try_import('ceilometerclient.v2.client') +cinderclient = importutils.try_import('cinderclient.v2.client') +designateclient = importutils.try_import('designateclient.v1') +glanceclient = importutils.try_import('glanceclient.v2.client') +heatclient = importutils.try_import('heatclient.v1.client') +keystoneclient = importutils.try_import('keystoneclient.v3.client') +ironic_inspector_client = importutils.try_import('ironic_inspector_client.v1') +ironicclient = importutils.try_import('ironicclient.v1.client') +magnumclient = importutils.try_import('magnumclient.v1.client') +mistralclient = importutils.try_import('mistralclient.api.v2.client') +muranoclient = importutils.try_import('muranoclient.v1.client') +neutronclient = importutils.try_import('neutronclient.v2_0.client') +novaclient = importutils.try_import('novaclient.client') +swift_client = importutils.try_import('swiftclient.client') +tackerclient = importutils.try_import('tackerclient.v1_0.client') +troveclient = importutils.try_import('troveclient.v1.client') +zaqarclient = importutils.try_import('zaqarclient.queues.v2.client') from mistral.actions.openstack import base from mistral import context @@ -82,7 +85,10 @@ class NovaAction(base.OpenStackAction): class GlanceAction(base.OpenStackAction): - _client_class = glanceclient.Client + + @classmethod + def _get_client_class(cls): + return glanceclient.Client def _get_client(self): ctx = context.ctx() @@ -91,7 +97,7 @@ class GlanceAction(base.OpenStackAction): glance_endpoint = keystone_utils.get_endpoint_for_project('glance') - return self._client_class( + return GlanceAction._get_client_class()( glance_endpoint.url, region_name=glance_endpoint.region, token=ctx.auth_token @@ -99,11 +105,14 @@ class GlanceAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class("fake_endpoint") + return cls._get_client_class()("fake_endpoint") class KeystoneAction(base.OpenStackAction): - _client_class = keystoneclient.Client + + @classmethod + def _get_client_class(cls): + return keystoneclient.Client def _get_client(self): ctx = context.ctx() @@ -125,7 +134,7 @@ class KeystoneAction(base.OpenStackAction): or keystone_utils.is_token_trust_scoped(ctx.auth_token)): kwargs['endpoint'] = ctx.auth_uri - client = self._client_class(**kwargs) + client = KeystoneAction._get_client_class()(**kwargs) client.management_url = ctx.auth_uri @@ -137,7 +146,7 @@ class KeystoneAction(base.OpenStackAction): authenticate = httpclient.HTTPClient.authenticate httpclient.HTTPClient.authenticate = lambda x: True - fake_client = cls._client_class() + fake_client = cls._get_client_class()() # Once we get fake client, return back authenticate method httpclient.HTTPClient.authenticate = authenticate @@ -146,7 +155,10 @@ class KeystoneAction(base.OpenStackAction): class CeilometerAction(base.OpenStackAction): - _client_class = ceilometerclient.Client + + @classmethod + def _get_client_class(cls): + return ceilometerclient.Client def _get_client(self): ctx = context.ctx() @@ -162,7 +174,7 @@ class CeilometerAction(base.OpenStackAction): {'tenant_id': ctx.project_id} ) - return self._client_class( + return CeilometerAction._get_client_class()( endpoint_url, region_name=ceilometer_endpoint.region, token=ctx.auth_token, @@ -171,11 +183,14 @@ class CeilometerAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class("") + return cls._get_client_class()("") class HeatAction(base.OpenStackAction): - _client_class = heatclient.Client + + @classmethod + def _get_client_class(cls): + return heatclient.Client def _get_client(self): ctx = context.ctx() @@ -192,7 +207,7 @@ class HeatAction(base.OpenStackAction): } ) - return self._client_class( + return HeatAction._get_client_class()( endpoint_url, region_name=heat_endpoint.region, token=ctx.auth_token, @@ -201,11 +216,14 @@ class HeatAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class("") + return cls._get_client_class()("") class NeutronAction(base.OpenStackAction): - _client_class = neutronclient.Client + + @classmethod + def _get_client_class(cls): + return neutronclient.Client def _get_client(self): ctx = context.ctx() @@ -214,7 +232,7 @@ class NeutronAction(base.OpenStackAction): neutron_endpoint = keystone_utils.get_endpoint_for_project('neutron') - return self._client_class( + return NeutronAction._get_client_class()( endpoint_url=neutron_endpoint.url, region_name=neutron_endpoint.region, token=ctx.auth_token, @@ -223,7 +241,10 @@ class NeutronAction(base.OpenStackAction): class CinderAction(base.OpenStackAction): - _client_class = cinderclient.Client + + @classmethod + def _get_client_class(cls): + return cinderclient.Client def _get_client(self): ctx = context.ctx() @@ -242,7 +263,7 @@ class CinderAction(base.OpenStackAction): } ) - client = self._client_class( + client = CinderAction._get_client_class()( ctx.user_name, ctx.auth_token, project_id=ctx.project_id, @@ -257,11 +278,14 @@ class CinderAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class() + return cls._get_client_class()() class MistralAction(base.OpenStackAction): - _client_class = mistralclient.Client + + @classmethod + def _get_client_class(cls): + return mistralclient.Client def _get_client(self): ctx = context.ctx() @@ -281,7 +305,7 @@ class MistralAction(base.OpenStackAction): auth_url = keystone_endpoint.url mistral_url = None - return self._client_class( + return MistralAction._get_client_class()( mistral_url=mistral_url, auth_token=ctx.auth_token, project_id=ctx.project_id, @@ -291,11 +315,14 @@ class MistralAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class() + return cls._get_client_class()() class TroveAction(base.OpenStackAction): - _client_class = troveclient.Client + + @classmethod + def _get_client_class(cls): + return troveclient.Client def _get_client(self): ctx = context.ctx() @@ -311,7 +338,7 @@ class TroveAction(base.OpenStackAction): {'tenant_id': ctx.project_id} ) - client = self._client_class( + client = TroveAction._get_client_class()( ctx.user_name, ctx.auth_token, project_id=ctx.project_id, @@ -326,11 +353,14 @@ class TroveAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class("fake_user", "fake_passwd") + return cls._get_client_class()("fake_user", "fake_passwd") class IronicAction(base.OpenStackAction): - _client_class = ironicclient.Client + + @classmethod + def _get_client_class(cls): + return ironicclient.Client def _get_client(self): ctx = context.ctx() @@ -339,7 +369,7 @@ class IronicAction(base.OpenStackAction): ironic_endpoint = keystone_utils.get_endpoint_for_project('ironic') - return self._client_class( + return IronicAction._get_client_class()( ironic_endpoint.url, token=ctx.auth_token, region_name=ironic_endpoint.region @@ -347,11 +377,14 @@ class IronicAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class("http://127.0.0.1:6385/") + return cls._get_client_class()("http://127.0.0.1:6385/") class BaremetalIntrospectionAction(base.OpenStackAction): - _client_class = ironic_inspector_client.ClientV1 + + @classmethod + def _get_client_class(cls): + return ironic_inspector_client.ClientV1 def _get_client(self): ctx = context.ctx() @@ -362,7 +395,7 @@ class BaremetalIntrospectionAction(base.OpenStackAction): service_type='baremetal-introspection' ) - return self._client_class( + return BaremetalIntrospectionAction._get_client_class()( api_version=1, inspector_url=inspector_endpoint.url, auth_token=ctx.auth_token, @@ -370,7 +403,10 @@ class BaremetalIntrospectionAction(base.OpenStackAction): class SwiftAction(base.OpenStackAction): - _client_class = swift_client.Connection + + @classmethod + def _get_client_class(cls): + return swift_client.Connection def _get_client(self): ctx = context.ctx() @@ -384,11 +420,14 @@ class SwiftAction(base.OpenStackAction): 'preauthtoken': ctx.auth_token } - return self._client_class(**kwargs) + return SwiftAction._get_client_class()(**kwargs) class ZaqarAction(base.OpenStackAction): - _client_class = zaqarclient.Client + + @classmethod + def _get_client_class(cls): + return zaqarclient.Client def _get_client(self): ctx = context.ctx() @@ -407,11 +446,11 @@ class ZaqarAction(base.OpenStackAction): auth_opts = {'backend': 'keystone', 'options': opts} conf = {'auth_opts': auth_opts} - return self._client_class(zaqar_endpoint.url, conf=conf) + return ZaqarAction._get_client_class()(zaqar_endpoint.url, conf=conf) @classmethod def _get_fake_client(cls): - return cls._client_class("") + return cls._get_client_class()("") @classmethod def _get_client_method(cls, client): @@ -481,7 +520,10 @@ class ZaqarAction(base.OpenStackAction): class BarbicanAction(base.OpenStackAction): - _client_class = barbicanclient.Client + + @classmethod + def _get_client_class(cls): + return barbicanclient.Client def _get_client(self): ctx = context.ctx() @@ -498,7 +540,7 @@ class BarbicanAction(base.OpenStackAction): tenant_id=ctx.project_id ) - return self._client_class( + return BarbicanAction._get_client_class()( project_id=ctx.project_id, endpoint=barbican_endpoint.url, auth=auth @@ -506,7 +548,7 @@ class BarbicanAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class( + return cls._get_client_class()( project_id="1", endpoint="http://127.0.0.1:9311" ) @@ -580,7 +622,10 @@ class BarbicanAction(base.OpenStackAction): class DesignateAction(base.OpenStackAction): - _client_class = designateclient.Client + + @classmethod + def _get_client_class(cls): + return designateclient.Client def _get_client(self): ctx = context.ctx() @@ -596,7 +641,7 @@ class DesignateAction(base.OpenStackAction): {'tenant_id': ctx.project_id} ) - client = self._client_class( + client = DesignateAction._get_client_class()( endpoint=designate_url, tenant_id=ctx.project_id, auth_url=ctx.auth_uri, @@ -611,11 +656,14 @@ class DesignateAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class() + return cls._get_client_class()() class MagnumAction(base.OpenStackAction): - _client_class = magnumclient.Client + + @classmethod + def _get_client_class(cls): + return magnumclient.Client def _get_client(self): ctx = context.ctx() @@ -626,7 +674,7 @@ class MagnumAction(base.OpenStackAction): auth_url = keystone_endpoint.url magnum_url = keystone_utils.get_endpoint_for_project('magnum').url - return self._client_class( + return MagnumAction._get_client_class()( magnum_url=magnum_url, auth_token=ctx.auth_token, project_id=ctx.project_id, @@ -636,11 +684,14 @@ class MagnumAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class() + return cls._get_client_class()() class MuranoAction(base.OpenStackAction): - _client_class = muranoclient.Client + + @classmethod + def _get_client_class(cls): + return muranoclient.Client def _get_client(self): ctx = context.ctx() @@ -650,7 +701,7 @@ class MuranoAction(base.OpenStackAction): keystone_endpoint = keystone_utils.get_keystone_endpoint_v2() murano_endpoint = keystone_utils.get_endpoint_for_project('murano') - return self._client_class( + return MuranoAction._get_client_class()( endpoint=murano_endpoint.url, token=ctx.auth_token, tenant=ctx.project_id, @@ -660,11 +711,14 @@ class MuranoAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class() + return cls._get_client_class()() class TackerAction(base.OpenStackAction): - _client_class = tackerclient.Client + + @classmethod + def _get_client_class(cls): + return tackerclient.Client def _get_client(self): ctx = context.ctx() @@ -674,7 +728,7 @@ class TackerAction(base.OpenStackAction): keystone_endpoint = keystone_utils.get_keystone_endpoint_v2() tacker_endpoint = keystone_utils.get_endpoint_for_project('tacker') - return self._client_class( + return TackerAction._get_client_class()( endpoint_url=tacker_endpoint.url, token=ctx.auth_token, tenant_id=ctx.project_id, @@ -684,4 +738,4 @@ class TackerAction(base.OpenStackAction): @classmethod def _get_fake_client(cls): - return cls._client_class() + return cls._get_client_class()() diff --git a/mistral/actions/openstack/base.py b/mistral/actions/openstack/base.py index 7a55b003..276960f1 100644 --- a/mistral/actions/openstack/base.py +++ b/mistral/actions/openstack/base.py @@ -31,7 +31,6 @@ class OpenStackAction(base.Action): which are constructed via OpenStack Action generators. """ _kwargs_for_run = {} - _client_class = None client_method_name = None def __init__(self, **kwargs): @@ -64,8 +63,8 @@ class OpenStackAction(base.Action): It is needed for getting client-method args and description for saving into DB. """ - # Default is simple _client_class instance - return cls._client_class() + # Default is simple _get_client_class instance + return cls._get_client_class() @classmethod def get_fake_client_method(cls):