Statistics
| Branch: | Tag: | Revision:

root / lib / errors.py @ 5c983ee5

History | View | Annotate | Download (8.7 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007 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
# not enough resources (iallocator failure, disk space, memory, etc.)
28
ECODE_NORES = "insufficient_resources"
29
# wrong arguments (at syntax level)
30
ECODE_INVAL = "wrong_input"
31
# wrong entity state
32
ECODE_STATE = "wrong_state"
33
# entity not found
34
ECODE_NOENT = "unknown_entity"
35
# entity already exists
36
ECODE_EXISTS = "already_exists"
37
# resource not unique (e.g. MAC or IP duplication)
38
ECODE_NOTUNIQUE = "resource_not_unique"
39
# internal cluster error
40
ECODE_FAULT = "internal_error"
41
# environment error (e.g. node disk error)
42
ECODE_ENVIRON = "environment_error"
43

    
44

    
45
class GenericError(Exception):
46
  """Base exception for Ganeti.
47

48
  """
49
  pass
50

    
51

    
52
class LVMError(GenericError):
53
  """LVM-related exception.
54

55
  This exception codifies problems with LVM setup.
56

57
  """
58
  pass
59

    
60

    
61
class LockError(GenericError):
62
  """Lock error exception.
63

64
  This signifies problems in the locking subsystem.
65

66
  """
67
  pass
68

    
69

    
70
class HypervisorError(GenericError):
71
  """Hypervisor-related exception.
72

73
  This is raised in case we can't communicate with the hypervisor
74
  properly.
75

76
  """
77
  pass
78

    
79

    
80
class ProgrammerError(GenericError):
81
  """Programming-related error.
82

83
  This is raised in cases we determine that the calling conventions
84
  have been violated, meaning we got some desynchronisation between
85
  parts of our code. It signifies a real programming bug.
86

87
  """
88
  pass
89

    
90

    
91
class BlockDeviceError(GenericError):
92
  """Block-device related exception.
93

94
  This is raised in case we can't setup the instance's block devices
95
  properly.
96

97
  """
98
  pass
99

    
100

    
101
class ConfigurationError(GenericError):
102
  """Configuration related exception.
103

104
  Things like having an instance with a primary node that doesn't
105
  exist in the config or such raise this exception.
106

107
  """
108
  pass
109

    
110

    
111
class RemoteError(GenericError):
112
  """Programming-related error on remote call.
113

114
  This is raised when an unhandled error occurs in a call to a
115
  remote node.  It usually signifies a real programming bug.
116

117
  """
118
  pass
119

    
120

    
121
class SignatureError(GenericError):
122
  """Error authenticating a remote message.
123

124
  This is raised when the hmac signature on a message doesn't verify correctly
125
  to the message itself. It can happen because of network unreliability or
126
  because of spurious traffic.
127

128
  """
129
  pass
130

    
131

    
132
class ParameterError(GenericError):
133
  """A passed parameter to a command is invalid.
134

135
  This is raised when the parameter passed to a request function is
136
  invalid. Correct code should have verified this before passing the
137
  request structure.
138

139
  The argument to this exception should be the parameter name.
140

141
  """
142
  pass
143

    
144

    
145
class OpPrereqError(GenericError):
146
  """Prerequisites for the OpCode are not fulfilled.
147

148
  This exception will have either one or two arguments. For the
149
  two-argument construction, the second argument should be one of the
150
  ECODE_* codes.
151

152
  """
153

    
154

    
155
class OpExecError(GenericError):
156
  """Error during OpCode execution.
157

158
  """
159

    
160

    
161
class OpCodeUnknown(GenericError):
162
  """Unknown opcode submitted.
163

164
  This signifies a mismatch between the definitions on the client and
165
  server side.
166

167
  """
168

    
169

    
170
class JobLost(GenericError):
171
  """Submitted job lost.
172

173
  The job was submitted but it cannot be found in the current job
174
  list.
175

176
  """
177

    
178

    
179
class ResolverError(GenericError):
180
  """Host name cannot be resolved.
181

182
  This is not a normal situation for Ganeti, as we rely on having a
183
  working resolver.
184

185
  The non-resolvable hostname is available as the first element of the
186
  args tuple; the other two elements of the tuple are the first two
187
  args of the socket.gaierror exception (error code and description).
188

189
  """
190

    
191

    
192
class HooksFailure(GenericError):
193
  """A generic hook failure.
194

195
  This signifies usually a setup misconfiguration.
196

197
  """
198

    
199

    
200
class HooksAbort(HooksFailure):
201
  """A required hook has failed.
202

203
  This caused an abort of the operation in the initial phase. This
204
  exception always has an attribute args which is a list of tuples of:
205
    - node: the source node on which this hooks has failed
206
    - script: the name of the script which aborted the run
207

208
  """
209

    
210

    
211
class UnitParseError(GenericError):
212
  """Unable to parse size unit.
213

214
  """
215

    
216

    
217
class TypeEnforcementError(GenericError):
218
  """Unable to enforce data type.
219

220
  """
221

    
222

    
223
class SshKeyError(GenericError):
224
  """Invalid SSH key.
225

226
  """
227

    
228

    
229
class TagError(GenericError):
230
  """Generic tag error.
231

232
  The argument to this exception will show the exact error.
233

234
  """
235

    
236

    
237
class CommandError(GenericError):
238
  """External command error.
239

240
  """
241

    
242

    
243
class StorageError(GenericError):
244
  """Storage-related exception.
245

246
  """
247

    
248

    
249
class InotifyError(GenericError):
250
  """Error raised when there is a failure setting up an inotify watcher.
251

252
  """
253

    
254

    
255
class QuitGanetiException(Exception):
256
  """Signal that Ganeti that it must quit.
257

258
  This is not necessarily an error (and thus not a subclass of
259
  GenericError), but it's an exceptional circumstance and it is thus
260
  treated. This instance should be instantiated with two values. The
261
  first one will specify the return code to the caller, and the second
262
  one will be the returned result (either as an error or as a normal
263
  result). Usually only the leave cluster rpc call should return
264
  status True (as there it's expected we quit), every other call will
265
  return status False (as a critical error was encountered).
266

267
  Examples::
268

269
    # Return a result of "True" to the caller, but quit ganeti afterwards
270
    raise QuitGanetiException(True, None)
271
    # Send an error to the caller, and quit ganeti
272
    raise QuitGanetiException(False, "Fatal safety violation, shutting down")
273

274
  """
275

    
276

    
277
class JobQueueError(GenericError):
278
  """Job queue error.
279

280
  """
281

    
282

    
283
class JobQueueDrainError(JobQueueError):
284
  """Job queue is marked for drain error.
285

286
  This is raised when a job submission attempt is made but the queue
287
  is marked for drain.
288

289
  """
290

    
291

    
292
class JobQueueFull(JobQueueError):
293
  """Job queue full error.
294

295
  Raised when job queue size reached its hard limit.
296

297
  """
298

    
299

    
300
class ConfdFatalError(GenericError):
301
  """A fatal failure in Ganeti confd.
302

303
  Events that compromise the ability of confd to proceed further.
304
  (for example: inability to load the config file)
305

306
  """
307

    
308

    
309
class ConfdRequestError(GenericError):
310
  """A request error in Ganeti confd.
311

312
  Events that should make confd abort the current request and proceed serving
313
  different ones.
314

315
  """
316

    
317

    
318
class ConfdMagicError(GenericError):
319
  """A magic fourcc error in Ganeti confd.
320

321
  Errors processing the fourcc in ganeti confd datagrams.
322

323
  """
324

    
325

    
326
class ConfdClientError(GenericError):
327
  """A magic fourcc error in Ganeti confd.
328

329
  Errors in the confd client library.
330

331
  """
332

    
333

    
334
class UdpDataSizeError(GenericError):
335
  """UDP payload too big.
336

337
  """
338

    
339

    
340
# errors should be added above
341

    
342

    
343
def GetErrorClass(name):
344
  """Return the class of an exception.
345

346
  Given the class name, return the class itself.
347

348
  @type name: str
349
  @param name: the exception name
350
  @rtype: class
351
  @return: the actual class, or None if not found
352

353
  """
354
  item = globals().get(name, None)
355
  if item is not None:
356
    if not (isinstance(item, type(Exception)) and
357
            issubclass(item, GenericError)):
358
      item = None
359
  return item
360

    
361

    
362
def EncodeException(err):
363
  """Encodes an exception into a format that L{MaybeRaise} will recognise.
364

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

368
  @type err: GenericError child
369
  @param err: usually a child of GenericError (but any exception
370
      will be accepted)
371
  @rtype: tuple
372
  @return: tuple of (exception name, exception arguments)
373

374
  """
375
  return (err.__class__.__name__, err.args)
376

    
377

    
378
def MaybeRaise(result):
379
  """Is this looks like an encoded Ganeti exception, raise it.
380

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

384
  """
385
  tlt = (tuple, list)
386
  if (isinstance(result, tlt) and len(result) == 2 and
387
      isinstance(result[1], tlt)):
388
    # custom ganeti errors
389
    err_class = GetErrorClass(result[0])
390
    if err_class is not None:
391
      raise err_class, tuple(result[1])