(grnet) Remove deprecated idx slot from NIC/Disk objects
[ganeti-local] / lib / errors.py
index 40a0ae7..f205f4a 100644 (file)
@@ -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
 # 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"
 
-class LVMError(GenericError):
-  """LVM-related exception.
+#: Wrong entity state
+ECODE_STATE = "wrong_state"
 
-  This exception codifies problems with LVM setup.
+#: 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 = 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,7 +167,6 @@ class RemoteError(GenericError):
   remote node.  It usually signifies a real programming bug.
 
   """
-  pass
 
 
 class SignatureError(GenericError):
@@ -106,7 +177,6 @@ class SignatureError(GenericError):
   because of spurious traffic.
 
   """
-  pass
 
 
 class ParameterError(GenericError):
@@ -119,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.
+
   """
 
 
@@ -134,6 +212,28 @@ class OpExecError(GenericError):
   """
 
 
+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):
   """Unknown opcode submitted.
 
@@ -152,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.
 
@@ -190,14 +296,24 @@ class UnitParseError(GenericError):
   """
 
 
+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.
 
   """
 
@@ -229,11 +345,11 @@ class InotifyError(GenericError):
 
 
 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
@@ -273,42 +389,77 @@ class JobQueueFull(JobQueueError):
   """
 
 
-class ConfdFatalError(GenericError):
-  """A fatal failure in Ganeti confd.
+class ConfdMagicError(GenericError):
+  """A magic fourcc error in Ganeti confd.
 
-  Events that compromise the ability of confd to proceed further.
-  (for example: inability to load the config file)
+  Errors processing the fourcc in ganeti confd datagrams.
 
   """
 
 
-class ConfdRequestError(GenericError):
-  """A request error in Ganeti confd.
+class ConfdClientError(GenericError):
+  """A magic fourcc error in Ganeti confd.
 
-  Events that should make confd abort the current request and proceed serving
-  different ones.
+  Errors in the confd client library.
 
   """
 
 
-class ConfdMagicError(GenericError):
-  """A magic fourcc error in Ganeti confd.
+class UdpDataSizeError(GenericError):
+  """UDP payload too big.
 
-  Errors processing the fourcc in ganeti confd datagrams.
+  """
+
+
+class NoCtypesError(GenericError):
+  """python ctypes module is not found in the system.
 
   """
 
 
-class ConfdClientError(GenericError):
-  """A magic fourcc error in Ganeti confd.
+class IPAddressError(GenericError):
+  """Generic IP address error.
 
-  Errors in the confd client library.
+  """
+
+
+class LuxiError(GenericError):
+  """LUXI error.
 
   """
 
 
-class UdpDataSizeError(GenericError):
-  """UDP payload too big.
+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.
 
   """
 
@@ -351,17 +502,34 @@ def EncodeException(err):
   return (err.__class__.__name__, err.args)
 
 
-def MaybeRaise(result):
-  """Is this looks like an encoded Ganeti exception, raise it.
+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 re-raise it.
+  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
-    err_class = GetErrorClass(result[0])
-    if err_class is not None:
-      raise err_class, tuple(result[1])
+    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)