#!/usr/bin/env python

import MySQLdb
import sys
import socket
import _mysql_exceptions
import datetime
import logging

# Setup logging
logger = logging.getLogger()
formatter = logging.Formatter('%(asctime)s | %(levelname)7s | %(message)s', 
                              '%Y-%m-%dT%H:%M:%S')
logging_output = logging.StreamHandler(sys.stderr)
logging_output.setFormatter(formatter)
logger.addHandler(logging_output)
logger.setLevel(logging.INFO)

if len(sys.argv) == 1:
    usage()
    sys.exit(1)
elif sys.argv[1] == 'all':
    nodesFilename = '/home/panstarrs/schastel/local/share/ippMhpccStorageNodes'
    nodesFile = open(nodesFilename)
    nodes = []
    for line in nodesFile:
        nodes.append(line[:-1])
elif sys.argv[1] == 'set0':
    nodes = [ "ipp004", "ipp005", "ipp006", "ipp007", "ipp008", 
              "ipp009", 
              "ipp060", "ipp061", "ipp062", "ipp063", ]
elif sys.argv[1] == 'set1':
    nodes = [ "ipp010", "ipp011", "ipp012", "ipp013", "ipp014", 
              "ipp015", "ipp016", "ipp017", "ipp018", "ipp019", ]
elif sys.argv[1] == 'set2':
    nodes = [ "ipp020", "ipp021", "ipp023", "ipp024", 
              "ipp025", "ipp026", "ipp027", "ipp028", "ipp029", ]
elif sys.argv[1] == 'set3':
    nodes = [ "ipp030", "ipp031", "ipp032", "ipp033", "ipp034", 
              "ipp035", "ipp036", "ipp037", "ipp038", "ipp039", ]
elif sys.argv[1] == 'set4':
    nodes = [ "ipp040", "ipp041", "ipp042", "ipp043", "ipp044", 
              "ipp045", "ipp046", "ipp047", "ipp048", "ipp049", ]
elif sys.argv[1] == 'set5':
    nodes = [ "ipp050", "ipp051", "ipp052", "ipp053", "ipp054", 
              "ipp055", "ipp056", "ipp057", "ipp058", "ipp059", ]
else:
    nodes = sys.argv[1:]

select_query = 'SELECT role, stage, lifetime, SUM(size), COUNT(*), status FROM %s_%s GROUP BY role, stage, lifetime, status'

insert_query = """INSERT INTO CurrentDiskUsage 
SET node='%s', role='%s', stage='%s', dirname='%s', sizes=%d, counts=%d, lifetime='%s', last_update=NOW(), status='%s'"""

update_query = """UPDATE CurrentDiskUsage 
SET sizes=%d, counts=%d, last_update=NOW()
WHERE node='%s' AND role='%s' AND stage='%s' AND dirname='%s' AND lifetime='%s' AND status='%s'"""

delete_undefined_query = """DELETE FROM CurrentDiskUsage
WHERE node='%s' AND (status='undefined' OR role='undfined')
"""

nodename = socket.gethostbyaddr(socket.gethostname())[0].split('.')[0]
if nodename != 'neverland':
    fm_db = MySQLdb.connect('ippc11', 'ippMonitor', 'ippMonitor',
                            'DisksMonitoring')
    fm_cursor = fm_db.cursor()
    dms_db = MySQLdb.connect('ippc11', 'ippuser', 'ipp',
                             'DiskMonitoringSummary')
    dms_cursor = dms_db.cursor()
else:
    fm_db = MySQLdb.connect('localhost', 'root', 'root',
                            'DisksMonitoring')
    fm_cursor = fm_db.cursor()
    dms_db = MySQLdb.connect('localhost', 'root', 'root',
                             'DiskMonitoringSummary')
    dms_cursor = dms_db.cursor()
    #Ignore all nodes specification on the test platform
    nodes = [ 'neverland' ]

letters = '0123456789abcdef'
for node in nodes:
    logger.info('Getting snapshot of node: %s' % node)
    for letter1 in letters:
        logger.info('... Getting snapshot for nebulous subdirectories starting with %s (%s0, %s1, ...)' % (letter1, 
                                                                                                             letter1, 
                                                                                                             letter1))
        for letter2 in letters:
            undefined_found = False
            dirname = '%s%s' % (letter1, letter2)
            fm_cursor.execute(select_query % (node, dirname))
            for (role, stage, lifetime, size, count, status) in fm_cursor.fetchall():
                if status == 'undefined':
                    undefined_found = True
                if size < 0: 
                    size=0
                try:
                    dms_cursor.execute(insert_query % (node[:6],
                                                       role, 
                                                       stage, 
                                                       dirname,
                                                       size, 
                                                       count,
                                                       lifetime,
                                                       status) )
                except Exception, e:
                    dms_cursor.execute(update_query % (size, 
                                                       count,
                                                       node[:6],
                                                       role, 
                                                       stage, 
                                                       dirname,
                                                       lifetime,
                                                       status) )
            if not undefined_found:
                logger.debug('... No undefined found for %s' % dirname)
                try:
                    logger.debug('... Trying deleting undefined entries')
                    dms_cursor.execute(delete_undefined_query % (node[:6]) )
                except Exception, e:
                    logger.debug('... Trying update')
                    dms_cursor.execute(update_query % (0, 
                                                       0,
                                                       node[:6],
                                                       'undefined', 
                                                       'undefined', 
                                                       dirname,
                                                       'undefined',
                                                       'undefined') )
            else:
                logger.warn('... There are still undefined values for %s (in %s)' % (node, dirname))
            # Now delete all entries with status set as 'deleted'
            logger.debug('... Deleting deleted entries from %s_%s' % (node, dirname))
            try:
                fm_cursor.execute('DELETE FROM %s_%s WHERE status=\'deleted\'' % (node, dirname))
                fm_db.commit()
            except _mysql_exceptions.OperationalError, e:
                try:
                    # Try again?!
                    fm_cursor.execute('DELETE FROM %s_%s WHERE status=\'deleted\'' % (node, dirname))
                    fm_db.commit()
                except _mysql_exceptions.OperationalError, e:
                    logger.warn("Couldn't delete 'deleted' entries from %s_%s"  % (node, dirname))
    try:
        stmt = 'CALL UpdateDailyByNode(\'%s\')' % node
        logger.info('... Calling UpdateDailyByNode: [%s]' % stmt)
        dms_cursor.execute(stmt)
    except _mysql_exceptions.OperationalError, e:
        logger.warn('... MySQL Exception caught when calling UpdateDailyByNode():  ' + str(e) + '')
    try:
        logger.info('... Trying to guess if running UpdateWeeklyByNode makes sense')
        today = datetime.datetime.today()
        last_week = '%d-%d' % (today.year, today.isocalendar()[1]-1)
        query = "SELECT COUNT(*), node, role, stage, lifetime, dirname, week, status FROM DiskUsageHistoryWeekly WHERE node = \'%s\' AND week = '%s' GROUP BY node, role, stage, lifetime, dirname, week, status" % (node, last_week)
        dms_cursor.execute(query)
        row = dms_cursor.fetchone()
        run_updateweekly = (row is None)
        if run_updateweekly:
            stmt = 'CALL UpdateWeeklyByNode(\'%s\')' % node
            logger.info('... Executing: %s' % stmt)
            dms_cursor.execute(stmt)
        else:
            logger.info('... UpdateWeekly() call cancelled since last week entry already in database: %s' % last_week)
    except _mysql_exceptions.OperationalError, e:
        logger.warn('... MySQL Exception caught when calling UpdateWeekly():  ' + str(e) )
    dms_db.commit()

dms_cursor.close()
dms_db.close()

fm_cursor.close()
fm_db.close()
