Commit 4d7f1820 by cloud

dashboard, manager, vm: added new scheduler functionality

parent aa92a44d
Pipeline #633 passed with stage
in 0 seconds
...@@ -65,7 +65,10 @@ ...@@ -65,7 +65,10 @@
"modified": "2014-02-19T21:11:34.671Z", "modified": "2014-02-19T21:11:34.671Z",
"priority": 1, "priority": 1,
"traits": [], "traits": [],
"host": 1 "host": 1,
"ram_weight": 1.0,
"cpu_weight": 1.0,
"time_stamp": "2017-12-13T21:08:08.819Z"
} }
} }
] ]
...@@ -67,15 +67,23 @@ def select_node(instance, nodes): ...@@ -67,15 +67,23 @@ def select_node(instance, nodes):
logger.warning('select_node: no enough RAM for %s', unicode(instance)) logger.warning('select_node: no enough RAM for %s', unicode(instance))
raise NotEnoughMemoryException() raise NotEnoughMemoryException()
# sort nodes first by processor usage, then priority # sort nodes first by sorting_key, then priority
nodes.sort(key=lambda n: n.priority, reverse=True) nodes.sort(key=lambda n: n.priority, reverse=True)
nodes.sort(key=free_cpu_time, reverse=True) nodes.sort(key=sorting_key, reverse=True)
result = nodes[0] result = nodes[0]
logger.info('select_node: %s for %s', unicode(result), unicode(instance)) logger.info('select_node: %s for %s', unicode(result), unicode(instance))
return result return result
def sorting_key(node):
"""Determines how valuable a node is for scheduling.
"""
if free_cpu_time(node) < free_ram(node):
return free_cpu_time(node)
return free_ram(node)
def has_traits(traits, node): def has_traits(traits, node):
"""True, if the node has all specified traits; otherwise, false. """True, if the node has all specified traits; otherwise, false.
""" """
...@@ -116,11 +124,27 @@ def free_cpu_time(node): ...@@ -116,11 +124,27 @@ def free_cpu_time(node):
Higher values indicate more idle time. Higher values indicate more idle time.
""" """
try: try:
activity = node.cpu_usage / 100 free_cpu_percent = 1 - node.cpu_usage
inactivity = 1 - activity weight = node.cpu_weight
cores = node.num_cores weighted_value = free_cpu_percent * weight
return cores * inactivity return weighted_value
except TypeError as e: except TypeError as e:
logger.warning('Got incorrect monitoring data for node %s. %s', logger.warning('Got incorrect monitoring data for node %s. %s',
unicode(node), unicode(e)) unicode(node), unicode(e))
return False # monitoring data is incorrect return False # monitoring data is incorrect
def free_ram(node):
"""Get an indicator number for free RAM on the node.
Higher value indicates more RAM.
"""
try:
free_ram_percent = 1 - node.ram_usage
weight = node.ram_weight
weighted_value = free_ram_percent * weight
return weighted_value
except TypeError as e:
logger.exception('Got incorrect monitoring data for node %s. %s',
unicode(node), unicode(e))
return 0
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-13 20:18
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('vm', '0002_interface_model'),
]
operations = [
migrations.AddField(
model_name='node',
name='cpu_weight',
field=models.FloatField(default=1.0, help_text='Indicates the relative CPU power of this node.', verbose_name='CPU Weight'),
),
migrations.AddField(
model_name='node',
name='ram_weight',
field=models.FloatField(default=1.0, help_text='Indicates the relative RAM quantity of this node.', verbose_name='RAM Weight'),
),
migrations.AddField(
model_name='node',
name='time_stamp',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, help_text='A timestamp for the node, used by the scheduler.', verbose_name='Last Scheduled Time Stamp'),
preserve_default=False,
),
]
...@@ -30,7 +30,7 @@ from time import time, sleep ...@@ -30,7 +30,7 @@ from time import time, sleep
from django.conf import settings from django.conf import settings
from django.db.models import ( from django.db.models import (
CharField, IntegerField, ForeignKey, BooleanField, ManyToManyField, CharField, IntegerField, ForeignKey, BooleanField, ManyToManyField,
FloatField, permalink, Sum FloatField, DateTimeField, permalink, Sum
) )
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -128,11 +128,15 @@ class Node(OperatedMixin, TimeStampedModel): ...@@ -128,11 +128,15 @@ class Node(OperatedMixin, TimeStampedModel):
enabled = BooleanField(verbose_name=_('enabled'), default=False, enabled = BooleanField(verbose_name=_('enabled'), default=False,
help_text=_('Indicates whether the node can ' help_text=_('Indicates whether the node can '
'be used for hosting.')) 'be used for hosting.'))
schedule_enabled = BooleanField(verbose_name=_('schedule enabled'), schedule_enabled = BooleanField(
default=False, help_text=_( verbose_name=_('schedule enabled'),
'Indicates whether a vm can be ' default=False,
'automatically scheduled to this ' help_text=_(
'node.')) 'Indicates whether a vm can be '
'automatically scheduled to this '
'node.'
)
)
traits = ManyToManyField(Trait, blank=True, traits = ManyToManyField(Trait, blank=True,
help_text=_("Declared traits."), help_text=_("Declared traits."),
verbose_name=_('traits')) verbose_name=_('traits'))
...@@ -140,6 +144,21 @@ class Node(OperatedMixin, TimeStampedModel): ...@@ -140,6 +144,21 @@ class Node(OperatedMixin, TimeStampedModel):
overcommit = FloatField(default=1.0, verbose_name=_("overcommit ratio"), overcommit = FloatField(default=1.0, verbose_name=_("overcommit ratio"),
help_text=_("The ratio of total memory with " help_text=_("The ratio of total memory with "
"to without overcommit.")) "to without overcommit."))
ram_weight = FloatField(
default=1.0,
help_text=_("Indicates the relative RAM quantity of this node."),
verbose_name=_("RAM Weight")
)
cpu_weight = FloatField(
default=1.0,
help_text=_("Indicates the relative CPU power of this node."),
verbose_name=_("CPU Weight")
)
time_stamp = DateTimeField(
auto_now_add=True,
help_text=_("A timestamp for the node, used by the scheduler."),
verbose_name=_("Last Scheduled Time Stamp")
)
class Meta: class Meta:
app_label = 'vm' app_label = 'vm'
...@@ -162,7 +181,7 @@ class Node(OperatedMixin, TimeStampedModel): ...@@ -162,7 +181,7 @@ class Node(OperatedMixin, TimeStampedModel):
self.get_remote_queue_name("vm", "fast") self.get_remote_queue_name("vm", "fast")
self.get_remote_queue_name("vm", "slow") self.get_remote_queue_name("vm", "slow")
self.get_remote_queue_name("net", "fast") self.get_remote_queue_name("net", "fast")
except: except Exception:
return False return False
else: else:
return True return True
...@@ -353,7 +372,7 @@ class Node(OperatedMixin, TimeStampedModel): ...@@ -353,7 +372,7 @@ class Node(OperatedMixin, TimeStampedModel):
continue continue
return retval return retval
except: except Exception:
logger.exception('Unhandled exception: ') logger.exception('Unhandled exception: ')
return self.remote_query(vm_tasks.get_node_metrics, timeout=30, return self.remote_query(vm_tasks.get_node_metrics, timeout=30,
priority="fast") priority="fast")
...@@ -413,7 +432,7 @@ class Node(OperatedMixin, TimeStampedModel): ...@@ -413,7 +432,7 @@ class Node(OperatedMixin, TimeStampedModel):
# [{'name': 'cloud-1234', 'state': 'RUNNING', ...}, ...] # [{'name': 'cloud-1234', 'state': 'RUNNING', ...}, ...]
try: try:
id = int(i['name'].split('-')[1]) id = int(i['name'].split('-')[1])
except: except Exception:
pass # name format doesn't match pass # name format doesn't match
else: else:
domains[id] = i['state'] domains[id] = i['state']
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment