#!/usr/bin/python3

import subprocess,re,sys,etcdlib,psutil
import time,threading,json,traceback,platform

from log import logger

class Container_Collector(threading.Thread):

    def __init__(self,etcdaddr,cluster_name,host,cpu_quota,mem_quota,test=False):
        threading.Thread.__init__(self)
        self.thread_stop = False
        self.host = host
        self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor" % (cluster_name))
        self.etcdser.setkey('/vnodes/cpu_quota', cpu_quota)
        self.etcdser.setkey('/vnodes/mem_quota', mem_quota)
        self.cpu_quota = float(cpu_quota)/100000.0
        self.mem_quota = float(mem_quota)*1000000/1024
        self.interval = 2
        self.test = test
        return

    def list_container(self):
        output = subprocess.check_output(["sudo lxc-ls"],shell=True)
        output = output.decode('utf-8')
        containers = re.split('\s+',output)
        return containers

    def collect_containerinfo(self,container_name):
        output = subprocess.check_output("sudo lxc-info -n %s" % (container_name),shell=True)
        output = output.decode('utf-8')
        parts = re.split('\n',output)
        info = {}
        basic_info = {}
        for part in parts:
            if not part == '':
                key_val = re.split(':',part)
                key = key_val[0]
                val = key_val[1]
                info[key] = val.lstrip()
        basic_info['Name'] = info['Name']
        basic_info['State'] = info['State']
        if(info['State'] == 'STOPPED'):
            self.etcdser.setkey('/vnodes/%s/basic_info'%(container_name), basic_info)
            return False
        basic_info['PID'] = info['PID']
        basic_info['IP'] = info['IP']
        self.etcdser.setkey('/vnodes/%s/basic_info'%(container_name), basic_info)
        cpu_parts = re.split(' +',info['CPU use'])
        cpu_val = cpu_parts[0].strip()
        cpu_unit = cpu_parts[1].strip()
        res = self.etcdser.getkey('/vnodes/%s/cpu_use'%(container_name))
        cpu_last = 0
        if res[0] == True:
            last_use = dict(eval(res[1]))
            cpu_last = float(last_use['val'])
        cpu_use = {}
        cpu_use['val'] = cpu_val
        cpu_use['unit'] = cpu_unit
        cpu_usedp = (float(cpu_val)-float(cpu_last))/(self.cpu_quota*self.interval*1.3)
        if(cpu_usedp > 1):
            cpu_usedp = 1
        cpu_use['usedp'] = cpu_usedp
        self.etcdser.setkey('vnodes/%s/cpu_use'%(container_name), cpu_use)
        mem_parts = re.split(' +',info['Memory use'])
        mem_val = mem_parts[0].strip()
        mem_unit = mem_parts[1].strip()
        mem_use = {}
        mem_use['val'] = mem_val
        mem_use['unit'] = mem_unit
        if(mem_unit == "MiB"):
            mem_val = float(mem_val) * 1024
        mem_usedp = float(mem_val) / self.mem_quota
        mem_use['usedp'] = mem_usedp
        self.etcdser.setkey('/vnodes/%s/mem_use'%(container_name), mem_use)
        #print(output)
        #print(parts)
        return True

    def run(self):
        cnt = 0
        while not self.thread_stop:
            containers = self.list_container()
            countR = 0
            conlist = []
            for container in containers:
                if not container == '':
                    conlist.append(container)
                    try:
                        if(self.collect_containerinfo(container)):
                            countR += 1
                    except Exception as err:
                        #pass
                        logger.warning(err)
            containers_num = len(containers)-1
            concnt = {}
            concnt['total'] = containers_num
            concnt['running'] = countR
            self.etcdser.setkey('/hosts/%s/containers'%(self.host), concnt)
            time.sleep(self.interval)
            if cnt == 0:
                self.etcdser.setkey('/hosts/%s/containerslist'%(self.host), conlist)
            cnt = (cnt+1)%5
            if self.test:
                break
        return

    def stop(self):
        self.thread_stop = True


class Collector(threading.Thread):

    def __init__(self,etcdaddr,cluster_name,host,test=False):
        threading.Thread.__init__(self)
        self.host = host
        self.thread_stop = False
        self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor/hosts/%s" % (cluster_name,host))
        self.interval = 1
        self.test=test
        return

    def collect_meminfo(self):
        meminfo = psutil.virtual_memory()
        memdict = {}
        memdict['total'] = meminfo.total/1024
        memdict['used'] = meminfo.used/1024
        memdict['free'] = meminfo.free/1024
        memdict['buffers'] = meminfo.buffers/1024
        memdict['cached'] = meminfo.cached/1024
        memdict['percent'] = meminfo.percent
        self.etcdser.setkey('/meminfo',memdict)
        #print(output)
        #print(memparts)
        return

    def collect_cpuinfo(self):
        cpuinfo = psutil.cpu_times_percent(interval=1,percpu=False)
        cpuset = {}
        cpuset['user'] = cpuinfo.user
        cpuset['system'] = cpuinfo.system
        cpuset['idle'] = cpuinfo.idle
        cpuset['iowait'] = cpuinfo.iowait
        self.etcdser.setkey('/cpuinfo',cpuset)
        output = subprocess.check_output(["cat /proc/cpuinfo"],shell=True)
        output = output.decode('utf-8')
        parts = output.split('\n')
        info = []
        idx = -1
        for part in parts:
            if not part == '':
                key_val = re.split(':',part)
                key = key_val[0].rstrip()
                if key == 'processor':
                    info.append({})
                    idx += 1
                val = key_val[1].lstrip()
                if key=='processor' or key=='model name' or key=='core id' or key=='cpu MHz' or key=='cache size' or key=='physical id':
                    info[idx][key] = val
        self.etcdser.setkey('/cpuconfig',info)
        return

    def collect_diskinfo(self):
        parts = psutil.disk_partitions()
        setval = []
        devices = {}
        for part in parts:
            if not part.device in devices:
                devices[part.device] = 1
                diskval = {}
                diskval['device'] = part.device
                diskval['mountpoint'] = part.mountpoint
                usage = psutil.disk_usage(part.mountpoint)
                diskval['total'] = usage.total
                diskval['used'] = usage.used
                diskval['free'] = usage.free
                diskval['percent'] = usage.percent
                setval.append(diskval)
        self.etcdser.setkey('/diskinfo', setval)
        #print(output)
        #print(diskparts)
        return

    def collect_osinfo(self):
        uname = platform.uname()
        osinfo = {}
        osinfo['platform'] = platform.platform()
        osinfo['system'] = uname.system
        osinfo['node'] = uname.node
        osinfo['release'] = uname.release
        osinfo['version'] = uname.version
        osinfo['machine'] = uname.machine
        osinfo['processor'] = uname.processor
        self.etcdser.setkey('/osinfo',osinfo)
        return

    def run(self):
        self.collect_osinfo()
        while not self.thread_stop:
            self.collect_meminfo()
            self.collect_cpuinfo()
            self.collect_diskinfo()
            self.etcdser.setkey('/running','True',6)
            time.sleep(self.interval)
            if self.test:
                break
            #   print(self.etcdser.getkey('/meminfo/total'))
        return

    def stop(self):
        self.thread_stop = True

class Container_Fetcher:
    def __init__(self,etcdaddr,cluster_name):
        self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor/vnodes" % (cluster_name))
        return

    def get_cpu_use(self,container_name):
        res = {}
        [ret, ans] = self.etcdser.getkey('/%s/cpu_use'%(container_name))
        if ret == True :
            res = dict(eval(ans))
            res['quota'] = self.etcdser.getkey('/cpu_quota')[1]
            return res
        else:
            logger.warning(ans)
            return res

    def get_mem_use(self,container_name):
        res = {}
        [ret, ans] = self.etcdser.getkey('/%s/mem_use'%(container_name))
        if ret == True :
            res = dict(eval(ans))
            res['quota'] = self.etcdser.getkey('/mem_quota')[1]
            return res
        else:
            logger.warning(ans)
            return res

    def get_basic_info(self,container_name):
        res = self.etcdser.getkey("/%s/basic_info"%(container_name))
        if res[0] == False:
            return {}
        res = dict(eval(res[1]))
        return res

class Fetcher:

    def __init__(self,etcdaddr,cluster_name,host):
        self.etcdser = etcdlib.Client(etcdaddr,"/%s/monitor/hosts/%s" % (cluster_name,host))
        return

    #def get_clcnt(self):
    #   return DockletMonitor.clcnt

    #def get_nodecnt(self):
    #   return DockletMonitor.nodecnt

    #def get_meminfo(self):
    #   return self.get_meminfo_('172.31.0.1')

    def get_meminfo(self):
        res = {}
        [ret, ans] = self.etcdser.getkey('/meminfo')
        if ret == True :
            res = dict(eval(ans))
            return res
        else:
            logger.warning(ans)
            return res

    def get_cpuinfo(self):
        res = {}
        [ret, ans] = self.etcdser.getkey('/cpuinfo')
        if ret == True :
            res = dict(eval(ans))
            return res
        else:
            logger.warning(ans)
            return res

    def get_cpuconfig(self):
        res = {}
        [ret, ans] = self.etcdser.getkey('/cpuconfig')
        if ret == True :
            res = list(eval(ans))
            return res
        else:
            logger.warning(ans)
            return res

    def get_diskinfo(self):
        res = []
        [ret, ans] = self.etcdser.getkey('/diskinfo')
        if ret == True :
            res = list(eval(ans))
            return res
        else:
            logger.warning(ans)
            return res

    def get_osinfo(self):
        res = {}
        [ret, ans] = self.etcdser.getkey('/osinfo')
        if ret == True:
            res = dict(eval(ans))
            return res
        else:
            logger.warning(ans)
            return res

    def get_containers(self):
        res = {}
        [ret, ans] = self.etcdser.getkey('/containers')
        if ret == True:
            res = dict(eval(ans))
            return res
        else:
            logger.warning(ans)
            return res

    def get_status(self):
        isexist = self.etcdser.getkey('/running')[0]
        if(isexist):
            return 'RUNNING'
        else:
            return 'STOPPED'

    def get_containerslist(self):
        res = list(eval(self.etcdser.getkey('/containerslist')[1]))
        return res
