[autotest] Make json_rpc raise meaningful exceptions

Add some dynamic suite exceptions to client/common_lib/error.py so
that different parts of the system can all reference them.  Then,
enable the json_rpc code to detect these exceptions coming back
over the wire, re-instantiate them on the client side, and raise
them.

BUG=chromium-os:30279
TEST=unit
TEST=use atest suite create to try to create a suite for a build that doesn't exist
TEST=use atest suite create to try to run a suite that doesn't exist

Change-Id: I1b6d56a7e1bdb63cc893a07581efc8decc0407f4
Reviewed-on: https://gerrit.chromium.org/gerrit/22250
Tested-by: Chris Masone <cmasone@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Ready: Chris Masone <cmasone@chromium.org>
diff --git a/client/common_lib/error.py b/client/common_lib/error.py
index 1823143..b903080 100644
--- a/client/common_lib/error.py
+++ b/client/common_lib/error.py
@@ -491,6 +491,54 @@
     "Raised when a repo isn't working in some way"
 
 
+class CrosDynamicSuiteException(Exception):
+    """
+    Base class for exceptions coming from dynamic suite code in server/cros/*.
+    """
+    pass
+
+
+class StageBuildFailure(CrosDynamicSuiteException):
+    """Raised when the dev server throws 500 while staging a build."""
+    pass
+
+
+class ControlFileEmpty(CrosDynamicSuiteException):
+    """Raised when the control file exists on the server, but can't be read."""
+    pass
+
+
+class AsynchronousBuildFailure(CrosDynamicSuiteException):
+    """Raised when the dev server throws 500 while finishing staging of a build.
+    """
+    pass
+
+
+class SuiteArgumentException(CrosDynamicSuiteException):
+    """Raised when improper arguments are used to run a suite."""
+    pass
+
+
+class InadequateHostsException(CrosDynamicSuiteException):
+    """Raised when there are too few hosts to run a suite."""
+    pass
+
+
+class NoHostsException(CrosDynamicSuiteException):
+    """Raised when there are no healthy hosts to run a suite."""
+    pass
+
+
+class ControlFileNotFound(CrosDynamicSuiteException):
+    """Raised when a control file cannot be found and/or read."""
+    pass
+
+
+class NoControlFileList(CrosDynamicSuiteException):
+    """Raised when to indicate that a listing can't be done."""
+    pass
+
+
 # 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():