#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import logging
#import setproctitle
from logging.handlers import RotatingFileHandler
from signal import SIGTERM
import time
import multiprocessing.managers
import socket
import threading
import commands
import copy
from datetime import datetime
import requests
try:
    import simplejson
    json=simplejson
except ImportError,e:
    import json

_LOG_INFO={
"log_level":logging.INFO,
"log_format":'%(asctime)-15s %(levelname)s %(lineno)s %(message)s',
"log_file":'/tmp/agent_api.log',
"log_max_size":100000000,
"log_backup":7,
}
_PID_FILE='/tmp/agent_api.pid'
_DEBUG=False
QUEUE_INFO={
	'queue_ip':'10.57.0.3',
	'queue_port':15555,
	'queue_auth':'Youxin'
	}
r,HOSTNAME=commands.getstatusoutput('hostname')

REGION_CONF={'hb1':'青岛',
	'hb2':'北京',
	'hb3':'张家口',
	'hb5':'呼和浩特',
	'hd1':'杭州',
	'hd2':'上海',
	'hn1':'深圳',
	'hk':'香港',
	}
REGION=''
for region in REGION_CONF:
    if HOSTNAME.find(region) != -1:
	REGION=REGION_CONF[region]
TOKEN_DICT={"JY_Login":""}
TOKEN_REFRESH_TIME=3600
API_INTERNAL=60

'''
此处添加需要检查的API地址
'''
API_TARGET={
        "JY_Login":[
          "https://xx.xx.com/aggregation-server/api/login-aggregation/v1", #交易登录接口
          {
           "source": "2",
           "areaCode": "86",
           "password": "RJU6_3VttTuiO0JpG8Cye9E=",
           "phoneNumber": "q1Mhu_vAgvKVMo1SUBCY="
         }, #post_data
        {'content-type': "application/json"},#header
        [],
        ], 
        "Hangqing_JuHe":["https://xx.xx.com/quotes-dataservice-app/api/v2/detail", #行情聚合接口
        {
        'ids': ["hk00780"],
        'level': 3
        },
        {'content-type':"application/json",
         'Authorization': "",
        },
        ["header","Authorization","JY_Login","POST"],
        ],
        "Hangqing_Anpan":["https://xx.xx.com/quotes-dataservice-app/api/v2-1/detail", #行情聚合暗盘接口
        {
        'ids': ["hk00780"],
        'level': 3
        },
        {'content-type':"application/json",
         'Authorization': "",
        },
        ["header","Authorization","JY_Login","POST"],
        ],
        "Hangqing_KLine":["https://xx.xx.com/quotes-dataservice-app/api/v2/kline?direction=0&id=ABA&level=0&start=0&type=9",#行情K线接口
         {},
        {'content-type':"application/json",
         'Authorization': "",
        },
        ["header","Authorization","JY_Login","GET"],
        ],
        "Hangqing_FenShi":["https://xx.xx.xx/quotesapp/api/v2-1/timesharing?level=2&days=1&id=hk00700",#行情分时接口
         {},
        {'content-type':"application/json",
         'Authorization': "",
        },
        ["header","Authorization","JY_Login","GET"],
         ],
         "Hangqing_Fenshi_HK":["https://xx.xx.com/quotes-ervice-app/api/v2-1/hktisharing?id=00700&type=0&level=2",#行情分时港版接口
        {},
        {'content-type':"application/json",
         'Authorization': "",
        },
        ["header","Authorization","JY_Login","GET"],
        ],
         "Hangqing_KLine_HK":["https://xx.xx.com/quotes--app/api/v2/hkkline?direction=0&id=usBABA&level=0&type=1",#行情港版K线接口
        {},
        {'content-type':"application/json",
         'Authorization': "",
        },
        ["header","Authorization","JY_Login","GET"],
        ],
        #"BAIDU_CHECK":"https://www.badiu.com/xx?123",
	}


'''
函数返回数据格式 {"hostname":"ld-hn1-1",
                   "type":"ping",
		   "result":1,
		   "datetime":"2018-08-20 19:00:01",
		   "target":"120.19.11.23",
		   "info":"",
		   'region':'',
		   "standby":''
		 }
'''

DEFAULT_DATA={
	"hostname":HOSTNAME,
	"type":'',
	"result":0,
	"datetime":"",
	"target":"",
	"region":REGION,
	"info":"",
	"standby":"",
	}

#刷新token线程
def set_token(queue,logger):
    global TOKEN_DICT,API_TARGET,TOKEN_REFRESH_TIME
    while True:
        for service,token in TOKEN_DICT.iteritems():
            url = API_TARGET.get(service,None)[0]
            if url:
                data = API_TARGET[service]
                headers = {}
                if len(data) == 4:
                    headers = data[2]
                post_data = data[1]
                try:
                    response = requests.post(url=url,data=json.dumps(post_data),headers=headers)
                    result = json.loads(response.text)
                    if 'data' in result and 'token' in result['data']:
                        TOKEN_DICT[service] = result['data']['token']
                except Exception as e:
                    logger.error(str(e))
        logger.info("Sleep "+str(TOKEN_REFRESH_TIME)+"s refresh token")
        time.sleep(TOKEN_REFRESH_TIME)

def check_api(queue,logger):
    global API_TARGET,TOKEN_DICT,API_INTERNAL
    target=API_TARGET
    while True:
        time.sleep(1)
        for k,v in target.iteritems():
            send_data=copy.deepcopy(DEFAULT_DATA)
            send_data['type']='Api'
	    send_data["datetime"]=datetime.strftime(datetime.now(),"%Y-%m-%d %H:%M:%S")
	    info=''
            logger.info("Do Service: "+k)
            if isinstance(v,list):
                send_data['target']=k+"_"+v[0]
                url = v[0]
                post_data = v[1]
                headers = v[2]
                method = None
                if len(v) == 4:
                    if not v[3]:
                        logger.info("skip login service")
                        continue
                    else:
                        include_type = v[3][0]
                        key = v[3][1]
                        token_service = v[3][2]
                        method = v[3][3]
                        token = TOKEN_DICT.get(token_service,None)
                        if token:
                            if include_type == "header":
                                headers[key] = token
                            elif include_type == "data":
                                post_data[key] = token
                            else:
                                logger.error("Type Error: "+k)
                                continue
                        else:
                            logger.info("token do not exists. skip")
                            continue
                try:
                    check_status = 0
	            b_time=time.time()
                    if method == "GET":
	                result=requests.get(url=url,headers=headers,timeout=12)
                    else:
	                result=requests.post(url=url,data=json.dumps(post_data),headers=headers,timeout=12)
	            e_time=time.time()
	            u_time=str(e_time-b_time)
	            if result.status_code != 200:
		        info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
		        check_status=1
	            else:
		        try:
		            d=result.json()
		            status=d.get('msg',None)
		            if status == "success":
		                info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
		            elif not status:
		                info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
		            else:
			        info="json data result key value is not 1"
			        check_status=1
		        except Exception as e:
		            logger.info(str(e))
		            info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
                except Exception as e:
                    check_status = 1
                    logger.info(str(e))
                    info = "请求超时"
            else:
                send_data['target']=k+"_"+v
	        try:
	            check_status=0 #0 is sucessed ,1 is failed
	            b_time=time.time()
	            result=requests.get(v,timeout=12)
	            e_time=time.time()
	            u_time=str(e_time-b_time)
	            if result.status_code != 200:
		        info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
		        check_status=1
	            else:
		        try:
		            d=result.json()
		            status=d.get('result',None)
		            if status == 1:
		                info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
		            elif not status:
		                info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
		            else:
			        info="json data result key value is not 1"
			        check_status=1
		        except Exception as e:
		            logger.info(str(e))
		            info="Status_code: %s Content_Length: %s , Response Time: %s s" %(str(result.status_code),result.headers.get("Content-Length","Null"),u_time)
	        except Exception as e:
	            check_status=1
	            logger.info(str(e))
	            info='响应时间超过12s'
	    send_data['info']=info
	    send_data['result']=check_status
            #logger.info(str(send_data))
	    try:
	        send_data=json.dumps(send_data)
	    except Exception as e:
	        logger.error(str(e))
	        send_data=None
	        continue
	    try:
	        queue.put(send_data)
	    except Exception as e:
	        logger.error(str(e))
	        return
	    send_data=None
            logger.info("end check api")
        time.sleep(API_INTERNAL)

#callbacks 填入编写的监控插件函数名,按照规定的数据格式返回数据
#CALL_BACKS=[check_ping,check_api,check_port]
CALL_BACKS=[set_token,check_api]
#CALL_BACKS=[check_api]
#检测时间间隔
CHECK_INTERNAL=1

class Daemon(object):
    def __init__(self):
	self._pid_file=_PID_FILE
	self._std_in_file='/dev/null'
	self._std_out_file='/dev/null'
	self._std_err_file=_LOG_INFO.get('log_file','/var/log/agent.log')
	self.logger_ok=False
	self.logger=None

    def set_logger(self):
	global _LOG_INFO,_DEBUG
	logging.basicConfig(level=logging.DEBUG,filename='/dev/null')
	Logger=logging.getLogger('Agent')
	log_level=_LOG_INFO.get('log_level',logging.INFO)
	log_format=logging.Formatter(_LOG_INFO.get('log_format',''))
	log_file=_LOG_INFO.get('log_file','/tmp/agent.log')
	if _DEBUG:
	    handler=logging.StreamHandler()
	else:
	    log_max_size=_LOG_INFO.get('log_max_size',100000)
	    log_backup=_LOG_INFO.get('log_backup',7)
	    log_folder=os.path.dirname(_LOG_INFO.get('log_file'))
	    if os.path.exists(log_folder):
		os.system('mkdir -p {0}'.format(log_folder))
	    handler=RotatingFileHandler(log_file,'a',log_max_size,log_backup)
	handler.setLevel(log_level)
	handler.setFormatter(log_format)
	Logger.addHandler(handler)
	if not self.logger:
	    self.logger=logging.getLogger('Agent')

    def init_logger(self):
	if not self.logger_ok:
	    self.logger_ok=True
	    self.set_logger()


    def daemonize(self):
	try:
	    pid=os.fork()
	    if pid > 0:
		sys.exit(0)
	except OSError,e:
	    self.logger.error(str(e))
	os.setsid()
	os.umask(0)
	try:
	    pid=os.fork()
	    if pid > 0:
		sys.exit(0)
	except OSError,e:
	    self.logger.error(str(e))
	for f in sys.stdout,sys.stderr:f.flush()
	si=file(self._std_in_file,'r')
	so=file(self._std_out_file,'a+')
	se=file(self._std_err_file,'a+',0)
	os.dup2(si.fileno(),sys.stdin.fileno())
	os.dup2(so.fileno(),sys.stdout.fileno())
	os.dup2(se.fileno(),sys.stderr.fileno())
	import atexit
	atexit.register(self.del_pidfile)
	#setproctitle.setproctitle('agent')
	pid=str(os.getpid())
	self.logger.info(str(pid))
	if not os.path.exists(os.path.dirname(self._pid_file)):
	    os.makedirs(os.path.dirname(self._pid_file))
	with open(self._pid_file,'w') as f:
	    f.write(pid)

    def start(self):
	if not _DEBUG:
	    if os.path.exists(self._pid_file):
		self.logger.info('agent is running ?')
		sys.exit(1)
	    self.daemonize()
	    self.logger.info('start agent success')
	else:
	    self.logger.info('start agent in debug mode')
	worker=Worker(CALL_BACKS)
	worker._init_worker(QUEUE_INFO)
	worker.start_loop()
    def stop(self):
	if not os.path.exists(self._pid_file):
	    self.logger.error('the pid file is not exists! stop fail')
	    sys.exit(1)
	pid=None
	with open(self._pid_file) as f:
	    pid=int(f.readline())
	if pid:
	    os.system('kill -9 {0}'.format(str(pid)))
	    self.logger.info('Stop publisher process Success')
	try:
	    os.remove(self._pid_file)
	except Exception as e:
	    pass
    def del_pidfile(self):
	os.remove(self._pid_file)

    def restart(self):
	self.stop()
	time.sleep(1)
	self.start()
    def parse_input(self,opt):
	if opt == 'start':
	    self.start()
	elif opt == 'stop':
	    self.stop()
	elif opt == 'restart':
	    self.restart()
	else:
	    self.logger.error('bad params ,exsample: ./agent.py  start|stop|restart')
	    sys.exit(1)


class Worker(object):
    def __init__(self,callbacks=None,internal=CHECK_INTERNAL):
	self._callbacks=callbacks
	self.logger=logging.getLogger('Agent')
	self._internal=internal
	self.manager=None

    def _init_worker(self,kw):
	self.ip=kw.get('queue_ip',None)
	self.port=kw.get('queue_port',None)
	auth=kw.get('queue_auth',None)
	if not self.ip or not self.port:
	    self.logger.error('IP or Port is None !')
	    sys.exit(1)
	if not self.try_connect():
	    return False
	reload(multiprocessing.managers)
	multiprocessing.managers.BaseManager.register('get_result_queue')
	if auth:
	    self.manager=multiprocessing.managers.BaseManager(address=(self.ip,self.port),authkey=auth)
	else:
	    self.manager=multiprocessing.managers.BaseManager(address=(self.ip,self.port))
	try:
	    self.manager.connect()
	    return True
	except Exception,e:
	    self.logger.error(str(e))
	    self.manager=None
	    return False

    def try_connect(self):
	sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 	sk.settimeout(5)
	try:
	    sk.connect((self.ip,self.port))
	    sk.close()
	    return True
   	except Exception ,e:
	    self.logger.error(str(e))
	    return False
    def start_loop(self):
	while True:
	    while True:
		if self._init_worker(QUEUE_INFO):
		    break
		self.logger.info('can not connect Publisher , try again after 3 sec')
		time.sleep(3)
	    callbacks=self._callbacks
	    threads=[]
	    queue=None
	    try:
	        queue=self.manager.get_result_queue()
	    except Exception as e:
		self.logger.error('Get Queue Timeout,Sleep 5s')
		time.sleep(5)
		continue
	    if callbacks:
		for callback in  callbacks:
		    threads.append(threading.Thread(target=callback,args=(queue,self.logger)))
		for t in threads:
		    try:
		        t.start()
		    except Exception as e:
			self.logger(str(e))
			threads.remove(t)
		for t in threads:
		    t.join(timeout=600)
	    self.logger.info('Sleep %d s' %(self._internal))
            time.sleep(self._internal)
	    self.logger.info('Start run callbacks')
		    


if __name__ == '__main__':
    if len(sys.argv) == 2:
	daemon=Daemon()
	daemon.init_logger()
	daemon.parse_input(sys.argv[1])
    else:
	print 'bad params'















