[autotest] Fix the RPC interface for get_status_task().

The interface failed to provide termination when the call chain
reached the shard that owned the target host.  This splits the
API into two parts:  `get_status_task()` and `get_host_status_task()`.
The former actually gets the status task from the local shard
(without forwarding).  The latter merely converts to a call to
`get_status_task()` targeted at the proper shard.

BUG=chromium:483485
TEST=test using local instance pointed at production database

Change-Id: I64411cab8a8b3f4bae0bf378c459099f32545a93
Reviewed-on: https://chromium-review.googlesource.com/268790
Reviewed-by: Mungyung Ryu <mkryu@google.com>
Tested-by: Richard Barnette <jrbarnette@chromium.org>
Commit-Queue: Richard Barnette <jrbarnette@chromium.org>
diff --git a/frontend/afe/rpc_interface.py b/frontend/afe/rpc_interface.py
index 80cc67e..d9fe281 100644
--- a/frontend/afe/rpc_interface.py
+++ b/frontend/afe/rpc_interface.py
@@ -1154,15 +1154,37 @@
 
 
 def get_status_task(host_id, end_time):
-    """Get the special task identifying a host's status.
+    """Get the "status task" for a host from the local shard.
 
-    Returns information for a single special task for a host
-    identifying whether the host was working or broken at the given
-    `end_time`.  A successful task indicates a working host; a
-    failed task indicates a broken host.
+    Returns a single special task representing the given host's
+    "status task".  The status task is a completed special task that
+    identifies whether the corresponding host was working or broken
+    when it completed.  A successful task indicates a working host;
+    a failed task indicates broken.
 
-    If the host is managed by a shard, this call forwards the
-    request.
+    This call will not be forward to a shard; the receiving server
+    must be the shard that owns the host.
+
+    @param host_id      Id in the database of the target host.
+    @param end_time     Time reference for the host's status.
+
+    @return A single task; its status (successful or not)
+            corresponds to the status of the host (working or
+            broken) at the given time.  If no task is found, return
+            `None`.
+
+    """
+    tasklist = rpc_utils.prepare_rows_as_nested_dicts(
+            status_history.get_status_task(host_id, end_time),
+            ('host', 'queue_entry'))
+    return tasklist[0] if tasklist else None
+
+
+def get_host_status_task(host_id, end_time):
+    """Get the "status task" for a host from its owning shard.
+
+    Finds the given host's owning shard, and forwards to it a call
+    to `get_status_task()` (see above).
 
     @param host_id      Id in the database of the target host.
     @param end_time     Time reference for the host's status.
@@ -1175,13 +1197,7 @@
     """
     host = models.Host.smart_get(host_id)
     if not host.shard:
-        tasklist = rpc_utils.prepare_rows_as_nested_dicts(
-                status_history.get_status_task(host_id, end_time),
-                ('host', 'queue_entry'))
-        if tasklist:
-            return tasklist[0]
-        else:
-            return None
+        return get_status_task(host_id, end_time)
     else:
         # The return values from AFE methods are post-processed
         # objects that aren't JSON-serializable.  So, we have to