| # Copyright (c) 2011 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. |
| |
| """Module containing methods and classes to interact with a devserver instance. |
| """ |
| |
| import os |
| import threading |
| import re |
| import sys |
| import time |
| |
| import constants |
| from chromite.lib import cros_build_lib |
| |
| # Wait up to 15 minutes for the dev server to start. It can take a while to |
| # start when generating payloads in parallel. |
| DEV_SERVER_TIMEOUT = 900 |
| |
| |
| def GetIPAddress(device='eth0'): |
| """Returns the IP Address for a given device using ifconfig. |
| |
| socket.gethostname() is insufficient for machines where the host files are |
| not set up "correctly." Since some of our builders may have this issue, |
| this method gives you a generic way to get the address so you are reachable |
| either via a VM or remote machine on the same network. |
| """ |
| result = cros_build_lib.RunCommandCaptureOutput( |
| ['/sbin/ifconfig', device], print_cmd=False) |
| match = re.search('.*inet addr:(\d+\.\d+\.\d+\.\d+).*', result.output) |
| if match: |
| return match.group(1) |
| cros_build_lib.Warning('Failed to find ip address in %r', result.output) |
| return None |
| |
| |
| def GenerateUpdateId(target, src, key, for_vm): |
| """Returns a simple representation id of target and src paths.""" |
| update_id = target |
| if src: update_id = '->'.join([src, update_id]) |
| if key: update_id = '+'.join([update_id, key]) |
| if not for_vm: update_id = '+'.join([update_id, 'patched_kernel']) |
| return update_id |
| |
| |
| class DevServerException(Exception): |
| """Thrown when the devserver fails to start up correctly.""" |
| |
| |
| class DevServerWrapper(threading.Thread): |
| """A Simple wrapper around a dev server instance.""" |
| |
| def __init__(self, test_root): |
| self.proc = None |
| self.test_root = test_root |
| self._log_filename = os.path.join(test_root, 'dev_server.log') |
| threading.Thread.__init__(self) |
| |
| def run(self): |
| # Kill previous running instance of devserver if it exists. |
| self.Stop() |
| cmd = ['start_devserver', '--archive_dir=./static', '--production'] |
| cros_build_lib.SudoRunCommand(cmd, enter_chroot=True, print_cmd=False, |
| log_stdout_to_file=self._log_filename, |
| combine_stdout_stderr=True, |
| cwd=constants.SOURCE_ROOT) |
| |
| def Stop(self): |
| """Kills the devserver instance if it exists.""" |
| cros_build_lib.SudoRunCommand(['pkill', '-f', 'devserver.py'], |
| error_code_ok=True, print_cmd=False) |
| |
| def PrintLog(self): |
| """Print devserver output.""" |
| print '--- Start output from %s ---' % self._log_filename |
| # Open in update mode in case the child process hasn't opened the file yet. |
| with open(self._log_filename) as log: |
| sys.stdout.writelines(log) |
| print '--- End output from %s ---' % self._log_filename |
| |
| def WaitUntilStarted(self): |
| """Wait until the devserver has started.""" |
| # Open in update mode in case the child process hasn't opened the file yet. |
| pos = 0 |
| with open(self._log_filename, 'w+') as log: |
| for _ in range(DEV_SERVER_TIMEOUT * 2): |
| log.seek(pos) |
| for line in log: |
| # When the dev server has started, it will print a line stating |
| # 'Bus STARTED'. Wait for that line to appear. |
| if 'Bus STARTED' in line: |
| return |
| # If we've read a complete line, and it doesn't contain the magic |
| # phrase, move on to the next line. |
| if line.endswith('\n'): |
| pos = log.tell() |
| # Looks like it hasn't started yet. Keep waiting... |
| time.sleep(0.5) |
| self.PrintLog() |
| raise DevServerException('Timeout waiting for the devserver to startup.') |
| |
| @classmethod |
| def GetDevServerURL(cls, port, sub_dir): |
| """Returns the dev server url for a given port and sub directory.""" |
| if not port: port = 8080 |
| url = 'http://%(ip)s:%(port)s' % {'ip': GetIPAddress(), 'port': str(port)} |
| if sub_dir: |
| url += '/' + sub_dir |
| |
| return url |
| |
| @classmethod |
| def WipePayloadCache(cls): |
| """Cleans up devserver cache of payloads.""" |
| cros_build_lib.Info('Cleaning up previously generated payloads.') |
| cmd = ['start_devserver', '--clear_cache', '--exit'] |
| cros_build_lib.SudoRunCommand( |
| cmd, enter_chroot=True, print_cmd=False, combine_stdout_stderr=True, |
| redirect_stdout=True, redirect_stderr=True, cwd=constants.SOURCE_ROOT) |