Commit 1bd118f7 by Bach Dániel

Merge branch 'issue-102-rebased' into 'master'

Fix node scalability #102
parents 6b0da54a 24cf80ad
{% load i18n %} {% load i18n %}
<div id="node-list-column-vm"> <div id="node-list-column-vm">
<a class="real-link" href="{% url "dashboard.views.node-detail" pk=record.pk %}#virtualmachines">{{ record.instance_set.count }}</a> <a class="real-link" href="{% url "dashboard.views.node-detail" pk=record.pk %}#virtualmachines">{{ value }}</a>
</div> </div>
...@@ -14,6 +14,7 @@ from django.core.exceptions import ( ...@@ -14,6 +14,7 @@ from django.core.exceptions import (
) )
from django.core import signing from django.core import signing
from django.core.urlresolvers import reverse, reverse_lazy from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import Count
from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import redirect, render, get_object_or_404 from django.shortcuts import redirect, render, get_object_or_404
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
...@@ -921,10 +922,13 @@ class VmList(LoginRequiredMixin, SingleTableView): ...@@ -921,10 +922,13 @@ class VmList(LoginRequiredMixin, SingleTableView):
class NodeList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView): class NodeList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
template_name = "dashboard/node-list.html" template_name = "dashboard/node-list.html"
model = Node
table_class = NodeListTable table_class = NodeListTable
table_pagination = False table_pagination = False
def get_queryset(self):
return Node.objects.annotate(
number_of_VMs=Count('instance_set')).select_related('host')
class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView): class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
template_name = "dashboard/group-list.html" template_name = "dashboard/group-list.html"
......
...@@ -25,6 +25,17 @@ from django.utils import timezone ...@@ -25,6 +25,17 @@ from django.utils import timezone
logger = getLogger(__name__) logger = getLogger(__name__)
def node_available(function):
"""Decorate methods to ignore disabled Nodes.
"""
def decorate(self, *args, **kwargs):
if self.enabled and self.online:
return function(self, *args, **kwargs)
else:
return None
return decorate
class Node(TimeStampedModel): class Node(TimeStampedModel):
"""A VM host machine, a hypervisor. """A VM host machine, a hypervisor.
...@@ -55,19 +66,22 @@ class Node(TimeStampedModel): ...@@ -55,19 +66,22 @@ class Node(TimeStampedModel):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
@method_cache(10, 5) @method_cache(10)
def get_online(self): def get_online(self):
"""Check if the node is online. """Check if the node is online.
Runs a remote ping task if the worker is running. Check if node is online by queue is available.
""" """
try: try:
return self.remote_query(vm_tasks.ping, timeout=1, default=False) self.get_remote_queue_name("vm")
except WorkerNotFound: except:
return False return False
else:
return True
online = property(get_online) online = property(get_online)
@node_available
@method_cache(300) @method_cache(300)
def get_num_cores(self): def get_num_cores(self):
"""Number of CPU threads available to the virtual machines. """Number of CPU threads available to the virtual machines.
...@@ -106,6 +120,7 @@ class Node(TimeStampedModel): ...@@ -106,6 +120,7 @@ class Node(TimeStampedModel):
self.get_num_cores(invalidate_cache=True) self.get_num_cores(invalidate_cache=True)
self.get_ram_size(invalidate_cache=True) self.get_ram_size(invalidate_cache=True)
@node_available
@method_cache(300) @method_cache(300)
def get_ram_size(self): def get_ram_size(self):
"""Bytes of total memory in the node. """Bytes of total memory in the node.
...@@ -115,6 +130,7 @@ class Node(TimeStampedModel): ...@@ -115,6 +130,7 @@ class Node(TimeStampedModel):
ram_size = property(get_ram_size) ram_size = property(get_ram_size)
@property @property
@node_available
def ram_size_with_overcommit(self): def ram_size_with_overcommit(self):
"""Bytes of total memory including overcommit margin. """Bytes of total memory including overcommit margin.
""" """
...@@ -198,6 +214,7 @@ class Node(TimeStampedModel): ...@@ -198,6 +214,7 @@ class Node(TimeStampedModel):
else: else:
return default return default
@node_available
def get_monitor_info(self): def get_monitor_info(self):
try: try:
handler = GraphiteHandler() handler = GraphiteHandler()
...@@ -229,17 +246,21 @@ class Node(TimeStampedModel): ...@@ -229,17 +246,21 @@ class Node(TimeStampedModel):
return collected return collected
@property @property
@node_available
def cpu_usage(self): def cpu_usage(self):
return float(self.get_monitor_info()["cpu.usage"]) / 100 return float(self.get_monitor_info()["cpu.usage"]) / 100
@property @property
@node_available
def ram_usage(self): def ram_usage(self):
return float(self.get_monitor_info()["memory.usage"]) / 100 return float(self.get_monitor_info()["memory.usage"]) / 100
@property @property
@node_available
def byte_ram_usage(self): def byte_ram_usage(self):
return self.ram_usage * self.ram_size return self.ram_usage * self.ram_size
@node_available
def update_vm_states(self): def update_vm_states(self):
"""Update state of Instances running on this Node. """Update state of Instances running on this Node.
...@@ -284,7 +305,8 @@ class Node(TimeStampedModel): ...@@ -284,7 +305,8 @@ class Node(TimeStampedModel):
@classmethod @classmethod
def get_state_count(cls, online, enabled): def get_state_count(cls, online, enabled):
return len([1 for i in cls.objects.filter(enabled=enabled).all() return len([1 for i in
cls.objects.filter(enabled=enabled).select_related('host')
if i.online == online]) if i.online == online])
@permalink @permalink
......
from django.core.cache import cache
from logging import getLogger
from manager.mancelery import celery from manager.mancelery import celery
logger = getLogger(__name__)
def check_queue(node_hostname, queue_id): def check_queue(node_hostname, queue_id):
drivers = ['vmdriver', 'netdriver', 'agentdriver'] """True if the queue is alive.
worker_list = [node_hostname + "." + d for d in drivers]
Example: check_queue('node01', 'vm'):
:param node_hostname: Short hostname of the node.
:param queue_id: Queue identifier (eg. vm).
"""
# drivers = ['vmdriver', 'netdriver', 'agentdriver']
# worker_list = [node_hostname + "." + d for d in drivers]
queue_name = node_hostname + "." + queue_id queue_name = node_hostname + "." + queue_id
inspect = celery.control.inspect(worker_list) active_queues = get_queues()
active_queues = inspect.active_queues()
if active_queues is None: if active_queues is None:
return False return False
# v is List of List of queues dict # v is List of List of queues dict
...@@ -18,6 +28,22 @@ def check_queue(node_hostname, queue_id): ...@@ -18,6 +28,22 @@ def check_queue(node_hostname, queue_id):
return False return False
def get_queues():
"""Get active celery queues.
Result is cached for 10 seconds!
"""
key = __name__ + u'queues'
result = cache.get(key)
if result is None:
inspect = celery.control.inspect()
inspect.timeout = 0.1
result = inspect.active_queues()
logger.debug('Queue list of length %d cached.', len(result))
cache.set(key, result, 10)
return result
@celery.task(name='vmdriver.create') @celery.task(name='vmdriver.create')
def deploy(params): def deploy(params):
pass pass
......
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