dev: add initial APIs to devserver to support cros auto-update.

This CL adds three APIs on devserver:
1. 'cros_au' API: to support 'start cros auto-update'.
2. 'get_au_status' API: to check the status of cros auto-update.
3. 'collect_au_log' API: to collect auto-update log from devserver.
4. 'handler_cleanup' API: delete the status file for tracking the progress of
   CrOS auto-update.
5. 'kill_au_proc' API: to kill unexpected auto-update process for DUT.

Also it updates the unittests and integration test.

The 'cros_au' API triggers a background process to support the whole
auto-update processes for a CrOS host, includes:
1. Transfer devserver/stateful update package.
2. If devserver cannot run on the host, restore the stateful partition.
3. If restore_stateful_partiton is not required, and stateful_update is
required, do stateful_update.
4. If stateful_update fails, or rootfs_update is required, do rootfs update.
5. Final check after the whole auto-update process.

BUG=chromium:613765
TEST=Locally ran 'ds.auto_update([dut], [image_path])';
Ran 'repair' for dut from local autotest instance;
Ran unittest, devserver_integration_test.

 Changes to be committed:
	modified:   Makefile
	new file:   cros_update.py
	new file:   cros_update_logging.py
	new file:   cros_update_progress.py
	new file:   cros_update_unittest.py
	modified:   devserver.py
	modified:   devserver_integration_test.py

Change-Id: I2e9c116bc1e0b07d37b540266fd252aee4fd6e84
Reviewed-on: https://chromium-review.googlesource.com/346199
Commit-Ready: Xixuan Wu <xixuan@chromium.org>
Tested-by: Xixuan Wu <xixuan@chromium.org>
Reviewed-by: Xixuan Wu <xixuan@chromium.org>
diff --git a/cros_update_progress.py b/cros_update_progress.py
new file mode 100644
index 0000000..9ab43e3
--- /dev/null
+++ b/cros_update_progress.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2016 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.
+
+"""A progress class for tracking CrOS auto-update process.
+
+This class is mainly designed for:
+  1. Set the pattern for generating the filenames of
+     track_status_file/execute_log_file.
+     track_status_file: Used for record the current step of CrOS auto-update
+                        process. Only has one line.
+     execute_log_file: Used for record the whole logging info of the CrOS
+                       auto-update process, including any debug information.
+  2. Write current auto-update process into the track_status_file.
+  3. Read current auto-update process from the track_status_file.
+
+This file also offers external functions that are related to add/check/delete
+the progress of the CrOS auto-update process.
+"""
+
+from __future__ import print_function
+
+import logging
+import os
+
+try:
+  from chromite.lib import osutils
+except ImportError as e:
+  logging.debug('chromite cannot be imported: %r', e)
+  osutils = None
+
+# Path for status tracking log.
+TRACK_LOG_FILE_PATH = '/tmp/auto-update/tracking_log/%s_%s.log'
+
+# Path for executing log.
+EXECUTE_LOG_FILE_PATH = '/tmp/auto-update/executing_log/%s_%s.log'
+
+# The string for update process finished
+FINISHED = 'Completed'
+ERROR_TAG = 'Error'
+
+
+def ReadOneLine(filename):
+  """Read one line from file.
+
+  Args:
+    filename: The file to be read.
+  """
+  return open(filename, 'r').readline().rstrip('\n')
+
+
+def IsProcessAlive(pid):
+  """Detect whether a process is alive or not.
+
+  Args:
+    pid: The process id.
+  """
+  path = '/proc/%s/stat' % pid
+  try:
+    stat = ReadOneLine(path)
+  except IOError:
+    if not os.path.exists(path):
+      return False
+
+    raise
+
+  return stat.split()[2] != 'Z'
+
+
+def GetExecuteLogFile(host_name, pid):
+  """Return the whole path of execute log file."""
+  if not os.path.exists(os.path.dirname(EXECUTE_LOG_FILE_PATH)):
+    osutils.SafeMakedirs(os.path.dirname(EXECUTE_LOG_FILE_PATH))
+
+  return EXECUTE_LOG_FILE_PATH % (host_name, pid)
+
+
+def GetTrackStatusFile(host_name, pid):
+  """Return the whole path of track status file."""
+  if not os.path.exists(os.path.dirname(TRACK_LOG_FILE_PATH)):
+    osutils.SafeMakedirs(os.path.dirname(TRACK_LOG_FILE_PATH))
+
+  return TRACK_LOG_FILE_PATH % (host_name, pid)
+
+
+def DelTrackStatusFile(host_name, pid):
+  """Delete the track status log."""
+  osutils.SafeUnlink(GetTrackStatusFile(host_name, pid))
+
+
+class AUProgress(object):
+  """Used for tracking the CrOS auto-update progress."""
+
+  def __init__(self, host_name, pid):
+    """Initialize a CrOS update progress instance.
+
+    Args:
+      host_name: The name of host, should be in the file_name of the status
+        tracking file of auto-update process.
+      pid: The process id, should be in the file_name too.
+    """
+    self.host_name = host_name
+    self.pid = pid
+
+  @property
+  def track_status_file(self):
+    """The track status file to record the CrOS auto-update progress."""
+    return GetTrackStatusFile(self.host_name, self.pid)
+
+  def WriteStatus(self, content):
+    """Write auto-update progress into status tracking file.
+
+    Args:
+      content: The content to be recorded.
+    """
+    if not self.track_status_file:
+      return
+
+    try:
+      with open(self.track_status_file, 'w') as out_log:
+        out_log.write(content)
+    except Exception as e:
+      logging.error('Cannot write au status: %r', e)
+
+  def ReadStatus(self):
+    """Read auto-update progress from status tracking file."""
+    return ReadOneLine(self.track_status_file)