Home | History | Annotate | Download | only in lxc
      1 # Copyright 2017 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 from contextlib import contextmanager
      5 
      6 import logging
      7 import multiprocessing
      8 import os
      9 import shutil
     10 import tempfile
     11 import SocketServer
     12 import SimpleHTTPServer
     13 
     14 import common
     15 from autotest_lib.client.bin import utils
     16 from autotest_lib.client.common_lib import error
     17 from autotest_lib.site_utils.lxc import constants
     18 
     19 
     20 @contextmanager
     21 def serve_locally(file_path):
     22     """Starts an http server on the localhost, to serve the given file.
     23 
     24     Copies the given file to a temporary location, then starts a local http
     25     server to serve that file.  Intended for use with unit tests that require
     26     some URL to download a file (see testInstallSsp as an example).
     27 
     28     @param file_path: The path of the file to serve.
     29 
     30     @return The URL at which the file will be served.
     31     """
     32     p = None
     33     try:
     34         # Copy the target file into a tmpdir for serving.
     35         tmpdir = tempfile.mkdtemp()
     36         shutil.copy(file_path, tmpdir)
     37 
     38         httpd = SocketServer.TCPServer(
     39                 ('', 0), SimpleHTTPServer.SimpleHTTPRequestHandler)
     40         port = httpd.socket.getsockname()[1]
     41 
     42         # Start the http daemon in the tmpdir to serve the file.
     43         def serve():
     44             """Serves the tmpdir."""
     45             os.chdir(tmpdir)
     46             httpd.serve_forever()
     47         p = multiprocessing.Process(target=serve)
     48         p.daemon = True
     49         p.start()
     50 
     51         utils.poll_for_condition(
     52                 condition=lambda: http_up(port),
     53                 timeout=constants.NETWORK_INIT_TIMEOUT,
     54                 sleep_interval=constants.NETWORK_INIT_CHECK_INTERVAL)
     55         url = 'http://127.0.0.1:{port}/{filename}'.format(
     56                 port=port, filename=os.path.basename(file_path))
     57         logging.debug('Serving %s as %s', file_path, url)
     58         yield url
     59     finally:
     60         if p is not None:
     61             p.terminate()
     62         shutil.rmtree(tmpdir)
     63 
     64 
     65 def http_up(port):
     66     """Checks for an http server on localhost:port.
     67 
     68     @param port: The port to check.
     69     """
     70     try:
     71         utils.run('curl --head http://127.0.0.1:%d' % port)
     72         return True
     73     except error.CmdError:
     74         return False
     75