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