PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/space/test_deploy/server-cluster.py

http://github.com/sirikata/sirikata
Python | 259 lines | 184 code | 49 blank | 26 comment | 27 complexity | 5eac0f34b519ea4d69f4cc76a5884b01 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #!/usr/bin/env python
  2. # This script manages running a bunch of space servers to generate a
  3. # single space. It isn't intended to be very flexible, just a
  4. # demonstration of how to run a multi-server space. It assumes it will
  5. # use specific implementations for a variety of features -- Redis
  6. # backed OSeg, a real Pinto server, HTTP commander enabled for easy
  7. # debugging, etc. You can customize a bit by specifying an additional
  8. # configuration file that will be loaded, but if you need to change
  9. # any of the settings we have hard-coded, you should just use this
  10. # script as a template.
  11. import server
  12. import socket
  13. import time
  14. from optparse import OptionParser
  15. import signal
  16. nservers = 2
  17. layout = (2, 1, 1)
  18. port_base = 6666
  19. hostname = socket.gethostname()
  20. blocksize = (4000, 8000, 8000)
  21. center = (0,0,0)
  22. pinto_ip = hostname
  23. pinto_port = 6665
  24. n_cseg_servers = 0
  25. n_cseg_upper_servers = 1
  26. cseg_ip = hostname
  27. cseg_port_base = 6235
  28. cseg_service_tcp_port = 6234 # The port space servers connect on
  29. oseg_prefix = 'myspace-'
  30. http_command_port_base = 9000
  31. # Currently we need to generate all of these settings before starting up since
  32. # they go into a file that is only read once
  33. def generate_ip_file():
  34. f = open('servermap.txt', 'w')
  35. # And the real data
  36. for ss in range(nservers):
  37. internal_port = port_base + 2*ss
  38. external_port = internal_port + 1
  39. print >>f, hostname + ':' + str(internal_port) + ':' + str(external_port)
  40. f.close()
  41. def generate_cseg_ip_file():
  42. # This servermap is used for cseg servers to contact each other (separate
  43. # from the port used for space servers to connect to them)
  44. f = open('cseg_servermap.txt', 'w')
  45. # And the real data
  46. for cs in range(n_cseg_servers):
  47. internal_port = cseg_port_base + 2*cs
  48. external_port = internal_port + 1
  49. print >>f, hostname + ':' + str(internal_port) + ':' + str(external_port)
  50. f.close()
  51. def get_region_and_layout():
  52. half_extents = [ block * num / 2 for block,num in zip(blocksize, layout)]
  53. neg = [ -x for x in half_extents ]
  54. pos = [ x for x in half_extents ]
  55. region = "<<%f,%f,%f>,<%f,%f,%f>>" % (neg[0]+center[0], neg[1]+center[1], neg[2]+center[2], pos[0]+center[0], pos[1]+center[1], pos[2]+center[2])
  56. layout_str = "<" + str(layout[0]) + "," + str(layout[1]) + "," + str(layout[2]) + ">"
  57. return (region, layout_str)
  58. def startCSeg(**kwargs):
  59. if n_cseg_servers == 0: return []
  60. generate_cseg_ip_file()
  61. region, layout = get_region_and_layout()
  62. ps = []
  63. for cs in range(n_cseg_servers):
  64. args = [
  65. # CSeg server IDs can't overlap with space server
  66. # IDs. Also, they must be the smallest IDs
  67. '--cseg-id=%d' % (cs+1),
  68. '--servermap=tabular',
  69. '--cseg-servermap-options=--filename=cseg_servermap.txt',
  70. '--layout=%s' % (layout),
  71. '--region=%s' % (region),
  72. '--cseg-service-tcp-port=' + str(cseg_service_tcp_port),
  73. '--num-cseg-servers=' + str(n_cseg_servers),
  74. '--num-upper-tree-cseg-servers=' + str(n_cseg_upper_servers)
  75. ]
  76. if 'cseg_config' in kwargs and kwargs['cseg_config']:
  77. args += [ '--cfg=' + kwargs['cseg_config'] ]
  78. ps += [ server.RunCSeg(args, **kwargs) ]
  79. return ps
  80. def startPinto(**kwargs):
  81. args = [
  82. '--port=' + str(pinto_port),
  83. '--handler=rtreecut',
  84. '--command.commander=http',
  85. '--command.commander-options=--port=' + str(http_command_port_base + 100),
  86. '--type=manual'
  87. ]
  88. if 'pinto_config' in kwargs and kwargs['pinto_config']:
  89. args += [ '--cfg=' + kwargs['pinto_config'] ]
  90. return [ server.RunPinto(args, **kwargs) ]
  91. def startSpace(**kwargs):
  92. generate_ip_file()
  93. ps = []
  94. for ss in range(nservers):
  95. region, layout = get_region_and_layout()
  96. # Kind of gross, but to make it possible to select which type
  97. # of pinto config to use (e.g. if you use --pinto-config to
  98. # load pinto with the manual plugin), we need to filter out
  99. # the --pinto setting if the space config file specifies it
  100. no_pinto = False
  101. if 'space_config' in kwargs and kwargs['space_config']:
  102. with open(kwargs['space_config']) as f:
  103. no_pinto = any([x.startswith('pinto=') for x in f.readlines()])
  104. args = [
  105. '--id=%d' % (ss+1),
  106. '--servermap=tabular',
  107. '--servermap-options=--filename=servermap.txt',
  108. '--layout=%s' % (layout),
  109. '--region=%s' % (region),
  110. '--oseg=redis',
  111. # Note we turn of transactions in redis for compatibility,
  112. # at the cost of potentially leaking some entries
  113. '--oseg-options=' + '--prefix=' + str(oseg_prefix) + ' --transactions=false',
  114. '--command.commander=http',
  115. '--command.commander-options=--port=' + str(http_command_port_base + ss),
  116. '--prox=libprox-manual',
  117. '--pinto=master-manual',
  118. '--moduleloglevel=prox=detailed'
  119. ]
  120. # if not no_pinto:
  121. # args += ['--pinto=master']
  122. args += ['--pinto-options=' + '--host=' + str(pinto_ip) + ' --port=' + str(pinto_port)]
  123. if n_cseg_servers > 0:
  124. args += [
  125. '--cseg=client',
  126. '--cseg-service-host=' + str(cseg_ip),
  127. '--cseg-service-tcp-port=' + str(cseg_service_tcp_port),
  128. ]
  129. if 'space_config' in kwargs and kwargs['space_config']:
  130. args += [ '--cfg=' + kwargs['space_config'] ]
  131. ps += [ server.RunSpace(ss, args, **kwargs) ]
  132. return ps
  133. def printOHTemplate(**kwargs):
  134. print
  135. print
  136. print "To start an object host connecting to this space, use at least the following parameters:"
  137. print
  138. print " cppoh %s %s" % (
  139. '--servermap=tabular',
  140. '--servermap-options=--filename=servermap.txt',
  141. )
  142. print
  143. def start(**kwargs):
  144. processes = []
  145. def terminate_children():
  146. for ps in processes:
  147. ps.terminate()
  148. for x in range(100):
  149. any_running = any([ps.returncode == None for ps in processes])
  150. if not any_running: break
  151. time.sleep(0.1)
  152. if any_running:
  153. for ps in processes:
  154. ps.kill()
  155. time.sleep(0.01)
  156. ps.kill()
  157. def sig_handler(signum, frame):
  158. print __file__, 'received signal', signum, ', killing children'
  159. terminate_children()
  160. signal.signal(signal.SIGTERM, sig_handler)
  161. signal.signal(signal.SIGHUP, sig_handler)
  162. processes += startCSeg(**kwargs)
  163. processes += startPinto(**kwargs)
  164. time.sleep(5)
  165. processes += startSpace(**kwargs)
  166. printOHTemplate(**kwargs)
  167. if 'duration' in kwargs and kwargs['duration']:
  168. time.sleep(kwargs['duration'])
  169. terminate_children()
  170. parser = OptionParser()
  171. parser.add_option("--sirikata", help="Path to sirikata binaries", action="store", type="str", dest="sirikata_path", default=None)
  172. parser.add_option("--term", help="Run services in terminals", action="store_true", dest="with_xterm", default=True)
  173. parser.add_option("--no-term", help="Don't run services in terminals", action="store_false", dest="with_xterm")
  174. parser.add_option("--debug", help="Don't run in a debugger", action="store_true", dest="debug", default=True)
  175. parser.add_option("--no-debug", help="Don't run in a debugger", action="store_false", dest="debug")
  176. parser.add_option("--valgrind", help="Run under valgrind", action="store_true", dest="valgrind", default=False)
  177. parser.add_option("--heap-check", help="Run with perftools heap check", action="store_true", dest="heapcheck", default=False)
  178. parser.add_option("--heap-profile", help="Run with perftools heap profiling", action="store_true", dest="heapprofile", default=False)
  179. parser.add_option("--heap-profile-interval", help="Frequency of heap snapshots (in bytes accumulated over all allocations)", action="store", type="int", dest="heapprofile_interval", default=100*1024*1024)
  180. parser.add_option("--space-config", help="Extra configuration file to load on space servers", action="store", type="string", dest="space_config", default=None)
  181. parser.add_option("--cseg-config", help="Extra configuration file to load on cseg servers", action="store", type="string", dest="cseg_config", default=None)
  182. parser.add_option("--pinto-config", help="Extra configuration file to load on pinto servers", action="store", type="string", dest="pinto_config", default=None)
  183. parser.add_option("--duration", help="Time to wait (and block) before killing child processes", action="store", type="int", dest="duration", default=None)
  184. parser.add_option("--save-log", help="If non-empty, saves logs to disk in the specified location with names like 'cseg-1.log'", action="store", type="str", dest="save_log", default="")
  185. (options, args) = parser.parse_args()
  186. # Options:
  187. # with_xterm - run services in terminals
  188. # debug - run services in gdb
  189. # valgrind - run services in valgrind
  190. # heapcheck - turn on heap checking to the specified level
  191. # heapprofile - turn on heap profiling, storing data to the specified destination
  192. # heapprofile_interval - when heap profiling is on, take a snapshot every time this many bytes (accumulated over all allocations) are allocated (100MB by default)
  193. start(
  194. sirikata_path=options.sirikata_path,
  195. with_xterm=options.with_xterm,
  196. debug=options.debug,
  197. valgrind=options.valgrind,
  198. heapcheck=options.heapcheck,
  199. heapprofile=options.heapprofile,
  200. heapprofile_interval=options.heapprofile_interval,
  201. space_config=options.space_config,
  202. cseg_config=options.cseg_config,
  203. pinto_config=options.pinto_config,
  204. duration=options.duration,
  205. save_log=options.save_log
  206. )