Merge branch 'stable-2.6-hotplug' into stable-2.6-ippool-hotplug-esi
[ganeti-local] / lib / errors.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Ganeti exception handling"""
23
24
25 # OpPrereqError failure types
26
27 # resolver errors
28 ECODE_RESOLVER = "resolver_error"
29 # not enough resources (iallocator failure, disk space, memory, etc.)
30 ECODE_NORES = "insufficient_resources"
31 # wrong arguments (at syntax level)
32 ECODE_INVAL = "wrong_input"
33 # wrong entity state
34 ECODE_STATE = "wrong_state"
35 # entity not found
36 ECODE_NOENT = "unknown_entity"
37 # entity already exists
38 ECODE_EXISTS = "already_exists"
39 # resource not unique (e.g. MAC or IP duplication)
40 ECODE_NOTUNIQUE = "resource_not_unique"
41 # internal cluster error
42 ECODE_FAULT = "internal_error"
43 # environment error (e.g. node disk error)
44 ECODE_ENVIRON = "environment_error"
45
46 #: List of all failure types
47 ECODE_ALL = frozenset([
48   ECODE_RESOLVER,
49   ECODE_NORES,
50   ECODE_INVAL,
51   ECODE_STATE,
52   ECODE_NOENT,
53   ECODE_EXISTS,
54   ECODE_NOTUNIQUE,
55   ECODE_FAULT,
56   ECODE_ENVIRON,
57   ])
58
59
60 class GenericError(Exception):
61   """Base exception for Ganeti.
62
63   """
64   pass
65
66
67 class LVMError(GenericError):
68   """LVM-related exception.
69
70   This exception codifies problems with LVM setup.
71
72   """
73   pass
74
75
76 class LockError(GenericError):
77   """Lock error exception.
78
79   This signifies problems in the locking subsystem.
80
81   """
82   pass
83
84
85 class PidFileLockError(LockError):
86   """PID file is already locked by another process.
87
88   """
89
90
91 class HypervisorError(GenericError):
92   """Hypervisor-related exception.
93
94   This is raised in case we can't communicate with the hypervisor
95   properly.
96
97   """
98   pass
99
100
101 class ProgrammerError(GenericError):
102   """Programming-related error.
103
104   This is raised in cases we determine that the calling conventions
105   have been violated, meaning we got some desynchronisation between
106   parts of our code. It signifies a real programming bug.
107
108   """
109   pass
110
111
112 class BlockDeviceError(GenericError):
113   """Block-device related exception.
114
115   This is raised in case we can't setup the instance's block devices
116   properly.
117
118   """
119   pass
120
121
122 class ConfigurationError(GenericError):
123   """Configuration related exception.
124
125   Things like having an instance with a primary node that doesn't
126   exist in the config or such raise this exception.
127
128   """
129   pass
130
131
132 class ConfigVersionMismatch(ConfigurationError):
133   """Version mismatch in the configuration file.
134
135   The error has two arguments: the expected and the actual found
136   version.
137
138   """
139   pass
140
141
142 class AddressPoolError(GenericError):
143   """Errors related to IP address pools.
144
145   """
146
147
148 class ReservationError(GenericError):
149   """Errors reserving a resource.
150
151   """
152
153
154 class RemoteError(GenericError):
155   """Programming-related error on remote call.
156
157   This is raised when an unhandled error occurs in a call to a
158   remote node.  It usually signifies a real programming bug.
159
160   """
161   pass
162
163
164 class SignatureError(GenericError):
165   """Error authenticating a remote message.
166
167   This is raised when the hmac signature on a message doesn't verify correctly
168   to the message itself. It can happen because of network unreliability or
169   because of spurious traffic.
170
171   """
172   pass
173
174
175 class ParameterError(GenericError):
176   """A passed parameter to a command is invalid.
177
178   This is raised when the parameter passed to a request function is
179   invalid. Correct code should have verified this before passing the
180   request structure.
181
182   The argument to this exception should be the parameter name.
183
184   """
185   pass
186
187
188 class OpPrereqError(GenericError):
189   """Prerequisites for the OpCode are not fulfilled.
190
191   This exception will have either one or two arguments. For the
192   two-argument construction, the second argument should be one of the
193   ECODE_* codes.
194
195   """
196
197
198 class OpExecError(GenericError):
199   """Error during OpCode execution.
200
201   """
202
203
204 class OpResultError(GenericError):
205   """Issue with OpCode result.
206
207   """
208
209
210 class OpCodeUnknown(GenericError):
211   """Unknown opcode submitted.
212
213   This signifies a mismatch between the definitions on the client and
214   server side.
215
216   """
217
218
219 class JobLost(GenericError):
220   """Submitted job lost.
221
222   The job was submitted but it cannot be found in the current job
223   list.
224
225   """
226
227
228 class JobFileCorrupted(GenericError):
229   """Job file could not be properly decoded/restored.
230
231   """
232
233
234 class ResolverError(GenericError):
235   """Host name cannot be resolved.
236
237   This is not a normal situation for Ganeti, as we rely on having a
238   working resolver.
239
240   The non-resolvable hostname is available as the first element of the
241   args tuple; the other two elements of the tuple are the first two
242   args of the socket.gaierror exception (error code and description).
243
244   """
245
246
247 class HooksFailure(GenericError):
248   """A generic hook failure.
249
250   This signifies usually a setup misconfiguration.
251
252   """
253
254
255 class HooksAbort(HooksFailure):
256   """A required hook has failed.
257
258   This caused an abort of the operation in the initial phase. This
259   exception always has an attribute args which is a list of tuples of:
260     - node: the source node on which this hooks has failed
261     - script: the name of the script which aborted the run
262
263   """
264
265
266 class UnitParseError(GenericError):
267   """Unable to parse size unit.
268
269   """
270
271
272 class ParseError(GenericError):
273   """Generic parse error.
274
275   Raised when unable to parse user input.
276
277   """
278
279
280 class TypeEnforcementError(GenericError):
281   """Unable to enforce data type.
282
283   """
284
285
286 class SshKeyError(GenericError):
287   """Invalid SSH key.
288
289   """
290
291
292 class X509CertError(GenericError):
293   """Invalid X509 certificate.
294
295   This error has two arguments: the certificate filename and the error cause.
296
297   """
298
299
300 class TagError(GenericError):
301   """Generic tag error.
302
303   The argument to this exception will show the exact error.
304
305   """
306
307
308 class CommandError(GenericError):
309   """External command error.
310
311   """
312
313
314 class StorageError(GenericError):
315   """Storage-related exception.
316
317   """
318
319
320 class InotifyError(GenericError):
321   """Error raised when there is a failure setting up an inotify watcher.
322
323   """
324
325
326 class QuitGanetiException(Exception):
327   """Signal Ganeti that it must quit.
328
329   This is not necessarily an error (and thus not a subclass of
330   GenericError), but it's an exceptional circumstance and it is thus
331   treated. This instance should be instantiated with two values. The
332   first one will specify the return code to the caller, and the second
333   one will be the returned result (either as an error or as a normal
334   result). Usually only the leave cluster rpc call should return
335   status True (as there it's expected we quit), every other call will
336   return status False (as a critical error was encountered).
337
338   Examples::
339
340     # Return a result of "True" to the caller, but quit ganeti afterwards
341     raise QuitGanetiException(True, None)
342     # Send an error to the caller, and quit ganeti
343     raise QuitGanetiException(False, "Fatal safety violation, shutting down")
344
345   """
346
347
348 class JobQueueError(GenericError):
349   """Job queue error.
350
351   """
352
353
354 class JobQueueDrainError(JobQueueError):
355   """Job queue is marked for drain error.
356
357   This is raised when a job submission attempt is made but the queue
358   is marked for drain.
359
360   """
361
362
363 class JobQueueFull(JobQueueError):
364   """Job queue full error.
365
366   Raised when job queue size reached its hard limit.
367
368   """
369
370
371 class ConfdRequestError(GenericError):
372   """A request error in Ganeti confd.
373
374   Events that should make confd abort the current request and proceed serving
375   different ones.
376
377   """
378
379
380 class ConfdMagicError(GenericError):
381   """A magic fourcc error in Ganeti confd.
382
383   Errors processing the fourcc in ganeti confd datagrams.
384
385   """
386
387
388 class ConfdClientError(GenericError):
389   """A magic fourcc error in Ganeti confd.
390
391   Errors in the confd client library.
392
393   """
394
395
396 class UdpDataSizeError(GenericError):
397   """UDP payload too big.
398
399   """
400
401
402 class NoCtypesError(GenericError):
403   """python ctypes module is not found in the system.
404
405   """
406
407
408 class IPAddressError(GenericError):
409   """Generic IP address error.
410
411   """
412
413
414 class LuxiError(GenericError):
415   """LUXI error.
416
417   """
418
419
420 class QueryFilterParseError(ParseError):
421   """Error while parsing query filter.
422
423   """
424   def GetDetails(self):
425     """Returns a list of strings with details about the error.
426
427     """
428     try:
429       (_, inner) = self.args
430     except IndexError:
431       return None
432
433     return [str(inner.line),
434             (" " * (inner.column - 1)) + "^",
435             str(inner)]
436
437
438 class RapiTestResult(GenericError):
439   """Exception containing results from RAPI test utilities.
440
441   """
442
443
444 # errors should be added above
445
446
447 def GetErrorClass(name):
448   """Return the class of an exception.
449
450   Given the class name, return the class itself.
451
452   @type name: str
453   @param name: the exception name
454   @rtype: class
455   @return: the actual class, or None if not found
456
457   """
458   item = globals().get(name, None)
459   if item is not None:
460     if not (isinstance(item, type(Exception)) and
461             issubclass(item, GenericError)):
462       item = None
463   return item
464
465
466 def EncodeException(err):
467   """Encodes an exception into a format that L{MaybeRaise} will recognise.
468
469   The passed L{err} argument will be formatted as a tuple (exception
470   name, arguments) that the MaybeRaise function will recognise.
471
472   @type err: GenericError child
473   @param err: usually a child of GenericError (but any exception
474       will be accepted)
475   @rtype: tuple
476   @return: tuple of (exception name, exception arguments)
477
478   """
479   return (err.__class__.__name__, err.args)
480
481
482 def GetEncodedError(result):
483   """If this looks like an encoded Ganeti exception, return it.
484
485   This function tries to parse the passed argument and if it looks
486   like an encoding done by EncodeException, it will return the class
487   object and arguments.
488
489   """
490   tlt = (tuple, list)
491   if (isinstance(result, tlt) and len(result) == 2 and
492       isinstance(result[1], tlt)):
493     # custom ganeti errors
494     errcls = GetErrorClass(result[0])
495     if errcls:
496       return (errcls, tuple(result[1]))
497
498   return None
499
500
501 def MaybeRaise(result):
502   """If this looks like an encoded Ganeti exception, raise it.
503
504   This function tries to parse the passed argument and if it looks
505   like an encoding done by EncodeException, it will re-raise it.
506
507   """
508   error = GetEncodedError(result)
509   if error:
510     (errcls, args) = error
511     # pylint: disable=W0142
512     raise errcls(*args)