Home | History | Annotate | Download | only in common_lib
      1 #pylint: disable-msg=C0111
      2 
      3 """
      4 Internal global error types
      5 """
      6 
      7 import sys, traceback
      8 from 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 
     16 def 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 
     26 class TimeoutException(Exception):
     27     """Generic exception raised on retry timeouts."""
     28 
     29 
     30 class JobContinue(SystemExit):
     31     """Allow us to bail out requesting continuance."""
     32 
     33 
     34 class JobComplete(SystemExit):
     35     """Allow us to bail out indicating continuation not required."""
     36 
     37 
     38 class AutotestError(Exception):
     39     """The parent of all errors deliberatly thrown within the client code."""
     40 
     41 
     42 class JobError(AutotestError):
     43     """Indicates an error which terminates and fails the whole job (ABORT)."""
     44 
     45 
     46 class 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 
     61 class 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 
     67 class TestError(TestBaseException):
     68     """Indicates that something went wrong with the test harness itself."""
     69     exit_status = "ERROR"
     70 
     71 
     72 class 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 
     78 class TestFail(TestBaseException):
     79     """Indicates that the test failed, but the job will not continue."""
     80     exit_status = "FAIL"
     81 
     82 
     83 class TestWarn(TestBaseException):
     84     """Indicates that bad things (may) have happened, but not an explicit
     85     failure."""
     86     exit_status = "WARN"
     87 
     88 
     89 class 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 
    104 class 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 
    119 class 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 
    149 class CmdTimeoutError(CmdError):
    150     """Indicates that a command timed out."""
    151 
    152 
    153 class PackageError(TestError):
    154     """Indicates an error trying to perform a package operation."""
    155 
    156 
    157 class BarrierError(JobError):
    158     """Indicates an error happened during a barrier operation."""
    159 
    160 
    161 class BarrierAbortError(BarrierError):
    162     """Indicate that the barrier was explicitly aborted by a member."""
    163 
    164 
    165 class InstallError(JobError):
    166     """Indicates an installation error which Terminates and fails the job."""
    167 
    168 
    169 class AutotestRunError(AutotestError):
    170     """Indicates a problem running server side control files."""
    171 
    172 
    173 class 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 
    179 class 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 
    196 class HostInstallTimeoutError(JobError):
    197     """
    198     Indicates the machine failed to be installed after the predetermined
    199     timeout.
    200     """
    201 
    202 
    203 class AutotestHostRunError(GenericHostRunError, AutotestError):
    204     pass
    205 
    206 
    207 class 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 
    223 class 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 
    233 class AutoservError(Exception):
    234     pass
    235 
    236 
    237 class AutoservSSHTimeout(AutoservError):
    238     """SSH experienced a connection timeout"""
    239 
    240 
    241 class AutoservRunError(GenericHostRunError, AutoservError):
    242     pass
    243 
    244 
    245 class AutoservSshPermissionDeniedError(AutoservRunError):
    246     """Indicates that a SSH permission denied error was encountered."""
    247 
    248 
    249 class AutoservUnsupportedError(AutoservError):
    250     """Error raised when you try to use an unsupported optional feature"""
    251 
    252 
    253 class AutoservHostError(AutoservError):
    254     """Error reaching a host"""
    255 
    256 
    257 class AutoservHostIsShuttingDownError(AutoservHostError):
    258     """Host is shutting down"""
    259 
    260 
    261 class AutoservNotMountedHostError(AutoservHostError):
    262     """Found unmounted partitions that should be mounted"""
    263 
    264 
    265 class AutoservSshPingHostError(AutoservHostError):
    266     """SSH ping failed"""
    267 
    268 
    269 class 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 
    281 class 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 
    293 class AutoservHardwareHostError(AutoservHostError):
    294     """Found hardware problems with the host"""
    295 
    296 
    297 class AutoservRebootError(AutoservError):
    298     """Error occured while rebooting a machine"""
    299 
    300 
    301 class AutoservShutdownError(AutoservRebootError):
    302     """Error occured during shutdown of machine"""
    303 
    304 
    305 class AutoservSuspendError(AutoservRebootError):
    306     """Error occured while suspending a machine"""
    307 
    308 
    309 class 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 
    321 class AutoservRepairTotalFailure(AutoservError):
    322     """Raised if all attempts to repair the DUT failed."""
    323 
    324 
    325 class AutoservInstallError(AutoservError):
    326     """Error occured while installing autotest on a host"""
    327 
    328 
    329 class AutoservPidAlreadyDeadError(AutoservError):
    330     """Error occured by trying to kill a nonexistant PID"""
    331 
    332 
    333 # packaging system errors
    334 
    335 class PackagingError(AutotestError):
    336     'Abstract error class for all packaging related errors.'
    337 
    338 
    339 class PackageUploadError(PackagingError):
    340     'Raised when there is an error uploading the package'
    341 
    342 
    343 class PackageFetchError(PackagingError):
    344     'Raised when there is an error fetching the package'
    345 
    346 
    347 class PackageRemoveError(PackagingError):
    348     'Raised when there is an error removing the package'
    349 
    350 
    351 class PackageInstallError(PackagingError):
    352     'Raised when there is an error installing the package'
    353 
    354 
    355 class RepoDiskFullError(PackagingError):
    356     'Raised when the destination for packages is full'
    357 
    358 
    359 class RepoWriteError(PackagingError):
    360     "Raised when packager cannot write to a repo's desitnation"
    361 
    362 
    363 class RepoUnknownError(PackagingError):
    364     "Raised when packager cannot write to a repo's desitnation"
    365 
    366 
    367 class RepoError(PackagingError):
    368     "Raised when a repo isn't working in some way"
    369 
    370 
    371 class StageControlFileFailure(Exception):
    372     """Exceptions encountered staging control files."""
    373 
    374 
    375 class CrosDynamicSuiteException(Exception):
    376     """
    377     Base class for exceptions coming from dynamic suite code in
    378     server/cros/dynamic_suite/*.
    379     """
    380 
    381 
    382 class StageBuildFailure(CrosDynamicSuiteException):
    383     """Raised when the dev server throws 500 while staging a build."""
    384 
    385 
    386 class ControlFileEmpty(CrosDynamicSuiteException):
    387     """Raised when the control file exists on the server, but can't be read."""
    388 
    389 
    390 class ControlFileMalformed(CrosDynamicSuiteException):
    391     """Raised when an invalid control file is read."""
    392 
    393 
    394 class AsynchronousBuildFailure(CrosDynamicSuiteException):
    395     """Raised when the dev server throws 500 while finishing staging of a build.
    396     """
    397 
    398 
    399 class SuiteArgumentException(CrosDynamicSuiteException):
    400     """Raised when improper arguments are used to run a suite."""
    401 
    402 
    403 class MalformedDependenciesException(CrosDynamicSuiteException):
    404     """Raised when a build has a malformed dependency_info file."""
    405 
    406 
    407 class InadequateHostsException(CrosDynamicSuiteException):
    408     """Raised when there are too few hosts to run a suite."""
    409 
    410 
    411 class NoHostsException(CrosDynamicSuiteException):
    412     """Raised when there are no healthy hosts to run a suite."""
    413 
    414 
    415 class ControlFileNotFound(CrosDynamicSuiteException):
    416     """Raised when a control file cannot be found and/or read."""
    417 
    418 
    419 class NoControlFileList(CrosDynamicSuiteException):
    420     """Raised to indicate that a listing can't be done."""
    421 
    422 
    423 class SuiteControlFileException(CrosDynamicSuiteException):
    424     """Raised when failing to list the contents of all control file."""
    425 
    426 
    427 class HostLockManagerReuse(CrosDynamicSuiteException):
    428     """Raised when a caller tries to re-use a HostLockManager instance."""
    429 
    430 
    431 class ReimageAbortedException(CrosDynamicSuiteException):
    432     """Raised when a Reimage job is aborted"""
    433 
    434 
    435 class UnknownReimageType(CrosDynamicSuiteException):
    436     """Raised when a suite passes in an invalid reimage type"""
    437 
    438 
    439 class NoUniquePackageFound(Exception):
    440     """Raised when an executable cannot be mapped back to a single package."""
    441 
    442 
    443 class RPCException(Exception):
    444     """Raised when an RPC encounters an error that a client might wish to
    445     handle specially."""
    446 
    447 
    448 class NoEligibleHostException(RPCException):
    449     """Raised when no host could satisfy the requirements of a job."""
    450 
    451 
    452 class UnmodifiableLabelException(RPCException):
    453     """Raised when an RPC tries to modify static labels."""
    454 
    455 
    456 class UnmodifiableAttributeException(RPCException):
    457     """Raised when an RPC tries to modify static attributes."""
    458 
    459 
    460 class InvalidBgJobCall(Exception):
    461     """Raised when an invalid call is made to a BgJob object."""
    462 
    463 
    464 class HeartbeatOnlyAllowedInShardModeException(Exception):
    465     """Raised when a heartbeat is attempted but not allowed."""
    466 
    467 
    468 class UnallowedRecordsSentToMaster(Exception):
    469     """Raised when an illegal record was sent from shard to master."""
    470 
    471 
    472 class 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 
    482 class InvalidDataError(Exception):
    483     """Exception raised when invalid data provided for database operation."""
    484 
    485 
    486 class ContainerError(Exception):
    487     """Exception raised when program runs into error using container."""
    488 
    489 
    490 class IllegalUser(Exception):
    491     """Exception raise when a program runs as an illegal user."""
    492 
    493 
    494 class AutoservDirectoryNotFoundError(AutoservHostError):
    495     """Exception raised when an expected directory is not found."""
    496 
    497 
    498 class 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.
    504 for _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