#! /usr/bin/env python
"""
Arast Daemon

The Arast daemon runs on the control node.

"""
import os

import argparse
import sys
import daemon
import logging
import json
import pymongo
import multiprocessing
import pika
import requests

from ConfigParser import SafeConfigParser
import consume
import shock

#context = daemon.DaemonContext(stdout=sys.stdout) #temp print to stdout
#TODO change to log file

#with context:
mgr = multiprocessing.Manager()
job_list = mgr.list()
kill_list = mgr.list()

def start(arast_server, config, num_threads, queue):
    # Read config file
    print config
    print "Reading from config file"
    cparser = SafeConfigParser()
    cparser.read(config)
    
    ## Retrieve shock url from arast server
    shockurl = json.loads(requests.get('http://{}:8000/shock'.format(arast_server)).text)['shockurl']
    try:

        print ' [.] Retrieved shock url: {}'.format(shockurl)
    except:
        shockurl = cparser.get('shock', 'host')
    arasturl =  cparser.get('meta','mongo.host')
    if not num_threads:
        num_threads =  cparser.get('compute','threads')

    mongo_port = int(cparser.get('meta','mongo.port'))
    if arast_server != '':
        arasturl = arast_server
    print " [.] Starting Assembly Service Compute Node"
    print " [.] AssemblyRAST host: %s" % arasturl
    print " [.] MongoDB port: %s" % cparser.get('meta','mongo.port')
    print " [.] RabbitMQ port: %s" % cparser.get('rabbitmq','port')
    
    # Check MongoDB status
    try:
        connection = pymongo.Connection(arasturl, mongo_port)
                      
        logging.info("MongoDB Info: %s" % connection.server_info())
    except:
        logging.error("MongoDB connection error: %s" % sys.exc_info()[0])
        sys.exit()
    print " [x] MongoDB connection successful."
    # Check RabbitMQ status
        #TODO
        
    print " [.] Connecting to Shock server..."
    url = "http://%s" % cparser.get('shock', 'host')
    res = shock.get(url, cparser.get('shock','admin_user'),
              cparser.get('shock','admin_pass'))
    
    if res is not None:
        print " [x] Shock connection successful"


    ## Start Monitor Thread
    kill_process = multiprocessing.Process(name='killd', target=start_kill_monitor,
                                           args=(arasturl,))
    kill_process.start()

    workers = []
    for i in range(int(num_threads)):
        worker_name = "[Worker %s]:" % i
        compute = consume.ArastConsumer(shockurl, arasturl, config, num_threads, 
                                        queue, kill_list, job_list)
        logging.info("[Master]: Starting %s" % worker_name)
        p = multiprocessing.Process(name=worker_name, target=compute.start)

        workers.append(p)
        p.start()

    workers[0].join()

def start_kill_monitor(arasturl):
    connection = pika.BlockingConnection(pika.ConnectionParameters(
            host = arasturl))
    channel = connection.channel()
    channel.exchange_declare(exchange='kill',
                             type='fanout')
    result = channel.queue_declare(exclusive=True)
    queue_name = result.method.queue
    channel.queue_bind(exchange='kill',
                       queue=queue_name)
    print ' [*] Waiting for kill commands'
    channel.basic_consume(kill_callback,
                          queue=queue_name,
                          no_ack=True)

    channel.start_consuming()

def kill_callback(ch, method, properties, body):
        print " [x] %r" % (body,)
        kill_request = json.loads(body)
        print 'job_list:', job_list
        for job_data in job_list:
            if kill_request['user'] == job_data['user'] and kill_request['job_id'] == str(job_data['job_id']):
                print 'on this node'
                kill_list.append(kill_request)




parser = argparse.ArgumentParser(prog='ar_computed', epilog='Use "arast command -h" for more information about a command.')

parser.add_argument("-v", "--verbose", help="increase output verbosity",
                    action="store_true")
parser.add_argument("-s", "--server", help="specify AssemblyRAST server",
                    action="store")
parser.add_argument("-c", "--config", help="specify configuration file",
                    action="store", required=True)
parser.add_argument("-t", "--threads", help="specify number of worker threads",
                    action="store", required=False)
parser.add_argument("-q", "--queue", help="specify a queue to pull from",
                    action="store", required=False)

args = parser.parse_args()
if args.verbose:
    logging.basicConfig(level=logging.DEBUG)
arasturl = ''
if args.server:
    arasturl = args.server
if args.queue:
    queue = args.queue
else:
    queue = None
if args.threads:
    num_threads = args.threads
else:
    num_threads = None
start(arasturl, args.config, num_threads, queue)

@@ -679,16 +679,72 @@
 config)%0A
+%0A    print %22 %5B.%5D Starting Assembly Service Compute Node%22
     %0A   
@@ -780,24 +780,37 @@
 rast server%0A
+    try:%0A    
     shockurl
@@ -903,18 +903,8 @@
 l'%5D%0A
-    try:%0A%0A
     
@@ -929,25 +929,25 @@
 trieved 
-s
+S
 hock 
-url
+URL
 : %7B%7D'.fo
@@ -1269,63 +1269,8 @@
 ver%0A
-    print %22 %5B.%5D Starting Assembly Service Compute Node%22
 %0A   
@@ -1800,16 +1800,17 @@
 ssful.%22%0A
+%0A
     # Ch
@@ -1921,41 +1921,27 @@
 p://
-%25s%22 %25 cparser.ge
+%7B%7D%22.forma
 t(
-'
 shock
-', 'host'
+url
 )%0A  
@@ -1965,121 +1965,291 @@
 (url
-, cparser.get('shock','admin_user'),%0A              cparser.get('shock','admin_pass'))%0A    %0A    if res is not None
+)%0A    %0A    if res is not None:%0A        print %22 %5Bx%5D Shock connection successful%22%0A    else:%0A        raise Exception(%22Shock connection error: %7B%7D%22.format(shockurl))%0A%0A    ## Check data write permissions%0A    datapath = cparser.get('compute', 'datapath')%0A    if os.access(datapath, os.W_OK)
 :%0A  
@@ -2264,43 +2264,143 @@
 int 
-%22 %5Bx%5D Shock connection successful%22%0A
+' %5B.%5D Storage path -- %7B%7D : OKAY'.format(datapath)%0A    else:%0A        raise Exception(' %5B.%5D Storage path -- %7B%7D : ERROR'.format(datapath))
 %0A%0A  

Check storage permissions on start