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