Rob Crittenden <rcrit...@redhat.com> wrote: > Jan Zelený wrote: > > Loading of the schema is now performed in the first request that requires > > it. > > > > https://fedorahosted.org/freeipa/ticket/583 > > > > Jan > > We still need to enforce that we get the schema, some low-level > functions depend on it. Also, if the UI doesn't get its aciattrs (which > are derived from the schema) then nothing will be editable. > > I'm getting this backtrace if I force no schema by disabling get_schema:
Ok, I'm sending new version, it should handle these exceptions better and the operation should fail if it needs the schema and the schema is not available for some reason. -- Thank you Jan Zeleny Red Hat Software Engineer Brno, Czech Republic
From 5ef34748ad1b2d055c86e6674f060d78ad2f8f5f Mon Sep 17 00:00:00 2001 From: Jan Zeleny <jzel...@redhat.com> Date: Tue, 15 Feb 2011 09:37:58 +0100 Subject: [PATCH] Don't load the LDAP schema during startup https://fedorahosted.org/freeipa/ticket/583 --- ipalib/encoder.py | 11 +++-- ipalib/plugins/baseldap.py | 6 ++- ipaserver/install/dsinstance.py | 2 +- ipaserver/plugins/ldap2.py | 79 ++++++++++++++++++++++++++------------ 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/ipalib/encoder.py b/ipalib/encoder.py index f23e5659e848d37db1072ff59aa7e11796b0836c..1874d903aa0dc2a8c9ee1497164b9d418457c82a 100644 --- a/ipalib/encoder.py +++ b/ipalib/encoder.py @@ -56,11 +56,12 @@ class Encoder(object): self.encoder_settings = EncoderSettings() def _decode_dict_val(self, key, val): - f = self.encoder_settings.decode_dict_vals_table.get( - self.encoder_settings.decode_dict_vals_table_keygen(key, val) - ) + key = self.encoder_settings.decode_dict_vals_table_keygen(key, val) + if key is None: + return None + f = self.encoder_settings.decode_dict_vals_table.get(key) if f: - return val + return f(val) return self.decode(val) def encode(self, var): @@ -155,6 +156,8 @@ class Encoder(object): self.encoder_settings.decode_postprocessor = lambda x: x for (k, v) in dct.iteritems(): dct[k] = self._decode_dict_val(k, v) + if dct[k] is None: + return None if not self.encoder_settings.decode_dict_vals_postprocess: self.encoder_settings.decode_postprocessor = tmp return dct diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index 3cb72d7b09cc8c8a77bd4e594660ee376d668013..8866c2f6f1c84b9b5b785562db34b82481a52fb9 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -394,7 +394,11 @@ class LDAPObject(Object): objectclasses += self.possible_objectclasses # Get list of available attributes for this object for use # in the ACI UI. - attrs = self.api.Backend.ldap2.schema.attribute_types(objectclasses) + schema = self.api.Backend.ldap2.get_schema() + if not schema: + attrs = [] + else: + attrs = schema.attribute_types(objectclasses) attrlist = [] # Go through the MUST first for (oid, attr) in attrs[0].iteritems(): diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 2544e167bdff28c13201c5371070ab729ca84b67..c2081700bb7348f4db7e3467f64d040effd07cbe 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -133,7 +133,7 @@ def has_managed_entries(host_name, dm_password): conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='cn=config') conn.connect(bind_dn='cn=Directory Manager', bind_pw=dm_password) (dn, attrs) = conn.get_entry('cn=Managed Entries,cn=plugins', - ['*'], time_limit=2, size_limit=3000) + ['*'], time_limit=2, size_limit=3000, override=True) return True except errors.NotFound: return False diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index d1e31f5e6eff20cd162c0a11eb4e4404b43ae4b2..3ef076a3dd0c92422bea8fdd29b01e8e311be8ae 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -184,12 +184,6 @@ def get_schema(url, conn=None): return _ldap.schema.SubSchema(schema_entry[1]) -# cache schema when importing module -try: - _schema = get_schema(api.env.ldap_uri) -except AttributeError: - _schema = None - # The UPG setting will be cached the first time a module checks it _upg = None @@ -229,7 +223,6 @@ class ldap2(CrudBackend, Encoder): def __init__(self, shared_instance=True, ldap_uri=None, base_dn=None, schema=None): - global _schema CrudBackend.__init__(self, shared_instance=shared_instance) Encoder.__init__(self) self.encoder_settings.encode_dict_keys = True @@ -249,7 +242,7 @@ class ldap2(CrudBackend, Encoder): self.base_dn = api.env.basedn except AttributeError: self.base_dn = '' - self.schema = schema or _schema + self.schema = schema def __del__(self): if self.isconnected(): @@ -260,7 +253,9 @@ class ldap2(CrudBackend, Encoder): def get_syntax(self, attr, value): if not self.schema: - return None + self.schema = get_schema(self.ldap_uri, self.conn) + if not self.schema: + return None obj = self.schema.get_obj(_ldap.schema.AttributeType, attr) if obj is not None: return obj.syntax @@ -269,7 +264,9 @@ class ldap2(CrudBackend, Encoder): def get_allowed_attributes(self, objectclasses): if not self.schema: - return [] + self.schema = get_schema(self.ldap_uri, self.conn) + if not self.schema: + return [] allowed_attributes = [] for oc in objectclasses: obj = self.schema.get_obj(_ldap.schema.ObjectClass, oc) @@ -286,10 +283,15 @@ class ldap2(CrudBackend, Encoder): If there is a problem loading the schema or the attribute is not in the schema return None """ - if self.schema: - obj = self.schema.get_obj(_ldap.schema.AttributeType, attr) - return obj and obj.single_value - return None + if not self.schema: + self.schema = get_schema(self.ldap_uri, self.conn) + if not self.schema: + # if we cannot load the schema, it's safer to assume + # the attribute is single-valued + return True + + obj = self.schema.get_obj(_ldap.schema.AttributeType, attr) + return obj and obj.single_value @encode_args(2, 3, 'bind_dn', 'bind_pw') def create_connection(self, ccache=None, bind_dn='', bind_pw='', @@ -310,7 +312,6 @@ class ldap2(CrudBackend, Encoder): Extends backend.Connectible.create_connection. """ - global _schema if tls_cacertfile is not None: _ldap.set_option(_ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile) if tls_certfile is not None: @@ -335,10 +336,10 @@ class ldap2(CrudBackend, Encoder): except _ldap.LDAPError, e: _handle_errors(e, **{}) - if self.schema is None and _schema is None: - # explicitly use setattr here so the schema can be set after - # the object is finalized. - object.__setattr__(self, 'schema', get_schema(self.ldap_uri, conn)) + # For now let's say the schema is None (will be loaded later) + # - explicitly use setattr here so the schema can be set after + # the object is finalized. + object.__setattr__(self, 'schema', None) return conn def destroy_connection(self): @@ -613,20 +614,26 @@ class ldap2(CrudBackend, Encoder): """ search_kw = {attr: value, 'objectClass': object_class} filter = self.make_filter(search_kw, rules=self.MATCH_ALL) - return self.find_entries(filter, attrs_list, base_dn)[0][0] + entries = self.find_entries(filter, attrs_list, base_dn)[0][0] + if entries[1] is None: + raise errors.InternalError() + return entries def get_entry(self, dn, attrs_list=None, time_limit=None, - size_limit=None, normalize=True): + size_limit=None, normalize=True, override=False): """ Get entry (dn, entry_attrs) by dn. Keyword arguments: attrs_list - list of attributes to return, all if None (default None) """ - return self.find_entries( + entries = self.find_entries( None, attrs_list, dn, self.SCOPE_BASE, time_limit=time_limit, size_limit=size_limit, normalize=normalize )[0][0] + if entries[1] is None and not override: + raise errors.InternalError() + return entries config_defaults = {'ipasearchtimelimit': [2], 'ipasearchrecordslimit': [0]} def get_ipa_config(self, attrs_list=None): @@ -639,14 +646,24 @@ class ldap2(CrudBackend, Encoder): )[0][0] except errors.NotFound: config_entry = {} + + if not config_entry: + raise errors.InternalError() + for a in self.config_defaults: if a not in config_entry: config_entry[a] = self.config_defaults[a] return (cdn, config_entry) - def get_schema(self): - """Returns a copy of the current LDAP schema.""" - return copy.deepcopy(self.schema) + def get_schema(self, deepcopy=False): + """ Returns either a reference to current schema or its deep copy """ + if not self.schema: + self.schema = get_schema(self.ldap_uri, self.conn) + + if (deepcopy): + return copy.deepcopy(self.schema) + else: + return self.schema def has_upg(self): """Returns True/False whether User-Private Groups are enabled. @@ -931,6 +948,9 @@ class ldap2(CrudBackend, Encoder): size_limit=size_limit, normalize=normalize) except errors.NotFound: netresults = [] + + if results is None: + results = [] results = results + netresults if membertype == MEMBERS_ALL: @@ -993,6 +1013,9 @@ class ldap2(CrudBackend, Encoder): size_limit=size_limit, normalize=normalize) except errors.NotFound: netresults = [] + + if results is None: + results = [] results = results + netresults try: (pbacresults, truncated) = self.find_entries(searchfilter, @@ -1001,6 +1024,9 @@ class ldap2(CrudBackend, Encoder): normalize=normalize) except errors.NotFound: pbacresults = [] + + if pbacresults is None: + pbacresults = [] results = results + pbacresults direct = [] @@ -1134,6 +1160,9 @@ class ldap2(CrudBackend, Encoder): (entries, truncated) = self.find_entries( filter, attrs_list, base_dn, scope ) + if entries is None: + return (len(output), output) + for (dn, entry_attrs) in entries: entry_attrs['dn'] = [dn] output.append(entry_attrs) -- 1.7.4
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel