[MobLab] Moblab Setup page.

* Adds a new page located at /moblab_setup
* 2 are on this page: 1 to upload a Boto Key and 1 to edit the config values.
* Link to /moblab_setup is visible only on a moblab system.
* RPC's that execute moblab_setup's actions are gated by a decorator that
  limits them to only run on a moblab_system.
* Unittests for new RPC's.
* Editting the config values, writes the full config to shadow_config.ini and
  reboots the system so changes takes effort.
* Resetting the config values, makes shadow_config.ini an empty file and
  reboots the system so it is restored.
* Uploading the boto key uses shutil.copyfile to write in the new boto file's
  contents to the boto file location.

BUG=chromium:396694
TEST=unittests, Uploaded a boto key and successfully ran a suite, editted
config and ensured changes were written into shadow_config, & reset config
and ensured that the default settings were restored.
DEPLOY=afe,apache
CQ-DEPEND=CL:212322
CQ-DEPEND=CL:212323
CQ-DEPEND=CL:212295

Change-Id: Ie354a2df310393045f3116e93004f58ea671de36
Reviewed-on: https://chromium-review.googlesource.com/209685
Reviewed-by: Simran Basi <sbasi@chromium.org>
Commit-Queue: Simran Basi <sbasi@chromium.org>
Tested-by: Simran Basi <sbasi@chromium.org>
diff --git a/frontend/afe/site_rpc_interface.py b/frontend/afe/site_rpc_interface.py
index 1c90778..cb6a4f7 100644
--- a/frontend/afe/site_rpc_interface.py
+++ b/frontend/afe/site_rpc_interface.py
@@ -9,8 +9,12 @@
 import common
 import datetime
 import logging
+import os
+import shutil
+import utils
 
 from autotest_lib.client.common_lib import error
+from autotest_lib.client.common_lib import global_config
 from autotest_lib.client.common_lib import priorities
 from autotest_lib.client.common_lib.cros import dev_server
 from autotest_lib.server import utils
@@ -18,6 +22,11 @@
 from autotest_lib.server.cros.dynamic_suite import control_file_getter
 from autotest_lib.server.cros.dynamic_suite import job_status
 from autotest_lib.server.cros.dynamic_suite import tools
+from autotest_lib.server.hosts import moblab_host
+
+
+_CONFIG = global_config.global_config
+MOBLAB_BOTO_LOCATION = '/home/moblab/.boto'
 
 
 # Relevant CrosDynamicSuiteExceptions are defined in client/common_lib/error.py.
@@ -191,3 +200,66 @@
                                           control_file=control_file,
                                           hostless=True,
                                           keyvals=timings)
+
+
+# TODO: hide the following rpcs under is_moblab
+def moblab_only(func):
+    """Ensure moblab specific functions only run on Moblab devices."""
+    def verify(*args, **kwargs):
+        if not utils.is_moblab():
+            raise error.RPCException('RPC: %s can only run on Moblab Systems!',
+                                     func.__name__)
+        return func(*args, **kwargs)
+    return verify
+
+
+@moblab_only
+def get_config_values():
+    """Returns all config values parsed from global and shadow configs.
+
+    Config values are grouped by sections, and each section is composed of
+    a list of name value pairs.
+    """
+    sections =_CONFIG.get_sections()
+    config_values = {}
+    for section in sections:
+        config_values[section] = _CONFIG.config.items(section)
+    return _rpc_utils().prepare_for_serialization(config_values)
+
+
+@moblab_only
+def update_config_handler(config_values):
+    """
+    Update config values and override shadow config.
+
+    @param config_values: See get_moblab_settings().
+    """
+    for section, config_value_list in config_values.iteritems():
+        for key, value in config_value_list:
+            _CONFIG.override_config_value(section, key, value)
+    if not _CONFIG.shadow_file or not os.path.exists(_CONFIG.shadow_file):
+        raise error.RPCException('Shadow config file does not exist.')
+
+    with open(_CONFIG.shadow_file, 'w') as config_file:
+        _CONFIG.config.write(config_file)
+    # TODO (sbasi) crbug.com/403916 - Remove the reboot command and
+    # instead restart the services that rely on the config values.
+    os.system('sudo reboot')
+
+
+@moblab_only
+def reset_config_settings():
+    with open(_CONFIG.shadow_file, 'w') as config_file:
+      pass
+    os.system('sudo reboot')
+
+
+@moblab_only
+def set_boto_key(boto_key):
+    """Update the boto_key file.
+
+    @param boto_key: File name of boto_key uploaded through handle_file_upload.
+    """
+    if not os.path.exists(boto_key):
+        raise error.RPCException('Boto key: %s does not exist!' % boto_key)
+    shutil.copyfile(boto_key, moblab_host.MOBLAB_BOTO_LOCATION)