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