diff options
author | sienkiew <sienkiew@d34015c8-bcbb-4646-8ac8-8ba5febf221d> | 2012-02-24 17:58:55 -0500 |
---|---|---|
committer | sienkiew <sienkiew@d34015c8-bcbb-4646-8ac8-8ba5febf221d> | 2012-02-24 17:58:55 -0500 |
commit | 6787ea30126ef097db80430f151ae0848dc25a9e (patch) | |
tree | 3379c847619ec9d518592f3db4193414a0a8d05f /steuermann/rexecd.py | |
parent | e80782b878fcc80f32a7aec6993c2cbdd5201885 (diff) | |
download | steuermann-6787ea30126ef097db80430f151ae0848dc25a9e.tar.gz |
steuermann rexec
git-svn-id: https://svn.stsci.edu/svn/ssb/etal/steuermann/trunk@556 d34015c8-bcbb-4646-8ac8-8ba5febf221d
Diffstat (limited to 'steuermann/rexecd.py')
-rw-r--r-- | steuermann/rexecd.py | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/steuermann/rexecd.py b/steuermann/rexecd.py new file mode 100644 index 0000000..712d48f --- /dev/null +++ b/steuermann/rexecd.py @@ -0,0 +1,242 @@ +# +# steuermann remote execution daemon - use this when you can't use +# something better (like ssh) to get your commands running in the +# other machine. +# +# Copyright 2012 Association of Universities for Research in Astronomy (AURA) +# + +import os +import time +import CGIHTTPServer +import BaseHTTPServer +import SocketServer +import platform +import subprocess +import urllib +import urlparse + +os.chdir('/') +print os.getcwd() + +##### +# + +valid_client_ip = ( + '130.167.180.22', # arzach + '130.167.180.4', # ssb + '130.167.237.185', # banana + '130.167.237.55', # vxp-dukat + ) + +##### +# +# This uses the python stock http server. Here is a request handler +# that services GET requests by executing the command passed in. +# All other requests are invalid. + +password = "pass" + +class my_handler( CGIHTTPServer.CGIHTTPRequestHandler ) : + + def __init__(self, request, client_address, server) : + # init the superclass + CGIHTTPServer.CGIHTTPRequestHandler.__init__(self, request, client_address, server) + + def reject_client(self) : + print self.client_address + if not ( self.client_address[0] in valid_client_ip ) : + self.bad_client('a') + return 1 + + if self.path.startswith('/' + password + '/' ) : + self.path = self.path[len(password)+2:] + else : + self.bad_client('p') + return 1 + + return 0 + + def do_GET(self) : + # GET /password/command... + # run the command + + if self.reject_client() : + return + + path = self.path + + print "GET",path + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write("Hello world: %s\n"%path) + self.wfile.flush() + + def bad_client(self, why) : + self.send_response(500) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write("bad client: %s\n"%why) + self.wfile.flush() + return + + def do_INVALID(self) : + self.send_response(500) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write("error\n") + self.wfile.flush() + return + + def do_POST(self) : + # POST password=pass&name=filename&data=filedata + # upload data to a file + + if self.reject_client() : + return + + print self.path + + + length = int(self.headers['Content-Length']) + data = self.rfile.read(length) + d = urlparse.parse_qs(data) + + for x in sorted([ x for x in d]) : + print x,d[x] + + if d['password'][0] != password : + self.bad_client('p') + return + + dirname = d['dirname'][0] + print "CD",dirname + os.chdir(dirname) + + if self.path == 'upload' : + + filename = d['filename'][0] + + mode = 'wb' + if 'mode' in d : + t = d['mode'][0] + if t == 't' or t == 'text' : + mode = 'w' + elif t == 'b' or t == 'binary' : + mode = 'wb' + else : + return self.bad_client('mode') + + f = open(filename,'wb') + f.write(d['data'][0]) + f.close() + + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write("uploaded %s\n"%filename) + self.wfile.flush() + + elif self.path == 'run' : + cmd = d['cmd'][0] + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.end_headers() + self.wfile.write("Hello world: %s\n"%cmd) + run_child(cmd, self.wfile) + self.wfile.write("done\n") + self.wfile.flush() + else : + return self.bad_client('c') + + + def do_HEAD(self) : + self.do_invalid() + + +class MultiThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): + pass + +#### + +windows = platform.system() == 'Windows' + +def run_child(path, wfile) : + env = os.environ + cmd = urllib.unquote_plus(path) + print "COMMAND",cmd + + # bug: implement timeouts + if windows : + status = subprocess_windows( cmd, wfile, env ) + else : + status = subprocess_unix( cmd, wfile, env ) + + # subprocess gives you weird status values + if status > 0 : + t_status="exit %d"%(status >> 8) + if status != 0 : + return_status = 1 + else : + return_status = 1 + t_status="signal %d" % ( - status ) + # subprocess does not tell you if there was a core + # dump, but there is nothing we can do about it. + + print "COMMAND EXIT:",status,t_status + + +def subprocess_windows(cmd, wfile, env ) : + # You might think that subprocess.Popen() would be portable, + # but you would be wrong. + # + # On Windows, sockets are NOT file descriptors. Since we are in a web server, wfile here is a socket. + + # print wfile.fileno() + # import msvcrt + # print msvcrt.get_osfhandle(wfile.fileno()) + p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, env = env, creationflags = subprocess.CREATE_NEW_PROCESS_GROUP ) + while 1 : + n = p.stdout.read(256) + if n == '' : + break + wfile.write(n) + return p.wait() + +def subprocess_unix( cmd, wfile, env ) : + p = subprocess.Popen( cmd, stdout=wfile, stderr=wfile, shell=True, env = env, preexec_fn=os.setpgrp ) + return p.wait() + +##### + + +def run( args = [ ] ) : + # you could parse args here if you wanted to. I don't care to spend + # the time. This is just here for people who can't (or don't want to) + # install a full featured web server just to try things out. + if len(args) > 0 : + ip = args[0] + else : + ip = platform.node() + + port = 7070 + + print "http://%s:%s/"%(str(ip),str(port)) + + httpd = MultiThreadedHTTPServer( (ip, port) , my_handler) + + sa = httpd.socket.getsockname() + print "Serving HTTP on", sa[0], "port", sa[1], "..." + while 1 : + httpd.handle_request() + +if __name__ == '__main__' : + run() + + +## +# in case we need to kill child processes: +# http://code.activestate.com/recipes/347462-terminating-a-subprocess-on-windows/ + + |