#!/usr/pythoncontroller/python

import sys
from testutil import *
from testhelpers import *
import time
import os
import json 
from subprocess import *
from threading import Thread, current_thread

def parseNameValuePairs(list):
    args = {}
    for arg in list:
        if arg.find('=') != -1:
            args[arg.split('=')[0]] = arg.split('=')[1]
    return args

def parseargs(listOfArgs):
    return parseNameValuePairs(listOfArgs[1:])

def help():
    print "Usage: show_vm_distribution openstack_ip=<OPENSTACK_IP>"
    sys.exit()

def ensureRequiredParamsPresent(dict, required_keys):
    for key in required_keys:
        if not dict.has_key(key):
            help()
            sys.exit()

def getFormat(message):
    return time.strftime('%d-%m-%Y-%H:%M:%S ', time.gmtime()) + ': %d : %s : ' % (os.getpid(), current_thread().name) + message

args = parseargs(sys.argv)
ensureRequiredParamsPresent(args, ['openstack_ip'])
openstack_ip = args['openstack_ip']

# get the openstack node ID
openstack_node_id = int(runOnOpenstackAndGetPairs(openstack_ip, '/root/osd get_groups --if=is_reserved --filter=disk_ids')['disk_idss'].strip('[').strip(']'))

#print "Not doing anything to speed up tests, change me later"
#sys.exit(0)

try:
    # nodeToNumReservedCores
    reserved_group_info = getGroupInfo(openstack_ip, '1')
    reserved_cores = reserved_group_info['cores']
    nodeToNumReservedCores = {}
    for core in reserved_cores.split(','):
        node = core.split('_')[0]
        if nodeToNumReservedCores.has_key(node):
            nodeToNumReservedCores[node] += 1
        else:
            nodeToNumReservedCores[node] = 1
    #print "nodeToNumReservedCores: %s" % nodeToNumReservedCores

    # now get group based stats
    out = runCommandOnNodeAndGetOutput(openstack_ip, '/root/osd get_groups --if-not=is_reserved --filter=id').strip()
    pairs = splitNameValuePairs(out)
    if pairs['result'] == 'FAILURE':
        raise Exception('Could not fetch group information, error %s' % out)
    group_ids = pairs['ids'].split(',')

    for group_id in group_ids:
        all_nodes = getNodesForGroup(openstack_ip, group_id)
	# cpu_overcommit, all_cores_for_group
	group_info = getGroupInfo(openstack_ip, group_id)
	cpu_overcommit = int(group_info['cpu_overcommit'])
	all_cores_for_group = group_info['cores'].split(',')
	#print "cpu_overcommit: %d, all_cores_for_group:%s" % (cpu_overcommit, all_cores_for_group)

	# avail_memorys, total_cores, committed_memorys, virtual_cores, node_mvgroup_ids
	all_nodes = all_nodes.split(',')
	nodeToAvailableMemory = {}
	nodeToTotalMemory = {}
	availableMemoryToNodes = {}
	nodeToCommittedMemory = {}
	nodeToPhysicalCores = {}
	nodeToVirtualCores = {}
	mvgroupidToNode = {}
	for node in all_nodes:
	    node_info = getNodeInfoMV(openstack_ip, node)
	    nodeToTotalMemory[node] = int(node_info['total_memory'])
	    nodeToAvailableMemory[node] = int(node_info['avail_memory'])
	    if availableMemoryToNodes.has_key(int(node_info['avail_memory'])):
		availableMemoryToNodes[int(node_info['avail_memory'])].append(node)
	    else:
		availableMemoryToNodes[int(node_info['avail_memory'])] = [node]

	    nodeToCommittedMemory[node] = int(node_info['committed_memory'])
	    nodeToPhysicalCores[node] = int(node_info['total_cores'])
	    nodeToVirtualCores[node] = int(node_info['virtual_cores'])
	    mvgroupidToNode[node_info['mvgroup_id']] = node
	#print "nodeToAvailableMemory: %s" % nodeToAvailableMemory
	#print "availableMemoryToNodes: %s" % availableMemoryToNodes
	#print "nodeToCommittedMemory: %s" % nodeToCommittedMemory
	#print "nodeToPhysicalCores: %s " % nodeToPhysicalCores
	#print "nodeToVirtualCores: %s" % nodeToVirtualCores
	#print "mvgroupidToNode: %s" % mvgroupidToNode
       
	nodeToAvailableCores = {}

	# disk_node_ids, disk_mvgroup_ids, disk_total_spaces, disk_used_spaces
        out = runCommandOnNodeAndGetOutput(openstack_ip, '/root/osd get_group --id=%s --datastores --filter=id' % group_id).strip()
        pairs = splitNameValuePairs(out)
        if pairs['result'] == 'FAILURE':
            raise Exception('Could not fetch datastore information for group %s, error %s' % (group_id, out))
        datastore_id = pairs['ids'].split(',')[0]
	nodes_info = runOnOpenstackAndGetPairs(openstack_ip, 
	    '/root/osd get_datastore --id=%s --disks --filter=id,mvgroup_id,used,total' % datastore_id)
	disk_node_ids = nodes_info['ids'].split(',')
	disk_mvgroup_ids = nodes_info['mvgroup_ids'].split(',')
	disk_total_spaces = nodes_info['totals'].split(',')
	disk_used_spaces = nodes_info['useds'].split(',')
	#print "disk_node_ids: %s, disk_mvgroup_ids: %s, disk_total_spaces: %s, disk_used_spaces: %s" % (disk_node_ids, disk_mvgroup_ids, disk_total_spaces, disk_used_spaces)

	# overcommit_disk
	datastore_info = runOnOpenstackAndGetPairs(openstack_ip, 
	    '/root/osd get_datastore --id=%s --filter=overcommit_disk' % datastore_id)
	overcommit_disk = datastore_info['overcommit_disk']
	#print "overcommit_disk: %s" % overcommit_disk

	# nodeToAvailableStorage
	nodeToAvailableStorage = {}
	index = 0
	for disk_mvgroup_id in disk_mvgroup_ids:
	    available_storage = int(disk_total_spaces[index]) - int(disk_used_spaces[index])
	    if mvgroupidToNode.has_key(disk_mvgroup_id):
		node_for_disk = mvgroupidToNode[disk_mvgroup_id]
	    if nodeToAvailableStorage.has_key(node_for_disk):
		if nodeToAvailableStorage[node_for_disk] > available_storage:
		    nodeToAvailableStorage[node_for_disk] = int(available_storage)
	    else:
		nodeToAvailableStorage[node_for_disk] = int(available_storage)

	#print "nodeToAvailableStorage: %s" % nodeToAvailableStorage
	# nodeToAvailableCores
	for node in nodeToVirtualCores.iterkeys():
	    virtual_core = nodeToVirtualCores[node]
	    total_core = nodeToPhysicalCores[node]
	    if cpu_overcommit:
		max_cores = ((total_core-nodeToNumReservedCores[node])*(100+cpu_overcommit))/100  
	    else:
		max_cores = total_core-nodeToNumReservedCores[node]
	    available_cores = max_cores - virtual_core 
	    nodeToAvailableCores[node] = available_cores

	#print "nodeToAvailableCores:%s"  % nodeToAvailableCores
        table = 'Group ID: %s\tCore_Overcommit: %d\n%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % (group_id, cpu_overcommit, 'Node', 'Total', 'Available', 'Committed', 'TotalPhysical', \
            'Reserved', 'Physical', 'Total', 'Used', 'Available', 'Available', 'VMs', 'Optimised', 'Nonoptimised', 'Load', 'NodeID', 'VDisk', 'Utilisation', 'Allocatedspace_MB')
        table += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % ('', 'memory', 'memory', 'memory', 'cores', 'cores', 'cores', 'cores', 'cores', 'cores', 'storage', '', 'VMs', 'VMs', '' , '', 'members', '', '')
	for node in nodeToAvailableMemory.iterkeys():
            #print getFormat("Getting instances for node: %s" % node)
	    instance_info = getInstancesForNode(openstack_ip, node)
            #print getFormat("Got instances for node: %s" % node)
            optimised = instance_info['optimised']
            non_optimised = instance_info['non_optimised']
            #for instance in instance_info['instances'].split(','):
                #owners = getStorageOwnersForVM(openstack_ip, instance)
                #if node in owners:
                
            #        optimised += 1
            #    else:
            #        non_optimised += 1
	    total_core_wo_oc = nodeToPhysicalCores[node]-nodeToNumReservedCores[node]
	    total_cores = (total_core_wo_oc*(100+cpu_overcommit))/100
            nodetoutilisationPairs = getNodeToUtilisationForStorageNode(openstack_ip, node)
            nodeid, utilisation = nodetoutilisationPairs[0]
            allocatedspace_MB = getNodeInfo(nodeid, openstack_ip)['allocatedspace_MB']
            load = getLoadOnNode(openstack_ip, node)
	    if nodeToAvailableStorage.has_key(node):
                if len(nodetoutilisationPairs) > 1:
                    temptable = ''
                    complete_utilisation = 0
                    complete_allocatedspace_MB = 0
                    total_vdisks = 0
                    for nodeid,utilisation in nodetoutilisationPairs:
                        num_vdisks = int(getVDiskMembersOnNode(openstack_ip, node, nodeid))
                        total_vdisks += num_vdisks
                        complete_utilisation += int(utilisation) 
                        allocatedspace_MB = getNodeInfo(nodeid, openstack_ip)['allocatedspace_MB']
                        complete_allocatedspace_MB += int(allocatedspace_MB)
                        if nodeid == openstack_node_id:
                            temptable += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                                ('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'OS-%s' % nodeid, str(num_vdisks), utilisation, allocatedspace_MB) 
                        else:
                            temptable += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                                ('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', nodeid, str(num_vdisks), utilisation, allocatedspace_MB) 
                    average_utilisation = complete_utilisation/len(nodetoutilisationPairs)
                    table += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                        (node, nodeToTotalMemory[node], nodeToAvailableMemory[node],
                        nodeToCommittedMemory[node], nodeToPhysicalCores[node], nodeToNumReservedCores[node], total_core_wo_oc,
                        total_cores, nodeToVirtualCores[node], nodeToAvailableCores[node], nodeToAvailableStorage[node], instance_info['num_instances'], optimised, non_optimised, load, 'Member', total_vdisks, str(average_utilisation), str(complete_allocatedspace_MB))
                    table += temptable
                else:
                    num_vdisks = getVDiskMembersOnNode(openstack_ip, node, nodeid)
                    if nodeid == openstack_node_id:
                        table += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                            (node, nodeToTotalMemory[node], nodeToAvailableMemory[node],
                            nodeToCommittedMemory[node], nodeToPhysicalCores[node], nodeToNumReservedCores[node], total_core_wo_oc,
                            total_cores, nodeToVirtualCores[node], nodeToAvailableCores[node], nodeToAvailableStorage[node], instance_info['num_instances'], optimised, non_optimised, load, 'OS-%s' % nodeid, num_vdisks, utilisation, allocatedspace_MB)
                    else:
                        table += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                            (node, nodeToTotalMemory[node], nodeToAvailableMemory[node],
                            nodeToCommittedMemory[node], nodeToPhysicalCores[node], nodeToNumReservedCores[node], total_core_wo_oc,
                            total_cores, nodeToVirtualCores[node], nodeToAvailableCores[node], nodeToAvailableStorage[node], instance_info['num_instances'], optimised, non_optimised, load, nodeid, num_vdisks, utilisation, allocatedspace_MB)
            else:
                if len(nodetoutilisationPairs) > 1:
                    temptable = ''
                    complete_utilisation = 0
                    complete_allocatedspace_MB = 0
                    total_vdisks = 0
                    for nodeid,utilisation in nodetoutilisationPairs:
                        num_vdisks = getVDiskMembersOnNode(openstack_ip, node, nodeid)
                        complete_utilisation += int(utilisation)
                        allocatedspace_MB = getNodeInfo(nodeid, openstack_ip)['allocatedspace_MB']
                        complete_allocatedspace_MB += int(allocatedspace_MB)
                        if nodeid == openstack_node_id:
                            temptable += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                                ('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'OS-%s' % nodeid, str(num_vdisks), utilisation, allocatedspace_MB)
                        else:
                            temptable += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                                ('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', nodeid, str(num_vdisks), utilisation, allocatedspace_MB)
                    average_utilisation = complete_utilisation/len(nodetoutilisationPairs)
                    table += '%4s\t%7s\t%9s\t%9s\t%13s\t%8s\t%8s\t%5s\t%5s\t%9s\t%9s\t%4s\t%9s\t%12s\t%5s\t%14s\t%7s\t%11s\t%17s\n' % \
                        (node, nodeToTotalMemory[node], nodeToAvailableMemory[node],
                        nodeToCommittedMemory[node], nodeToPhysicalCores[node], nodeToNumReservedCores[node], total_core_wo_oc,
                        total_cores, nodeToVirtualCores[node], nodeToAvailableCores[node], '0', instance_info['num_instances'], optimised, non_optimised, load, 'Member', total_vdisks, str(average_utilisation), str(complete_allocatedspace_MB))
                    table += temptable
        print table
finally:
    pass
