X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/686d74337a38adc1d666ae372405ac037f4ad5a9..68169c48c4503cb69504e645ad164577deaf25c1:/lib/errors.py?ds=sidebyside diff --git a/lib/errors.py b/lib/errors.py index 6efd9aa..f205f4a 100644 --- a/lib/errors.py +++ b/lib/errors.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc. # # 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 @@ -19,23 +19,64 @@ # 02110-1301, USA. -"""Ganeti exception handling""" +"""Ganeti exception handling. +""" -class GenericError(Exception): - """Base exception for Ganeti. +from ganeti import compat - """ - pass +# OpPrereqError failure types + +#: Resolver errors +ECODE_RESOLVER = "resolver_error" + +#: Not enough resources (iallocator failure, disk space, memory, etc.) +ECODE_NORES = "insufficient_resources" + +#: Temporarily out of resources; operation can be tried again +ECODE_TEMP_NORES = "temp_insufficient_resources" + +#: Wrong arguments (at syntax level) +ECODE_INVAL = "wrong_input" + +#: Wrong entity state +ECODE_STATE = "wrong_state" + +#: Entity not found +ECODE_NOENT = "unknown_entity" -class LVMError(GenericError): - """LVM-related exception. +#: Entity already exists +ECODE_EXISTS = "already_exists" - This exception codifies problems with LVM setup. +#: Resource not unique (e.g. MAC or IP duplication) +ECODE_NOTUNIQUE = "resource_not_unique" + +#: Internal cluster error +ECODE_FAULT = "internal_error" + +#: Environment error (e.g. node disk error) +ECODE_ENVIRON = "environment_error" + +#: List of all failure types +ECODE_ALL = compat.UniqueFrozenset([ + ECODE_RESOLVER, + ECODE_NORES, + ECODE_TEMP_NORES, + ECODE_INVAL, + ECODE_STATE, + ECODE_NOENT, + ECODE_EXISTS, + ECODE_NOTUNIQUE, + ECODE_FAULT, + ECODE_ENVIRON, + ]) + + +class GenericError(Exception): + """Base exception for Ganeti. """ - pass class LockError(GenericError): @@ -44,7 +85,12 @@ class LockError(GenericError): This signifies problems in the locking subsystem. """ - pass + + +class PidFileLockError(LockError): + """PID file is already locked by another process. + + """ class HypervisorError(GenericError): @@ -54,7 +100,15 @@ class HypervisorError(GenericError): properly. """ - pass + + +class HotplugError(HypervisorError): + """Hotplug-related exception. + + This is raised in case a hotplug action fails or is not supported. + It is currently used only by KVM hypervisor. + + """ class ProgrammerError(GenericError): @@ -65,7 +119,6 @@ class ProgrammerError(GenericError): parts of our code. It signifies a real programming bug. """ - pass class BlockDeviceError(GenericError): @@ -75,7 +128,6 @@ class BlockDeviceError(GenericError): properly. """ - pass class ConfigurationError(GenericError): @@ -85,7 +137,27 @@ class ConfigurationError(GenericError): exist in the config or such raise this exception. """ - pass + + +class ConfigVersionMismatch(ConfigurationError): + """Version mismatch in the configuration file. + + The error has two arguments: the expected and the actual found + version. + + """ + + +class AddressPoolError(GenericError): + """Errors related to IP address pools. + + """ + + +class ReservationError(GenericError): + """Errors reserving a resource. + + """ class RemoteError(GenericError): @@ -95,19 +167,14 @@ class RemoteError(GenericError): remote node. It usually signifies a real programming bug. """ - pass - -class InvalidOS(GenericError): - """Missing OS on node. - This is raised when an OS exists on the master (or is otherwise - requested to the code) but not on the target node. +class SignatureError(GenericError): + """Error authenticating a remote message. - This exception has three arguments: - - the name of the os - - the source directory, if any - - the reason why we consider this an invalid OS (text of error message) + This is raised when the hmac signature on a message doesn't verify correctly + to the message itself. It can happen because of network unreliability or + because of spurious traffic. """ @@ -122,12 +189,20 @@ class ParameterError(GenericError): The argument to this exception should be the parameter name. """ - pass + + +class ResultValidationError(GenericError): + """The iallocation results fails validation. + + """ class OpPrereqError(GenericError): """Prerequisites for the OpCode are not fulfilled. + This exception has two arguments: an error message, and one of the + ECODE_* codes. + """ @@ -137,10 +212,26 @@ class OpExecError(GenericError): """ -class OpRetryError(OpExecError): - """Error during OpCode execution, action can be retried. +class OpResultError(GenericError): + """Issue with OpCode result. + + """ + + +class DeviceCreationError(GenericError): + """Error during the creation of a device. + + This exception should contain the list of the devices actually created + up to now, in the form of pairs (node, device) """ + def __init__(self, message, created_devices): + GenericError.__init__(self) + self.message = message + self.created_devices = created_devices + + def __str__(self): + return self.message class OpCodeUnknown(GenericError): @@ -161,6 +252,12 @@ class JobLost(GenericError): """ +class JobFileCorrupted(GenericError): + """Job file could not be properly decoded/restored. + + """ + + class ResolverError(GenericError): """Host name cannot be resolved. @@ -199,8 +296,24 @@ class UnitParseError(GenericError): """ -class SshKeyError(GenericError): - """Invalid SSH key. +class ParseError(GenericError): + """Generic parse error. + + Raised when unable to parse user input. + + """ + + +class TypeEnforcementError(GenericError): + """Unable to enforce data type. + + """ + + +class X509CertError(GenericError): + """Invalid X509 certificate. + + This error has two arguments: the certificate filename and the error cause. """ @@ -219,20 +332,36 @@ class CommandError(GenericError): """ +class StorageError(GenericError): + """Storage-related exception. + + """ + + +class InotifyError(GenericError): + """Error raised when there is a failure setting up an inotify watcher. + + """ + + class QuitGanetiException(Exception): - """Signal that Ganeti that it must quit. + """Signal Ganeti that it must quit. + + This is not necessarily an error (and thus not a subclass of + GenericError), but it's an exceptional circumstance and it is thus + treated. This exception should be instantiated with two values. The + first one will specify the return code to the caller, and the second + one will be the returned result (either as an error or as a normal + result). Usually only the leave cluster rpc call should return + status True (as there it's expected we quit), every other call will + return status False (as a critical error was encountered). - This is not necessarily an error (and thus not a subclass of GenericError), - but it's an exceptional circumstance and it is thus treated. This instance - should be instantiated with two values. The first one will specify whether an - error should returned to the caller, and the second one will be the returned - result (either as an error or as a normal result). + Examples:: - Examples: # Return a result of "True" to the caller, but quit ganeti afterwards - raise QuitGanetiException(False, True) + raise QuitGanetiException(True, None) # Send an error to the caller, and quit ganeti - raise QuitGanetiException(True, "Fatal safety violation, shutting down") + raise QuitGanetiException(False, "Fatal safety violation, shutting down") """ @@ -252,6 +381,89 @@ class JobQueueDrainError(JobQueueError): """ +class JobQueueFull(JobQueueError): + """Job queue full error. + + Raised when job queue size reached its hard limit. + + """ + + +class ConfdMagicError(GenericError): + """A magic fourcc error in Ganeti confd. + + Errors processing the fourcc in ganeti confd datagrams. + + """ + + +class ConfdClientError(GenericError): + """A magic fourcc error in Ganeti confd. + + Errors in the confd client library. + + """ + + +class UdpDataSizeError(GenericError): + """UDP payload too big. + + """ + + +class NoCtypesError(GenericError): + """python ctypes module is not found in the system. + + """ + + +class IPAddressError(GenericError): + """Generic IP address error. + + """ + + +class LuxiError(GenericError): + """LUXI error. + + """ + + +class QueryFilterParseError(ParseError): + """Error while parsing query filter. + + This exception must be instantiated with two values. The first one is a + string with an error description, the second one is an instance of a subclass + of C{pyparsing.ParseBaseException} (used to display the exact error + location). + + """ + def GetDetails(self): + """Returns a list of strings with details about the error. + + """ + try: + (_, inner) = self.args + except IndexError: + return None + + return [str(inner.line), + (" " * (inner.column - 1)) + "^", + str(inner)] + + +class RapiTestResult(GenericError): + """Exception containing results from RAPI test utilities. + + """ + + +class FileStoragePathError(GenericError): + """Error from file storage path validation. + + """ + + # errors should be added above @@ -272,3 +484,52 @@ def GetErrorClass(name): issubclass(item, GenericError)): item = None return item + + +def EncodeException(err): + """Encodes an exception into a format that L{MaybeRaise} will recognise. + + The passed L{err} argument will be formatted as a tuple (exception + name, arguments) that the MaybeRaise function will recognise. + + @type err: GenericError child + @param err: usually a child of GenericError (but any exception + will be accepted) + @rtype: tuple + @return: tuple of (exception name, exception arguments) + + """ + return (err.__class__.__name__, err.args) + + +def GetEncodedError(result): + """If this looks like an encoded Ganeti exception, return it. + + This function tries to parse the passed argument and if it looks + like an encoding done by EncodeException, it will return the class + object and arguments. + + """ + tlt = (tuple, list) + if (isinstance(result, tlt) and len(result) == 2 and + isinstance(result[1], tlt)): + # custom ganeti errors + errcls = GetErrorClass(result[0]) + if errcls: + return (errcls, tuple(result[1])) + + return None + + +def MaybeRaise(result): + """If this looks like an encoded Ganeti exception, raise it. + + This function tries to parse the passed argument and if it looks + like an encoding done by EncodeException, it will re-raise it. + + """ + error = GetEncodedError(result) + if error: + (errcls, args) = error + # pylint: disable=W0142 + raise errcls(*args)