2008-07-18 17:51:34 +00:00
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
2008-07-18 20:31:12 +00:00
# see file 'COPYING' for use and warranty inmsgion
2008-07-18 17:51:34 +00:00
#
# 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
"""
2008-07-31 18:57:10 +00:00
All custom errors raised by ` ipalib ` package .
2008-09-03 22:29:01 +00:00
Also includes a few utility functions for raising exceptions .
2008-07-18 17:51:34 +00:00
"""
2008-10-16 23:33:44 -04:00
IPA_ERROR_BASE = 1000
2008-08-29 23:53:04 +00:00
TYPE_FORMAT = ' %s : need a %r ; got %r '
2008-08-29 03:48:33 +00:00
2008-09-02 16:42:39 +00:00
def raise_TypeError ( value , type_ , name ) :
2008-08-29 03:48:33 +00:00
"""
2008-08-29 07:05:06 +00:00
Raises a TypeError with a nicely formatted message and helpful attributes .
2008-08-29 03:48:33 +00:00
2008-08-29 07:05:06 +00:00
The TypeError raised will have three custom attributes :
2008-08-29 03:48:33 +00:00
2008-09-02 16:42:39 +00:00
` ` value ` ` - The value ( of incorrect type ) passed as argument .
2008-08-29 06:04:38 +00:00
2008-08-29 23:53:04 +00:00
` ` type ` ` - The type expected for the argument .
2008-08-29 06:04:38 +00:00
2008-09-02 16:42:39 +00:00
` ` name ` ` - The name ( identifier ) of the argument in question .
2008-08-29 04:29:29 +00:00
2008-08-29 07:05:06 +00:00
There is no edict that all TypeError should be raised with raise_TypeError ,
2008-08-29 04:29:29 +00:00
but when it fits , use it . . . it makes the unit tests faster to write and
the debugging easier to read .
2008-08-29 06:04:38 +00:00
Here is an example :
2008-10-07 22:35:45 -06:00
>> > raise_TypeError ( u ' Hello, world! ' , str , ' message ' )
2008-08-29 06:04:38 +00:00
Traceback ( most recent call last ) :
File " <stdin> " , line 1 , in < module >
2008-10-07 22:35:45 -06:00
File " ipalib/errors.py " , line 65 , in raise_TypeError
2008-08-29 07:05:06 +00:00
raise e
2008-10-07 22:35:45 -06:00
TypeError : message : need a < type ' str ' > ; got u ' Hello, world! '
2008-08-29 07:05:06 +00:00
2008-09-02 16:42:39 +00:00
: param value : The value ( of incorrect type ) passed as argument .
2008-08-29 23:53:04 +00:00
: param type_ : The type expected for the argument .
2008-09-02 16:42:39 +00:00
: param name : The name ( identifier ) of the argument in question .
2008-08-29 03:48:33 +00:00
"""
2008-08-29 23:53:04 +00:00
assert type ( type_ ) is type , TYPE_FORMAT % ( ' type_ ' , type , type_ )
2008-08-29 07:05:06 +00:00
assert type ( value ) is not type_ , ' value: %r is a %r ' % ( value , type_ )
2008-09-02 16:42:39 +00:00
assert type ( name ) is str , TYPE_FORMAT % ( ' name ' , str , name )
2008-08-29 23:53:04 +00:00
e = TypeError ( TYPE_FORMAT % ( name , type_ , value ) )
2008-08-29 07:05:06 +00:00
setattr ( e , ' value ' , value )
2008-09-02 16:42:39 +00:00
setattr ( e , ' type ' , type_ )
setattr ( e , ' name ' , name )
2008-08-29 07:05:06 +00:00
raise e
2008-08-29 03:48:33 +00:00
2008-09-02 17:44:07 +00:00
def check_type ( value , type_ , name , allow_none = False ) :
2008-08-29 23:53:04 +00:00
assert type ( name ) is str , TYPE_FORMAT % ( ' name ' , str , name )
assert type ( type_ ) is type , TYPE_FORMAT % ( ' type_ ' , type , type_ )
2008-09-02 17:44:07 +00:00
assert type ( allow_none ) is bool , TYPE_FORMAT % ( ' allow_none ' , bool , allow_none )
if value is None and allow_none :
2008-08-29 23:53:04 +00:00
return
if type ( value ) is not type_ :
2008-09-02 16:42:39 +00:00
raise_TypeError ( value , type_ , name )
2008-09-02 15:15:03 +00:00
return value
2008-08-29 23:53:04 +00:00
2008-09-02 17:44:07 +00:00
def check_isinstance ( value , type_ , name , allow_none = False ) :
2008-08-29 23:53:04 +00:00
assert type ( type_ ) is type , TYPE_FORMAT % ( ' type_ ' , type , type_ )
2008-09-02 16:42:39 +00:00
assert type ( name ) is str , TYPE_FORMAT % ( ' name ' , str , name )
2008-09-02 17:44:07 +00:00
assert type ( allow_none ) is bool , TYPE_FORMAT % ( ' allow_none ' , bool , allow_none )
if value is None and allow_none :
2008-08-29 23:53:04 +00:00
return
if not isinstance ( value , type_ ) :
2008-09-02 16:42:39 +00:00
raise_TypeError ( value , type_ , name )
2008-09-02 15:15:03 +00:00
return value
2008-08-29 23:53:04 +00:00
2008-10-23 21:21:51 -06:00
class IPAError ( StandardError ) :
2008-08-08 17:11:29 +00:00
"""
2008-09-03 19:38:39 +00:00
Base class for all custom IPA errors .
2008-08-08 17:11:29 +00:00
Use this base class for your custom IPA errors unless there is a
specific reason to subclass from AttributeError , KeyError , etc .
"""
2008-09-03 19:38:39 +00:00
format = None
def __init__ ( self , * args ) :
2008-08-08 21:40:03 +00:00
self . args = args
2008-08-08 17:11:29 +00:00
def __str__ ( self ) :
2008-08-08 21:40:03 +00:00
"""
Returns the string representation of this exception .
"""
2008-09-03 19:38:39 +00:00
return self . format % self . args
2008-07-18 17:51:34 +00:00
2008-09-10 20:05:45 +00:00
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 )
2008-08-07 03:38:49 +00:00
class ValidationError ( IPAError ) :
2008-09-03 19:38:39 +00:00
"""
Base class for all types of validation errors .
"""
format = ' invalid %r value %r : %s '
2008-08-07 03:38:49 +00:00
2008-09-03 18:48:58 +00:00
def __init__ ( self , name , value , error , index = None ) :
2008-09-03 19:38:39 +00:00
"""
: 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
"""
2008-09-03 20:05:24 +00:00
assert type ( name ) is str
assert index is None or ( type ( index ) is int and index > = 0 )
2008-08-08 21:40:03 +00:00
self . name = name
self . value = value
self . error = error
2008-09-03 18:48:58 +00:00
self . index = index
2008-08-13 04:11:26 +00:00
IPAError . __init__ ( self , name , value , error )
2008-08-07 03:38:49 +00:00
2008-08-07 06:23:02 +00:00
2008-09-03 18:32:49 +00:00
class ConversionError ( ValidationError ) :
2008-09-03 21:53:15 +00:00
"""
Raised when a value cannot be converted to the correct type .
"""
2008-09-03 18:32:49 +00:00
2008-09-03 21:53:15 +00:00
def __init__ ( self , name , value , type_ , index = None ) :
self . type = type_
ValidationError . __init__ ( self , name , value , type_ . conversion_error ,
index = index ,
)
2008-09-03 18:32:49 +00:00
2008-08-07 06:23:02 +00:00
class RuleError ( ValidationError ) :
2008-08-13 05:14:12 +00:00
"""
2008-09-03 19:38:39 +00:00
Raised when a value fails a validation rule .
2008-08-13 05:14:12 +00:00
"""
2008-09-03 19:38:39 +00:00
def __init__ ( self , name , value , error , rule , index = None ) :
2008-09-03 22:14:25 +00:00
assert callable ( rule )
self . rule = rule
ValidationError . __init__ ( self , name , value , error , index = index )
2008-07-28 04:34:25 +00:00
2008-08-13 05:14:12 +00:00
class RequirementError ( ValidationError ) :
"""
Raised when a required option was not provided .
"""
def __init__ ( self , name ) :
2008-09-03 22:29:01 +00:00
ValidationError . __init__ ( self , name , None , ' Required ' )
2008-08-13 05:14:12 +00:00
2008-07-28 04:34:25 +00:00
2008-07-19 04:28:03 +00:00
class RegistrationError ( IPAError ) :
2008-08-08 17:11:29 +00:00
"""
Base class for errors that occur during plugin registration .
"""
2008-07-28 04:34:25 +00:00
2008-08-05 06:33:09 +00:00
class NameSpaceError ( RegistrationError ) :
2008-08-08 17:11:29 +00:00
msg = ' name %r does not re.match %r '
2008-08-05 06:33:09 +00:00
2008-07-28 04:34:25 +00:00
class SubclassError ( RegistrationError ) :
2008-08-08 17:11:29 +00:00
"""
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 '
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __init__ ( self , cls , allowed ) :
2008-08-08 21:40:03 +00:00
self . cls = cls
self . allowed = allowed
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __str__ ( self ) :
2008-08-08 21:40:03 +00:00
return self . msg % ( self . cls , self . allowed )
2008-07-28 04:34:25 +00:00
class DuplicateError ( RegistrationError ) :
2008-08-08 17:11:29 +00:00
"""
Raised when registering a plugin whose exact class has already been
registered .
"""
msg = ' %r at %d was already registered '
2008-07-19 06:03:34 +00:00
2008-08-08 17:11:29 +00:00
def __init__ ( self , cls ) :
2008-08-08 21:40:03 +00:00
self . cls = cls
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __str__ ( self ) :
2008-08-08 21:40:03 +00:00
return self . msg % ( self . cls , id ( self . cls ) )
2008-07-28 04:34:25 +00:00
class OverrideError ( RegistrationError ) :
2008-08-08 17:11:29 +00:00
"""
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) '
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __init__ ( self , base , cls ) :
2008-08-08 21:40:03 +00:00
self . base = base
self . cls = cls
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __str__ ( self ) :
2008-08-08 21:40:03 +00:00
return self . msg % ( self . base . __name__ , self . cls . __name__ , self . cls )
2008-07-28 04:34:25 +00:00
class MissingOverrideError ( RegistrationError ) :
2008-08-08 17:11:29 +00:00
"""
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 '
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __init__ ( self , base , cls ) :
2008-08-08 21:40:03 +00:00
self . base = base
self . cls = cls
2008-07-28 04:34:25 +00:00
2008-08-08 17:11:29 +00:00
def __str__ ( self ) :
2008-08-08 21:40:03 +00:00
return self . msg % ( self . base . __name__ , self . cls . __name__ , self . cls )
2008-10-08 23:31:49 -04:00
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 NotFound ( GenericError ) :
""" Entry not found """
faultCode = 1003
2008-10-09 01:43:23 -04:00
class DuplicateEntry ( GenericError ) :
2008-10-08 23:31:49 -04:00
""" This entry already exists """
faultCode = 1004
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
2008-10-13 17:17:00 -04:00
class NotGroupMember ( InputError ) :
""" This entry is not a member of the group """
faultCode = 1009
2008-10-08 23:31:49 -04:00
class AdminsImmutable ( InputError ) :
""" The admins group cannot be renamed """
2008-10-13 17:17:00 -04:00
faultCode = 1010
2008-10-08 23:31:49 -04:00
class UsernameTooLong ( InputError ) :
""" The requested username is too long """
2008-10-13 17:17:00 -04:00
faultCode = 1011
2008-10-08 23:31:49 -04:00
class PrincipalError ( GenericError ) :
""" There is a problem with the kerberos principal """
2008-10-13 17:17:00 -04:00
faultCode = 1012
2008-10-08 23:31:49 -04:00
class MalformedServicePrincipal ( PrincipalError ) :
""" The requested service principal is not of the form: service/fully-qualified host name """
2008-10-13 17:17:00 -04:00
faultCode = 1013
2008-10-08 23:31:49 -04:00
class RealmMismatch ( PrincipalError ) :
""" The realm for the principal does not match the realm for this IPA server """
2008-10-13 17:17:00 -04:00
faultCode = 1014
2008-10-08 23:31:49 -04:00
class PrincipalRequired ( PrincipalError ) :
""" You cannot remove IPA server service principals """
2008-10-13 17:17:00 -04:00
faultCode = 1015
2008-10-08 23:31:49 -04:00
class InactivationError ( GenericError ) :
""" This entry cannot be inactivated """
2008-10-13 17:17:00 -04:00
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
2008-10-08 23:31:49 -04:00
class ConnectionError ( GenericError ) :
""" Connection to database failed """
2008-10-13 17:17:00 -04:00
faultCode = 1020
2008-10-08 23:31:49 -04:00
class NoCCacheError ( GenericError ) :
""" No Kerberos credentials cache is available. Connection cannot be made """
2008-10-13 17:17:00 -04:00
faultCode = 1021
2008-10-08 23:31:49 -04:00
class GSSAPIError ( GenericError ) :
""" GSSAPI Authorization error """
2008-10-13 17:17:00 -04:00
faultCode = 1022
2008-10-08 23:31:49 -04:00
class ServerUnwilling ( GenericError ) :
""" Account inactivated. Server is unwilling to perform """
2008-10-13 17:17:00 -04:00
faultCode = 1023
2008-10-08 23:31:49 -04:00
class ConfigurationError ( GenericError ) :
""" A configuration error occurred """
2008-10-13 17:17:00 -04:00
faultCode = 1024
2008-10-08 23:31:49 -04:00
class DefaultGroup ( ConfigurationError ) :
""" You cannot remove the default users group """
2008-10-13 17:17:00 -04:00
faultCode = 1025
2008-10-08 23:31:49 -04:00
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 \
2008-10-09 01:43:23 -04:00
code == getattr ( v , ' faultCode ' , None ) :
2008-10-08 23:31:49 -04:00
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