Instance startup: lock primary node
[ganeti-local] / lib / errors.py
index 9fd9868..3847353 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
 #
 #
 
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 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
 #
 # 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"""
 
 
 """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.
 
 class GenericError(Exception):
   """Base exception for Ganeti.
 
@@ -47,6 +82,12 @@ class LockError(GenericError):
   pass
 
 
   pass
 
 
+class PidFileLockError(LockError):
+  """PID file is already locked by another process.
+
+  """
+
+
 class HypervisorError(GenericError):
   """Hypervisor-related exception.
 
 class HypervisorError(GenericError):
   """Hypervisor-related exception.
 
@@ -88,6 +129,22 @@ class ConfigurationError(GenericError):
   pass
 
 
   pass
 
 
+class ConfigVersionMismatch(ConfigurationError):
+  """Version mismatch in the configuration file.
+
+  The error has two arguments: the expected and the actual found
+  version.
+
+  """
+  pass
+
+
+class ReservationError(GenericError):
+  """Errors reserving a resource.
+
+  """
+
+
 class RemoteError(GenericError):
   """Programming-related error on remote call.
 
 class RemoteError(GenericError):
   """Programming-related error on remote call.
 
@@ -125,6 +182,10 @@ class ParameterError(GenericError):
 class OpPrereqError(GenericError):
   """Prerequisites for the OpCode are not fulfilled.
 
 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.
+
   """
 
 
   """
 
 
@@ -134,8 +195,8 @@ class OpExecError(GenericError):
   """
 
 
   """
 
 
-class OpRetryError(OpExecError):
-  """Error during OpCode execution, action can be retried.
+class OpResultError(GenericError):
+  """Issue with OpCode result.
 
   """
 
 
   """
 
@@ -158,6 +219,12 @@ class JobLost(GenericError):
   """
 
 
   """
 
 
+class JobFileCorrupted(GenericError):
+  """Job file could not be properly decoded/restored.
+
+  """
+
+
 class ResolverError(GenericError):
   """Host name cannot be resolved.
 
 class ResolverError(GenericError):
   """Host name cannot be resolved.
 
@@ -196,6 +263,14 @@ 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 TypeEnforcementError(GenericError):
   """Unable to enforce data type.
 
@@ -208,6 +283,14 @@ class SshKeyError(GenericError):
   """
 
 
   """
 
 
+class X509CertError(GenericError):
+  """Invalid X509 certificate.
+
+  This error has two arguments: the certificate filename and the error cause.
+
+  """
+
+
 class TagError(GenericError):
   """Generic tag error.
 
 class TagError(GenericError):
   """Generic tag error.
 
@@ -235,7 +318,7 @@ class InotifyError(GenericError):
 
 
 class QuitGanetiException(Exception):
 
 
 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
 
   This is not necessarily an error (and thus not a subclass of
   GenericError), but it's an exceptional circumstance and it is thus
@@ -279,15 +362,6 @@ class JobQueueFull(JobQueueError):
   """
 
 
   """
 
 
-class ConfdFatalError(GenericError):
-  """A fatal failure in Ganeti confd.
-
-  Events that compromise the ability of confd to proceed further.
-  (for example: inability to load the config file)
-
-  """
-
-
 class ConfdRequestError(GenericError):
   """A request error in Ganeti confd.
 
 class ConfdRequestError(GenericError):
   """A request error in Ganeti confd.
 
@@ -319,6 +393,42 @@ class UdpDataSizeError(GenericError):
   """
 
 
   """
 
 
+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.
+
+  """
+  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)]
+
+
 # errors should be added above
 
 
 # errors should be added above
 
 
@@ -357,17 +467,33 @@ def EncodeException(err):
   return (err.__class__.__name__, err.args)
 
 
   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
 
   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
 
   """
   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
+    raise errcls(args)