closes #20: run a series of script reacting to a trigger

This commit is contained in:
Davide Alberani 2015-04-17 20:31:50 +02:00
parent ef7732758a
commit b3aa4c79d5
2 changed files with 41 additions and 50 deletions

7
data/triggers/README.txt Normal file
View file

@ -0,0 +1,7 @@
Directory for scripts that will be executed when a given action is encoutered.
You have to put your scripts into {action}.d subdirectories; the scripts must be executable.
Valid actions:
- attends (attends.d): a person is attending at an event

View file

@ -19,6 +19,7 @@ limitations under the License.
import os
import glob
import datetime
import subprocess
import tornado.httpserver
@ -31,6 +32,8 @@ from tornado import gen, escape
import utils
import backend
PROCESS_TIMEOUT = 60
class BaseHandler(tornado.web.RequestHandler):
"""Base class for request handlers."""
@ -74,25 +77,6 @@ class CollectionHandler(BaseHandler):
# set of documents we're managing (a collection in MongoDB or a table in a SQL database)
collection = None
def run_command(self, cmd, callback=None):
self.ioloop = tornado.ioloop.IOLoop.instance()
p = subprocess.Popen(cmd, close_fds=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
import datetime
self.tm = self.ioloop.add_timeout(datetime.timedelta(seconds=3), lambda: self.timeout(callback, p))
self.ioloop.add_handler(p.stdout.fileno(),
self.async_callback(self.on_response, callback, p), self.ioloop.READ)
def timeout(self, callback, pipe, *args):
pipe.kill()
callback((pipe, 'killed process'))
def on_response(self, callback, pipe, fd, events):
self.ioloop.remove_timeout(self.tm)
stdoutdata, stderrdata = pipe.communicate()
callback((pipe.returncode, stdoutdata))
self.ioloop.remove_handler(fd)
def _filter_results(self, results, params):
"""Filter a list using keys and values from a dictionary.
@ -167,42 +151,45 @@ class CollectionHandler(BaseHandler):
self.db.delete(self.collection, id_)
self.write({'success': True})
def run(self, cmd):
p = subprocess.Popen([cmd],)
def run_command(self, cmd, callback=None):
"""Execute the given action.
:param cmd: the command to be run with its command line arguments
:type cmd: list
"""
self.ioloop = tornado.ioloop.IOLoop.instance()
p = subprocess.Popen(cmd, close_fds=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.ioloop.add_handler(p.stdout.fileno(),
self.async_callback(self.on_response, callback, p), self.ioloop.READ)
# also set a timeout
self.timeout = self.ioloop.add_timeout(datetime.timedelta(seconds=PROCESS_TIMEOUT),
lambda: self.on_timeout(callback, p))
def on_timeout(self, callback, pipe, *args):
"""Kill a process that is taking too long to complete."""
pipe.kill()
callback((None, 'killed process pid:%d' % pipe.pid))
def on_response(self, callback, pipe, fd, events):
"""Handle the execution of a script."""
self.ioloop.remove_timeout(self.timeout)
stdoutdata, stderrdata = pipe.communicate()
callback((pipe.returncode, stdoutdata))
self.ioloop.remove_handler(fd)
@gen.coroutine
def run_triggers(self, action):
"""Asynchronously execute triggers for the given action.
:param action: action name; scripts in directory ./data/triggers/{action}.d will be run
:type action: str
"""
for script in glob.glob(os.path.join(self.data_dir, 'triggers', '%s.d' % action, '*')):
if not (os.path.isfile(script) and os.access(script, os.X_OK)):
continue
print script
#self.run_command(script)
ret, resp = yield gen.Task(self.run_command, [script])
print ret, resp
class TestHandler2(CollectionHandler):
def get(self):
self.run_triggers('attends')
def action(action):
def action_decorator(funct):
def funct_wrapper(*args, **kwrds):
result = funct(*args, **kwrds)
print 'aaaa', args, kwrds
return result
return funct_wrapper
return action_decorator
class TestHandler(CollectionHandler):
@gen.coroutine
@action('salta')
def get(self):
#ret, resp = yield gen.Task(self.run_command, ['echo', str(self.arguments)])
ret, resp = yield gen.Task(self.run_command, ['sleep', '10'])
self.write('ok: %s: %s\n' % (ret, resp))
self.finish()
class PersonsHandler(CollectionHandler):
"""Handle requests for Persons."""
@ -377,9 +364,6 @@ def run():
(r"/events/?(?P<id_>\w+)?/?(?P<resource>\w+)?/?(?P<resource_id>\w+)?", EventsHandler, init_params),
(r"/(?:index.html)?", RootHandler, init_params),
(r"/ebcsvpersons", EbCSVImportPersonsHandler, init_params),
(r"/test", TestHandler, init_params),
(r"/test2", TestHandler2, init_params),
(r'/(.*)', tornado.web.StaticFileHandler, {"path": "angular_app"})
],
template_path=os.path.join(os.path.dirname(__file__), "templates"),