Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright 2012 the V8 project authors. All rights reserved.
      4 # Redistribution and use in source and binary forms, with or without
      5 # modification, are permitted provided that the following conditions are
      6 # met:
      7 #
      8 #     * Redistributions of source code must retain the above copyright
      9 #       notice, this list of conditions and the following disclaimer.
     10 #     * Redistributions in binary form must reproduce the above
     11 #       copyright notice, this list of conditions and the following
     12 #       disclaimer in the documentation and/or other materials provided
     13 #       with the distribution.
     14 #     * Neither the name of Google Inc. nor the names of its
     15 #       contributors may be used to endorse or promote products derived
     16 #       from this software without specific prior written permission.
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 
     31 import os
     32 import subprocess
     33 import sys
     34 
     35 
     36 PIDFILE = "/tmp/v8-distributed-testing-server.pid"
     37 ROOT = os.path.abspath(os.path.dirname(sys.argv[0]))
     38 
     39 
     40 def _PrintUsage():
     41   print("""Usage: python %s COMMAND
     42 
     43 Where COMMAND can be any of:
     44   start     Starts the server. Forks to the background.
     45   stop      Stops the server.
     46   restart   Stops, then restarts the server.
     47   setup     Creates or updates the environment for the server to run.
     48   update    Alias for "setup".
     49   trust <keyfile>  Adds the given public key to the list of trusted keys.
     50   help      Displays this help text.
     51   """ % sys.argv[0])
     52 
     53 
     54 def _IsDaemonRunning():
     55   return os.path.exists(PIDFILE)
     56 
     57 
     58 def _Cmd(cmd):
     59   code = subprocess.call(cmd, shell=True)
     60   if code != 0:
     61     print("Command '%s' returned error code %d" % (cmd, code))
     62     sys.exit(code)
     63 
     64 
     65 def Update():
     66   # Create directory for private data storage.
     67   data_dir = os.path.join(ROOT, "data")
     68   if not os.path.exists(data_dir):
     69     os.makedirs(data_dir)
     70 
     71   # Create directory for trusted public keys of peers (and self).
     72   trusted_dir = os.path.join(ROOT, "trusted")
     73   if not os.path.exists(trusted_dir):
     74     os.makedirs(trusted_dir)
     75 
     76   # Install UltraJSON. It is much faster than Python's builtin json.
     77   try:
     78     import ujson  #@UnusedImport
     79   except ImportError:
     80     # Install pip if it doesn't exist.
     81     code = subprocess.call("which pip > /dev/null", shell=True)
     82     if code != 0:
     83       apt_get_code = subprocess.call("which apt-get > /dev/null", shell=True)
     84       if apt_get_code == 0:
     85         print("Installing pip...")
     86         _Cmd("sudo apt-get install python-pip")
     87       else:
     88         print("Please install pip on your machine. You can get it at: "
     89               "http://www.pip-installer.org/en/latest/installing.html "
     90               "or via your distro's package manager.")
     91         sys.exit(1)
     92     print("Using pip to install UltraJSON...")
     93     _Cmd("sudo pip install ujson")
     94 
     95   # Make sure we have a key pair for signing binaries.
     96   privkeyfile = os.path.expanduser("~/.ssh/v8_dtest")
     97   if not os.path.exists(privkeyfile):
     98     _Cmd("ssh-keygen -t rsa -f %s -N '' -q" % privkeyfile)
     99   fingerprint = subprocess.check_output("ssh-keygen -lf %s" % privkeyfile,
    100                                         shell=True)
    101   fingerprint = fingerprint.split(" ")[1].replace(":", "")[:16]
    102   pubkeyfile = os.path.join(trusted_dir, "%s.pem" % fingerprint)
    103   if (not os.path.exists(pubkeyfile) or
    104       os.path.getmtime(pubkeyfile) < os.path.getmtime(privkeyfile)):
    105     _Cmd("openssl rsa -in %s -out %s -pubout" % (privkeyfile, pubkeyfile))
    106     with open(pubkeyfile, "a") as f:
    107       f.write(fingerprint + "\n")
    108     datafile = os.path.join(data_dir, "mypubkey")
    109     with open(datafile, "w") as f:
    110       f.write(fingerprint + "\n")
    111 
    112   # Check out or update the server implementation in the current directory.
    113   testrunner_dir = os.path.join(ROOT, "testrunner")
    114   if os.path.exists(os.path.join(testrunner_dir, "server/daemon.py")):
    115     _Cmd("cd %s; svn up" % testrunner_dir)
    116   else:
    117     path = ("http://v8.googlecode.com/svn/branches/bleeding_edge/"
    118             "tools/testrunner")
    119     _Cmd("svn checkout --force %s %s" % (path, testrunner_dir))
    120 
    121   # Update this very script.
    122   path = ("http://v8.googlecode.com/svn/branches/bleeding_edge/"
    123           "tools/test-server.py")
    124   scriptname = os.path.abspath(sys.argv[0])
    125   _Cmd("svn cat %s > %s" % (path, scriptname))
    126 
    127   # Check out or update V8.
    128   v8_dir = os.path.join(ROOT, "v8")
    129   if os.path.exists(v8_dir):
    130     _Cmd("cd %s; git fetch" % v8_dir)
    131   else:
    132     _Cmd("git clone git://github.com/v8/v8.git %s" % v8_dir)
    133 
    134   print("Finished.")
    135 
    136 
    137 # Handle "setup" here, because when executing that we can't import anything
    138 # else yet.
    139 if __name__ == "__main__" and len(sys.argv) == 2:
    140   if sys.argv[1] in ("setup", "update"):
    141     if _IsDaemonRunning():
    142       print("Please stop the server before updating. Exiting.")
    143       sys.exit(1)
    144     Update()
    145     sys.exit(0)
    146   # Other parameters are handled below.
    147 
    148 
    149 #==========================================================
    150 # At this point we can assume that the implementation is available,
    151 # so we can import it.
    152 try:
    153   from testrunner.server import constants
    154   from testrunner.server import local_handler
    155   from testrunner.server import main
    156 except Exception, e:
    157   print(e)
    158   print("Failed to import implementation. Have you run 'setup'?")
    159   sys.exit(1)
    160 
    161 
    162 def _StartDaemon(daemon):
    163   if not os.path.isdir(os.path.join(ROOT, "v8")):
    164     print("No 'v8' working directory found. Have you run 'setup'?")
    165     sys.exit(1)
    166   daemon.start()
    167 
    168 
    169 if __name__ == "__main__":
    170   if len(sys.argv) == 2:
    171     arg = sys.argv[1]
    172     if arg == "start":
    173       daemon = main.Server(PIDFILE, ROOT)
    174       _StartDaemon(daemon)
    175     elif arg == "stop":
    176       daemon = main.Server(PIDFILE, ROOT)
    177       daemon.stop()
    178     elif arg == "restart":
    179       daemon = main.Server(PIDFILE, ROOT)
    180       daemon.stop()
    181       _StartDaemon(daemon)
    182     elif arg in ("help", "-h", "--help"):
    183       _PrintUsage()
    184     elif arg == "status":
    185       if not _IsDaemonRunning():
    186         print("Server not running.")
    187       else:
    188         print(local_handler.LocalQuery([constants.REQUEST_STATUS]))
    189     else:
    190       print("Unknown command")
    191       _PrintUsage()
    192       sys.exit(2)
    193   elif len(sys.argv) == 3:
    194     arg = sys.argv[1]
    195     if arg == "approve":
    196       filename = sys.argv[2]
    197       if not os.path.exists(filename):
    198         print("%s does not exist.")
    199         sys.exit(1)
    200       filename = os.path.abspath(filename)
    201       if _IsDaemonRunning():
    202         response = local_handler.LocalQuery([constants.ADD_TRUSTED, filename])
    203       else:
    204         daemon = main.Server(PIDFILE, ROOT)
    205         response = daemon.CopyToTrusted(filename)
    206       print("Added certificate %s to trusted certificates." % response)
    207     else:
    208       print("Unknown command")
    209       _PrintUsage()
    210       sys.exit(2)
    211   else:
    212     print("Unknown command")
    213     _PrintUsage()
    214     sys.exit(2)
    215   sys.exit(0)
    216