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