#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pysphere import VIServer
import logging, re, os, inspect, sys, argparse
from threading import Thread
from Queue import Queue

# ------------------------------------------------------------------------------------------------------------
# third-party lib handling
rackpath = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"../python/lib/racktables")))
syncpath = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"../../pyRackSync")))
confpath = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"../conf")))
sys.path.insert(0, rackpath)
sys.path.insert(0, syncpath)
sys.path.insert(0, confpath)
from client import *
from RacktablesSyncClient import *
from config import __config__;
# ------------------------------------------------------------------------------------------------------------



global viPool
viPool = Queue()

global rtPool
rtPool = Queue()

def syncObject(vmItem):
    """Build an object tree from vSphere

    :param vmItem: vmPath as reported by get_registered_vms (string)

    """
    viPoolItem = viPool.get()
    vm = viPoolItem[1].get_vm_by_path(vmItem)
    viPool.put(viPoolItem)

    vmProperties = vm.get_properties(from_cache=False)

    # build the sync object
    vmObject = {}

    vmName = vmProperties["name"]
    logging.debug("Processing item %s" % vmName)

    if vmName[0:6].isdigit():
        vmName = vmName[7:]

    vmObject["name"] = vmName
    vmObject["network"] = {}

    for deviceIdx, device in vmProperties["devices"].items():
            if not "macAddress" in device:
                continue

            vmDev = device["label"][-1]
            vmDev = int(vmDev) - 1
            vmDev = "eth" + str(vmDev)

            vmObject["network"][vmDev] = { 
                "name": vmDev,
                "mac" : device["macAddress"],
                "net" : device["summary"],
                "fqdn": vmName + __config__["general"]["dnssuffix"],
                "force": __config__["general"]["force"]
            }

    vmIp = vm.get_property("ip_address", from_cache=False)

    if vmIp and len(vmObject["network"]) == 1:
        vmObject["network"][vmDev]["ip"] = vmIp

    vmObject["attrs"] = {
        "17"   : vmProperties["memory_mb"] / 1024,
        # Custom attribute
        "10000": vmProperties["num_cpu"],
        "3"    : vmName + __config__["general"]["dnssuffix"]
    }

    contactRegExp = re.compile("^[^\s]+\s[^\s]+$")
    if contactRegExp.match(vm.properties.parent.name):
        # Contact person only if parent folder matches "Firstname Lastname"
        vmObject["attrs"]["14"] = vm.properties.parent.name

    vmObject["forceattrs"] = __config__["general"]["forceattrs"]
    vmObject["network"]["force"] = __config__["general"]["force"]

    vmObject["objtype_id"] = __config__["general"]["objtype_id"]
    vmObject["linkparent"] = __config__["general"]["linkparent"]

    logging.debug("Starting sync for item %s" % vmName)
    rtPoolItem = rtPool.get()
    rtPoolItem[1].doSyncObject(vmObject)
    rtPool.put(rtPoolItem)

def createRtWorker(QueueObj, items=5):
    """Create workers of type RacktablesClient

    :param QueueObj: Object queue to add the worker to
    :param items: Number of items to add to the queue

    """
    for x in range(0,items - 1):
        logging.debug("Adding RT worker %s" % str(x))
        rtSyncClient = {}
        rtSyncClient[0] = "Racktables-" + str(x)
        rtClient = RacktablesClient(__config__["racktables"]["apiurl"],
            __config__["racktables"]["username"],
            __config__["racktables"]["password"])
        rtSyncClient[1] = RacktablesSyncClient(rtClient)
        QueueObj.put(rtSyncClient)

def createVmWorker(QueueObj, items=5):
    """Create workers of type VIServer

    Keyword Arguments:
    :param QueueObj: Object queue to add the worker to
    :param items: Number of items to add to the queue

    """
    for x in range(0,items - 1):
        logging.debug("Adding VM worker %s" % str(x))
        vmServer = {}
        vmServer[0] = "VMWare-" + str(x)
        vmServer[1] = VIServer()
        vmServer[1].connect(__config__["vsphere"]["server"], 
            __config__["vsphere"]["username"], 
            __config__["vsphere"]["password"])
        QueueObj.put(vmServer)

def main():
    """Main function
    """ 
    parser = argparse.ArgumentParser(prog="pyVspDS")
    parser.add_argument('-v', '--verbose',action="store_true", 
                        help="increase output verbosity")
    parser.add_argument('-H', '--host',type=str,
                        help="Only synchronize hosts fuzzy matching this string.")
    parser.add_argument('-f', '--force',action="store_true",
                        help="Force update.")
    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG,
                            format='[%(levelname)s] (%(threadName)-10s) %(message)s')
    else:
        logging.basicConfig(format='[%(levelname)s] (%(threadName)-10s) %(message)s')

    if args.force:
        __config__["general"]["force"] = True
    
    createVmWorker(viPool, 5)
    createRtWorker(rtPool, 5)
    
    vmRegExp = re.compile("^.*\]\ (.*?)\/.*$")
    
    viPoolItem = viPool.get()
    vmList = viPoolItem[1].get_registered_vms(status="poweredOn")
    viPool.put(viPoolItem)
    
    for vmItem in vmList:
        try:
            if not args.host:
                Thread(name=str(vmRegExp.split(vmItem)[1]), target=syncObject, args=(vmItem,)).start()
                continue
            if args.host.lower() in vmItem.lower():
                Thread(name=str(vmRegExp.split(vmItem)[1]), target=syncObject, args=(vmItem,)).start()
        except Exception, errtxt:
            logging.exception("Error: " + str(errtxt))
    

if __name__ == "__main__":
    main()
