1#pylint: disable-msg=C0111
2
3"""
4Internal global error types
5"""
6
7import sys, traceback
8from traceback import format_exception
9
10# Add names you want to be imported by 'from errors import *' to this list.
11# This must be list not a tuple as we modify it to include all of our
12# the Exception classes we define below at the end of this file.
13__all__ = ['format_error']
14
15
16def format_error():
17    t, o, tb = sys.exc_info()
18    trace = format_exception(t, o, tb)
19    # Clear the backtrace to prevent a circular reference
20    # in the heap -- as per tutorial
21    tb = ''
22
23    return ''.join(trace)
24
25
26class TimeoutException(Exception):
27    """
28    Generic exception raised on retry timeouts.
29    """
30    pass
31
32
33class JobContinue(SystemExit):
34    """Allow us to bail out requesting continuance."""
35    pass
36
37
38class JobComplete(SystemExit):
39    """Allow us to bail out indicating continuation not required."""
40    pass
41
42
43class AutotestError(Exception):
44    """The parent of all errors deliberatly thrown within the client code."""
45    def __str__(self):
46        return Exception.__str__(self)
47
48
49class JobError(AutotestError):
50    """Indicates an error which terminates and fails the whole job (ABORT)."""
51    pass
52
53
54class UnhandledJobError(JobError):
55    """Indicates an unhandled error in a job."""
56    def __init__(self, unhandled_exception):
57        if isinstance(unhandled_exception, JobError):
58            JobError.__init__(self, *unhandled_exception.args)
59        elif isinstance(unhandled_exception, str):
60            JobError.__init__(self, unhandled_exception)
61        else:
62            msg = "Unhandled %s: %s"
63            msg %= (unhandled_exception.__class__.__name__,
64                    unhandled_exception)
65            msg += "\n" + traceback.format_exc()
66            JobError.__init__(self, msg)
67
68
69class TestBaseException(AutotestError):
70    """The parent of all test exceptions."""
71    # Children are required to override this.  Never instantiate directly.
72    exit_status = "NEVER_RAISE_THIS"
73
74
75class TestError(TestBaseException):
76    """Indicates that something went wrong with the test harness itself."""
77    exit_status = "ERROR"
78
79
80class TestNAError(TestBaseException):
81    """Indictates that the test is Not Applicable.  Should be thrown
82    when various conditions are such that the test is inappropriate."""
83    exit_status = "TEST_NA"
84
85
86class TestFail(TestBaseException):
87    """Indicates that the test failed, but the job will not continue."""
88    exit_status = "FAIL"
89
90
91class TestWarn(TestBaseException):
92    """Indicates that bad things (may) have happened, but not an explicit
93    failure."""
94    exit_status = "WARN"
95
96
97class TestFailRetry(TestFail):
98    """Indicates that the test failed, but in a manner that may be retried
99    if test retries are enabled for this test."""
100    exit_status = "FAIL"
101
102
103class UnhandledTestError(TestError):
104    """Indicates an unhandled error in a test."""
105    def __init__(self, unhandled_exception):
106        if isinstance(unhandled_exception, TestError):
107            TestError.__init__(self, *unhandled_exception.args)
108        elif isinstance(unhandled_exception, str):
109            TestError.__init__(self, unhandled_exception)
110        else:
111            msg = "Unhandled %s: %s"
112            msg %= (unhandled_exception.__class__.__name__,
113                    unhandled_exception)
114            msg += "\n" + traceback.format_exc()
115            TestError.__init__(self, msg)
116
117
118class UnhandledTestFail(TestFail):
119    """Indicates an unhandled fail in a test."""
120    def __init__(self, unhandled_exception):
121        if isinstance(unhandled_exception, TestFail):
122            TestFail.__init__(self, *unhandled_exception.args)
123        elif isinstance(unhandled_exception, str):
124            TestFail.__init__(self, unhandled_exception)
125        else:
126            msg = "Unhandled %s: %s"
127            msg %= (unhandled_exception.__class__.__name__,
128                    unhandled_exception)
129            msg += "\n" + traceback.format_exc()
130            TestFail.__init__(self, msg)
131
132
133class CmdError(TestError):
134    """Indicates that a command failed, is fatal to the test unless caught."""
135    def __init__(self, command, result_obj, additional_text=None):
136        TestError.__init__(self, command, result_obj, additional_text)
137        self.command = command
138        self.result_obj = result_obj
139        self.additional_text = additional_text
140
141    def __str__(self):
142        if self.result_obj.exit_status is None:
143            msg = "Command <%s> failed and is not responding to signals"
144            msg %= self.command
145        else:
146            msg = "Command <%s> failed, rc=%d"
147            msg %= (self.command, self.result_obj.exit_status)
148
149        if self.additional_text:
150            msg += ", " + self.additional_text
151        msg += '\n' + repr(self.result_obj)
152        return msg
153
154
155class CmdTimeoutError(CmdError):
156    """Indicates that a command timed out."""
157    pass
158
159
160class PackageError(TestError):
161    """Indicates an error trying to perform a package operation."""
162    pass
163
164
165class BarrierError(JobError):
166    """Indicates an error happened during a barrier operation."""
167    pass
168
169
170class BarrierAbortError(BarrierError):
171    """Indicate that the barrier was explicitly aborted by a member."""
172    pass
173
174
175class InstallError(JobError):
176    """Indicates an installation error which Terminates and fails the job."""
177    pass
178
179
180class AutotestRunError(AutotestError):
181    """Indicates a problem running server side control files."""
182    pass
183
184
185class AutotestTimeoutError(AutotestError):
186    """This exception is raised when an autotest test exceeds the timeout
187    parameter passed to run_timed_test and is killed.
188    """
189    pass
190
191
192class GenericHostRunError(Exception):
193    """Indicates a problem in the host run() function running in either client
194    or server code.
195
196    Should always be constructed with a tuple of two args (error description
197    (str), run result object). This is a common class used to create the client
198    and server side versions of it when the distinction is useful.
199    """
200    def __init__(self, description, result_obj):
201        self.description = description
202        self.result_obj = result_obj
203        Exception.__init__(self, description, result_obj)
204
205    def __str__(self):
206        return self.description + '\n' + repr(self.result_obj)
207
208
209class HostInstallTimeoutError(JobError):
210    """
211    Indicates the machine failed to be installed after the predetermined
212    timeout.
213    """
214    pass
215
216
217class AutotestHostRunError(GenericHostRunError, AutotestError):
218    pass
219
220
221# server-specific errors
222
223class AutoservError(Exception):
224    pass
225
226
227class AutoservSSHTimeout(AutoservError):
228    """SSH experienced a connection timeout"""
229    pass
230
231
232class AutoservRunError(GenericHostRunError, AutoservError):
233    pass
234
235
236class AutoservSshPermissionDeniedError(AutoservRunError):
237    """Indicates that a SSH permission denied error was encountered."""
238    pass
239
240
241class AutoservUnsupportedError(AutoservError):
242    """Error raised when you try to use an unsupported optional feature"""
243    pass
244
245
246class AutoservHostError(AutoservError):
247    """Error reaching a host"""
248    pass
249
250
251class AutoservHostIsShuttingDownError(AutoservHostError):
252    """Host is shutting down"""
253    pass
254
255
256class AutoservNotMountedHostError(AutoservHostError):
257    """Found unmounted partitions that should be mounted"""
258    pass
259
260
261class AutoservSshPingHostError(AutoservHostError):
262    """SSH ping failed"""
263    pass
264
265
266class AutoservDiskFullHostError(AutoservHostError):
267    """Not enough free disk space on host"""
268
269    def __init__(self, path, want_gb, free_space_gb):
270        super(AutoservDiskFullHostError, self).__init__(
271            'Not enough free space on %s - %.3fGB free, want %.3fGB' %
272                    (path, free_space_gb, want_gb))
273        self.path = path
274        self.want_gb = want_gb
275        self.free_space_gb = free_space_gb
276
277
278class AutoservNoFreeInodesError(AutoservHostError):
279    """Not enough free i-nodes on host"""
280
281    def __init__(self, path, want_inodes, free_inodes):
282        super(AutoservNoFreeInodesError, self).__init__(
283            'Not enough free inodes on %s - %d free, want %d' %
284                    (path, free_inodes, want_inodes))
285        self.path = path
286        self.want_inodes = want_inodes
287        self.free_inodes = free_inodes
288
289
290class AutoservHardwareHostError(AutoservHostError):
291    """Found hardware problems with the host"""
292    pass
293
294
295class AutoservRebootError(AutoservError):
296    """Error occured while rebooting a machine"""
297    pass
298
299
300class AutoservShutdownError(AutoservRebootError):
301    """Error occured during shutdown of machine"""
302    pass
303
304
305class AutoservSuspendError(AutoservRebootError):
306    """Error occured while suspending a machine"""
307    pass
308
309
310class AutoservSubcommandError(AutoservError):
311    """Indicates an error while executing a (forked) subcommand"""
312    def __init__(self, func, exit_code):
313        AutoservError.__init__(self, func, exit_code)
314        self.func = func
315        self.exit_code = exit_code
316
317    def __str__(self):
318        return ("Subcommand %s failed with exit code %d" %
319                (self.func, self.exit_code))
320
321
322class AutoservRepairTotalFailure(AutoservError):
323    """Raised if all attempts to repair the DUT failed."""
324    pass
325
326
327class AutoservInstallError(AutoservError):
328    """Error occured while installing autotest on a host"""
329    pass
330
331
332class AutoservPidAlreadyDeadError(AutoservError):
333    """Error occured by trying to kill a nonexistant PID"""
334    pass
335
336
337# packaging system errors
338
339class PackagingError(AutotestError):
340    'Abstract error class for all packaging related errors.'
341
342
343class PackageUploadError(PackagingError):
344    'Raised when there is an error uploading the package'
345
346
347class PackageFetchError(PackagingError):
348    'Raised when there is an error fetching the package'
349
350
351class PackageRemoveError(PackagingError):
352    'Raised when there is an error removing the package'
353
354
355class PackageInstallError(PackagingError):
356    'Raised when there is an error installing the package'
357
358
359class RepoDiskFullError(PackagingError):
360    'Raised when the destination for packages is full'
361
362
363class RepoWriteError(PackagingError):
364    "Raised when packager cannot write to a repo's desitnation"
365
366
367class RepoUnknownError(PackagingError):
368    "Raised when packager cannot write to a repo's desitnation"
369
370
371class RepoError(PackagingError):
372    "Raised when a repo isn't working in some way"
373
374
375class StageControlFileFailure(Exception):
376    """Exceptions encountered staging control files."""
377    pass
378
379
380class CrosDynamicSuiteException(Exception):
381    """
382    Base class for exceptions coming from dynamic suite code in
383    server/cros/dynamic_suite/*.
384    """
385    pass
386
387
388class StageBuildFailure(CrosDynamicSuiteException):
389    """Raised when the dev server throws 500 while staging a build."""
390    pass
391
392
393class ControlFileEmpty(CrosDynamicSuiteException):
394    """Raised when the control file exists on the server, but can't be read."""
395    pass
396
397
398class ControlFileMalformed(CrosDynamicSuiteException):
399    """Raised when an invalid control file is read."""
400    pass
401
402
403class AsynchronousBuildFailure(CrosDynamicSuiteException):
404    """Raised when the dev server throws 500 while finishing staging of a build.
405    """
406    pass
407
408
409class SuiteArgumentException(CrosDynamicSuiteException):
410    """Raised when improper arguments are used to run a suite."""
411    pass
412
413
414class MalformedDependenciesException(CrosDynamicSuiteException):
415    """Raised when a build has a malformed dependency_info file."""
416    pass
417
418
419class InadequateHostsException(CrosDynamicSuiteException):
420    """Raised when there are too few hosts to run a suite."""
421    pass
422
423
424class NoHostsException(CrosDynamicSuiteException):
425    """Raised when there are no healthy hosts to run a suite."""
426    pass
427
428
429class ControlFileNotFound(CrosDynamicSuiteException):
430    """Raised when a control file cannot be found and/or read."""
431    pass
432
433
434class NoControlFileList(CrosDynamicSuiteException):
435    """Raised to indicate that a listing can't be done."""
436    pass
437
438
439class SuiteControlFileException(CrosDynamicSuiteException):
440    """Raised when failing to list the contents of all control file."""
441    pass
442
443
444class HostLockManagerReuse(CrosDynamicSuiteException):
445    """Raised when a caller tries to re-use a HostLockManager instance."""
446    pass
447
448
449class ReimageAbortedException(CrosDynamicSuiteException):
450    """Raised when a Reimage job is aborted"""
451    pass
452
453
454class UnknownReimageType(CrosDynamicSuiteException):
455    """Raised when a suite passes in an invalid reimage type"""
456    pass
457
458
459class NoUniquePackageFound(Exception):
460    """Raised when an executable cannot be mapped back to a single package."""
461    pass
462
463
464class RPCException(Exception):
465    """Raised when an RPC encounters an error that a client might wish to
466    handle specially."""
467    pass
468
469
470class NoEligibleHostException(RPCException):
471    """Raised when no host could satisfy the requirements of a job."""
472    pass
473
474
475class InvalidBgJobCall(Exception):
476    """Raised when an invalid call is made to a BgJob object."""
477    pass
478
479
480class HeartbeatOnlyAllowedInShardModeException(Exception):
481    """Raised when a heartbeat is attempted but not allowed."""
482    pass
483
484
485class UnallowedRecordsSentToMaster(Exception):
486    pass
487
488
489class InvalidDataError(Exception):
490    """Exception raised when invalid data provided for database operation.
491    """
492    pass
493
494
495class ContainerError(Exception):
496    """Exception raised when program runs into error using container.
497    """
498
499
500class IllegalUser(Exception):
501    """Exception raise when a program runs as an illegal user."""
502
503
504# This MUST remain at the end of the file.
505# Limit 'from error import *' to only import the exception instances.
506for _name, _thing in locals().items():
507    try:
508        if issubclass(_thing, Exception):
509            __all__.append(_name)
510    except TypeError:
511        pass  # _thing not a class
512__all__ = tuple(__all__)
513