summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-04-20 13:58:26 -0400
committerRob Crittenden <rcritten@redhat.com>2009-04-20 13:58:26 -0400
commit64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a (patch)
treea4543df175f8bf0efcd200662a9e7f00fea7bf52 /ipalib
parenta9387b48e66ca93cc8323869de25fe3f777567b6 (diff)
downloadfreeipa-64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a.tar.gz
freeipa-64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a.tar.xz
freeipa-64fa3dd4c3a03e7a677453c9150f84ffc4e91c7a.zip
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.
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/cli.py8
-rw-r--r--ipalib/errors.py441
-rw-r--r--ipalib/errors2.py174
-rw-r--r--ipalib/plugins/basegroup.py2
-rw-r--r--ipalib/plugins/passwd.py14
-rw-r--r--ipalib/util.py21
6 files changed, 194 insertions, 466 deletions
diff --git a/ipalib/cli.py b/ipalib/cli.py
index 11b56e36f..36c945f2b 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -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
diff --git a/ipalib/errors.py b/ipalib/errors.py
deleted file mode 100644
index c27d85dea..000000000
--- a/ipalib/errors.py
+++ /dev/null
@@ -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
diff --git a/ipalib/errors2.py b/ipalib/errors2.py
index 7e752d824..341421e56 100644
--- a/ipalib/errors2.py
+++ b/ipalib/errors2.py
@@ -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
diff --git a/ipalib/plugins/basegroup.py b/ipalib/plugins/basegroup.py
index 7cba75a47..b93fdc8d9 100644
--- a/ipalib/plugins/basegroup.py
+++ b/ipalib/plugins/basegroup.py
@@ -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
diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py
index a599276f4..cc7ab5861 100644
--- a/ipalib/plugins/passwd.py
+++ b/ipalib/plugins/passwd.py
@@ -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(
diff --git a/ipalib/util.py b/ipalib/util.py
index 3e47cc3a1..54529b14c 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -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)