mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Finish work replacing the errors module with errors2
Once this is committed we can start the process of renaming errors2 as errors. I thought that combinig this into one commit would be more difficult to review.
This commit is contained in:
@@ -26,7 +26,7 @@ try:
|
||||
from ipapython import entity, ipautil, config
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
|
||||
from ipalib import errors, errors2
|
||||
from ipalib import errors2
|
||||
import ldap
|
||||
import logging
|
||||
import re
|
||||
|
@@ -36,8 +36,7 @@ import frontend
|
||||
import backend
|
||||
import plugable
|
||||
import util
|
||||
from errors2 import PublicError, CommandError, HelpError, InternalError
|
||||
import errors
|
||||
from errors2 import PublicError, CommandError, HelpError, InternalError, NoSuchNamespaceError, ValidationError
|
||||
from constants import CLI_TAB
|
||||
from parameters import Password, Bytes
|
||||
from request import ugettext as _
|
||||
@@ -456,7 +455,7 @@ class show_api(frontend.Application):
|
||||
else:
|
||||
for name in namespaces:
|
||||
if name not in self.api:
|
||||
raise errors.NoSuchNamespaceError(name)
|
||||
raise NoSuchNamespaceError(name=name)
|
||||
names = namespaces
|
||||
lines = self.__traverse(names)
|
||||
ml = max(len(l[1]) for l in lines)
|
||||
@@ -478,7 +477,6 @@ class show_api(frontend.Application):
|
||||
s = '%d attributes show.' % len(lines)
|
||||
self.Backend.textui.print_dashed(s)
|
||||
|
||||
|
||||
def __traverse(self, names):
|
||||
lines = []
|
||||
for name in names:
|
||||
@@ -635,7 +633,7 @@ class cli(backend.Executioner):
|
||||
if value is not None:
|
||||
kw[param.name] = value
|
||||
break
|
||||
except errors.ValidationError, e:
|
||||
except ValidationError, e:
|
||||
error = e.error
|
||||
|
||||
|
||||
|
441
ipalib/errors.py
441
ipalib/errors.py
@@ -1,441 +0,0 @@
|
||||
# Authors:
|
||||
# Jason Gerard DeRose <jderose@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2008 Red Hat
|
||||
# see file 'COPYING' for use and warranty inmsgion
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 only
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
All custom errors raised by `ipalib` package.
|
||||
|
||||
Also includes a few utility functions for raising exceptions.
|
||||
"""
|
||||
|
||||
IPA_ERROR_BASE = 1000
|
||||
|
||||
TYPE_FORMAT = '%s: need a %r; got %r'
|
||||
|
||||
def raise_TypeError(value, type_, name):
|
||||
"""
|
||||
Raises a TypeError with a nicely formatted message and helpful attributes.
|
||||
|
||||
The TypeError raised will have three custom attributes:
|
||||
|
||||
``value`` - The value (of incorrect type) passed as argument.
|
||||
|
||||
``type`` - The type expected for the argument.
|
||||
|
||||
``name`` - The name (identifier) of the argument in question.
|
||||
|
||||
There is no edict that all TypeError should be raised with raise_TypeError,
|
||||
but when it fits, use it... it makes the unit tests faster to write and
|
||||
the debugging easier to read.
|
||||
|
||||
Here is an example:
|
||||
|
||||
>>> raise_TypeError(u'Hello, world!', str, 'message')
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File "ipalib/errors.py", line 65, in raise_TypeError
|
||||
raise e
|
||||
TypeError: message: need a <type 'str'>; got u'Hello, world!'
|
||||
|
||||
:param value: The value (of incorrect type) passed as argument.
|
||||
:param type_: The type expected for the argument.
|
||||
:param name: The name (identifier) of the argument in question.
|
||||
"""
|
||||
|
||||
assert type(type_) is type, TYPE_FORMAT % ('type_', type, type_)
|
||||
assert type(value) is not type_, 'value: %r is a %r' % (value, type_)
|
||||
assert type(name) is str, TYPE_FORMAT % ('name', str, name)
|
||||
e = TypeError(TYPE_FORMAT % (name, type_, value))
|
||||
setattr(e, 'value', value)
|
||||
setattr(e, 'type', type_)
|
||||
setattr(e, 'name', name)
|
||||
raise e
|
||||
|
||||
|
||||
def check_type(value, type_, name, allow_none=False):
|
||||
assert type(name) is str, TYPE_FORMAT % ('name', str, name)
|
||||
assert type(type_) is type, TYPE_FORMAT % ('type_', type, type_)
|
||||
assert type(allow_none) is bool, TYPE_FORMAT % ('allow_none', bool, allow_none)
|
||||
if value is None and allow_none:
|
||||
return
|
||||
if type(value) is not type_:
|
||||
raise_TypeError(value, type_, name)
|
||||
return value
|
||||
|
||||
|
||||
def check_isinstance(value, type_, name, allow_none=False):
|
||||
assert type(type_) is type, TYPE_FORMAT % ('type_', type, type_)
|
||||
assert type(name) is str, TYPE_FORMAT % ('name', str, name)
|
||||
assert type(allow_none) is bool, TYPE_FORMAT % ('allow_none', bool, allow_none)
|
||||
if value is None and allow_none:
|
||||
return
|
||||
if not isinstance(value, type_):
|
||||
raise_TypeError(value, type_, name)
|
||||
return value
|
||||
|
||||
|
||||
class IPAError(StandardError):
|
||||
"""
|
||||
Base class for all custom IPA errors.
|
||||
|
||||
Use this base class for your custom IPA errors unless there is a
|
||||
specific reason to subclass from AttributeError, KeyError, etc.
|
||||
"""
|
||||
|
||||
format = None
|
||||
faultCode = 1
|
||||
|
||||
def __init__(self, *args):
|
||||
self.args = args
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Returns the string representation of this exception.
|
||||
"""
|
||||
return self.format % self.args
|
||||
|
||||
|
||||
class InvocationError(IPAError):
|
||||
pass
|
||||
|
||||
|
||||
class UnknownCommandError(InvocationError):
|
||||
format = 'unknown command "%s"'
|
||||
|
||||
class NoSuchNamespaceError(InvocationError):
|
||||
format = 'api has no such namespace: %s'
|
||||
|
||||
def _(text):
|
||||
return text
|
||||
|
||||
|
||||
class SubprocessError(StandardError):
|
||||
def __init__(self, returncode, argv):
|
||||
self.returncode = returncode
|
||||
self.argv = argv
|
||||
StandardError.__init__(self,
|
||||
'return code %d from %r' % (returncode, argv)
|
||||
)
|
||||
|
||||
class HandledError(StandardError):
|
||||
"""
|
||||
Base class for errors that can be raised across a remote procedure call.
|
||||
"""
|
||||
|
||||
code = 1
|
||||
|
||||
def __init__(self, message=None, **kw):
|
||||
self.kw = kw
|
||||
if message is None:
|
||||
message = self.format % kw
|
||||
StandardError.__init__(self, message)
|
||||
|
||||
|
||||
class UnknownError(HandledError):
|
||||
"""
|
||||
Raised when the true error is not a handled error.
|
||||
"""
|
||||
|
||||
format = _('An unknown internal error has occurred')
|
||||
|
||||
|
||||
class CommandError(HandledError):
|
||||
"""
|
||||
Raised when an unknown command is called client-side.
|
||||
"""
|
||||
format = _('Unknown command %(name)r')
|
||||
|
||||
|
||||
class RemoteCommandError(HandledError):
|
||||
format = 'Server at %(uri)r has no command %(name)r'
|
||||
|
||||
|
||||
class UnknownHelpError(InvocationError):
|
||||
format = 'no command nor topic "%s"'
|
||||
|
||||
|
||||
class ArgumentError(IPAError):
|
||||
"""
|
||||
Raised when a command is called with wrong number of arguments.
|
||||
"""
|
||||
|
||||
format = '%s %s'
|
||||
|
||||
def __init__(self, command, error):
|
||||
self.command = command
|
||||
self.error = error
|
||||
IPAError.__init__(self, command.name, error)
|
||||
|
||||
|
||||
class ValidationError(IPAError):
|
||||
"""
|
||||
Base class for all types of validation errors.
|
||||
"""
|
||||
|
||||
format = 'invalid %r value %r: %s'
|
||||
|
||||
def __init__(self, name, value, error, index=None):
|
||||
"""
|
||||
:param name: The name of the value that failed validation.
|
||||
:param value: The value that failed validation.
|
||||
:param error: The error message describing the failure.
|
||||
:param index: If multivalue, index of value in multivalue tuple
|
||||
"""
|
||||
assert type(name) is str
|
||||
assert index is None or (type(index) is int and index >= 0)
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.error = error
|
||||
self.index = index
|
||||
IPAError.__init__(self, name, value, error)
|
||||
|
||||
|
||||
class ConversionError(ValidationError):
|
||||
"""
|
||||
Raised when a value cannot be converted to the correct type.
|
||||
"""
|
||||
|
||||
def __init__(self, name, value, type_, index=None):
|
||||
self.type = type_
|
||||
ValidationError.__init__(self, name, value, type_.conversion_error,
|
||||
index=index,
|
||||
)
|
||||
|
||||
|
||||
class RuleError(ValidationError):
|
||||
"""
|
||||
Raised when a value fails a validation rule.
|
||||
"""
|
||||
def __init__(self, name, value, error, rule, index=None):
|
||||
assert callable(rule)
|
||||
self.rule = rule
|
||||
ValidationError.__init__(self, name, value, error, index=index)
|
||||
|
||||
|
||||
class RequirementError(ValidationError):
|
||||
"""
|
||||
Raised when a required option was not provided.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
ValidationError.__init__(self, name, None, 'Required')
|
||||
|
||||
|
||||
class RegistrationError(IPAError):
|
||||
"""
|
||||
Base class for errors that occur during plugin registration.
|
||||
"""
|
||||
|
||||
|
||||
class SubclassError(RegistrationError):
|
||||
"""
|
||||
Raised when registering a plugin that is not a subclass of one of the
|
||||
allowed bases.
|
||||
"""
|
||||
msg = 'plugin %r not subclass of any base in %r'
|
||||
|
||||
def __init__(self, cls, allowed):
|
||||
self.cls = cls
|
||||
self.allowed = allowed
|
||||
|
||||
def __str__(self):
|
||||
return self.msg % (self.cls, self.allowed)
|
||||
|
||||
|
||||
class DuplicateError(RegistrationError):
|
||||
"""
|
||||
Raised when registering a plugin whose exact class has already been
|
||||
registered.
|
||||
"""
|
||||
msg = '%r at %d was already registered'
|
||||
|
||||
def __init__(self, cls):
|
||||
self.cls = cls
|
||||
|
||||
def __str__(self):
|
||||
return self.msg % (self.cls, id(self.cls))
|
||||
|
||||
|
||||
class OverrideError(RegistrationError):
|
||||
"""
|
||||
Raised when override=False yet registering a plugin that overrides an
|
||||
existing plugin in the same namespace.
|
||||
"""
|
||||
msg = 'unexpected override of %s.%s with %r (use override=True if intended)'
|
||||
|
||||
def __init__(self, base, cls):
|
||||
self.base = base
|
||||
self.cls = cls
|
||||
|
||||
def __str__(self):
|
||||
return self.msg % (self.base.__name__, self.cls.__name__, self.cls)
|
||||
|
||||
|
||||
class MissingOverrideError(RegistrationError):
|
||||
"""
|
||||
Raised when override=True yet no preexisting plugin with the same name
|
||||
and base has been registered.
|
||||
"""
|
||||
msg = '%s.%s has not been registered, cannot override with %r'
|
||||
|
||||
def __init__(self, base, cls):
|
||||
self.base = base
|
||||
self.cls = cls
|
||||
|
||||
def __str__(self):
|
||||
return self.msg % (self.base.__name__, self.cls.__name__, self.cls)
|
||||
|
||||
class GenericError(IPAError):
|
||||
"""Base class for our custom exceptions"""
|
||||
faultCode = 1000
|
||||
fromFault = False
|
||||
def __str__(self):
|
||||
try:
|
||||
return str(self.args[0]['args'][0])
|
||||
except:
|
||||
try:
|
||||
return str(self.args[0])
|
||||
except:
|
||||
return str(self.__dict__)
|
||||
|
||||
class DatabaseError(GenericError):
|
||||
"""A database error has occurred"""
|
||||
faultCode = 1001
|
||||
|
||||
class MidairCollision(GenericError):
|
||||
"""Change collided with another change"""
|
||||
faultCode = 1002
|
||||
|
||||
class MissingDN(GenericError):
|
||||
"""The distinguished name (DN) is missing"""
|
||||
faultCode = 1005
|
||||
|
||||
class EmptyModlist(GenericError):
|
||||
"""No modifications to be performed"""
|
||||
faultCode = 1006
|
||||
|
||||
class InputError(GenericError):
|
||||
"""Error on input"""
|
||||
faultCode = 1007
|
||||
|
||||
class SameGroupError(InputError):
|
||||
"""You can't add a group to itself"""
|
||||
faultCode = 1008
|
||||
|
||||
class NotGroupMember(InputError):
|
||||
"""This entry is not a member of the group"""
|
||||
faultCode = 1009
|
||||
|
||||
class AdminsImmutable(InputError):
|
||||
"""The admins group cannot be renamed"""
|
||||
faultCode = 1010
|
||||
|
||||
class UsernameTooLong(InputError):
|
||||
"""The requested username is too long"""
|
||||
faultCode = 1011
|
||||
|
||||
class PrincipalError(GenericError):
|
||||
"""There is a problem with the kerberos principal"""
|
||||
faultCode = 1012
|
||||
|
||||
class PrincipalRequired(PrincipalError):
|
||||
"""You cannot remove IPA server service principals"""
|
||||
faultCode = 1015
|
||||
|
||||
class InactivationError(GenericError):
|
||||
"""This entry cannot be inactivated"""
|
||||
faultCode = 1016
|
||||
|
||||
class AlreadyActiveError(InactivationError):
|
||||
"""This entry is already locked"""
|
||||
faultCode = 1017
|
||||
|
||||
class AlreadyInactiveError(InactivationError):
|
||||
"""This entry is already unlocked"""
|
||||
faultCode = 1018
|
||||
|
||||
class HasNSAccountLock(InactivationError):
|
||||
"""This entry appears to have the nsAccountLock attribute in it so the Class of Service activation/inactivation will not work. You will need to remove the attribute nsAccountLock for this to work."""
|
||||
faultCode = 1019
|
||||
|
||||
class ConnectionError(GenericError):
|
||||
"""Connection to database failed"""
|
||||
faultCode = 1020
|
||||
|
||||
class NoCCacheError(GenericError):
|
||||
"""No Kerberos credentials cache is available. Connection cannot be made"""
|
||||
faultCode = 1021
|
||||
|
||||
class GSSAPIError(GenericError):
|
||||
"""GSSAPI Authorization error"""
|
||||
faultCode = 1022
|
||||
|
||||
class ServerUnwilling(GenericError):
|
||||
"""Account inactivated. Server is unwilling to perform"""
|
||||
faultCode = 1023
|
||||
|
||||
class ConfigurationError(GenericError):
|
||||
"""A configuration error occurred"""
|
||||
faultCode = 1024
|
||||
|
||||
class DefaultGroup(ConfigurationError):
|
||||
"""You cannot remove the default users group"""
|
||||
faultCode = 1025
|
||||
|
||||
class InvalidUserPrincipal(GenericError):
|
||||
"""Invalid user principal"""
|
||||
faultCode = 1028
|
||||
|
||||
class FunctionDeprecated(GenericError):
|
||||
"""Raised by a deprecated function"""
|
||||
faultCode = 2000
|
||||
|
||||
def convertFault(fault):
|
||||
"""Convert a fault to the corresponding Exception type, if possible"""
|
||||
code = getattr(fault,'faultCode',None)
|
||||
if code is None:
|
||||
return fault
|
||||
for v in globals().values():
|
||||
if type(v) == type(Exception) and issubclass(v,GenericError) and \
|
||||
code == getattr(v,'faultCode',None):
|
||||
ret = v(fault.faultString)
|
||||
ret.fromFault = True
|
||||
return ret
|
||||
#otherwise...
|
||||
return fault
|
||||
|
||||
def listFaults():
|
||||
"""Return a list of faults
|
||||
|
||||
Returns a list of dictionaries whose keys are:
|
||||
faultCode: the numeric code used in fault conversion
|
||||
name: the name of the exception
|
||||
desc: the description of the exception (docstring)
|
||||
"""
|
||||
ret = []
|
||||
for n,v in globals().items():
|
||||
if type(v) == type(Exception) and issubclass(v,GenericError):
|
||||
code = getattr(v,'faultCode',None)
|
||||
if code is None:
|
||||
continue
|
||||
info = {}
|
||||
info['faultCode'] = code
|
||||
info['name'] = n
|
||||
info['desc'] = getattr(v,'__doc__',None)
|
||||
ret.append(info)
|
||||
ret.sort(lambda a,b: cmp(a['faultCode'],b['faultCode']))
|
||||
return ret
|
@@ -699,6 +699,21 @@ class ValidationError(InvocationError):
|
||||
format = _('invalid %(name)r: %(error)s')
|
||||
|
||||
|
||||
class NoSuchNamespaceError(InvocationError):
|
||||
"""
|
||||
**3010** Raised when an unknown namespace is requested.
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise NoSuchNamespaceError(name='Plugins')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NoSuchNamespaceError: api has no such namespace: Plugins
|
||||
"""
|
||||
|
||||
errno = 3010
|
||||
format = _('api has no such namespace: %(name)r')
|
||||
|
||||
|
||||
##############################################################################
|
||||
# 4000 - 4999: Execution errors
|
||||
@@ -822,6 +837,102 @@ class AlreadyPosixGroup(ExecutionError):
|
||||
errno = 4007
|
||||
format = _('This is already a posix group')
|
||||
|
||||
class MalformedUserPrincipal(ExecutionError):
|
||||
"""
|
||||
**4008** Raised when a user principal is not of the form: user@REALM
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise MalformedUserPrincipal(principal=jsmith@@EXAMPLE.COM)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
MalformedUserPrincipal: Principal is not of the form user@REALM: jsmith@@EXAMPLE.COM
|
||||
|
||||
"""
|
||||
|
||||
errno = 4008
|
||||
format = _('Principal is not of the form user@REALM: %(principal)r')
|
||||
|
||||
class AlreadyActive(ExecutionError):
|
||||
"""
|
||||
**4009** Raised when an entry is made active that is already active
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise AlreadyActive()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AlreadyActive: This entry is already unlocked
|
||||
|
||||
"""
|
||||
|
||||
errno = 4009
|
||||
format = _('This entry is already unlocked')
|
||||
|
||||
class AlreadyInactive(ExecutionError):
|
||||
"""
|
||||
**4010** Raised when an entry is made inactive that is already inactive
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise AlreadyInactive()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AlreadyInactive: This entry is already locked
|
||||
|
||||
"""
|
||||
|
||||
errno = 4010
|
||||
format = _('This entry is already locked')
|
||||
|
||||
class HasNSAccountLock(ExecutionError):
|
||||
"""
|
||||
**4011** Raised when an entry has the nsAccountLock attribute set
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise HasNSAccountLock()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
HasNSAccountLock: This entry has nsAccountLock set, it cannot be locked or unlocked
|
||||
|
||||
"""
|
||||
|
||||
errno = 4011
|
||||
format = _('This entry has nsAccountLock set, it cannot be locked or unlocked')
|
||||
|
||||
class NotGroupMember(ExecutionError):
|
||||
"""
|
||||
**4012** Raised when a non-member is attempted to be removed from a group
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise NotGroupMember()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NotGroupMember: This entry is not a member of the group
|
||||
|
||||
"""
|
||||
|
||||
errno = 4012
|
||||
format = _('This entry is not a member of the group')
|
||||
|
||||
class RecursiveGroup(ExecutionError):
|
||||
"""
|
||||
**4013** Raised when a group is added as a member of itself
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise RecursiveGroup()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
RecursiveGroup: A group may not be a member of itself
|
||||
|
||||
"""
|
||||
|
||||
errno = 4013
|
||||
format = _('A group may not be a member of itself')
|
||||
|
||||
class BuiltinError(ExecutionError):
|
||||
"""
|
||||
**4100** Base class for builtin execution errors (*4100 - 4199*).
|
||||
@@ -854,6 +965,69 @@ class LDAPError(ExecutionError):
|
||||
errno = 4200
|
||||
|
||||
|
||||
class MidairCollision(ExecutionError):
|
||||
"""
|
||||
**4201** Raised when a change collides with another change
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise MidairCollision()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
MidairCollision: change collided with another change
|
||||
"""
|
||||
|
||||
errno = 4201
|
||||
format = _('change collided with another change')
|
||||
|
||||
|
||||
class EmptyModlist(ExecutionError):
|
||||
"""
|
||||
**4202** Raised when an LDAP update makes no changes
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise EmptyModlist()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
EmptyModlist: no modifications to be performed
|
||||
"""
|
||||
|
||||
errno = 4202
|
||||
format = _('no modifications to be performed')
|
||||
|
||||
|
||||
class DatabaseError(ExecutionError):
|
||||
"""
|
||||
**4203** Raised when an LDAP error is not otherwise handled
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise DatabaseError(desc="Can't contact LDAP server", info="")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
DatabaseError: Can't contact LDAP server:
|
||||
"""
|
||||
|
||||
errno = 4203
|
||||
format = _('%(desc)r:%(info)r')
|
||||
|
||||
|
||||
class LimitsExceeded(ExecutionError):
|
||||
"""
|
||||
**4204** Raised when search limits are exceeded.
|
||||
|
||||
For example:
|
||||
|
||||
>>> raise LimitsExceeded()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
LimitsExceeded: limits exceeded for this query
|
||||
"""
|
||||
|
||||
errno = 4204
|
||||
format = _('limits exceeded for this query')
|
||||
|
||||
|
||||
##############################################################################
|
||||
# 5000 - 5999: Generic errors
|
||||
|
@@ -21,7 +21,7 @@
|
||||
Base plugin for groups.
|
||||
"""
|
||||
|
||||
from ipalib import api, crud, errors, errors2
|
||||
from ipalib import api, crud, errors2
|
||||
from ipalib import Object, Command # Plugin base classes
|
||||
from ipalib import Str, Int, Flag, List # Parameter types
|
||||
from ldap.dn import escape_dn_chars
|
||||
|
@@ -21,7 +21,7 @@
|
||||
Frontend plugins for password changes.
|
||||
"""
|
||||
|
||||
from ipalib import api, errors, util
|
||||
from ipalib import api, errors2, util
|
||||
from ipalib import Command # Plugin base classes
|
||||
from ipalib import Str, Password # Parameter types
|
||||
|
||||
@@ -30,13 +30,13 @@ class passwd(Command):
|
||||
'Edit existing password policy.'
|
||||
|
||||
takes_args = (
|
||||
Password('password'),
|
||||
Str('principal?',
|
||||
Str('principal',
|
||||
cli_name='user',
|
||||
primary_key=True,
|
||||
autofill=True,
|
||||
default_from=util.get_current_principal,
|
||||
create_default=lambda **kw: util.get_current_principal(),
|
||||
),
|
||||
Password('password'),
|
||||
)
|
||||
|
||||
def execute(self, principal, password):
|
||||
@@ -48,13 +48,13 @@ class passwd(Command):
|
||||
|
||||
Returns the entry
|
||||
|
||||
:param param uid: The login name of the user being updated.
|
||||
:param kw: Not used.
|
||||
:param principal: The login name or principal of the user
|
||||
:param password: the new password
|
||||
"""
|
||||
if principal.find('@') > 0:
|
||||
u = principal.split('@')
|
||||
if len(u) > 2:
|
||||
raise errors.InvalidUserPrincipal(principal)
|
||||
raise errors2.MalformedUserPrincipal(principal=principal)
|
||||
else:
|
||||
principal = principal+"@"+self.api.env.realm
|
||||
dn = self.Backend.ldap.find_entry_dn(
|
||||
|
@@ -22,24 +22,21 @@ Various utility functions.
|
||||
"""
|
||||
|
||||
import os
|
||||
from os import path
|
||||
import imp
|
||||
import optparse
|
||||
import logging
|
||||
import time
|
||||
from types import NoneType
|
||||
from xmlrpclib import Binary
|
||||
import krbV
|
||||
import socket
|
||||
from ipalib import errors2
|
||||
|
||||
|
||||
def get_current_principal():
|
||||
try:
|
||||
return krbV.default_context().default_ccache().principal().name
|
||||
return unicode(krbV.default_context().default_ccache().principal().name)
|
||||
except krbV.Krb5Error:
|
||||
#TODO: do a kinit
|
||||
print "Unable to get kerberos principal"
|
||||
return None
|
||||
#TODO: do a kinit?
|
||||
raise errors2.CCacheError()
|
||||
|
||||
def get_fqdn():
|
||||
fqdn = ""
|
||||
@@ -57,16 +54,16 @@ def find_modules_in_dir(src_dir):
|
||||
"""
|
||||
Iterate through module names found in ``src_dir``.
|
||||
"""
|
||||
if not (path.abspath(src_dir) == src_dir and path.isdir(src_dir)):
|
||||
if not (os.path.abspath(src_dir) == src_dir and os.path.isdir(src_dir)):
|
||||
return
|
||||
if path.islink(src_dir):
|
||||
if os.path.islink(src_dir):
|
||||
return
|
||||
suffix = '.py'
|
||||
for name in sorted(os.listdir(src_dir)):
|
||||
if not name.endswith(suffix):
|
||||
continue
|
||||
pyfile = path.join(src_dir, name)
|
||||
if path.islink(pyfile) or not path.isfile(pyfile):
|
||||
pyfile = os.path.join(src_dir, name)
|
||||
if os.path.islink(pyfile) or not os.path.isfile(pyfile):
|
||||
continue
|
||||
module = name[:-len(suffix)]
|
||||
if module == '__init__':
|
||||
@@ -92,7 +89,7 @@ def import_plugins_subpackage(name):
|
||||
plugins = __import__(name + '.plugins').plugins
|
||||
except ImportError:
|
||||
return
|
||||
src_dir = path.dirname(path.abspath(plugins.__file__))
|
||||
src_dir = os.path.dirname(os.path.abspath(plugins.__file__))
|
||||
for name in find_modules_in_dir(src_dir):
|
||||
full_name = '%s.%s' % (plugins.__name__, name)
|
||||
__import__(full_name)
|
||||
|
@@ -29,7 +29,7 @@ from ipaserver.install import installutils
|
||||
from ipaserver import ipaldap
|
||||
from ipapython import entity, ipautil
|
||||
from ipalib import util
|
||||
from ipalib import errors, errors2
|
||||
from ipalib import errors2
|
||||
import ldap
|
||||
import logging
|
||||
import krbV
|
||||
@@ -310,10 +310,10 @@ class LDAPUpdate:
|
||||
while True:
|
||||
try:
|
||||
entry = self.conn.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)", attrlist)
|
||||
except errors2.NotFound:
|
||||
except errors2.NotFound, e:
|
||||
logging.error("Task not found: %s", dn)
|
||||
return
|
||||
except errors.DatabaseError, e:
|
||||
except errors2.DatabaseError, e:
|
||||
logging.error("Task lookup failure %s", e)
|
||||
return
|
||||
|
||||
@@ -484,7 +484,7 @@ class LDAPUpdate:
|
||||
# Doesn't exist, start with the default entry
|
||||
entry = new_entry
|
||||
logging.info("New entry: %s", entry.dn)
|
||||
except errors.DatabaseError:
|
||||
except errors2.DatabaseError:
|
||||
# Doesn't exist, start with the default entry
|
||||
entry = new_entry
|
||||
logging.info("New entry, using default value: %s", entry.dn)
|
||||
@@ -521,10 +521,10 @@ class LDAPUpdate:
|
||||
if self.live_run and updated:
|
||||
self.conn.updateEntry(entry.dn, entry.origDataDict(), entry.toDict())
|
||||
logging.info("Done")
|
||||
except errors.EmptyModlist:
|
||||
except errors2.EmptyModlist:
|
||||
logging.info("Entry already up-to-date")
|
||||
updated = False
|
||||
except errors.DatabaseError, e:
|
||||
except errors2.DatabaseError, e:
|
||||
logging.error("Update failed: %s", e)
|
||||
updated = False
|
||||
|
||||
|
@@ -32,7 +32,7 @@ import ldap.sasl
|
||||
from ldap.controls import LDAPControl,DecodeControlTuples,EncodeControlTuples
|
||||
from ldap.ldapobject import SimpleLDAPObject
|
||||
from ipaserver import ipautil
|
||||
from ipalib import errors, errors2
|
||||
from ipalib import errors2
|
||||
|
||||
# Global variable to define SASL auth
|
||||
sasl_auth = ldap.sasl.sasl({},'GSSAPI')
|
||||
@@ -264,6 +264,50 @@ class IPAdmin(SimpleLDAPObject):
|
||||
|
||||
return sctrl
|
||||
|
||||
def __handle_errors(self, e, **kw):
|
||||
"""
|
||||
Centralize error handling in one place.
|
||||
|
||||
e is the error to be raised
|
||||
**kw is an exception-specific list of options
|
||||
"""
|
||||
if not isinstance(e,ldap.TIMEOUT):
|
||||
desc = e.args[0]['desc'].strip()
|
||||
info = e.args[0].get('info','').strip()
|
||||
else:
|
||||
desc = ''
|
||||
info = ''
|
||||
|
||||
try:
|
||||
# re-raise the error so we can handle it
|
||||
raise e
|
||||
except ldap.NO_SUCH_OBJECT, e:
|
||||
args = kw.get('args', '')
|
||||
raise errors2.NotFound(msg=notfound(args))
|
||||
except ldap.ALREADY_EXISTS, e:
|
||||
raise errors2.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':
|
||||
raise errors2.DuplicateEntry()
|
||||
else:
|
||||
raise errors2.DatabaseError(desc=desc,info=info)
|
||||
except ldap.INSUFFICIENT_ACCESS, e:
|
||||
raise errors2.ACIError(info=info)
|
||||
except ldap.NO_SUCH_ATTRIBUTE:
|
||||
# this is raised when a 'delete' attribute isn't found.
|
||||
# it indicates the previous attribute was removed by another
|
||||
# update, making the oldentry stale.
|
||||
raise errors2.MidairCollision()
|
||||
except ldap.ADMINLIMIT_EXCEEDED, e:
|
||||
raise errors2.LimitsExceeded()
|
||||
except ldap.SIZELIMIT_EXCEEDED, e:
|
||||
raise errors2.LimitsExceeded()
|
||||
except ldap.TIMELIMIT_EXCEEDED, e:
|
||||
raise errors2.LimitsExceeded()
|
||||
except ldap.LDAPError, e:
|
||||
raise errors2.DatabaseError(desc=desc,info=info)
|
||||
|
||||
def toLDAPURL(self):
|
||||
return "ldap://%s:%d/" % (self.host,self.port)
|
||||
|
||||
@@ -271,11 +315,14 @@ class IPAdmin(SimpleLDAPObject):
|
||||
self.proxydn = proxydn
|
||||
|
||||
def set_krbccache(self, krbccache, principal):
|
||||
if krbccache is not None:
|
||||
os.environ["KRB5CCNAME"] = krbccache
|
||||
self.sasl_interactive_bind_s("", sasl_auth)
|
||||
self.principal = principal
|
||||
self.proxydn = None
|
||||
try:
|
||||
if krbccache is not None:
|
||||
os.environ["KRB5CCNAME"] = krbccache
|
||||
self.sasl_interactive_bind_s("", sasl_auth)
|
||||
self.principal = principal
|
||||
self.proxydn = None
|
||||
except ldap.LDAPError, e:
|
||||
self.__handle_errors(e, **{})
|
||||
|
||||
def do_simple_bind(self, binddn="cn=directory manager", bindpw=""):
|
||||
self.binddn = binddn
|
||||
@@ -293,10 +340,9 @@ class IPAdmin(SimpleLDAPObject):
|
||||
try:
|
||||
res = self.search(*args)
|
||||
objtype, obj = self.result(res)
|
||||
except ldap.NO_SUCH_OBJECT, e:
|
||||
raise errors2.NotFound(msg=notfound(args))
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
|
||||
if not obj:
|
||||
raise errors2.NotFound(msg=notfound(args))
|
||||
@@ -316,11 +362,9 @@ class IPAdmin(SimpleLDAPObject):
|
||||
try:
|
||||
res = self.search(*args)
|
||||
objtype, obj = self.result(res)
|
||||
except (ldap.ADMINLIMIT_EXCEEDED, ldap.SIZELIMIT_EXCEEDED), e:
|
||||
# Too many results returned by search
|
||||
raise e
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
|
||||
if not obj:
|
||||
raise errors2.NotFound(msg=notfound(args))
|
||||
@@ -357,7 +401,8 @@ class IPAdmin(SimpleLDAPObject):
|
||||
ldap.TIMELIMIT_EXCEEDED), e:
|
||||
partial = 1
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
|
||||
if not entries:
|
||||
raise errors2.NotFound(msg=notfound(args))
|
||||
@@ -379,18 +424,9 @@ class IPAdmin(SimpleLDAPObject):
|
||||
if sctrl is not None:
|
||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||
self.add_s(*args)
|
||||
except ldap.ALREADY_EXISTS, e:
|
||||
raise errors2.DuplicateEntry
|
||||
except ldap.CONSTRAINT_VIOLATION, e:
|
||||
# This error gets thrown by the uniqueness plugin
|
||||
if e.args[0].get('info','') == 'Another entry with the same attribute value already exists':
|
||||
raise errors2.DuplicateEntry
|
||||
else:
|
||||
raise errors.DatabaseError, e
|
||||
except ldap.INSUFFICIENT_ACCESS, e:
|
||||
raise errors2.ACIError(info=e.args[0].get('info',''))
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
return True
|
||||
|
||||
def updateRDN(self, dn, newrdn):
|
||||
@@ -407,7 +443,8 @@ class IPAdmin(SimpleLDAPObject):
|
||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||
self.modrdn_s(dn, newrdn, delold=1)
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
return True
|
||||
|
||||
def updateEntry(self,dn,oldentry,newentry):
|
||||
@@ -425,15 +462,9 @@ class IPAdmin(SimpleLDAPObject):
|
||||
if sctrl is not None:
|
||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||
self.modify_s(dn, modlist)
|
||||
# this is raised when a 'delete' attribute isn't found.
|
||||
# it indicates the previous attribute was removed by another
|
||||
# update, making the oldentry stale.
|
||||
except ldap.NO_SUCH_ATTRIBUTE:
|
||||
raise errors.MidairCollision
|
||||
except ldap.INSUFFICIENT_ACCESS, e:
|
||||
raise errors2.ACIError(info=e.args[0].get('info',''))
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
return True
|
||||
|
||||
def generateModList(self, old_entry, new_entry):
|
||||
@@ -491,7 +522,8 @@ class IPAdmin(SimpleLDAPObject):
|
||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||
self.modify_s(dn, modlist)
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
return True
|
||||
|
||||
def deleteEntry(self,*args):
|
||||
@@ -503,10 +535,9 @@ class IPAdmin(SimpleLDAPObject):
|
||||
if sctrl is not None:
|
||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||
self.delete_s(*args)
|
||||
except ldap.INSUFFICIENT_ACCESS, e:
|
||||
raise errors2.ACIError(info=e.args[0].get('info',''))
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
return True
|
||||
|
||||
def modifyPassword(self,dn,oldpass,newpass):
|
||||
@@ -524,7 +555,8 @@ class IPAdmin(SimpleLDAPObject):
|
||||
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
|
||||
self.passwd_s(dn, oldpass, newpass)
|
||||
except ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
kw = {'args': args}
|
||||
self.__handle_errors(e, **kw)
|
||||
return True
|
||||
|
||||
def __wrapmethods(self):
|
||||
|
@@ -44,7 +44,7 @@ from ldap.controls import LDAPControl
|
||||
from ldap.ldapobject import SimpleLDAPObject
|
||||
|
||||
from ipalib import api
|
||||
from ipalib import errors, errors2
|
||||
from ipalib import errors2
|
||||
from ipalib.crud import CrudBackend
|
||||
|
||||
# attribute syntax to python type mapping, 'SYNTAX OID': type
|
||||
@@ -87,7 +87,7 @@ def _load_schema(host, port):
|
||||
conn.unbind_s()
|
||||
except _ldap.LDAPError, e:
|
||||
# TODO: raise a more appropriate exception
|
||||
raise errors.DatabaseError
|
||||
self.__handle_errors(e, **{})
|
||||
except IndexError:
|
||||
# no 'cn=schema' entry in LDAP? some servers use 'cn=subschema'
|
||||
# TODO: DS uses 'cn=schema', support for other server?
|
||||
@@ -168,6 +168,51 @@ class ldap2(CrudBackend):
|
||||
else:
|
||||
entry_attrs[k] = attr_type(v)
|
||||
|
||||
def __handle_errors(self, e, **kw):
|
||||
"""
|
||||
Centralize error handling in one place.
|
||||
|
||||
e is the error to be raised
|
||||
**kw is an exception-specific list of options
|
||||
"""
|
||||
if not isinstance(e,ldap.TIMEOUT):
|
||||
desc = e.args[0]['desc'].strip()
|
||||
info = e.args[0].get('info','').strip()
|
||||
else:
|
||||
desc = ''
|
||||
info = ''
|
||||
|
||||
try:
|
||||
# re-raise the error so we can handle it
|
||||
raise e
|
||||
except _ldap.NO_SUCH_OBJECT, e:
|
||||
# args = kw.get('args', '')
|
||||
# raise errors2.NotFound(msg=notfound(args))
|
||||
raise errors2.NotFound()
|
||||
except _ldap.ALREADY_EXISTS, e:
|
||||
raise errors2.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':
|
||||
raise errors2.DuplicateEntry()
|
||||
else:
|
||||
raise errors2.DatabaseError(desc=desc,info=info)
|
||||
except _ldap.INSUFFICIENT_ACCESS, e:
|
||||
raise errors2.ACIError(info=info)
|
||||
except _ldap.NO_SUCH_ATTRIBUTE:
|
||||
# this is raised when a 'delete' attribute isn't found.
|
||||
# it indicates the previous attribute was removed by another
|
||||
# update, making the oldentry stale.
|
||||
raise errors2.MidairCollision()
|
||||
except _ldap.ADMINLIMIT_EXCEEDED, e:
|
||||
raise errors2.LimitsExceeded()
|
||||
except _ldap.SIZELIMIT_EXCEEDED, e:
|
||||
raise errors2.LimitsExceeded()
|
||||
except _ldap.TIMELIMIT_EXCEEDED, e:
|
||||
raise errors2.LimitsExceeded()
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors2.DatabaseError(desc=desc,info=info)
|
||||
|
||||
def create_connection(self, host=None, port=None, ccache=None,
|
||||
bind_dn='', bind_pw='', debug_level=255,
|
||||
tls_cacertfile=None, tls_certfile=None, tls_keyfile=None):
|
||||
@@ -291,15 +336,8 @@ class ldap2(CrudBackend):
|
||||
# pass arguments to python-ldap
|
||||
try:
|
||||
self.conn.add_s(dn, list(entry_attrs_copy.iteritems()))
|
||||
except _ldap.ALREADY_EXISTS, e:
|
||||
raise errors2.DuplicateEntry
|
||||
except _ldap.CONSTRAINT_VIOLATION, e:
|
||||
if e.args[0].get('info', '') == _uniqueness_plugin_error:
|
||||
raise errors2.DuplicateEntry
|
||||
else:
|
||||
raise errors.DatabaseError, e
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
self.__handle_errors(e, **{})
|
||||
|
||||
# generating filters for find_entry
|
||||
# some examples:
|
||||
@@ -403,7 +441,7 @@ class ldap2(CrudBackend):
|
||||
_ldap.SIZELIMIT_EXCEEDED), e:
|
||||
raise e
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
self.__handle_errors(e, **{})
|
||||
if not res:
|
||||
raise errors2.NotFound()
|
||||
|
||||
@@ -450,7 +488,7 @@ class ldap2(CrudBackend):
|
||||
try:
|
||||
self.conn.rename_s(dn, new_rdn, delold=int(del_old))
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
self.__handle_errors(e, **{})
|
||||
|
||||
def _generate_modlist(self, dn, entry_attrs):
|
||||
# get original entry
|
||||
@@ -500,15 +538,13 @@ class ldap2(CrudBackend):
|
||||
# generate modlist
|
||||
modlist = self._generate_modlist(dn, entry_attrs_copy)
|
||||
if not modlist:
|
||||
raise errors.EmptyModlist
|
||||
raise errors2.EmptyModlist()
|
||||
|
||||
# pass arguments to python-ldap
|
||||
try:
|
||||
self.conn.modify_s(dn, modlist)
|
||||
except _ldap.NO_SUCH_ATTRIBUTE:
|
||||
raise errors.MidairCollision
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
self.__handle_errors(e, **{})
|
||||
|
||||
def delete_entry(self, dn):
|
||||
"""Delete entry."""
|
||||
@@ -519,10 +555,8 @@ class ldap2(CrudBackend):
|
||||
# pass arguments to python-ldap
|
||||
try:
|
||||
self.conn.delete_s(dn)
|
||||
except _ldap.INSUFFICIENT_ACCESS, e:
|
||||
raise errors.InsuficientAccess, e
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
self.__handle_errors(e, **{})
|
||||
|
||||
def modify_password(self, dn, old_pass, new_pass):
|
||||
"""Set user password."""
|
||||
@@ -536,7 +570,7 @@ class ldap2(CrudBackend):
|
||||
try:
|
||||
self.passwd_s(dn, odl_pass, new_pass)
|
||||
except _ldap.LDAPError, e:
|
||||
raise errors.DatabaseError, e
|
||||
self.__handle_errors(e, **{})
|
||||
|
||||
def add_entry_to_group(self, dn, group_dn, member_attr='member'):
|
||||
"""Add entry to group."""
|
||||
@@ -545,7 +579,7 @@ class ldap2(CrudBackend):
|
||||
group_dn = self.normalize_dn(group_dn)
|
||||
# check if we're not trying to add group into itself
|
||||
if dn == group_dn:
|
||||
raise errors.SameGroupError
|
||||
raise errors2.SameGroupError()
|
||||
# check if the entry exists
|
||||
(dn, entry_attrs) = self.get_entry(dn, ['objectClass'])
|
||||
|
||||
@@ -575,7 +609,7 @@ class ldap2(CrudBackend):
|
||||
try:
|
||||
members.remove(dn)
|
||||
except ValueError:
|
||||
raise errors.NotGroupMember
|
||||
raise errors2.NotGroupMember()
|
||||
group_entry_attrs[member_attr] = members
|
||||
|
||||
# update group entry
|
||||
@@ -592,11 +626,11 @@ class ldap2(CrudBackend):
|
||||
account_lock_attr = account_lock_attr[0].lower()
|
||||
if active:
|
||||
if account_lock_attr == 'false':
|
||||
raise errors.AlreadyActiveError
|
||||
raise errors2.AlreadyActive()
|
||||
else:
|
||||
if account_lock_attr == 'true':
|
||||
raise errors.AlreadyInactiveError
|
||||
|
||||
raise errors2.AlreadyInactive()
|
||||
|
||||
# check if nsAccountLock attribute is in the entry itself
|
||||
is_member = False
|
||||
member_of_attr = entry_attrs.get('memberOf', [])
|
||||
@@ -605,7 +639,7 @@ class ldap2(CrudBackend):
|
||||
is_member = True
|
||||
break
|
||||
if not is_member and entry_attrs.has_key('nsAccountLock'):
|
||||
raise errors.HasNSAccountLock
|
||||
raise errors2.HasNSAccountLock()
|
||||
|
||||
activated_filter = '(cn=activated)'
|
||||
inactivated_filter = '(cn=inactivated)'
|
||||
@@ -619,7 +653,7 @@ class ldap2(CrudBackend):
|
||||
(group_dn, group_entry_attrs) = entries[0]
|
||||
try:
|
||||
self.remove_entry_from_group(dn, group_dn)
|
||||
except errors.NotGroupMember:
|
||||
except errors2.NotGroupMember:
|
||||
pass
|
||||
|
||||
# add the entry to the activated/inactivated group if necessary
|
||||
@@ -638,11 +672,11 @@ class ldap2(CrudBackend):
|
||||
(group_dn, group_entry_attrs) = entries[0]
|
||||
try:
|
||||
self.add_entry_to_group(dn, group_dn)
|
||||
except errors.EmptyModlist:
|
||||
except errors2.EmptyModlist:
|
||||
if active:
|
||||
raise errors.AlreadyActiveError
|
||||
raise errors2.AlreadyActive()
|
||||
else:
|
||||
raise errors.AlreadyInactiveError
|
||||
raise errors2.AlreadyInactive()
|
||||
|
||||
def activate_entry(self, dn):
|
||||
"""Mark entry active."""
|
||||
|
@@ -23,7 +23,7 @@ import re
|
||||
from ipalib.request import context
|
||||
from ipaserver import ipaldap
|
||||
import ipautil
|
||||
from ipalib import errors, errors2
|
||||
from ipalib import errors2
|
||||
from ipalib import api
|
||||
|
||||
def convert_entry(ent):
|
||||
@@ -341,16 +341,16 @@ def mark_entry_active (dn):
|
||||
|
||||
if entry.get('nsaccountlock', 'false').lower() == "false":
|
||||
api.log.debug("IPA: already active")
|
||||
raise errors.AlreadyActiveError
|
||||
raise errors2.AlreadyActive()
|
||||
|
||||
if has_nsaccountlock(dn):
|
||||
api.log.debug("IPA: appears to have the nsaccountlock attribute")
|
||||
raise errors.HasNSAccountLock
|
||||
raise errors2.HasNSAccountLock()
|
||||
|
||||
group = get_entry_by_cn("inactivated", None)
|
||||
try:
|
||||
remove_member_from_group(entry.get('dn'), group.get('dn'))
|
||||
except errors.NotGroupMember:
|
||||
except errors2.NotGroupMember:
|
||||
# Perhaps the user is there as a result of group membership
|
||||
pass
|
||||
|
||||
@@ -377,18 +377,18 @@ def mark_entry_inactive (dn):
|
||||
|
||||
if entry.get('nsaccountlock', 'false').lower() == "true":
|
||||
api.log.debug("IPA: already marked as inactive")
|
||||
raise errors.AlreadyInactiveError
|
||||
raise errors2.AlreadyInactive()
|
||||
|
||||
if has_nsaccountlock(dn):
|
||||
api.log.debug("IPA: appears to have the nsaccountlock attribute")
|
||||
raise errors.HasNSAccountLock
|
||||
raise errors2.HasNSAccountLock()
|
||||
|
||||
# First see if they are in the activated group as this will override
|
||||
# the our inactivation.
|
||||
group = get_entry_by_cn("activated", None)
|
||||
try:
|
||||
remove_member_from_group(dn, group.get('dn'))
|
||||
except errors.NotGroupMember:
|
||||
except errors2.NotGroupMember:
|
||||
# this is fine, they may not be explicitly in this group
|
||||
pass
|
||||
|
||||
@@ -405,7 +405,7 @@ def add_member_to_group(member_dn, group_dn, memberattr='member'):
|
||||
api.log.info("IPA: add_member_to_group '%s' to '%s'" % (member_dn, group_dn))
|
||||
if member_dn.lower() == group_dn.lower():
|
||||
# You can't add a group to itself
|
||||
raise errors.SameGroupError
|
||||
raise errors2.RecursiveGroup()
|
||||
|
||||
group = get_entry_by_dn(group_dn, None)
|
||||
if group is None:
|
||||
@@ -423,10 +423,7 @@ def add_member_to_group(member_dn, group_dn, memberattr='member'):
|
||||
members.append(member_dn)
|
||||
group[memberattr] = members
|
||||
|
||||
try:
|
||||
return update_entry(group)
|
||||
except errors.EmptyModlist:
|
||||
raise
|
||||
return update_entry(group)
|
||||
|
||||
def remove_member_from_group(member_dn, group_dn, memberattr='member'):
|
||||
"""Remove a member_dn from an existing group."""
|
||||
@@ -444,7 +441,7 @@ def remove_member_from_group(member_dn, group_dn, memberattr='member'):
|
||||
|
||||
members = group.get(memberattr, False)
|
||||
if not members:
|
||||
raise errors.NotGroupMember
|
||||
raise errors2.NotGroupMember()
|
||||
|
||||
if isinstance(members,basestring):
|
||||
members = [members]
|
||||
@@ -453,15 +450,10 @@ def remove_member_from_group(member_dn, group_dn, memberattr='member'):
|
||||
try:
|
||||
members.remove(member_dn)
|
||||
except ValueError:
|
||||
# member is not in the group
|
||||
# FIXME: raise more specific error?
|
||||
raise errors.NotGroupMember
|
||||
raise errors2.NotGroupMember()
|
||||
except Exception, e:
|
||||
raise e
|
||||
|
||||
group[memberattr] = members
|
||||
|
||||
try:
|
||||
return update_entry(group)
|
||||
except errors.EmptyModlist:
|
||||
raise
|
||||
return update_entry(group)
|
||||
|
@@ -1,289 +0,0 @@
|
||||
# Authors:
|
||||
# Jason Gerard DeRose <jderose@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2008 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 only
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
Test the `ipalib.errors` module.
|
||||
"""
|
||||
|
||||
from tests.util import raises, ClassChecker
|
||||
from ipalib import errors
|
||||
|
||||
|
||||
type_format = '%s: need a %r; got %r'
|
||||
|
||||
|
||||
def check_TypeError(f, value, type_, name, **kw):
|
||||
e = raises(TypeError, f, value, type_, name, **kw)
|
||||
assert e.value is value
|
||||
assert e.type is type_
|
||||
assert e.name is name
|
||||
assert str(e) == type_format % (name, type_, value)
|
||||
|
||||
|
||||
def test_raise_TypeError():
|
||||
"""
|
||||
Test the `ipalib.errors.raise_TypeError` function.
|
||||
"""
|
||||
f = errors.raise_TypeError
|
||||
value = 'Hello.'
|
||||
type_ = unicode
|
||||
name = 'message'
|
||||
|
||||
check_TypeError(f, value, type_, name)
|
||||
|
||||
# name not an str
|
||||
fail_name = 42
|
||||
e = raises(AssertionError, f, value, type_, fail_name)
|
||||
assert str(e) == type_format % ('name', str, fail_name), str(e)
|
||||
|
||||
# type_ not a type:
|
||||
fail_type = unicode()
|
||||
e = raises(AssertionError, f, value, fail_type, name)
|
||||
assert str(e) == type_format % ('type_', type, fail_type)
|
||||
|
||||
# type(value) is type_:
|
||||
fail_value = u'How are you?'
|
||||
e = raises(AssertionError, f, fail_value, type_, name)
|
||||
assert str(e) == 'value: %r is a %r' % (fail_value, type_)
|
||||
|
||||
|
||||
def test_check_type():
|
||||
"""
|
||||
Test the `ipalib.errors.check_type` function.
|
||||
"""
|
||||
f = errors.check_type
|
||||
value = 'How are you?'
|
||||
type_ = str
|
||||
name = 'greeting'
|
||||
|
||||
# Should pass:
|
||||
assert value is f(value, type_, name)
|
||||
assert None is f(None, type_, name, allow_none=True)
|
||||
|
||||
# Should raise TypeError
|
||||
check_TypeError(f, None, type_, name)
|
||||
check_TypeError(f, value, basestring, name)
|
||||
check_TypeError(f, value, unicode, name)
|
||||
|
||||
# name not an str
|
||||
fail_name = unicode(name)
|
||||
e = raises(AssertionError, f, value, type_, fail_name)
|
||||
assert str(e) == type_format % ('name', str, fail_name)
|
||||
|
||||
# type_ not a type:
|
||||
fail_type = 42
|
||||
e = raises(AssertionError, f, value, fail_type, name)
|
||||
assert str(e) == type_format % ('type_', type, fail_type)
|
||||
|
||||
# allow_none not a bool:
|
||||
fail_bool = 0
|
||||
e = raises(AssertionError, f, value, type_, name, allow_none=fail_bool)
|
||||
assert str(e) == type_format % ('allow_none', bool, fail_bool)
|
||||
|
||||
|
||||
def test_check_isinstance():
|
||||
"""
|
||||
Test the `ipalib.errors.check_isinstance` function.
|
||||
"""
|
||||
f = errors.check_isinstance
|
||||
value = 'How are you?'
|
||||
type_ = str
|
||||
name = 'greeting'
|
||||
|
||||
# Should pass:
|
||||
assert value is f(value, type_, name)
|
||||
assert value is f(value, basestring, name)
|
||||
assert None is f(None, type_, name, allow_none=True)
|
||||
|
||||
# Should raise TypeError
|
||||
check_TypeError(f, None, type_, name)
|
||||
check_TypeError(f, value, unicode, name)
|
||||
|
||||
# name not an str
|
||||
fail_name = unicode(name)
|
||||
e = raises(AssertionError, f, value, type_, fail_name)
|
||||
assert str(e) == type_format % ('name', str, fail_name)
|
||||
|
||||
# type_ not a type:
|
||||
fail_type = 42
|
||||
e = raises(AssertionError, f, value, fail_type, name)
|
||||
assert str(e) == type_format % ('type_', type, fail_type)
|
||||
|
||||
# allow_none not a bool:
|
||||
fail_bool = 0
|
||||
e = raises(AssertionError, f, value, type_, name, allow_none=fail_bool)
|
||||
assert str(e) == type_format % ('allow_none', bool, fail_bool)
|
||||
|
||||
|
||||
class test_IPAError(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.errors.IPAError` exception.
|
||||
"""
|
||||
_cls = errors.IPAError
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.errors.IPAError` exception.
|
||||
"""
|
||||
assert self.cls.__bases__ == (StandardError,)
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.errors.IPAError.__init__` method.
|
||||
"""
|
||||
args = ('one fish', 'two fish')
|
||||
e = self.cls(*args)
|
||||
assert e.args == args
|
||||
assert self.cls().args == tuple()
|
||||
|
||||
def test_str(self):
|
||||
"""
|
||||
Test the `ipalib.errors.IPAError.__str__` method.
|
||||
"""
|
||||
f = 'The %s color is %s.'
|
||||
class custom_error(self.cls):
|
||||
format = f
|
||||
for args in [('sexiest', 'red'), ('most-batman-like', 'black')]:
|
||||
e = custom_error(*args)
|
||||
assert e.args == args
|
||||
assert str(e) == f % args
|
||||
|
||||
|
||||
class test_ValidationError(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.errors.ValidationError` exception.
|
||||
"""
|
||||
_cls = errors.ValidationError
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.errors.ValidationError` exception.
|
||||
"""
|
||||
assert self.cls.__bases__ == (errors.IPAError,)
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.errors.ValidationError.__init__` method.
|
||||
"""
|
||||
name = 'login'
|
||||
value = 'Whatever'
|
||||
error = 'Must be lowercase.'
|
||||
for index in (None, 3):
|
||||
e = self.cls(name, value, error, index=index)
|
||||
assert e.name is name
|
||||
assert e.value is value
|
||||
assert e.error is error
|
||||
assert e.index is index
|
||||
assert str(e) == 'invalid %r value %r: %s' % (name, value, error)
|
||||
# Check that index default is None:
|
||||
assert self.cls(name, value, error).index is None
|
||||
# Check non str name raises AssertionError:
|
||||
raises(AssertionError, self.cls, unicode(name), value, error)
|
||||
# Check non int index raises AssertionError:
|
||||
raises(AssertionError, self.cls, name, value, error, index=5.0)
|
||||
# Check negative index raises AssertionError:
|
||||
raises(AssertionError, self.cls, name, value, error, index=-2)
|
||||
|
||||
|
||||
class test_ConversionError(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.errors.ConversionError` exception.
|
||||
"""
|
||||
_cls = errors.ConversionError
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.errors.ConversionError` exception.
|
||||
"""
|
||||
assert self.cls.__bases__ == (errors.ValidationError,)
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.errors.ConversionError.__init__` method.
|
||||
"""
|
||||
name = 'some_arg'
|
||||
value = '42.0'
|
||||
class type_(object):
|
||||
conversion_error = 'Not an integer'
|
||||
for index in (None, 7):
|
||||
e = self.cls(name, value, type_, index=index)
|
||||
assert e.name is name
|
||||
assert e.value is value
|
||||
assert e.type is type_
|
||||
assert e.error is type_.conversion_error
|
||||
assert e.index is index
|
||||
assert str(e) == 'invalid %r value %r: %s' % (name, value,
|
||||
type_.conversion_error)
|
||||
# Check that index default is None:
|
||||
assert self.cls(name, value, type_).index is None
|
||||
|
||||
|
||||
class test_RuleError(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.errors.RuleError` exception.
|
||||
"""
|
||||
_cls = errors.RuleError
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.errors.RuleError` exception.
|
||||
"""
|
||||
assert self.cls.__bases__ == (errors.ValidationError,)
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.errors.RuleError.__init__` method.
|
||||
"""
|
||||
name = 'whatever'
|
||||
value = 'The smallest weird number.'
|
||||
def my_rule(value):
|
||||
return 'Value is bad.'
|
||||
error = my_rule(value)
|
||||
for index in (None, 42):
|
||||
e = self.cls(name, value, error, my_rule, index=index)
|
||||
assert e.name is name
|
||||
assert e.value is value
|
||||
assert e.error is error
|
||||
assert e.rule is my_rule
|
||||
# Check that index default is None:
|
||||
assert self.cls(name, value, error, my_rule).index is None
|
||||
|
||||
|
||||
class test_RequirementError(ClassChecker):
|
||||
"""
|
||||
Test the `ipalib.errors.RequirementError` exception.
|
||||
"""
|
||||
_cls = errors.RequirementError
|
||||
|
||||
def test_class(self):
|
||||
"""
|
||||
Test the `ipalib.errors.RequirementError` exception.
|
||||
"""
|
||||
assert self.cls.__bases__ == (errors.ValidationError,)
|
||||
|
||||
def test_init(self):
|
||||
"""
|
||||
Test the `ipalib.errors.RequirementError.__init__` method.
|
||||
"""
|
||||
name = 'givenname'
|
||||
e = self.cls(name)
|
||||
assert e.name is name
|
||||
assert e.value is None
|
||||
assert e.error == 'Required'
|
||||
assert e.index is None
|
@@ -26,7 +26,7 @@ from tests.util import check_TypeError, ClassChecker, create_test_api
|
||||
from tests.util import assert_equal
|
||||
from ipalib.constants import TYPE_ERROR
|
||||
from ipalib.base import NameSpace
|
||||
from ipalib import frontend, backend, plugable, errors2, errors, parameters, config
|
||||
from ipalib import frontend, backend, plugable, errors2, parameters, config
|
||||
|
||||
def test_RULE_FLAG():
|
||||
assert frontend.RULE_FLAG == 'validation_rule'
|
||||
|
@@ -25,7 +25,7 @@ import inspect
|
||||
from tests.util import raises, no_set, no_del, read_only
|
||||
from tests.util import getitem, setitem, delitem
|
||||
from tests.util import ClassChecker, create_test_api
|
||||
from ipalib import plugable, errors, errors2
|
||||
from ipalib import plugable, errors2
|
||||
|
||||
|
||||
class test_SetProxy(ClassChecker):
|
||||
|
@@ -26,7 +26,6 @@ import socket
|
||||
import nose
|
||||
from ipalib import api, request
|
||||
from ipalib import errors2
|
||||
from ipalib import errors
|
||||
|
||||
# Initialize the API. We do this here so that one can run the tests
|
||||
# individually instead of at the top-level. If API.bootstrap()
|
||||
|
Reference in New Issue
Block a user