[autotest] Store afe_host in and remove host attributes to/from machine dict.

There are multiple times when the AFE is queried for random bits of info
(host attibutes, labels, etc).  To reduce the number of calls, store the
AFE host object into the machine dict so we can store it into the host class.
I chose the AbstractSSHHost class to grab it out of the arg dict since that
is used both by CrosHost and ADBHost.

Also removed host attributes as a class instance attribute since
afe_host contains all that info already.

Also use the os labels to do host class detection.

BUG=chromium:546741
TEST=Tested a couple scenarios:
- Manually on moblab to make sure cros/adb/testbed devices all pass
  dummy tests.
- Trybot job on gnawty-paladin.
- Moblab dummy suite run to ensure no breaking backward compatibility changes
  (moblab on R52 and testing with a tryjob gnawty build).
- test_{that,droid}.py on a cros/adbhost device.

Change-Id: I101c478c0f27f9fd444ccd4699a5c94e76d3b17e
Reviewed-on: https://chromium-review.googlesource.com/349990
Commit-Ready: Kevin Cheng <kevcheng@chromium.org>
Tested-by: Kevin Cheng <kevcheng@chromium.org>
Reviewed-by: Kevin Cheng <kevcheng@chromium.org>
diff --git a/server/site_utils.py b/server/site_utils.py
index 804ccc6..da556bb 100644
--- a/server/site_utils.py
+++ b/server/site_utils.py
@@ -66,6 +66,21 @@
                     *args, **kwargs)
         return cls._instances[cls]
 
+class EmptyAFEHost(object):
+    """Object to represent an AFE host object when there is no AFE."""
+
+    def __init__(self):
+        """
+        We'll be setting the instance attributes as we use them.  Right now
+        we only use attributes and labels but as time goes by and other
+        attributes are used from an actual AFE Host object (check
+        rpc_interfaces.get_hosts()), we'll add them in here so users won't be
+        perplexed why their host's afe_host object complains that attribute
+        doesn't exist.
+        """
+        self.attributes = {}
+        self.labels = []
+
 
 def ParseBuildName(name):
     """Format a build name, given board, type, milestone, and manifest num.
@@ -672,12 +687,21 @@
 def get_host_info_from_machine(machine):
     """Lookup host information from a machine string or dict.
 
-    @returns: Tuple of (hostname, host_attributes)
+    @returns: Tuple of (hostname, afe_host)
     """
     if isinstance(machine, dict):
-        return (machine['hostname'], machine['host_attributes'])
+        return (machine['hostname'], machine['afe_host'])
     else:
-        return (machine, {})
+        return (machine, EmptyAFEHost())
+
+
+def get_afe_host_from_machine(machine):
+    """Return the afe_host from the machine dict if possible.
+
+    @returns: AFE host object.
+    """
+    _, afe_host = get_host_info_from_machine(machine)
+    return afe_host
 
 
 def get_creds_abspath(creds_file):
@@ -710,7 +734,5 @@
 
     @return: True if the machine is a testbed, False otherwise.
     """
-    _, attributes = get_host_info_from_machine(machine)
-    if len(attributes.get('serials', '').split(',')) > 1:
-        return True
-    return False
+    _, afe_host = get_host_info_from_machine(machine)
+    return len(afe_host.attributes.get('serials', '').split(',')) > 1