|
8 | 8 | import tornado.netutil |
9 | 9 | import time |
10 | 10 |
|
11 | | -flask_app = flask.Flask(__name__) |
12 | | -PROCESSES_DEFAULT = 10 |
| 11 | +PROCESSES_DEFAULT = 10 # TODO: IS TORNADO MULTI-THREADED (processed) BY DEFAULT? |
13 | 12 | PORT = 8080 |
14 | 13 | initialized = False |
15 | 14 | config = None |
16 | 15 | db_conn = None |
17 | 16 |
|
| 17 | +tornado_app = tornado.web.Application([ |
| 18 | + (r".*", SockFileHandler), |
| 19 | +]) |
| 20 | + |
18 | 21 | # run once per process |
19 | 22 | def init(): |
20 | 23 | global initialized, config, db_conn |
21 | 24 | if initialized: |
22 | 25 | return |
23 | | - sys.stdout = sys.stderr # flask supresses stdout :( |
| 26 | + |
24 | 27 | if config.get('db', None) == 'rethinkdb': |
25 | 28 | host = config.get('rethinkdb.host', 'localhost') |
26 | 29 | port = config.get('rethinkdb.port', 28015) |
27 | 30 | print 'Connect to %s:%d' % (host, port) |
28 | 31 | db_conn = rethinkdb.connect(host, port) |
29 | 32 | initialized = True |
30 | 33 |
|
31 | | -# catch everything |
32 | | -@flask_app.route('/', defaults={'path': ''}, methods=['POST']) |
33 | | -@flask_app.route('/<path:path>', methods=['POST']) |
34 | | -def flask_post(path): |
35 | | - try: |
36 | | - init() |
37 | | - data = flask.request.get_data() |
38 | | - try: |
39 | | - event = json.loads(data) |
40 | | - except Exception: |
41 | | - return ('bad POST data: "%s"' % str(data), 400) |
42 | | - return json.dumps(lambda_func.handler(db_conn, event)) |
43 | | - except Exception as e: |
44 | | - print(e) |
45 | | - return (traceback.format_exc(), 500) # internal error |
| 34 | + # assume user handler code is /handler/lambda_func.py |
| 35 | + sys.path.append('/handler') |
| 36 | + import lambda_func |
46 | 37 |
|
47 | 38 | class SockFileHandler(tornado.web.RequestHandler): |
| 39 | + # POST header for actual requests |
48 | 40 | def post(self): |
49 | 41 | try: |
50 | 42 | init() |
51 | 43 | data = self.request.body |
52 | | - try : |
| 44 | + try: |
53 | 45 | event = json.loads(data) |
54 | 46 | except: |
55 | 47 | self.set_status(400) |
56 | | - self.write('bad POST data: "%s"'%str(data)) |
| 48 | + self.write('bad POST data: "%s"' % str(data)) |
57 | 49 | return |
| 50 | + |
58 | 51 | self.write(json.dumps(lambda_func.handler(db_conn, event))) |
| 52 | + |
59 | 53 | except Exception: |
60 | 54 | self.set_status(500) # internal error |
61 | 55 | self.write(traceback.format_exc()) |
62 | 56 |
|
63 | | -tornado_app = tornado.web.Application([ |
64 | | - (r".*", SockFileHandler), |
65 | | -]) |
| 57 | + # GET header for forkenter |
| 58 | + def get(self): |
| 59 | + try: |
| 60 | + data = self.request.body |
| 61 | + try: |
| 62 | + forkconf = json.loads(data) |
66 | 63 |
|
67 | | -def start_container(conf): |
68 | | - sys.path.append('/handler') |
69 | | - global lambda_func, config |
70 | | - |
71 | | - import lambda_func # assume submitted .py file is /handler/lambda_func |
72 | | - config = conf |
73 | | - |
74 | | - if 'sock_file' in config: |
75 | | - #f.write("listening socket\n") |
76 | | - # listen on sock file with Tornado |
77 | | - server = tornado.httpserver.HTTPServer(tornado_app) |
78 | | - socket = tornado.netutil.bind_unix_socket('/host/' + config['sock_file']) |
79 | | - server.add_socket(socket) |
80 | | - tornado.ioloop.IOLoop.instance().start() |
81 | | - else: |
82 | | - #f.write("listening flask\n") |
83 | | - # listen on port with Flask |
84 | | - procs = config.get('processes', PROCESSES_DEFAULT) |
85 | | - flask_app.run(processes=procs, host='0.0.0.0', port=PORT) |
86 | | - |
87 | | -def listen(path): |
88 | | - args = "" |
89 | | - with open(path) as fifo: |
90 | | - while True: |
91 | | - data = fifo.read() |
92 | | - if len(data) == 0: |
93 | | - break |
94 | | - args += data |
95 | | - return args |
| 64 | + except: |
| 65 | + self.set_status(400) |
| 66 | + self.write('malformed forkenter request: "%s"' % str(data)) |
| 67 | + return |
96 | 68 |
|
97 | | -def main(): |
98 | | - sys.stdout = sys.stderr |
99 | | - if len(sys.argv) < 2: |
100 | | - print("Usage: %s <fifo>" % sys.argv[0]) |
101 | | - sys.exit(1) |
102 | | - |
103 | | - fifo = os.path.abspath(sys.argv[1]) |
104 | | - |
105 | | - #f = open('/tmp/log', 'w') |
106 | | - while True: |
107 | | - print("host listening") |
108 | | - #f.write("host listening\n") |
109 | | - pid, conf = listen(fifo).split(None, 1) |
110 | | - conf = json.loads(conf) |
111 | | - print("pid: %s\nconf: %s\n" % (pid, conf)) |
112 | | - #f.write("pid: %s\nconf: %s\n" % (pid, conf)) |
113 | | - |
114 | | - r = ns.forkenter(pid) |
115 | | - # child escape |
116 | | - if r == 0: |
117 | | - print("forkentered") |
118 | | - #f.write("forkentered\n") |
119 | | - break |
| 69 | + ns.forkenter(forkconf['pid']) |
| 70 | + |
| 71 | + except Exception: |
| 72 | + self.set_status(500) |
| 73 | + self.write('failed to forkenter with request: "%s"' % str(data)) |
| 74 | + self.write(traceback.format_exc()) |
120 | 75 |
|
| 76 | + |
| 77 | +def listen(): |
| 78 | + server = tornado.httpserver.HTTPServer(tornado_app) |
| 79 | + socket = tornado.netutil.bind_unix_socket('/host/' + config['sock_file']) |
| 80 | + server.add_socket(socket) |
| 81 | + tornado.ioloop.IOLoop.instance().start() |
| 82 | + |
| 83 | +def main(): |
121 | 84 | try: |
122 | | - start_container(conf) |
| 85 | + listen() |
123 | 86 | except Exception as e: |
124 | 87 | print(e) |
125 | 88 |
|
|
0 commit comments