Move certain content from client/ to server/site_utils.py

This moves the lab status functions and ParseBuildName().  They
were out of place in client/common_lib, as they're only needed/
meaningful in server side code.

BUG=None
TEST=run driver_unittest.py

Change-Id: I756291f27d7b041f0a907dee4004c3b447def929
Reviewed-on: https://chromium-review.googlesource.com/178306
Reviewed-by: Richard Barnette <jrbarnette@chromium.org>
Commit-Queue: Richard Barnette <jrbarnette@chromium.org>
Tested-by: Richard Barnette <jrbarnette@chromium.org>
diff --git a/client/common_lib/error.py b/client/common_lib/error.py
index 076d7f4..7aa74dc 100644
--- a/client/common_lib/error.py
+++ b/client/common_lib/error.py
@@ -604,16 +604,6 @@
     pass
 
 
-class LabIsDownException(Exception):
-    """Raised when the Lab is Down"""
-    pass
-
-
-class BoardIsDisabledException(Exception):
-    """Raised when a certain board is disabled in the Lab"""
-    pass
-
-
 class NoUniquePackageFound(Exception):
     """Raised when an executable cannot be mapped back to a single package."""
     pass
diff --git a/client/common_lib/site_utils.py b/client/common_lib/site_utils.py
index 37bc872..f5c9069 100644
--- a/client/common_lib/site_utils.py
+++ b/client/common_lib/site_utils.py
@@ -1,7 +1,7 @@
 # Copyright (c) 2012 The Chromium 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 json
+
 import logging
 import os
 import re
@@ -19,28 +19,6 @@
 
 _LOCAL_HOST_LIST = ('localhost', '127.0.0.1')
 
-LAB_GOOD_STATES = ('open', 'throttled')
-
-
-class ParseBuildNameException(Exception):
-    """Raised when ParseBuildName() cannot parse a build name."""
-    pass
-
-
-def ParseBuildName(name):
-    """Format a build name, given board, type, milestone, and manifest num.
-
-    @param name: a build name, e.g. 'x86-alex-release/R20-2015.0.0'
-    @return board: board the manifest is for, e.g. x86-alex.
-    @return type: one of 'release', 'factory', or 'firmware'
-    @return milestone: (numeric) milestone the manifest was associated with.
-    @return manifest: manifest number, e.g. '2015.0.0'
-    """
-    match = re.match(r'([\w-]+)-(\w+)/R(\d+)-([\d.ab-]+)', name)
-    if match and len(match.groups()) == 4:
-        return match.groups()
-    raise ParseBuildNameException('%s is a malformed build name.' % name)
-
 
 def ping(host, deadline=None, tries=None, timeout=60):
     """Attempt to ping |host|.
@@ -245,75 +223,6 @@
     return socket.gethostname() if host in _LOCAL_HOST_LIST else host
 
 
-def get_lab_status():
-      """Grabs the current lab status and message.
-
-      @returns a dict with keys 'lab_is_up' and 'message'. lab_is_up points
-               to a boolean and message points to a string.
-      """
-      result = {'lab_is_up' : True, 'message' : ''}
-      status_url = global_config.global_config.get_config_value('CROS',
-              'lab_status_url')
-      max_attempts = 5
-      retry_waittime = 1
-      for _ in range(max_attempts):
-          try:
-              response = urllib2.urlopen(status_url)
-          except IOError as e:
-              logging.debug('Error occured when grabbing the lab status: %s.',
-                            e)
-              time.sleep(retry_waittime)
-              continue
-          # Check for successful response code.
-          if response.getcode() == 200:
-              data = json.load(response)
-              result['lab_is_up'] = data['general_state'] in LAB_GOOD_STATES
-              result['message'] = data['message']
-              return result
-          time.sleep(retry_waittime)
-      # We go ahead and say the lab is open if we can't get the status.
-      logging.warn('Could not get a status from %s', status_url)
-      return result
-
-
-def check_lab_status(board=None):
-    """Check if the lab is up and if we can schedule suites to run.
-
-    Also checks if the lab is disabled for that particular board, and if so
-    will raise an error to prevent new suites from being scheduled for that
-    board.
-
-    @param board: board name that we want to check the status of.
-
-    @raises error.LabIsDownException if the lab is not up.
-    @raises error.BoardIsDisabledException if the desired board is currently
-                                           disabled.
-    """
-    # Ensure we are trying to schedule on the actual lab.
-    if not (global_config.global_config.get_config_value('SERVER',
-            'hostname').startswith('cautotest')):
-        return
-
-    # First check if the lab is up.
-    lab_status = get_lab_status()
-    if not lab_status['lab_is_up']:
-        raise error.LabIsDownException('Chromium OS Lab is currently not up: '
-                                       '%s.' % lab_status['message'])
-
-    # Check if the board we wish to use is disabled.
-    # Lab messages should be in the format of:
-    # Lab is 'status' [boards not to be ran] (comment). Example:
-    # Lab is Open [stumpy, kiev, x86-alex] (power_resume rtc causing duts to go
-    # down)
-    boards_are_disabled = re.search('\[(.*)\]', lab_status['message'])
-    if board and boards_are_disabled:
-        if board in boards_are_disabled.group(1):
-            raise error.BoardIsDisabledException('Chromium OS Lab is '
-                    'currently not allowing suites to be scheduled on board '
-                    '%s: %s' % (board, lab_status['message']))
-    return
-
-
 def urlopen_socket_timeout(url, data=None, timeout=5):
     """
     Wrapper to urllib2.urlopen with a socket timeout.
diff --git a/server/hosts/cros_host.py b/server/hosts/cros_host.py
index bbceede..48cc6f3 100644
--- a/server/hosts/cros_host.py
+++ b/server/hosts/cros_host.py
@@ -15,7 +15,6 @@
 from autotest_lib.client.bin 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 site_utils
 from autotest_lib.client.common_lib.cros import autoupdater
 from autotest_lib.client.common_lib.cros import dev_server
 from autotest_lib.client.common_lib.cros import retry
@@ -424,9 +423,9 @@
         # restage. If we're doing things right we should not see multiple
         # devservers for a given board/build/branch path.
         try:
-            board, build_type, branch = site_utils.ParseBuildName(
+            board, build_type, branch = server_utils.ParseBuildName(
                                                 image_name)[:3]
-        except site_utils.ParseBuildNameException:
+        except server_utils.ParseBuildNameException:
             pass
         else:
             devserver = devserver_url[
diff --git a/server/site_utils.py b/server/site_utils.py
index c1390bf..65e1643 100644
--- a/server/site_utils.py
+++ b/server/site_utils.py
@@ -3,11 +3,14 @@
 # found in the LICENSE file.
 
 
+import httplib
+import json
 import logging
 import re
+import time
 import urllib2
-import httplib
 
+import common
 from autotest_lib.client.common_lib import base_utils, global_config
 from autotest_lib.server.cros.dynamic_suite import constants
 
@@ -19,6 +22,40 @@
 _CHROMIUM_BUILD_URL = global_config.global_config.get_config_value(
     'NOTIFICATIONS', 'chromium_build_url', default='')
 
+LAB_GOOD_STATES = ('open', 'throttled')
+
+
+class LabIsDownException(Exception):
+    """Raised when the Lab is Down"""
+    pass
+
+
+class BoardIsDisabledException(Exception):
+    """Raised when a certain board is disabled in the Lab"""
+    pass
+
+
+class ParseBuildNameException(Exception):
+    """Raised when ParseBuildName() cannot parse a build name."""
+    pass
+
+
+def ParseBuildName(name):
+    """Format a build name, given board, type, milestone, and manifest num.
+
+    @param name: a build name, e.g. 'x86-alex-release/R20-2015.0.0'
+
+    @return board: board the manifest is for, e.g. x86-alex.
+    @return type: one of 'release', 'factory', or 'firmware'
+    @return milestone: (numeric) milestone the manifest was associated with.
+    @return manifest: manifest number, e.g. '2015.0.0'
+
+    """
+    match = re.match(r'([\w-]+)-(\w+)/R(\d+)-([\d.ab-]+)', name)
+    if match and len(match.groups()) == 4:
+        return match.groups()
+    raise ParseBuildNameException('%s is a malformed build name.' % name)
+
 
 def get_label_from_afe(hostname, label_prefix, afe):
     """Retrieve a host's specific label from the AFE.
@@ -117,3 +154,71 @@
                 (source_url, ssh_cmd, dest_path))
     base_utils.run(wget_cmd)
 
+
+def get_lab_status():
+    """Grabs the current lab status and message.
+
+    @returns a dict with keys 'lab_is_up' and 'message'. lab_is_up points
+             to a boolean and message points to a string.
+    """
+    result = {'lab_is_up' : True, 'message' : ''}
+    status_url = global_config.global_config.get_config_value('CROS',
+            'lab_status_url')
+    max_attempts = 5
+    retry_waittime = 1
+    for _ in range(max_attempts):
+        try:
+            response = urllib2.urlopen(status_url)
+        except IOError as e:
+            logging.debug('Error occured when grabbing the lab status: %s.',
+                          e)
+            time.sleep(retry_waittime)
+            continue
+        # Check for successful response code.
+        if response.getcode() == 200:
+            data = json.load(response)
+            result['lab_is_up'] = data['general_state'] in LAB_GOOD_STATES
+            result['message'] = data['message']
+            return result
+        time.sleep(retry_waittime)
+    # We go ahead and say the lab is open if we can't get the status.
+    logging.warn('Could not get a status from %s', status_url)
+    return result
+
+
+def check_lab_status(board=None):
+    """Check if the lab is up and if we can schedule suites to run.
+
+    Also checks if the lab is disabled for that particular board, and if so
+    will raise an error to prevent new suites from being scheduled for that
+    board.
+
+    @param board: board name that we want to check the status of.
+
+    @raises LabIsDownException if the lab is not up.
+    @raises BoardIsDisabledException if the desired board is currently
+                                           disabled.
+    """
+    # Ensure we are trying to schedule on the actual lab.
+    if not (global_config.global_config.get_config_value('SERVER',
+            'hostname').startswith('cautotest')):
+        return
+
+    # First check if the lab is up.
+    lab_status = get_lab_status()
+    if not lab_status['lab_is_up']:
+        raise LabIsDownException('Chromium OS Lab is currently not up: '
+                                       '%s.' % lab_status['message'])
+
+    # Check if the board we wish to use is disabled.
+    # Lab messages should be in the format of:
+    # Lab is 'status' [boards not to be ran] (comment). Example:
+    # Lab is Open [stumpy, kiev, x86-alex] (power_resume rtc causing duts to go
+    # down)
+    boards_are_disabled = re.search('\[(.*)\]', lab_status['message'])
+    if board and boards_are_disabled:
+        if board in boards_are_disabled.group(1):
+            raise BoardIsDisabledException('Chromium OS Lab is '
+                    'currently not allowing suites to be scheduled on board '
+                    '%s: %s' % (board, lab_status['message']))
+    return
diff --git a/site_utils/run_suite.py b/site_utils/run_suite.py
index 7b0d1c8..689b45d 100755
--- a/site_utils/run_suite.py
+++ b/site_utils/run_suite.py
@@ -19,8 +19,9 @@
 
 import common
 
-from autotest_lib.client.common_lib import global_config, error, utils, enum
-from autotest_lib.client.common_lib import site_utils, priorities
+from autotest_lib.client.common_lib import global_config, enum
+from autotest_lib.client.common_lib import priorities
+from autotest_lib.server import utils
 from autotest_lib.server.cros.dynamic_suite import constants
 from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
 from autotest_lib.server.cros.dynamic_suite import job_status
@@ -437,8 +438,8 @@
         @return: The key used to log timing information in statsd.
         """
         try:
-            _board, build_type, branch = site_utils.ParseBuildName(build)[:3]
-        except site_utils.ParseBuildNameException as e:
+            _board, build_type, branch = utils.ParseBuildName(build)[:3]
+        except utils.ParseBuildNameException as e:
             logging.error(str(e))
             branch = 'Unknown'
             build_type = 'Unknown'
@@ -597,7 +598,7 @@
     try:
         if not options.bypass_labstatus:
             utils.check_lab_status(options.board)
-    except (error.LabIsDownException, error.BoardIsDisabledException) as e:
+    except (utils.LabIsDownException, utils.BoardIsDisabledException) as e:
         logging.warning('Error Message: %s', e)
         return RETURN_CODES.WARNING
 
diff --git a/site_utils/suite_scheduler/driver.py b/site_utils/suite_scheduler/driver.py
index 669e420..cda71f5 100644
--- a/site_utils/suite_scheduler/driver.py
+++ b/site_utils/suite_scheduler/driver.py
@@ -8,7 +8,7 @@
 import task, timed_event
 
 import common
-from autotest_lib.client.common_lib import error, site_utils
+from autotest_lib.server import utils
 
 class Driver(object):
     """Implements the main loop of the suite_scheduler.
@@ -133,8 +133,8 @@
         for e in self._events.itervalues():
             if e.ShouldHandle():
                 try:
-                    site_utils.check_lab_status()
-                except error.LabIsDownException as ex:
+                    utils.check_lab_status()
+                except utils.LabIsDownException as ex:
                     logging.debug('Skipping event %s, because lab is down '
                                   'with message: %s', e.keyword, ex.message)
                     continue
@@ -152,7 +152,7 @@
         @param keywords: iterable of event keywords to force
         @param build_name: instead of looking up builds to test, test this one.
         """
-        board, type, milestone, manifest = site_utils.ParseBuildName(build_name)
+        board, type, milestone, manifest = utils.ParseBuildName(build_name)
         branch_builds = {task.PickBranchName(type, milestone): [build_name]}
         logging.info('Testing build R%s-%s on %s', milestone, manifest, board)
 
diff --git a/site_utils/suite_scheduler/driver_unittest.py b/site_utils/suite_scheduler/driver_unittest.py
index f379ceb..f949ceb 100644
--- a/site_utils/suite_scheduler/driver_unittest.py
+++ b/site_utils/suite_scheduler/driver_unittest.py
@@ -15,7 +15,7 @@
 
 import common
 from autotest_lib.server import frontend
-from autotest_lib.client.common_lib import site_utils, error
+from autotest_lib.server import utils
 from constants import Labels
 
 
@@ -56,7 +56,7 @@
         self.mox.StubOutWithMock(timed_event.Nightly, 'CreateFromConfig')
         self.mox.StubOutWithMock(timed_event.Weekly, 'CreateFromConfig')
         self.mox.StubOutWithMock(build_event.NewBuild, 'CreateFromConfig')
-        self.mox.StubOutWithMock(site_utils, 'check_lab_status')
+        self.mox.StubOutWithMock(utils, 'check_lab_status')
         timed_event.Nightly.CreateFromConfig(
             mox.IgnoreArg(), self.mv).AndReturn(mock_nightly)
         timed_event.Weekly.CreateFromConfig(
@@ -89,16 +89,16 @@
 
 
     def _ExpectLabStatusQuery(self, lab_up=True, message='No message.'):
-        """Expect one call to site_utils.check_lab_status
+        """Expect one call to utils.check_lab_status
         @param lab_up: True if lab shoule be up. False if lab should be down.
                        Default: True.
         @param message: String message with which lab should be down, if down.
         """
         if lab_up:
-            site_utils.check_lab_status()
+            utils.check_lab_status()
         else:
-            site_utils.check_lab_status().AndRaise(
-                error.LabIsDownException(message))
+            utils.check_lab_status().AndRaise(
+                utils.LabIsDownException(message))
 
 
     def _ExpectHandle(self, event, group):