#
#
-# 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
"""Ganeti exception handling"""
+# OpPrereqError failure types
+
+# resolver errors
+ECODE_RESOLVER = "resolver_error"
+# not enough resources (iallocator failure, disk space, memory, etc.)
+ECODE_NORES = "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"
+# entity already exists
+ECODE_EXISTS = "already_exists"
+# 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 = frozenset([
+ ECODE_RESOLVER,
+ ECODE_NORES,
+ ECODE_INVAL,
+ ECODE_STATE,
+ ECODE_NOENT,
+ ECODE_EXISTS,
+ ECODE_NOTUNIQUE,
+ ECODE_FAULT,
+ ECODE_ENVIRON,
+ ])
+
+
class GenericError(Exception):
"""Base exception for Ganeti.
"""
- pass
-class LVMError(GenericError):
- """LVM-related exception.
+class LockError(GenericError):
+ """Lock error exception.
- This exception codifies problems with LVM setup.
+ This signifies problems in the locking subsystem.
"""
- pass
-class LockError(GenericError):
- """Lock error exception.
-
- This signifies problems in the locking subsystem.
+class PidFileLockError(LockError):
+ """PID file is already locked by another process.
"""
- pass
class HypervisorError(GenericError):
properly.
"""
- pass
class ProgrammerError(GenericError):
parts of our code. It signifies a real programming bug.
"""
- pass
class BlockDeviceError(GenericError):
properly.
"""
- pass
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 ReservationError(GenericError):
+ """Errors reserving a resource.
+
+ """
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.
"""
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 will have either one or two arguments. For the
+ two-argument construction, the second argument should be one of the
+ ECODE_* codes.
+
"""
"""
-class OpRetryError(OpExecError):
- """Error during OpCode execution, action can be retried.
+class OpResultError(GenericError):
+ """Issue with OpCode result.
"""
"""
+class JobFileCorrupted(GenericError):
+ """Job file could not be properly decoded/restored.
+
+ """
+
+
class ResolverError(GenericError):
"""Host name cannot be resolved.
"""
+
+class ParseError(GenericError):
+ """Generic parse error.
+
+ Raised when unable to parse user input.
+
+ """
+
+
class TypeEnforcementError(GenericError):
"""Unable to enforce data type.
"""
-class SshKeyError(GenericError):
- """Invalid SSH key.
+
+class X509CertError(GenericError):
+ """Invalid X509 certificate.
+
+ This error has two arguments: the certificate filename and the error cause.
"""
"""
+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 instance should be instantiated with two values. The
+ 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
"""
+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
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)