# HG changeset patch # User Atul Varma # Date 1275333508 25200 # Node ID 0efba0cf0ca3052fed07d87058405d0ac0796911 # Parent f2fef5bb03965d15eed2cc34de5738be68c2b65f added resource usage limits, /status endpoint diff -r f2fef5bb0396 -r 0efba0cf0ca3 boxes/evil.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boxes/evil.js Mon May 31 12:18:28 2010 -0700 @@ -0,0 +1,6 @@ +function handle() { + var foo = []; + while (1) { + foo.push("i am nomming your memory forever!"); + } +} diff -r f2fef5bb0396 -r 0efba0cf0ca3 sjsbox/box.py --- a/sjsbox/box.py Mon May 31 11:00:29 2010 -0700 +++ b/sjsbox/box.py Mon May 31 12:18:28 2010 -0700 @@ -1,7 +1,17 @@ import logging +import resource import multiprocessing as mproc class BoxChild(object): + LIMITS = { + resource.RLIMIT_DATA: (1024 * 1024, 1024 * 2048), + resource.RLIMIT_STACK: (1024 * 512, 1024 * 1024), + resource.RLIMIT_RSS: (1024 * 1024, 1024 * 2048), + resource.RLIMIT_AS: (1024 * 1024, 1024 * 2048), + resource.RLIMIT_CPU: (5, 10), + resource.RLIMIT_NOFILE: (10, 20) + } + def __init__(self, f, pipe): if f.name.endswith('.js'): import sjsbox.js @@ -16,11 +26,21 @@ if cmd == 'shutdown': self.__impl.shutdown() return + elif cmd == 'status': + rusage = resource.getrusage(resource.RUSAGE_SELF) + props = [name for name in dir(rusage) + if name.startswith('ru_')] + retval = {} + for name in props: + retval[name] = getattr(rusage, name) + self.pipe.send(retval) elif cmd == 'handle': self.pipe.send(self.__impl.handle(*args)) @classmethod def start(klass, *args, **kwargs): + for name, limits in klass.LIMITS.items(): + resource.setrlimit(name, limits) obj = klass(*args, **kwargs) obj.run() @@ -47,6 +67,11 @@ self.child_pipe.send(('handle', (method, path))) return self.child_pipe.recv() + @property + def status(self): + self.child_pipe.send(('status', ())) + return self.child_pipe.recv() + def shutdown(self): self.child_pipe.send(('shutdown', None)) self.child.join(self.TIMEOUT) diff -r f2fef5bb0396 -r 0efba0cf0ca3 sjsbox/server.py --- a/sjsbox/server.py Mon May 31 11:00:29 2010 -0700 +++ b/sjsbox/server.py Mon May 31 12:18:28 2010 -0700 @@ -17,16 +17,23 @@ [('Content-Type', 'text/plain')]) return ['Not Found: %s' % environ['PATH_INFO']] + def json_response(obj): + start_response('200 OK', + [('Content-Type', self.JSON_TYPE)]) + return [json.dumps(obj)] + path_parts = environ['PATH_INFO'].split('/')[1:] if path_parts: boxname = path_parts[0] - if boxname in self.boxes: + if boxname == 'status': + if len(path_parts) != 2 or path_parts[1] not in self.boxes: + return error_404() + return json_response(self.boxes[path_parts[1]].status) + elif boxname in self.boxes: kwargs = dict(method=environ['REQUEST_METHOD'], path='/%s' % '/'.join(path_parts[1:])) retval = self.boxes[boxname].handle(**kwargs) if retval == 404: return error_404() - start_response('200 OK', - [('Content-Type', self.JSON_TYPE)]) - return [json.dumps(retval)] + return json_response(retval) return error_404() diff -r f2fef5bb0396 -r 0efba0cf0ca3 tests/test_box.py --- a/tests/test_box.py Mon May 31 11:00:29 2010 -0700 +++ b/tests/test_box.py Mon May 31 12:18:28 2010 -0700 @@ -21,6 +21,13 @@ def test_contains_works(self): self.assertTrue('foo' in self.boxes) + def test_handle_works(self): + self.assertEqual(self.boxes['foo'].handle('GET', '/'), + 404) + + def test_status_works(self): + self.assertTrue('ru_maxrss' in self.boxes['foo'].status) + def test_update_works(self): self.boxes.update() self.assertEqual(self.boxes['foo'].handle('GET', '/'),