Improve the standard error message in the lab if an update fails.

Produce a more meaningful (but still generic) error message in the lab
if an update fails to apply.

BUG=chromium:246779
TEST=New unittest + trybots

Change-Id: Ib3be5fe27d7fd60732f9d20db4a08d1994358939
Reviewed-on: https://chromium-review.googlesource.com/179543
Reviewed-by: Richard Barnette <jrbarnette@chromium.org>
Commit-Queue: Don Garrett <dgarrett@chromium.org>
Tested-by: Don Garrett <dgarrett@chromium.org>
diff --git a/client/common_lib/cros/autoupdater.py b/client/common_lib/cros/autoupdater.py
index af2dae3..e641c4a 100644
--- a/client/common_lib/cros/autoupdater.py
+++ b/client/common_lib/cros/autoupdater.py
@@ -222,9 +222,18 @@
         logging.info('Triggering update via: %s', autoupdate_cmd)
         try:
             self._run(autoupdate_cmd)
-        except error.AutoservRunError, e:
-            raise RootFSUpdateError('Update triggering failed on %s: %s' %
-                                    (self.host.hostname, str(e)))
+        except (error.AutoservSshPermissionDeniedError,
+                error.AutoservSSHError,
+                error.AutoservSSHTimeout) as e:
+            raise RootFSUpdateError('SSH on %s is seeing %s' %
+                                    (self.host.hostname, type(e).__name__))
+
+        except error.AutoservRunError as e:
+            raise RootFSUpdateError(
+                'devserver unreachable, payload unavailable, '
+                'or AU bug (unlikely) on %s: %s' %
+                (self.host.hostname, type(e).__name__))
+
 
     def _verify_update_completed(self):
         """Verifies that an update has completed.
diff --git a/client/common_lib/cros/autoupdater_unittest.py b/client/common_lib/cros/autoupdater_unittest.py
index 51cd3c9..a36185b 100755
--- a/client/common_lib/cros/autoupdater_unittest.py
+++ b/client/common_lib/cros/autoupdater_unittest.py
@@ -9,6 +9,7 @@
 import common
 
 import autoupdater
+from autotest_lib.client.common_lib import error
 
 
 class TestAutoUpdater(mox.MoxTestBase):
@@ -318,6 +319,55 @@
         self.assertTrue(updater.check_version_to_confirm_install())
 
 
+    def testTriggerUpdate(self):
+        """Tests that we correctly handle updater errors."""
+        self.mox.StubOutWithMock(autoupdater.ChromiumOSUpdater, '_run')
+        update_url = 'http://server/test/url'
+        host = self.mox.CreateMockAnything()
+        host.hostname = 'test_host'
+
+        expected_cmd = ('/usr/bin/update_engine_client --check_for_update '
+                        '--omaha_url=http://server/test/url')
+
+        updater = autoupdater.ChromiumOSUpdater(update_url, host=host)
+
+        # Test with success.
+        autoupdater.ChromiumOSUpdater._run(expected_cmd)
+
+        # SSH Timeout
+        autoupdater.ChromiumOSUpdater._run(expected_cmd).AndRaise(
+                error.AutoservSSHTimeout("ssh timed out", 255))
+
+        # SSH Permission Error
+        autoupdater.ChromiumOSUpdater._run(expected_cmd).AndRaise(
+                error.AutoservSshPermissionDeniedError("ssh timed out", 255))
+
+        # Generic SSH Error
+        autoupdater.ChromiumOSUpdater._run(expected_cmd).AndRaise(
+                error.AutoservSSHError("ssh timed out", 255))
+
+        # Command Failed Error
+        autoupdater.ChromiumOSUpdater._run(expected_cmd).AndRaise(
+                error.AutoservRunError("ssh timed out", 1))
+
+        self.mox.ReplayAll()
+
+        # Verify Success.
+        updater.trigger_update()
+
+        # Verify each type of error listed above.
+        self.assertRaises(autoupdater.RootFSUpdateError,
+                          updater.trigger_update)
+        self.assertRaises(autoupdater.RootFSUpdateError,
+                          updater.trigger_update)
+        self.assertRaises(autoupdater.RootFSUpdateError,
+                          updater.trigger_update)
+        self.assertRaises(autoupdater.RootFSUpdateError,
+                          updater.trigger_update)
+
+        self.mox.VerifyAll()
+
+
     def testUpdateStateful(self):
         """Tests that we call the stateful update script with the correct args.
         """
diff --git a/client/common_lib/error.py b/client/common_lib/error.py
index 7aa74dc..cc35bbd 100644
--- a/client/common_lib/error.py
+++ b/client/common_lib/error.py
@@ -367,7 +367,12 @@
     pass
 
 
-class AutoservSSHTimeout(AutoservError):
+class AutoservSSHError(AutoservError):
+    """Generic SSH Error."""
+    pass
+
+
+class AutoservSSHTimeout(AutoservSSHError):
     """SSH experienced a connection timeout"""
     pass