Example #1
0
# This holds all the tasks.  They are pulled from this directory
# with a FIFO execution style.  The tasks are identified by the pid of
# the requesting process.  Unless the tasks really jam up and the server
# is rebooted, there's no chance of collision.
local_queue_dir = '/tmp/jsonrpc_queue'

# This holds all the temporary files for the tasks.  It is only used
# here as the root of the cleanup process.  Each task identifies its own
# tmpdir whish is the home directory for the task.   This will almost always 
# be the same as queue filename.  But there # is still the option for the 
# user to identify a specific tmpdir to run from.
jsonrpc_tmpdir = '/tmp/jsonrpc'


rpc_service = rpc_service_setup()

class JSONRPCDaemon(Daemon):
    "Daemon class for processing JSON RPC requests"

    def run_an_item(self,qfile_list):
        "Pulls an item from the queue, and sends it to the rpc_service."
        
        # Get the contents of the oldest file.
        oldest = qfile_list[0]
        oldest_time = os.stat(local_queue_dir + '/' + oldest).st_mtime
        for qf in qfile_list[1:]:
            qf_time = os.stat(local_queue_dir + '/' + qf).st_mtime
            if qf_time < oldest_time:
                oldest = qf
                oldest_time = qf_time
Example #2
0
def main():

    # This sets up all the json_procs to accessuble for the rpc_service.
    rpc_service = rpc_service_setup()

    # QUERY_STRING could have these options
    #    signature  Required for any service access.  This is an hmak/sha1
    #               hash againt the request string.
    #    diag ..... Run "run_diagnostics"  This allows the user to get a lot
    #               of info on what might be happening on the server.
    #    async .... Send the request to the asynchronous queue.
    #    tmpdir ... User explicitly sets the tmpdir for the task execution.
    #    log ...... Logs the request, response, and environment in
    #               tmpdir/jsonrpc.log
    option_dict = cgi.parse_qs(os.environ['QUERY_STRING'])


    # Check that there is a signature.
    if not 'signature' in option_dict:
        print json.dumps({
            "jsonrpc": "2.0", 
            "error": {"code": -32098, "message": "No signature."}, 
            "id": None});
        return
        pass
  
    # Read the request data.
    form = cgi.FieldStorage()
  
    request_str = ''
    multipart_keys = []
    if form.type == 'multipart/form-data':
        ## Read the "jsonrpc" part, and collect all the names of the file parts.
        for part_key in form.keys():
            if part_key == 'jsonrpc':
                request_str = form['jsonrpc'].value
            else:
                multipart_keys.append(part_key);
    else:
        if not form.file:
            print json.dumps({
                "jsonrpc": "2.0", 
                "error": {"code": -32099, "message": "No post data."}, 
                "id": None});
            return
        request_str = form.file.read()

    # The default hashkey is the local DNS name.  This can be changed to grab
    # the user-data string by uncommenting the code below.
    #
    # The main idea is that we want a hashkey that is easily accessible, but
    # hard to guess. The local DNS fits the bill because an intruder needs to
    # know both the the public and private DNS names to get access to the
    # JSONRPC service.  Instance tags were considered but they require 
    # the AWS_SECRET_ACCESS_KEY to get.  My feeling is that the extra
    # security provided to this instance by using the AWS secret key, isn't 
    # worth the risk of exposing the key.
    #
    ud = None
    ud = urllib2.urlopen('http://169.254.169.254/latest/meta-data/local-hostname')
    #try:
    #    ud = urllib2.urlopen('http://169.254.169.254/latest/user-data')
    #except Exception:
    #    ud = urllib2.urlopen('http://169.254.169.254/latest/meta-data/local-hostname')
    hashkey = ud.read()
    h = hmac.new(hashkey,request_str,sha)
    target_sig = base64.b64encode(h.digest())
    
    if target_sig != option_dict['signature'][0]:
        data = ''
        # data += '~'+hashkey+'~'+request_str+'~'+target_sig+'~'+str(option_dict['signature'][0])+'~'
        print json.dumps({
            "jsonrpc": "2.0", 
            "error": {
                "code": -32097, 
                "message": "Invalid Signature.",
                "data": data
                }, 
            "id": None});
        return

    # output all diagnostic data
    if 'diag' in option_dict and option_dict['diag'][0]:
        diag_info = diagnostic_data(option_dict)
        print json.dumps(diag_info, indent=4)
        return;
   
    # Establish a tmpdir location.
    # A user specified a tmpdir then is relative to tht tmpdir_root.
    # All diretories are created as needed.
    global tmpdir_root
    if 'tmpdir' in option_dict:
        tmpdir = tmpdir_root + '/' + option_dict['tmpdir'][0]
    else:
        tmpdir = tmpdir_root + '/' + str(os.getpid())
    if not os.access(tmpdir,os.F_OK):
        os.makedirs(tmpdir)
    os.chdir(tmpdir)
 
    # Now handle file uploads if necessary
    for part in multipart_keys:
        outfd = open(form[part].filename,'w')

        inbytes = form[part].file.read(1000000)
        while inbytes:
            outfd.write(inbytes)
            inbytes = form[part].file.read(1000000)
        outfd.close()

    result = ''
    if 'async' in option_dict and option_dict['async'][0]:
        ## Item to be put in the async queue.  Currently just need a tmpdir
        ## and the request.
        async_item = {
                'tmpdir': tmpdir, 
                'request': json.loads(request_str)
                }
        rpc_queue_dir = '/tmp/jsonrpc_queue'
        queue_path = rpc_queue_dir + '/' + str(os.getpid())
        f = open(queue_path,'w')
        f.write(json.dumps(async_item))

        result = json.dumps({'queue_path': queue_path })
        print json.dumps({
            "jsonrpc": "2.0", 
            "result": json.loads(result),
            "id": None
            });
    else:
        # synchronous execution.
        result = rpc_service.call(request_str)
        print result
    
    if 'log' in option_dict and option_dict['log'][0]:
        # Logs request, response, and environment to "tmpdir/jsonrpc.log"
        log_fd = open('jsonrpc.log','w')
        log_fd.write('{"Request":' + request_str + ', ')
        log_fd.write('"Result":' + json.dumps(result) + ', ')

        log_fd.write('"Environment": [')
        env_keys = sorted(os.environ.keys())
        env_out = ''
        for k in env_keys:
            env_out += '["'+k+'"' + ', '+ json.dumps(os.environ[k]) + '], '
        
        log_fd.write(env_out[:-2]+']}')
        log_fd.close()