diff --git a/apps/clustering/links.py b/apps/clustering/links.py index 009a2aa584..54058d9528 100644 --- a/apps/clustering/links.py +++ b/apps/clustering/links.py @@ -6,7 +6,7 @@ from navigation.api import Link from .permissions import PERMISSION_NODES_VIEW, PERMISSION_EDIT_CLUSTER_CONFIGURATION -tool_link = Link(text=_(u'clustering'), view='node_list', icon='server.png', permissions=[PERMISSION_NODES_VIEW]) # children_view_regex=[r'^index_setup', r'^template_node']) +tool_link = Link(text=_(u'clustering'), view='node_list', icon='server.png', permissions=[PERMISSION_NODES_VIEW]) node_list = Link(text=_(u'node list'), view='node_list', sprite='server', permissions=[PERMISSION_NODES_VIEW]) clustering_config_edit = Link(text=_(u'edit cluster configuration'), view='clustering_config_edit', sprite='server_edit', permissions=[PERMISSION_EDIT_CLUSTER_CONFIGURATION]) setup_link = Link(text=_(u'cluster configuration'), view='clustering_config_edit', icon='server.png', permissions=[PERMISSION_EDIT_CLUSTER_CONFIGURATION]) diff --git a/apps/clustering/literals.py b/apps/clustering/literals.py index 99c97f50d2..0644f7b5c4 100644 --- a/apps/clustering/literals.py +++ b/apps/clustering/literals.py @@ -1,3 +1,15 @@ +from django.utils.translation import ugettext_lazy as _ + DEFAULT_NODE_HEARTBEAT_INTERVAL = 10 DEFAULT_NODE_HEARTBEAT_TIMEOUT = 60 DEFAULT_DEAD_NODE_REMOVAL_INTERVAL = 10 + +NODE_STATE_HEALTHY = 'h' +NODE_STATE_DEAD = 'd' + +NODE_STATE_CHOICES = ( + (NODE_STATE_HEALTHY, _(u'healthy')), + (NODE_STATE_DEAD, _(u'dead')), +) + +DEFAULT_JOB_QUEUE_POLL_INTERVAL = 2 diff --git a/apps/clustering/migrations/0006_auto__add_field_node_state.py b/apps/clustering/migrations/0006_auto__add_field_node_state.py new file mode 100644 index 0000000000..7d8b7f98d8 --- /dev/null +++ b/apps/clustering/migrations/0006_auto__add_field_node_state.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Node.state' + db.add_column('clustering_node', 'state', + self.gf('django.db.models.fields.CharField')(default='h', max_length=4), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Node.state' + db.delete_column('clustering_node', 'state') + + + models = { + 'clustering.clusteringconfig': { + 'Meta': {'object_name': 'ClusteringConfig'}, + 'dead_node_removal_interval': ('django.db.models.fields.PositiveIntegerField', [], {'default': '10'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lock_id': ('django.db.models.fields.CharField', [], {'default': '1', 'unique': 'True', 'max_length': '1'}), + 'node_heartbeat_interval': ('django.db.models.fields.PositiveIntegerField', [], {'default': '10'}), + 'node_heartbeat_timeout': ('django.db.models.fields.PositiveIntegerField', [], {'default': '60'}) + }, + 'clustering.node': { + 'Meta': {'object_name': 'Node'}, + 'cpuload': ('django.db.models.fields.FloatField', [], {'default': '0.0', 'blank': 'True'}), + 'heartbeat': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 8, 2, 0, 0)', 'blank': 'True'}), + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'memory_usage': ('django.db.models.fields.FloatField', [], {'default': '0.0', 'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'default': "'h'", 'max_length': '4'}) + } + } + + complete_apps = ['clustering'] \ No newline at end of file diff --git a/apps/clustering/models.py b/apps/clustering/models.py index 3715184310..f7474f22bb 100644 --- a/apps/clustering/models.py +++ b/apps/clustering/models.py @@ -13,7 +13,7 @@ from django.utils.translation import ugettext, ugettext_lazy as _ from common.models import Singleton from .literals import (DEFAULT_NODE_HEARTBEAT_INTERVAL, DEFAULT_NODE_HEARTBEAT_TIMEOUT, - DEFAULT_DEAD_NODE_REMOVAL_INTERVAL) + DEFAULT_DEAD_NODE_REMOVAL_INTERVAL, NODE_STATE_HEALTHY, NODE_STATE_CHOICES, NODE_STATE_DEAD) class NodeManager(models.Manager): @@ -31,7 +31,11 @@ class Node(models.Model): cpuload = models.FloatField(blank=True, default=0.0, verbose_name=_(u'cpu load')) heartbeat = models.DateTimeField(blank=True, default=datetime.datetime.now(), verbose_name=_(u'last heartbeat check')) memory_usage = models.FloatField(blank=True, default=0.0, verbose_name=_(u'memory usage')) - + state = models.CharField(max_length=4, + choices=NODE_STATE_CHOICES, + default=NODE_STATE_HEALTHY, + verbose_name=_(u'state')) + objects = NodeManager() @classmethod @@ -50,7 +54,10 @@ class Node(models.Model): info = Node.platform_info() self.cpuload = info['cpuload'] self.memory_usage = info['memory_usage'] - + + def if_healthy(self): + return self.health == NODE_STATE_HEALTHY + def save(self, *args, **kwargs): self.heartbeat = datetime.datetime.now() return super(Node, self).save(*args, **kwargs) @@ -62,10 +69,10 @@ class Node(models.Model): class ClusteringConfigManager(models.Manager): def dead_nodes(self): - return Node.objects.filter(heartbeat__lt=datetime.datetime.now() - datetime.timedelta(seconds=self.model.get().node_heartbeat_timeout)) + return self.model.objects.filter(heartbeat__lt=datetime.datetime.now() - datetime.timedelta(seconds=self.model.get().node_heartbeat_timeout)) - def delete_dead_nodes(self): - self.dead_nodes().delete() + def check_dead_nodes(self): + self.dead_nodes().update(healty=NODE_STATE_DEAD) def zombiest_node(self): try: diff --git a/apps/clustering/tasks.py b/apps/clustering/tasks.py index c5938047d9..cc1e6aea63 100644 --- a/apps/clustering/tasks.py +++ b/apps/clustering/tasks.py @@ -21,5 +21,5 @@ def node_heartbeat(): @simple_locking('house_keeping', 10) def house_keeping(): logger.debug('starting') - ClusteringConfig.objects.delete_dead_nodes() + ClusteringConfig.objects.check_dead_nodes() diff --git a/apps/clustering/views.py b/apps/clustering/views.py index 675299916f..07cb50e80c 100644 --- a/apps/clustering/views.py +++ b/apps/clustering/views.py @@ -41,7 +41,10 @@ def node_list(request): 'name': _(u'memory usage'), 'attribute': 'memory_usage', }, - + { + 'name': _(u'state'), + 'attribute': 'get_state_display', + }, ], 'hide_object': True, }