[moblab] Initial Version of moblab_RunSuite test.

Updated moblab_host with the following functions:
* find_and_add_duts to find DUTs on the subnet and add them if they
  are not already in the AFE.
* run_as_moblab function to run commands as the moblab user.
* wait_afe_up function to gate tasks that rely on the AFE being up.

Added a new MoblabTest class that handles basic Moblab test tasks that
will be common to Moblab tests:
* Installing a boto file.
* Setting the image_storage_server to use.

Added the initial version of Moblab_RunSuite test which runs a suite
on a Moblab.
* Currently just has one control file that kicks off the smoke suite.

BUG=chromium:388462
TEST=Ran via test_that.

Change-Id: I697f5b94afc88633e213d3b35b53f8f7d5a6240b
Reviewed-on: https://chromium-review.googlesource.com/210592
Tested-by: Simran Basi <sbasi@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Reviewed-by: Dan Shi <dshi@chromium.org>
Commit-Queue: Simran Basi <sbasi@chromium.org>
diff --git a/server/cros/moblab_test.py b/server/cros/moblab_test.py
new file mode 100644
index 0000000..b2c0a95
--- /dev/null
+++ b/server/cros/moblab_test.py
@@ -0,0 +1,81 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import logging
+import os
+import re
+
+from autotest_lib.client.common_lib import error, global_config
+from autotest_lib.server import test
+from autotest_lib.server.hosts import moblab_host
+
+
+DEFAULT_IMAGE_STORAGE_SERVER = global_config.global_config.get_config_value(
+        'CROS', 'image_storage_server')
+MOBLAB_BOTO_FILE_DEST = '/home/moblab/.boto'
+STORAGE_SERVER_REGEX = 'gs://.*/'
+
+
+class MoblabTest(test.test):
+    """Base class for Moblab tests.
+    """
+
+    def initialize(self, host, boto_path='',
+                   image_storage_server=DEFAULT_IMAGE_STORAGE_SERVER):
+        """Initialize the Moblab Host.
+
+        * Installs a boto file.
+        * Sets up the image storage server for this test.
+        * Finds and adds DUTs on the testing subnet.
+
+        @param boto_path: Path to the boto file we want to install.
+        @param image_storage_server: image storage server to use for grabbing
+                                     images from Google Storage.
+        """
+        super(MoblabTest, self).initialize()
+        self._host = host
+        self.install_boto_file(boto_path)
+        self.set_image_storage_server(image_storage_server)
+        self._host.wait_afe_up()
+        self._host.find_and_add_duts()
+
+
+    def install_boto_file(self, boto_path=''):
+        """Install a boto file on the Moblab device.
+
+        @param boto_path: Path to the boto file to install. If None, sends the
+                          boto file in the current HOME directory.
+
+        @raises error.TestError if the boto file does not exist.
+        """
+        if not boto_path:
+            boto_path = os.path.join(os.getenv('HOME'), '.boto')
+        if not os.path.exists(boto_path):
+            raise error.TestError('Boto File:%s does not exist.' % boto_path)
+        self._host.send_file(boto_path, MOBLAB_BOTO_FILE_DEST)
+        self._host.run('chown moblab:moblab %s' % MOBLAB_BOTO_FILE_DEST)
+
+
+    def set_image_storage_server(self, image_storage_server):
+        """Set the image storage server.
+
+        @param image_storage_server: Name of image storage server to use. Must
+                                     follow format or gs://bucket-name/
+                                     (Note trailing slash is required).
+
+        @raises error.TestError if the image_storage_server is incorrectly
+                                formatted.
+        """
+        if not re.match(STORAGE_SERVER_REGEX, image_storage_server):
+            raise error.TestError(
+                    'Image Storage Server supplied is not in the correct '
+                    'format. Must start with gs:// and end with a trailing '
+                    'slash: %s' % image_storage_server)
+        logging.debug('Setting image_storage_server to %s',
+                      image_storage_server)
+        # If the image_storage_server is already set, delete it.
+        self._host.run('sed -i /image_storage_server/d %s' %
+                       moblab_host.SHADOW_CONFIG_PATH, ignore_status=True)
+        self._host.run("sed -i '/\[CROS\]/ a\image_storage_server: "
+                       "%s' %s" %(image_storage_server,
+                                  moblab_host.SHADOW_CONFIG_PATH))
\ No newline at end of file