plugable: Pass API to plugins on initialization rather than using set_api

https://fedorahosted.org/freeipa/ticket/3090

Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
This commit is contained in:
Jan Cholasta
2015-06-22 10:58:43 +00:00
parent 2d1515323a
commit e39fe4ed31
38 changed files with 209 additions and 278 deletions

View File

@@ -292,7 +292,7 @@ does that, and the backend plugins are only installed on the server. The
``user_add.execute()`` method, which is only called when in a server context,
is implemented as a series of calls to methods on the ``ldap`` backend plugin.
When `plugable.Plugin.set_api()` is called, each plugin stores a reference to
When `plugable.Plugin.__init__()` is called, each plugin stores a reference to
the `plugable.API` instance it has been loaded into. So your plugin can
access the ``my_backend`` plugin as ``self.api.Backend.my_backend``.
@@ -668,7 +668,7 @@ See the `ipalib.cli.textui` plugin for a description of its methods.
Logging from your plugin
------------------------
After `plugable.Plugin.set_api()` is called, your plugin will have a
After `plugable.Plugin.__init__()` is called, your plugin will have a
``self.log`` attribute. Plugins should only log through this attribute.
For example:

View File

@@ -43,8 +43,8 @@ class Connectible(Backend):
`request.destroy_context()` can properly close all open connections.
"""
def __init__(self, shared_instance=False):
Backend.__init__(self)
def __init__(self, api, shared_instance=False):
Backend.__init__(self, api)
if shared_instance:
self.id = self.name
else:

View File

@@ -715,7 +715,7 @@ class help(frontend.Local):
self._builtins = []
# build help topics
for c in self.Command():
for c in self.api.Command():
if c.NO_CLI:
continue

View File

@@ -1250,12 +1250,12 @@ class Attribute(Plugin):
# Create stubs for attributes that are set in _on_finalize()
__obj = Plugin.finalize_attr('_Attribute__obj')
def __init__(self):
def __init__(self, api):
m = self.NAME_REGEX.match(type(self).__name__)
assert m
self.__obj_name = m.group('obj')
self.__attr_name = m.group('attr')
super(Attribute, self).__init__()
super(Attribute, self).__init__(api)
def __get_obj_name(self):
return self.__obj_name
@@ -1347,9 +1347,6 @@ class Method(Attribute, Command):
extra_options_first = False
extra_args_first = False
def __init__(self):
super(Method, self).__init__()
def get_output_params(self):
for param in self.obj.params():
if 'no_output' in param.flags:

View File

@@ -224,8 +224,9 @@ class Plugin(ReadOnly):
label = None
def __init__(self):
self.__api = None
def __init__(self, api):
assert api is not None
self.__api = api
self.__finalize_called = False
self.__finalized = False
self.__finalize_lock = threading.RLock()
@@ -254,14 +255,27 @@ class Plugin(ReadOnly):
)
)
def __get_api(self):
@property
def api(self):
"""
Return `API` instance passed to `set_api()`.
If `set_api()` has not yet been called, None is returned.
Return `API` instance passed to `__init__()`.
"""
return self.__api
api = property(__get_api)
# FIXME: for backward compatibility only
@property
def env(self):
return self.__api.env
# FIXME: for backward compatibility only
@property
def Backend(self):
return self.__api.Backend
# FIXME: for backward compatibility only
@property
def Command(self):
return self.__api.Command
def finalize(self):
"""
@@ -336,23 +350,6 @@ class Plugin(ReadOnly):
"attribute '%s' of plugin '%s' was not set in finalize()" % (self.name, obj.name)
)
def set_api(self, api):
"""
Set reference to `API` instance.
"""
assert self.__api is None, 'set_api() can only be called once'
assert api is not None, 'set_api() argument cannot be None'
self.__api = api
if not isinstance(api, API):
return
for name in api:
assert not hasattr(self, name)
setattr(self, name, api[name])
for name in ('env', 'context'):
if hasattr(api, name):
assert not hasattr(self, name)
setattr(self, name, getattr(api, name))
def call(self, executable, *args):
"""
Call ``executable`` with ``args`` using subprocess.call().
@@ -746,7 +743,7 @@ class API(DictProxy):
try:
instance = plugins[klass]
except KeyError:
instance = plugins[klass] = klass()
instance = plugins[klass] = klass(self)
members.append(instance)
plugin_info.setdefault(
'%s.%s' % (klass.__module__, klass.__name__),
@@ -760,9 +757,6 @@ class API(DictProxy):
self.__d[name] = namespace
object.__setattr__(self, name, namespace)
for instance in plugins.itervalues():
instance.set_api(self)
for klass, instance in plugins.iteritems():
if not production_mode:
assert instance.api is self

View File

@@ -879,7 +879,7 @@ can use their Kerberos accounts.''')
return dict(result={}, failed={}, enabled=False, compat=True)
# connect to DS
ds_ldap = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='')
ds_ldap = ldap2(self.api, ldap_uri=ldapuri)
cacert = None
if options.get('cacertfile') is not None:

View File

@@ -133,11 +133,6 @@ class plugins(LocalOrRemote):
)
def execute(self, **options):
plugins = sorted(self.api.plugins, key=lambda o: o.plugin)
return dict(
result=dict(
(p.plugin, p.bases) for p in plugins
),
count=len(plugins),
result=dict(self.api.plugins),
)

View File

@@ -945,9 +945,7 @@ class user_status(LDAPQuery):
if host == api.env.host:
other_ldap = self.obj.backend
else:
other_ldap = ldap2(shared_instance=False,
ldap_uri='ldap://%s' % host,
base_dn=self.api.env.basedn)
other_ldap = ldap2(self.api, ldap_uri='ldap://%s' % host)
try:
other_ldap.connect(ccache=os.environ['KRB5CCNAME'])
except Exception, e: