scheduler.py 2.02 KB
Newer Older
1 2 3 4
from django.db.models import Sum


class NotEnoughMemoryException(Exception):
5

6 7 8 9 10 11 12 13
    def __init__(self, message=None):
        if message is None:
            message = "No node has enough memory to accomodate the guest."

        Exception.__init__(self, message)


class TraitsUnsatisfiableException(Exception):
14

15 16 17 18 19 20 21
    def __init__(self, message=None):
        if message is None:
            message = "No node can satisfy all required traits of the guest."

        Exception.__init__(self, message)


22
def select_node(instance, nodes):
23
    ''' Select a node for hosting an instance based on its requirements.
tarokkk committed
24
    '''
25
    # check required traits
26 27
    nodes = [n for n in nodes
             if n.enabled and has_traits(instance.req_traits.all(), n)]
28 29 30 31 32 33 34 35 36 37
    if not nodes:
        raise TraitsUnsatisfiableException()

    # check required RAM
    nodes = [n for n in nodes if has_enough_ram(instance.ram_size, n)]
    if not nodes:
        raise NotEnoughMemoryException()

    # sort nodes first by processor usage, then priority
    nodes.sort(key=lambda n: n.priority, reverse=True)
38
    nodes.sort(key=free_cpu_time, reverse=True)
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

    return nodes[0]


def has_traits(traits, node):
    """True, if the node has all specified traits; otherwise, false.
    """
    traits = set(traits)
    return traits.issubset(node.traits.all())


def has_enough_ram(ram_size, node):
    """True, if the node has enough memory to accomodate a guest requiring
       ram_size mebibytes of memory; otherwise, false.
    """
    total = node.ram_size
55
    used = (node.ram_usage / 100) * total
56 57 58 59 60 61 62 63 64
    unused = total - used

    overcommit = node.ram_size_with_overcommit
    reserved = node.instance_set.aggregate(r=Sum('ram_size'))['r'] or 0
    free = overcommit - reserved

    return ram_size < unused and ram_size < free


65 66
def free_cpu_time(node):
    """Get an indicator number for idle processor time on the node.
67

68
    Higher values indicate more idle time.
69
    """
70
    activity = node.cpu_usage / 100
71 72
    inactivity = 1 - activity
    cores = node.num_cores
73
    return cores * inactivity