diff options
author | Jan Cholasta <jcholast@redhat.com> | 2011-11-01 08:58:05 -0400 |
---|---|---|
committer | Alexander Bokovoy <abokovoy@redhat.com> | 2012-01-02 11:51:26 +0300 |
commit | 9beb467d98cb16e09fcda5ebbeb27056dfff3a2d (patch) | |
tree | d374273454f5fa5627eb1fe83782c437cdbddde2 | |
parent | 46d3abc450db20c3e4c0854dbf9e711f59db3bff (diff) | |
download | freeipa.git-9beb467d98cb16e09fcda5ebbeb27056dfff3a2d.tar.gz freeipa.git-9beb467d98cb16e09fcda5ebbeb27056dfff3a2d.tar.xz freeipa.git-9beb467d98cb16e09fcda5ebbeb27056dfff3a2d.zip |
Fix attempted write to attribute of read-only object.
Add new class "cachedproperty" for creating property-like attributes
that cache the return value of a method call.
Also fix few issues in the unit tests to enable them to succeed.
ticket 1959
-rw-r--r-- | ipalib/dn.py | 2 | ||||
-rw-r--r-- | ipalib/errors.py | 6 | ||||
-rw-r--r-- | ipalib/util.py | 34 | ||||
-rw-r--r-- | ipaserver/install/ldapupdate.py | 4 | ||||
-rw-r--r-- | ipaserver/ipaldap.py | 2 | ||||
-rw-r--r-- | ipaserver/plugins/dogtag.py | 10 | ||||
-rw-r--r-- | ipaserver/plugins/ldap2.py | 2 | ||||
-rw-r--r-- | tests/test_ipalib/test_plugable.py | 2 | ||||
-rw-r--r-- | tests/test_ipaserver/test_ldap.py | 10 |
9 files changed, 55 insertions, 17 deletions
diff --git a/ipalib/dn.py b/ipalib/dn.py index dc3119d9..6f2f7deb 100644 --- a/ipalib/dn.py +++ b/ipalib/dn.py @@ -1092,7 +1092,7 @@ class DN(object): return rdns elif isinstance(value, (tuple, list)): if len(value) != 2: - raise ValueError("tuple or list must be 2-valued, not \"%s\"" % (rdn)) + raise ValueError("tuple or list must be 2-valued, not \"%s\"" % (value)) rdn = RDN(value, first_key_match=self.first_key_match) return rdn else: diff --git a/ipalib/errors.py b/ipalib/errors.py index 5b634880..f115f0c4 100644 --- a/ipalib/errors.py +++ b/ipalib/errors.py @@ -448,10 +448,10 @@ class RefererError(PublicError): For example: - >>> raise RefererError() + >>> raise RefererError(referer='referer') Traceback (most recent call last): ... - RefererError: Missing or invalid HTTP Referer + RefererError: Missing or invalid HTTP Referer, referer """ errno = 911 @@ -1537,7 +1537,7 @@ class DependentEntry(ExecutionError): >>> raise DependentEntry(label=u'SELinux User Map', key=u'test', dependent=u'test1') Traceback (most recent call last): ... - DependentEntry: Not registered yet + DependentEntry: test cannot be deleted because SELinux User Map test1 requires it """ diff --git a/ipalib/util.py b/ipalib/util.py index ffa27594..d575329e 100644 --- a/ipalib/util.py +++ b/ipalib/util.py @@ -27,6 +27,7 @@ import time import socket import re from types import NoneType +from weakref import WeakKeyDictionary from ipalib import errors from ipalib.text import _ @@ -272,3 +273,36 @@ def validate_hostname(hostname): if not all(regex_name.match(part) for part in hostname.split(".")): raise ValueError(_('hostname parts may only include letters, numbers, and - ' \ '(which is not allowed as the last character)')) + +class cachedproperty(object): + """ + A property-like attribute that caches the return value of a method call. + + When the attribute is first read, the method is called and its return + value is saved and returned. On subsequent reads, the saved value is + returned. + + Typical usage: + class C(object): + @cachedproperty + def attr(self): + return 'value' + """ + __slots__ = ('getter', 'store') + + def __init__(self, getter): + self.getter = getter + self.store = WeakKeyDictionary() + + def __get__(self, obj, cls): + if obj is None: + return None + if obj not in self.store: + self.store[obj] = self.getter(obj) + return self.store[obj] + + def __set__(self, obj, value): + raise AttributeError("can't set attribute") + + def __delete__(self, obj): + raise AttributeError("can't delete attribute") diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 91d3d83c..8fbfeaf5 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -700,7 +700,7 @@ class LDAPUpdate: self.conn.deleteEntry(dn) self.modified = True except errors.NotFound, e: - root_logger.info("%s did not exist:%s", (dn, e)) + root_logger.info("%s did not exist:%s", dn, e) self.modified = True except errors.DatabaseError, e: root_logger.error("Delete failed: %s", e) @@ -717,7 +717,7 @@ class LDAPUpdate: self.conn.deleteEntry(dn) self.modified = True except errors.NotFound, e: - root_logger.info("%s did not exist:%s", (dn, e)) + root_logger.info("%s did not exist:%s", dn, e) self.modified = True except errors.DatabaseError, e: root_logger.error("Delete failed: %s", e) diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py index ae36dd23..4dca6046 100644 --- a/ipaserver/ipaldap.py +++ b/ipaserver/ipaldap.py @@ -314,7 +314,7 @@ class IPAdmin(IPAEntryLDAPObject): raise errors.DuplicateEntry() except ldap.CONSTRAINT_VIOLATION, e: # This error gets thrown by the uniqueness plugin - if info == 'Another entry with the same attribute value already exists': + if info.startswith('Another entry with the same attribute value already exists'): raise errors.DuplicateEntry() else: raise errors.DatabaseError(desc=desc,info=info) diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py index 23d06abc..b31058c1 100644 --- a/ipaserver/plugins/dogtag.py +++ b/ipaserver/plugins/dogtag.py @@ -1200,6 +1200,7 @@ import os, random, ldap from ipaserver.plugins import rabase from ipalib.errors import NetworkError, CertificateOperationError from ipalib.constants import TYPE_ERROR +from ipalib.util import cachedproperty from ipapython import dogtag from ipalib import _ @@ -1218,7 +1219,6 @@ class ra(rabase.rabase): self.ipa_key_size = "2048" self.ipa_certificate_nickname = "ipaCert" self.ca_certificate_nickname = "caCert" - self.ca_host = None try: f = open(self.pwd_file, "r") self.password = f.readline().strip() @@ -1266,7 +1266,8 @@ class ra(rabase.rabase): pass return None - def _select_ca(self): + @cachedproperty + def ca_host(self): """ :return: host as str @@ -1293,8 +1294,6 @@ class ra(rabase.rabase): Perform an HTTP request. """ - if self.ca_host == None: - self.ca_host = self._select_ca() return dogtag.http_request(self.ca_host, port, url, **kw) def _sslget(self, url, port, **kw): @@ -1306,9 +1305,6 @@ class ra(rabase.rabase): Perform an HTTPS request """ - - if self.ca_host == None: - self.ca_host = self._select_ca() return dogtag.https_request(self.ca_host, port, url, self.sec_dir, self.password, self.ipa_certificate_nickname, **kw) def get_parse_result_xml(self, xml_text, parse_func): diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index 4bfc849d..06980345 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -210,7 +210,7 @@ def _handle_errors(e, **kw): raise errors.DuplicateEntry() except _ldap.CONSTRAINT_VIOLATION: # This error gets thrown by the uniqueness plugin - if info == 'Another entry with the same attribute value already exists': + if info.startswith('Another entry with the same attribute value already exists'): raise errors.DuplicateEntry() else: raise errors.DatabaseError(desc=desc, info=info) diff --git a/tests/test_ipalib/test_plugable.py b/tests/test_ipalib/test_plugable.py index 23b73309..3355e057 100644 --- a/tests/test_ipalib/test_plugable.py +++ b/tests/test_ipalib/test_plugable.py @@ -247,7 +247,7 @@ class test_Plugin(ClassChecker): info = 'whatever' e = raises(StandardError, check) assert str(e) == \ - "check.info attribute ('whatever') conflicts with Plugin logger" + "info is already bound to tests.test_ipalib.test_plugable.check()" def test_set_api(self): """ diff --git a/tests/test_ipaserver/test_ldap.py b/tests/test_ipaserver/test_ldap.py index abfd1be7..1bbd94fb 100644 --- a/tests/test_ipaserver/test_ldap.py +++ b/tests/test_ipaserver/test_ldap.py @@ -112,7 +112,15 @@ class test_ldap(object): myapi.register(service) myapi.register(service_show) myapi.finalize() - myapi.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw='password') + + pwfile = api.env.dot_ipa + os.sep + ".dmpw" + if ipautil.file_exists(pwfile): + fp = open(pwfile, "r") + dm_password = fp.read().rstrip() + fp.close() + else: + raise nose.SkipTest("No directory manager password in %s" % pwfile) + myapi.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dm_password) result = myapi.Command['service_show']('ldap/%s@%s' % (api.env.host, api.env.realm,)) entry_attrs = result['result'] |