
import SocketServer
import socket
import logging
from logging import handlers
import os
import types
import traceback
import win32serviceutil
import win32service
import win32evtlogutil
import _winreg
import xml.dom.minidom

DEFAULT_PORT = 25285

def getSolidIceInstallPath():
    retval = os.environ['temp']
    try:
        key_path = 'SOFTWARE\\RedHat\\SetupInfo'
        root = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_path)
        retval, v_type = _winreg.QueryValueEx(root,"InstallLocation")
    finally:
        return str(retval)

def getLogsDirectory(solidIcePath):
    NetConsoleDir = os.path.join(solidIcePath, "NetConsole")
    if not os.path.isdir(NetConsoleDir):
        os.mkdir(NetConsoleDir)
    NetConsoleLogDir = os.path.join(NetConsoleDir, "logs")
    if not os.path.isdir(NetConsoleLogDir):
        os.mkdir(NetConsoleLogDir)
    retval = NetConsoleLogDir
    return retval

def getHostPortFromRegistry():
    port = DEFAULT_PORT
    host = socket.gethostname()
    try:
        key_path = 'SOFTWARE\\RedHat\\NetConsole'
        root = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_path)
        host, v_type = _winreg.QueryValueEx(root,"Host")
        port, v_type = _winreg.QueryValueEx(root,"Port")
        port = int(port)
    except:
        logging.getLogger("NetConsole").error(traceback.format_exc())
        logging.getLogger("NetConsole").error("Failed getting Host, Port from registry path %s"%(key_path))
    return (host, port)



global LOG_DIR
LOG_DIR = None
#the max size of the rotating log file in bytes
MAX_LOGFILE_SIZE = 100000
#the number of rotating log files
BACKUP_COUNT=5

def addLogger(ip, format='%(asctime)s %(message)s'):
    try:
        #TODO configure a rotating file handler
        #newHandler = logging.FileHandler(filename=os.path.join(LOG_DIR,"%s.log"%(ip)))
        newHandler = handlers.RotatingFileHandler(filename=os.path.join(LOG_DIR,"%s.log"%(ip)),
                                        mode='a',
                                        maxBytes=MAX_LOGFILE_SIZE,
                                        backupCount=BACKUP_COUNT)
        newHandler.setLevel(logging.NOTSET)
        newFormatter = logging.Formatter(format)
        newHandler.setFormatter(newFormatter)
        logging.getLogger(ip).addHandler(newHandler)
        logging.getLogger("NetConsole").debug("ip = '%s' - entered"%(ip))
    except:
        logging.getLogger("NetConsole").error(traceback.format_exc())



class NetConsoleHandler(SocketServer.BaseRequestHandler):
    
    def tryLog(self,ip,data):
        #logging.getLogger("NetConsole").debug("ip='%s', data='%s'"%(ip,data))
        curLogger = logging.getLogger(ip)
        if len(curLogger.handlers) == 0:
            addLogger(ip)
            curLogger = logging.getLogger(ip)
        curLogger.info(data)

    
    def handle(self):
        try:
            remote = self.client_address
            curip = remote[0]
            data, skt = self.request
            self.tryLog(curip,data)
        except:
            logging.getLogger("NetConsole").error(traceback.format_exc())
            

class NetConsoleServer(SocketServer.UDPServer):
    def __init__(self, host, port):
        self._enabled = False
        try:
            logging.getLogger("NetConsole").info("entered")
            self.ip = socket.gethostbyname(host)
            self.port = port
            myaddr = (self.ip, self.port)
            logging.getLogger("NetConsole").info("hostname='%s', ip='%s', port='%s'"%(host, self.ip, str(self.port)))
            SocketServer.UDPServer.__init__(self, myaddr, NetConsoleHandler)
            self._enabled = True
        except:
            logging.getLogger("NetConsole").error(traceback.format_exc())
            
    def controled_serve_forever(self):
        logging.getLogger("NetConsole").info("entered")
        while self._enabled:
            try:
                self.handle_request()
            except:
                logging.getLogger("NetConsole").error(traceback.format_exc())
            
    def shutdown(self):
        try:
            logging.getLogger("NetConsole").debug("entered")
            self._enabled = False
            srvaddr = (self.ip, self.port)
            data = "Stopping the NetConsoleServer"
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            sock.bind(('',0))
            sock.sendto(data, srvaddr)
        except:
            logging.getLogger("NetConsole").error(traceback.format_exc())
            



class pyNetConsoleService(win32serviceutil.ServiceFramework):
    _svc_name_ = "RHEVMNetConsole"
    _svc_display_name_ = "RHEVM Net Console"
    _svc_description_ = "RHEVM Net Console service - listens to a UDP port and logs in the messages sent from the VDSs "
    _svc_deps_ = ["EventLog"]
    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        self.consoleServer.shutdown()

    def SvcDoRun(self):
        global LOG_DIR
        import servicemanager
        # Write a 'started' event to the event log...
        win32evtlogutil.ReportEvent(self._svc_name_,
                                    servicemanager.PYS_SERVICE_STARTED,
                                    0, # category
                                    servicemanager.EVENTLOG_INFORMATION_TYPE,
                                    (self._svc_name_, ''))
        solidIcePath = getSolidIceInstallPath()
        LOG_DIR = getLogsDirectory(solidIcePath)
        logging.getLogger('').setLevel(logging.DEBUG)
        addLogger("NetConsole", '%(asctime)s::%(levelname)s::%(funcName)s::%(message)s')
        host,port = getHostPortFromRegistry()
        self.consoleServer = NetConsoleServer(host,port)
        self.consoleServer.controled_serve_forever()
        

        # and write a 'stopped' event to the event log.
        win32evtlogutil.ReportEvent(self._svc_name_,
                                    servicemanager.PYS_SERVICE_STOPPED,
                                    0, # category
                                    servicemanager.EVENTLOG_INFORMATION_TYPE,
                                    (self._svc_name_, ''))


if __name__ == '__main__':
    # Note that this code will not be run in the 'frozen' exe-file!!!
    win32serviceutil.HandleCommandLine(pyNetConsoleService)
