diff options
-rw-r--r-- | ipalib/errors.py | 17 | ||||
-rw-r--r-- | ipaserver/plugins/ldap2.py | 7 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_host_plugin.py | 35 |
3 files changed, 58 insertions, 1 deletions
diff --git a/ipalib/errors.py b/ipalib/errors.py index cad6e37b4..04211e6ed 100644 --- a/ipalib/errors.py +++ b/ipalib/errors.py @@ -1210,6 +1210,23 @@ class AttrValueNotFound(ExecutionError): format = _('%(attr)s does not contain \'%(value)s\'') +class SingleMatchExpected(ExecutionError): + """ + **4027** Raised when a search should return a single match + + For example: + + >>> raise SingleMatchExpected(found=9) + Traceback (most recent call last): + ... + SingleMatchExpected: The search criteria was not specific enough. Expected 1 and found 9. + """ + + errno = 4027 + rval = 1 + format = _('The search criteria was not specific enough. Expected 1 and found %(found)d.') + + class BuiltinError(ExecutionError): """ **4100** Base class for builtin execution errors (*4100 - 4199*). diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index 5d6d21d43..6f34984ca 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -620,7 +620,12 @@ 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, truncated) = self.find_entries(filter, attrs_list, base_dn) + + if len(entries) > 1: + raise errors.SingleMatchExpected(found=len(entries)) + else: + return entries[0] def get_entry(self, dn, attrs_list=None, time_limit=None, size_limit=None, normalize=True): diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py index f4e020ed7..793729629 100644 --- a/tests/test_xmlrpc/test_host_plugin.py +++ b/tests/test_xmlrpc/test_host_plugin.py @@ -39,6 +39,8 @@ dn2 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn) fqdn3 = u'testhost2.%s' % api.env.domain short3 = u'testhost2' dn3 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn3, api.env.basedn) +fqdn4 = u'testhost2.lab.%s' % api.env.domain +dn4 = u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn4, api.env.basedn) # We can use the same cert we generated for the service tests fd = open('tests/test_xmlrpc/service.crt', 'r') @@ -53,6 +55,7 @@ class test_host(Declarative): ('host_del', [fqdn1], {}), ('host_del', [fqdn2], {}), ('host_del', [fqdn3], {}), + ('host_del', [fqdn4], {}), ('service_del', [service1], {}), ] @@ -295,6 +298,32 @@ class test_host(Declarative): dict( + desc='Create %r' % fqdn4, + command=('host_add', [fqdn4], + dict( + description=u'Test host 4', + l=u'Undisclosed location 4', + force=True, + ), + ), + expected=dict( + value=fqdn4, + summary=u'Added host "%s"' % fqdn4, + result=dict( + dn=dn4, + fqdn=[fqdn4], + description=[u'Test host 4'], + l=[u'Undisclosed location 4'], + krbprincipalname=[u'host/%s@%s' % (fqdn4, api.env.realm)], + objectclass=objectclasses.host, + ipauniqueid=[fuzzy_uuid], + managedby_host=[u'%s' % fqdn4], + ), + ), + ), + + + dict( desc='Add managedby_host %r to %r' % (fqdn1, fqdn3), command=('host_add_managedby', [fqdn3], dict( @@ -363,6 +392,12 @@ class test_host(Declarative): ), + dict( + desc='Show a host with multiple matches %s' % short3, + command=('host_show', [short3], {}), + expected=errors.SingleMatchExpected(found=2), + ), + dict( desc='Try to rename %r' % fqdn1, |