#!/usr/bin/env python
#
#   ConVirt   -  Copyright (c) 2008 Convirture Corp.
#   ======
#
# ConVirt is a Virtualization management tool with a graphical user
# interface that allows for performing the standard set of VM operations
# (start, stop, pause, kill, shutdown, reboot, snapshot, etc...). It
# also attempts to simplify various aspects of VM lifecycle management.
#
#
# This software is subject to the GNU General Public License, Version 2 (GPLv2)
# and for details, please consult it at:
#
#    http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
# 
#
#

from convirt.core.model.ManagedNode import ManagedNode

class ServerGroup:
    def __init__(self, name, node_list = None, group_vars = None):
        self.name = name
        self.id = name
        self.n_list = {}   # dict()
        self.groupVars = {} # dict

        self.alloc_policy = SimpleAllocationPolicy(self) #TBD: parametrise!
        
        if node_list is not None:
            self.n_list = node_list

        if group_vars is not None:
            self.groupVars = group_vars

    def getName(self):
        return self.name
                    
    def getNodeNames(self):
        return self.n_list.keys()
    
    def getNodeList(self):
        return self.n_list

    def getNode(self,name):
        return self.n_list.get(name)
    
    def getGroupVars(self):
        return self.groupVars
    
    def getGroupVarValue(self, var):
        return self.groupVars.get( var )

    def getAllocationCandidate(self, ctx):
        return self.alloc_policy.getNext(ctx)

    def setGroupVars(self, vars):
        self.groupVars = vars
        
    # note does not update the store. Should not be called by client.
    def _addNode(self, node):
        if self.n_list.get(node.hostname) is None:
            self.n_list[node.hostname] = node
        else:
            raise Exception("Node %s already exists." %
                            (node.hostname,))


    def _removeNode(self, name):
        if name in self.getNodeNames():
            del self.n_list[name]
                    
    def __str__(self):
        return  self.name + "||" + str(self.n_list.keys()) + "||" + str(self.groupVars.keys())
        

class SimpleAllocationPolicy:
    """
    Policy for determining the best provisioning candidate
    amongst a group's members. A candidate is selected if
    it has the minimum:
        1. VM CPU utilisation
        2. VM Mem allocation
        3. number of VM's configured        
    in that order.
    """
    def __init__(self, group = None):
        self._group = group

    def setGroup(self, group):
        self._group = group

    def filter_node(self, node, ctx):
        result = node.is_authenticated()
        if ctx and result and ctx.image:
            result =  node.is_image_compatible(ctx.image)
        #print "returning ", result, " for ", node.hostname
        return result
    
    def getNext(self, ctx):
        list = [(self._group.getNode(n).get_metrics()['VM_TOTAL_CPU(%)'],
                 self._group.getNode(n).get_metrics()['VM_TOTAL_MEM(%)'],
                 self._group.getNode(n).get_VM_count(),
                 self._group.getNode(n).hostname) \
                for n in self._group.getNodeNames() if self.filter_node(self._group.getNode(n), ctx)]
        if len(list) == 0:
            return None
        else:
            return self._group.getNode(min(list)[3])

        
    
