Statistics
| Branch: | Tag: | Revision:

root / lib / errors.py @ 966e1580

History | View | Annotate | Download (10.8 kB)

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

    
26
from ganeti import compat
27

    
28

    
29
# OpPrereqError failure types
30

    
31
#: Resolver errors
32
ECODE_RESOLVER = "resolver_error"
33

    
34
#: Not enough resources (iallocator failure, disk space, memory, etc.)
35
ECODE_NORES = "insufficient_resources"
36

    
37
#: Temporarily out of resources; operation can be tried again
38
ECODE_TEMP_NORES = "temp_insufficient_resources"
39

    
40
#: Wrong arguments (at syntax level)
41
ECODE_INVAL = "wrong_input"
42

    
43
#: Wrong entity state
44
ECODE_STATE = "wrong_state"
45

    
46
#: Entity not found
47
ECODE_NOENT = "unknown_entity"
48

    
49
#: Entity already exists
50
ECODE_EXISTS = "already_exists"
51

    
52
#: Resource not unique (e.g. MAC or IP duplication)
53
ECODE_NOTUNIQUE = "resource_not_unique"
54

    
55
#: Internal cluster error
56
ECODE_FAULT = "internal_error"
57

    
58
#: Environment error (e.g. node disk error)
59
ECODE_ENVIRON = "environment_error"
60

    
61
#: List of all failure types
62
ECODE_ALL = compat.UniqueFrozenset([
63
  ECODE_RESOLVER,
64
  ECODE_NORES,
65
  ECODE_TEMP_NORES,
66
  ECODE_INVAL,
67
  ECODE_STATE,
68
  ECODE_NOENT,
69
  ECODE_EXISTS,
70
  ECODE_NOTUNIQUE,
71
  ECODE_FAULT,
72
  ECODE_ENVIRON,
73
  ])
74

    
75

    
76
class GenericError(Exception):
77
  """Base exception for Ganeti.
78

79
  """
80

    
81

    
82
class LockError(GenericError):
83
  """Lock error exception.
84

85
  This signifies problems in the locking subsystem.
86

87
  """
88

    
89

    
90
class PidFileLockError(LockError):
91
  """PID file is already locked by another process.
92

93
  """
94

    
95

    
96
class HypervisorError(GenericError):
97
  """Hypervisor-related exception.
98

99
  This is raised in case we can't communicate with the hypervisor
100
  properly.
101

102
  """
103

    
104

    
105
class ProgrammerError(GenericError):
106
  """Programming-related error.
107

108
  This is raised in cases we determine that the calling conventions
109
  have been violated, meaning we got some desynchronisation between
110
  parts of our code. It signifies a real programming bug.
111

112
  """
113

    
114

    
115
class BlockDeviceError(GenericError):
116
  """Block-device related exception.
117

118
  This is raised in case we can't setup the instance's block devices
119
  properly.
120

121
  """
122

    
123

    
124
class ConfigurationError(GenericError):
125
  """Configuration related exception.
126

127
  Things like having an instance with a primary node that doesn't
128
  exist in the config or such raise this exception.
129

130
  """
131

    
132

    
133
class ConfigVersionMismatch(ConfigurationError):
134
  """Version mismatch in the configuration file.
135

136
  The error has two arguments: the expected and the actual found
137
  version.
138

139
  """
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

    
162

    
163
class SignatureError(GenericError):
164
  """Error authenticating a remote message.
165

166
  This is raised when the hmac signature on a message doesn't verify correctly
167
  to the message itself. It can happen because of network unreliability or
168
  because of spurious traffic.
169

170
  """
171

    
172

    
173
class ParameterError(GenericError):
174
  """A passed parameter to a command is invalid.
175

176
  This is raised when the parameter passed to a request function is
177
  invalid. Correct code should have verified this before passing the
178
  request structure.
179

180
  The argument to this exception should be the parameter name.
181

182
  """
183

    
184

    
185
class ResultValidationError(GenericError):
186
  """The iallocation results fails validation.
187

188
  """
189

    
190

    
191
class OpPrereqError(GenericError):
192
  """Prerequisites for the OpCode are not fulfilled.
193

194
  This exception has two arguments: an error message, and one of the
195
  ECODE_* codes.
196

197
  """
198

    
199

    
200
class OpExecError(GenericError):
201
  """Error during OpCode execution.
202

203
  """
204

    
205

    
206
class OpResultError(GenericError):
207
  """Issue with OpCode result.
208

209
  """
210

    
211

    
212
class OpCodeUnknown(GenericError):
213
  """Unknown opcode submitted.
214

215
  This signifies a mismatch between the definitions on the client and
216
  server side.
217

218
  """
219

    
220

    
221
class JobLost(GenericError):
222
  """Submitted job lost.
223

224
  The job was submitted but it cannot be found in the current job
225
  list.
226

227
  """
228

    
229

    
230
class JobFileCorrupted(GenericError):
231
  """Job file could not be properly decoded/restored.
232

233
  """
234

    
235

    
236
class ResolverError(GenericError):
237
  """Host name cannot be resolved.
238

239
  This is not a normal situation for Ganeti, as we rely on having a
240
  working resolver.
241

242
  The non-resolvable hostname is available as the first element of the
243
  args tuple; the other two elements of the tuple are the first two
244
  args of the socket.gaierror exception (error code and description).
245

246
  """
247

    
248

    
249
class HooksFailure(GenericError):
250
  """A generic hook failure.
251

252
  This signifies usually a setup misconfiguration.
253

254
  """
255

    
256

    
257
class HooksAbort(HooksFailure):
258
  """A required hook has failed.
259

260
  This caused an abort of the operation in the initial phase. This
261
  exception always has an attribute args which is a list of tuples of:
262
    - node: the source node on which this hooks has failed
263
    - script: the name of the script which aborted the run
264

265
  """
266

    
267

    
268
class UnitParseError(GenericError):
269
  """Unable to parse size unit.
270

271
  """
272

    
273

    
274
class ParseError(GenericError):
275
  """Generic parse error.
276

277
  Raised when unable to parse user input.
278

279
  """
280

    
281

    
282
class TypeEnforcementError(GenericError):
283
  """Unable to enforce data type.
284

285
  """
286

    
287

    
288
class X509CertError(GenericError):
289
  """Invalid X509 certificate.
290

291
  This error has two arguments: the certificate filename and the error cause.
292

293
  """
294

    
295

    
296
class TagError(GenericError):
297
  """Generic tag error.
298

299
  The argument to this exception will show the exact error.
300

301
  """
302

    
303

    
304
class CommandError(GenericError):
305
  """External command error.
306

307
  """
308

    
309

    
310
class StorageError(GenericError):
311
  """Storage-related exception.
312

313
  """
314

    
315

    
316
class InotifyError(GenericError):
317
  """Error raised when there is a failure setting up an inotify watcher.
318

319
  """
320

    
321

    
322
class QuitGanetiException(Exception):
323
  """Signal Ganeti that it must quit.
324

325
  This is not necessarily an error (and thus not a subclass of
326
  GenericError), but it's an exceptional circumstance and it is thus
327
  treated. This exception should be instantiated with two values. The
328
  first one will specify the return code to the caller, and the second
329
  one will be the returned result (either as an error or as a normal
330
  result). Usually only the leave cluster rpc call should return
331
  status True (as there it's expected we quit), every other call will
332
  return status False (as a critical error was encountered).
333

334
  Examples::
335

336
    # Return a result of "True" to the caller, but quit ganeti afterwards
337
    raise QuitGanetiException(True, None)
338
    # Send an error to the caller, and quit ganeti
339
    raise QuitGanetiException(False, "Fatal safety violation, shutting down")
340

341
  """
342

    
343

    
344
class JobQueueError(GenericError):
345
  """Job queue error.
346

347
  """
348

    
349

    
350
class JobQueueDrainError(JobQueueError):
351
  """Job queue is marked for drain error.
352

353
  This is raised when a job submission attempt is made but the queue
354
  is marked for drain.
355

356
  """
357

    
358

    
359
class JobQueueFull(JobQueueError):
360
  """Job queue full error.
361

362
  Raised when job queue size reached its hard limit.
363

364
  """
365

    
366

    
367
class ConfdMagicError(GenericError):
368
  """A magic fourcc error in Ganeti confd.
369

370
  Errors processing the fourcc in ganeti confd datagrams.
371

372
  """
373

    
374

    
375
class ConfdClientError(GenericError):
376
  """A magic fourcc error in Ganeti confd.
377

378
  Errors in the confd client library.
379

380
  """
381

    
382

    
383
class UdpDataSizeError(GenericError):
384
  """UDP payload too big.
385

386
  """
387

    
388

    
389
class NoCtypesError(GenericError):
390
  """python ctypes module is not found in the system.
391

392
  """
393

    
394

    
395
class IPAddressError(GenericError):
396
  """Generic IP address error.
397

398
  """
399

    
400

    
401
class LuxiError(GenericError):
402
  """LUXI error.
403

404
  """
405

    
406

    
407
class QueryFilterParseError(ParseError):
408
  """Error while parsing query filter.
409

410
  This exception must be instantiated with two values. The first one is a
411
  string with an error description, the second one is an instance of a subclass
412
  of C{pyparsing.ParseBaseException} (used to display the exact error
413
  location).
414

415
  """
416
  def GetDetails(self):
417
    """Returns a list of strings with details about the error.
418

419
    """
420
    try:
421
      (_, inner) = self.args
422
    except IndexError:
423
      return None
424

    
425
    return [str(inner.line),
426
            (" " * (inner.column - 1)) + "^",
427
            str(inner)]
428

    
429

    
430
class RapiTestResult(GenericError):
431
  """Exception containing results from RAPI test utilities.
432

433
  """
434

    
435

    
436
class FileStoragePathError(GenericError):
437
  """Error from file storage path validation.
438

439
  """
440

    
441

    
442
# errors should be added above
443

    
444

    
445
def GetErrorClass(name):
446
  """Return the class of an exception.
447

448
  Given the class name, return the class itself.
449

450
  @type name: str
451
  @param name: the exception name
452
  @rtype: class
453
  @return: the actual class, or None if not found
454

455
  """
456
  item = globals().get(name, None)
457
  if item is not None:
458
    if not (isinstance(item, type(Exception)) and
459
            issubclass(item, GenericError)):
460
      item = None
461
  return item
462

    
463

    
464
def EncodeException(err):
465
  """Encodes an exception into a format that L{MaybeRaise} will recognise.
466

467
  The passed L{err} argument will be formatted as a tuple (exception
468
  name, arguments) that the MaybeRaise function will recognise.
469

470
  @type err: GenericError child
471
  @param err: usually a child of GenericError (but any exception
472
      will be accepted)
473
  @rtype: tuple
474
  @return: tuple of (exception name, exception arguments)
475

476
  """
477
  return (err.__class__.__name__, err.args)
478

    
479

    
480
def GetEncodedError(result):
481
  """If this looks like an encoded Ganeti exception, return it.
482

483
  This function tries to parse the passed argument and if it looks
484
  like an encoding done by EncodeException, it will return the class
485
  object and arguments.
486

487
  """
488
  tlt = (tuple, list)
489
  if (isinstance(result, tlt) and len(result) == 2 and
490
      isinstance(result[1], tlt)):
491
    # custom ganeti errors
492
    errcls = GetErrorClass(result[0])
493
    if errcls:
494
      return (errcls, tuple(result[1]))
495

    
496
  return None
497

    
498

    
499
def MaybeRaise(result):
500
  """If this looks like an encoded Ganeti exception, raise it.
501

502
  This function tries to parse the passed argument and if it looks
503
  like an encoding done by EncodeException, it will re-raise it.
504

505
  """
506
  error = GetEncodedError(result)
507
  if error:
508
    (errcls, args) = error
509
    # pylint: disable=W0142
510
    raise errcls(*args)