| #pylint: disable-msg=C0111 |
| |
| """ |
| Internal global error types |
| """ |
| |
| import sys, traceback |
| from traceback import format_exception |
| |
| # Add names you want to be imported by 'from errors import *' to this list. |
| # This must be list not a tuple as we modify it to include all of our |
| # the Exception classes we define below at the end of this file. |
| __all__ = ['format_error'] |
| |
| |
| def format_error(): |
| t, o, tb = sys.exc_info() |
| trace = format_exception(t, o, tb) |
| # Clear the backtrace to prevent a circular reference |
| # in the heap -- as per tutorial |
| tb = '' |
| |
| return ''.join(trace) |
| |
| |
| class TimeoutException(Exception): |
| """Generic exception raised on retry timeouts.""" |
| |
| |
| class JobContinue(SystemExit): |
| """Allow us to bail out requesting continuance.""" |
| |
| |
| class JobComplete(SystemExit): |
| """Allow us to bail out indicating continuation not required.""" |
| |
| |
| class AutotestError(Exception): |
| """The parent of all errors deliberatly thrown within the client code.""" |
| |
| |
| class JobError(AutotestError): |
| """Indicates an error which terminates and fails the whole job (ABORT).""" |
| |
| |
| class UnhandledJobError(JobError): |
| """Indicates an unhandled error in a job.""" |
| def __init__(self, unhandled_exception): |
| if isinstance(unhandled_exception, JobError): |
| JobError.__init__(self, *unhandled_exception.args) |
| elif isinstance(unhandled_exception, basestring): |
| JobError.__init__(self, unhandled_exception) |
| else: |
| msg = "Unhandled %s: %s" |
| msg %= (unhandled_exception.__class__.__name__, |
| unhandled_exception) |
| msg += "\n" + traceback.format_exc() |
| JobError.__init__(self, msg) |
| |
| |
| class TestBaseException(AutotestError): |
| """The parent of all test exceptions.""" |
| # Children are required to override this. Never instantiate directly. |
| exit_status = "NEVER_RAISE_THIS" |
| |
| |
| class TestError(TestBaseException): |
| """Indicates that something went wrong with the test harness itself.""" |
| exit_status = "ERROR" |
| |
| |
| class TestNAError(TestBaseException): |
| """Indictates that the test is Not Applicable. Should be thrown |
| when various conditions are such that the test is inappropriate.""" |
| exit_status = "TEST_NA" |
| |
| |
| class TestFail(TestBaseException): |
| """Indicates that the test failed, but the job will not continue.""" |
| exit_status = "FAIL" |
| |
| |
| class TestWarn(TestBaseException): |
| """Indicates that bad things (may) have happened, but not an explicit |
| failure.""" |
| exit_status = "WARN" |
| |
| |
| class UnhandledTestError(TestError): |
| """Indicates an unhandled error in a test.""" |
| def __init__(self, unhandled_exception): |
| if isinstance(unhandled_exception, TestError): |
| TestError.__init__(self, *unhandled_exception.args) |
| elif isinstance(unhandled_exception, basestring): |
| TestError.__init__(self, unhandled_exception) |
| else: |
| msg = "Unhandled %s: %s" |
| msg %= (unhandled_exception.__class__.__name__, |
| unhandled_exception) |
| msg += "\n" + traceback.format_exc() |
| TestError.__init__(self, msg) |
| |
| |
| class UnhandledTestFail(TestFail): |
| """Indicates an unhandled fail in a test.""" |
| def __init__(self, unhandled_exception): |
| if isinstance(unhandled_exception, TestFail): |
| TestFail.__init__(self, *unhandled_exception.args) |
| elif isinstance(unhandled_exception, basestring): |
| TestFail.__init__(self, unhandled_exception) |
| else: |
| msg = "Unhandled %s: %s" |
| msg %= (unhandled_exception.__class__.__name__, |
| unhandled_exception) |
| msg += "\n" + traceback.format_exc() |
| TestFail.__init__(self, msg) |
| |
| |
| class CmdError(TestError): |
| """Indicates that a command failed, is fatal to the test unless caught. |
| |
| @type command: str |
| @type result_obj: autotest_lib.client.common_lib.utils.CmdResult |
| @type additional_text: str | None |
| """ |
| def __init__(self, command, result_obj, additional_text=None): |
| TestError.__init__(self, command, result_obj, additional_text) |
| self.command = command |
| self.result_obj = result_obj |
| self.additional_text = additional_text |
| |
| def __str__(self): |
| if self.result_obj.exit_status is None: |
| msg = "Command <%s> failed and is not responding to signals" |
| msg %= self.command |
| else: |
| msg = "Command <%s> failed, rc=%d" |
| msg %= (self.command, self.result_obj.exit_status) |
| |
| if self.additional_text: |
| msg += ", " + self.additional_text |
| msg += '\n' + repr(self.result_obj) |
| return msg |
| |
| def __eq__(self, other): |
| if type(self) == type(other): |
| return (self.command == other.command |
| and self.result_obj == other.result_obj |
| and self.additional_text == other.additional_text) |
| else: |
| return NotImplemented |
| |
| |
| class CmdTimeoutError(CmdError): |
| """Indicates that a command timed out.""" |
| |
| |
| class PackageError(TestError): |
| """Indicates an error trying to perform a package operation.""" |
| |
| |
| class BarrierError(JobError): |
| """Indicates an error happened during a barrier operation.""" |
| |
| |
| class BarrierAbortError(BarrierError): |
| """Indicate that the barrier was explicitly aborted by a member.""" |
| |
| |
| class InstallError(JobError): |
| """Indicates an installation error which Terminates and fails the job.""" |
| |
| |
| class AutotestRunError(AutotestError): |
| """Indicates a problem running server side control files.""" |
| |
| |
| class AutotestTimeoutError(AutotestError): |
| """This exception is raised when an autotest test exceeds the timeout |
| parameter passed to run_timed_test and is killed. |
| """ |
| |
| |
| class GenericHostRunError(Exception): |
| """Indicates a problem in the host run() function running in either client |
| or server code. |
| |
| Should always be constructed with a tuple of two args (error description |
| (str), run result object). This is a common class used to create the client |
| and server side versions of it when the distinction is useful. |
| """ |
| def __init__(self, description, result_obj): |
| self.description = description |
| self.result_obj = result_obj |
| Exception.__init__(self, description, result_obj) |
| |
| def __str__(self): |
| return self.description + '\n' + repr(self.result_obj) |
| |
| |
| class HostInstallTimeoutError(JobError): |
| """ |
| Indicates the machine failed to be installed after the predetermined |
| timeout. |
| """ |
| |
| |
| class AutotestHostRunError(GenericHostRunError, AutotestError): |
| pass |
| |
| |
| class AutotestHostRunCmdError(AutotestHostRunError): |
| """Indicates that the command run via Host.run failed. |
| |
| This is equivalent to CmdError when raised from a Host object instead of |
| directly on the DUT using utils.run |
| """ |
| |
| def __init__(self, command, result_obj, additional_text=''): |
| description = command |
| if additional_text: |
| description += ' (%s)' % additional_text |
| super(AutotestHostRunCmdError, self).__init__(description, result_obj) |
| self.command = command |
| self.additional_text = additional_text |
| |
| |
| class AutotestHostRunTimeoutError(AutotestHostRunCmdError): |
| """Indicates that a command run via Host.run timed out. |
| |
| This is equivalent to CmdTimeoutError when raised from a Host object instead |
| of directly on the DUT using utils.run |
| """ |
| |
| |
| # server-specific errors |
| |
| class AutoservError(Exception): |
| pass |
| |
| |
| class AutoservSSHTimeout(AutoservError): |
| """SSH experienced a connection timeout""" |
| |
| |
| class AutoservRunError(GenericHostRunError, AutoservError): |
| pass |
| |
| |
| class AutoservSshPermissionDeniedError(AutoservRunError): |
| """Indicates that a SSH permission denied error was encountered.""" |
| |
| |
| class AutoservUnsupportedError(AutoservError): |
| """Error raised when you try to use an unsupported optional feature""" |
| |
| |
| class AutoservHostError(AutoservError): |
| """Error reaching a host""" |
| |
| |
| class AutoservHostIsShuttingDownError(AutoservHostError): |
| """Host is shutting down""" |
| |
| |
| class AutoservNotMountedHostError(AutoservHostError): |
| """Found unmounted partitions that should be mounted""" |
| |
| |
| class AutoservSshPingHostError(AutoservHostError): |
| """SSH ping failed""" |
| |
| |
| class AutoservDiskFullHostError(AutoservHostError): |
| """Not enough free disk space on host""" |
| |
| def __init__(self, path, want_gb, free_space_gb): |
| super(AutoservDiskFullHostError, self).__init__( |
| 'Not enough free space on %s - %.3fGB free, want %.3fGB' % |
| (path, free_space_gb, want_gb)) |
| self.path = path |
| self.want_gb = want_gb |
| self.free_space_gb = free_space_gb |
| |
| |
| class AutoservNoFreeInodesError(AutoservHostError): |
| """Not enough free i-nodes on host""" |
| |
| def __init__(self, path, want_inodes, free_inodes): |
| super(AutoservNoFreeInodesError, self).__init__( |
| 'Not enough free inodes on %s - %d free, want %d' % |
| (path, free_inodes, want_inodes)) |
| self.path = path |
| self.want_inodes = want_inodes |
| self.free_inodes = free_inodes |
| |
| |
| class AutoservHardwareHostError(AutoservHostError): |
| """Found hardware problems with the host""" |
| |
| |
| class AutoservRebootError(AutoservError): |
| """Error occured while rebooting a machine""" |
| |
| |
| class AutoservShutdownError(AutoservRebootError): |
| """Error occured during shutdown of machine""" |
| |
| |
| class AutoservSuspendError(AutoservRebootError): |
| """Error occured while suspending a machine""" |
| |
| |
| class AutoservSubcommandError(AutoservError): |
| """Indicates an error while executing a (forked) subcommand""" |
| def __init__(self, func, exit_code): |
| AutoservError.__init__(self, func, exit_code) |
| self.func = func |
| self.exit_code = exit_code |
| |
| def __str__(self): |
| return ("Subcommand %s failed with exit code %d" % |
| (self.func, self.exit_code)) |
| |
| |
| class AutoservRepairTotalFailure(AutoservError): |
| """Raised if all attempts to repair the DUT failed.""" |
| |
| |
| class AutoservInstallError(AutoservError): |
| """Error occured while installing autotest on a host""" |
| |
| |
| class AutoservPidAlreadyDeadError(AutoservError): |
| """Error occured by trying to kill a nonexistant PID""" |
| |
| |
| # packaging system errors |
| |
| class PackagingError(AutotestError): |
| 'Abstract error class for all packaging related errors.' |
| |
| |
| class PackageUploadError(PackagingError): |
| 'Raised when there is an error uploading the package' |
| |
| |
| class PackageFetchError(PackagingError): |
| 'Raised when there is an error fetching the package' |
| |
| |
| class PackageRemoveError(PackagingError): |
| 'Raised when there is an error removing the package' |
| |
| |
| class PackageInstallError(PackagingError): |
| 'Raised when there is an error installing the package' |
| |
| |
| class RepoDiskFullError(PackagingError): |
| 'Raised when the destination for packages is full' |
| |
| |
| class RepoWriteError(PackagingError): |
| "Raised when packager cannot write to a repo's desitnation" |
| |
| |
| class RepoUnknownError(PackagingError): |
| "Raised when packager cannot write to a repo's desitnation" |
| |
| |
| class RepoError(PackagingError): |
| "Raised when a repo isn't working in some way" |
| |
| |
| class StageControlFileFailure(Exception): |
| """Exceptions encountered staging control files.""" |
| |
| |
| class CrosDynamicSuiteException(Exception): |
| """ |
| Base class for exceptions coming from dynamic suite code in |
| server/cros/dynamic_suite/*. |
| """ |
| |
| |
| class StageBuildFailure(CrosDynamicSuiteException): |
| """Raised when the dev server throws 500 while staging a build.""" |
| |
| |
| class ControlFileEmpty(CrosDynamicSuiteException): |
| """Raised when the control file exists on the server, but can't be read.""" |
| |
| |
| class ControlFileMalformed(CrosDynamicSuiteException): |
| """Raised when an invalid control file is read.""" |
| |
| |
| class AsynchronousBuildFailure(CrosDynamicSuiteException): |
| """Raised when the dev server throws 500 while finishing staging of a build. |
| """ |
| |
| |
| class SuiteArgumentException(CrosDynamicSuiteException): |
| """Raised when improper arguments are used to run a suite.""" |
| |
| |
| class MalformedDependenciesException(CrosDynamicSuiteException): |
| """Raised when a build has a malformed dependency_info file.""" |
| |
| |
| class InadequateHostsException(CrosDynamicSuiteException): |
| """Raised when there are too few hosts to run a suite.""" |
| |
| |
| class NoHostsException(CrosDynamicSuiteException): |
| """Raised when there are no healthy hosts to run a suite.""" |
| |
| |
| class ControlFileNotFound(CrosDynamicSuiteException): |
| """Raised when a control file cannot be found and/or read.""" |
| |
| |
| class NoControlFileList(CrosDynamicSuiteException): |
| """Raised to indicate that a listing can't be done.""" |
| |
| |
| class SuiteControlFileException(CrosDynamicSuiteException): |
| """Raised when failing to list the contents of all control file.""" |
| |
| |
| class HostLockManagerReuse(CrosDynamicSuiteException): |
| """Raised when a caller tries to re-use a HostLockManager instance.""" |
| |
| |
| class ReimageAbortedException(CrosDynamicSuiteException): |
| """Raised when a Reimage job is aborted""" |
| |
| |
| class UnknownReimageType(CrosDynamicSuiteException): |
| """Raised when a suite passes in an invalid reimage type""" |
| |
| |
| class NoUniquePackageFound(Exception): |
| """Raised when an executable cannot be mapped back to a single package.""" |
| |
| |
| class RPCException(Exception): |
| """Raised when an RPC encounters an error that a client might wish to |
| handle specially.""" |
| |
| |
| class NoEligibleHostException(RPCException): |
| """Raised when no host could satisfy the requirements of a job.""" |
| |
| |
| class UnmodifiableLabelException(RPCException): |
| """Raised when an RPC tries to modify static labels.""" |
| |
| |
| class UnmodifiableAttributeException(RPCException): |
| """Raised when an RPC tries to modify static attributes.""" |
| |
| |
| class InvalidBgJobCall(Exception): |
| """Raised when an invalid call is made to a BgJob object.""" |
| |
| |
| class HeartbeatOnlyAllowedInShardModeException(Exception): |
| """Raised when a heartbeat is attempted but not allowed.""" |
| |
| |
| class UnallowedRecordsSentToMain(Exception): |
| """Raised when an illegal record was sent from shard to main.""" |
| |
| |
| class IgnorableUnallowedRecordsSentToMain(UnallowedRecordsSentToMain): |
| """Raised when non-fatal illegal record was sent from shard. |
| |
| This exception may be raised by rpc model logic on main, but will |
| not be returned back to heartbeat client. It indicates that some records |
| may have been illegal, but the main is ignoring those records and |
| proceeding with the rest of the heartbeat handling. |
| """ |
| |
| |
| class InvalidDataError(Exception): |
| """Exception raised when invalid data provided for database operation.""" |
| |
| |
| class ContainerError(Exception): |
| """Exception raised when program runs into error using container.""" |
| |
| |
| class IllegalUser(Exception): |
| """Exception raise when a program runs as an illegal user.""" |
| |
| |
| class AutoservDirectoryNotFoundError(AutoservHostError): |
| """Exception raised when an expected directory is not found.""" |
| |
| |
| class AutoservDiskSizeUnknownError(AutoservHostError): |
| """Exception raised when the disk space could not be determined.""" |
| |
| |
| # This MUST remain at the end of the file. |
| # Limit 'from error import *' to only import the exception instances. |
| for _name, _thing in locals().items(): |
| try: |
| if issubclass(_thing, Exception): |
| __all__.append(_name) |
| except TypeError: |
| pass # _thing not a class |
| __all__ = tuple(__all__) |