[prev in list] [next in list] [prev in thread] [next in thread] 

List:       luci-commits
Subject:    [Luci-commits] [luci] Fix to cope with cluster membership changes that happen outside of luci. If no
From:       rmccabe () fedoraproject ! org (rmccabe)
Date:       2010-09-30 18:57:27
Message-ID: 20100930185727.2B9FF1201DE () lists ! fedorahosted ! org
[Download RAW message or body]

commit bb6cabd0e7b32487b0f389b70164528605d5abd9
Author: Ryan McCabe <rmccabe at redhat.com>
Date:   Thu Sep 30 14:56:33 2010 -0400

    Fix to cope with cluster membership changes that happen outside of luci. If nodes \
are added or removed since we've last seen the cluster, create or delete database \
node objects as necessary.

 luci/controllers/cluster.py |    6 +++-
 luci/lib/db_helpers.py      |   61 ++++++++++++++++++++++++++++++++++++------
 luci/lib/ricci_helpers.py   |    9 +++++-
 3 files changed, 64 insertions(+), 12 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index 8a7999a..742a487 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -17,7 +17,7 @@ from pylons.i18n import ugettext as _
 
 # project specific imports
 from luci.lib.base import BaseController
-from luci.lib.db_helpers import get_cluster_list, get_model_for_cluster, \
get_status_for_cluster, db_remove_cluster, get_agent_for_cluster, get_cluster_db_obj \
+from luci.lib.db_helpers import get_cluster_list, get_model_for_cluster, \
get_status_for_cluster, db_remove_cluster, get_agent_for_cluster, get_cluster_db_obj, \
reconcile_db_with_conf  import luci.lib.ricci_helpers as rh
 from luci.lib.flash2 import flash2
 import luci.widget_validators.validate_cluster_prop as vcp
@@ -108,6 +108,10 @@ class IndividualClusterController(BaseController):
     def get_model(self):
         if not self.model:
             self.model = get_model_for_cluster(self.name, self.get_agent())
+            try:
+                reconcile_db_with_conf(self.name, self.model.getNodeNames())
+            except:
+                log.exception("Error reconciling db with conf")
         return self.model
 
     def get_status(self):
diff --git a/luci/lib/db_helpers.py b/luci/lib/db_helpers.py
index bfd98ff..7322a51 100644
--- a/luci/lib/db_helpers.py
+++ b/luci/lib/db_helpers.py
@@ -19,6 +19,8 @@ from luci.lib.ricci_defines import RICCI_BATCH_FAILURES_MAX
 from luci.lib.ricci_communicator import RicciCommunicator
 import luci.lib.ricci_queries as rq
 
+from tg import app_globals
+
 import transaction
 import logging
 log = logging.getLogger(__name__)
@@ -234,24 +236,65 @@ def db_remove_cluster(cluster_name):
         return False
     return True
 
-def db_remove_cluster_node(cluster_name, node_name):
-    node_to_remove = None
+def db_remove_cluster_nodes(cluster_obj, node_list):
+    kill_list = []
     try:
-        cluster_obj = get_cluster_db_obj(cluster_name)
         for i in cluster_obj.nodes:
-            if i.node_name == node_name or i.hostname == node_name:
-                node_to_remove = i
-                break
+            if i.node_name in node_list or i.hostname in node_list:
+                kill_list.append(i)
 
-        if node_to_remove is not None:
-            DBSession.delete(node_to_remove)
+        if len(kill_list) is not None:
+            [DBSession.delete(i) for i in kill_list]
             DBSession.flush()
             transaction.commit()
             return True
     except:
-        log.exception('Error removing node "%s" from the database' % node_name)
+        log.exception('Error removing nodes "%s" from the database'
+            % ', '.join(node_list))
     return False
 
+def db_add_cluster_node(cluster_obj, name, ricci_host=None, ricci_port=None):
+    node_obj = Node(node_name=name,
+                    hostname=ricci_host or name,
+                    ipaddr=ricci_host or name,
+                    display_name=name,
+                    port=ricci_port or app_globals.DEFAULT_RICCI_PORT,
+                    cluster=[cluster_obj])
+    DBSession.add(node_obj)
+
+# We keep a list of the nodes for each cluster (and some associated
+# data (e.g., ricci hostname, ricci port) in our local database. If changes
+# are made to the cluster membership outside of this luci instance, our
+# node info may diverge from the info in the current cluster.conf.
+# Consequentially, we need to reconcile the node list info we get from
+# ricci (which it gets from modclusterd) with our database.
+def reconcile_db_with_conf(cluster_name, conf_nodelist):
+    cluster_obj = get_cluster_db_obj(cluster_name)
+    if cluster_obj == None:
+        # This should probably never happen.
+        log.error('No cluster database object was found for cluster "%s"'
+            % cluster_name)
+        return None
+
+    db_nodelist = set([i.node_name for i in cluster_obj.nodes])
+    conf_nodelist = set(conf_nodelist)
+
+    stale_nodes = db_nodelist - conf_nodelist
+    if len(stale_nodes) > 0:
+        # we need to purge the db objects for these (former) nodes
+        ret = db_remove_cluster_nodes(cluster_obj, stale_nodes)
+        if ret is not True:
+            log.debug('An error occurred while attempting to remove stale DB objects \
for nodes "%s"' % ', '.join(stale_nodes)) +
+    new_nodes = conf_nodelist - db_nodelist
+    if len(new_nodes) > 0:
+        # we need to create a new database entry for these nodes
+        for i in new_nodes:
+            db_add_cluster_node(cluster_obj, i)
+        DBSession.flush()
+        transaction.commit()
+    return conf_nodelist != db_nodelist
+
 def get_cluster_task_status(cluster_name):
     task_status = {}
 
diff --git a/luci/lib/ricci_helpers.py b/luci/lib/ricci_helpers.py
index db897cc..511cb39 100644
--- a/luci/lib/ricci_helpers.py
+++ b/luci/lib/ricci_helpers.py
@@ -12,7 +12,7 @@ from pylons.i18n import ugettext as _
 from luci.model import metadata, DBSession
 from luci.model.objects import Node, Cluster, Task
 from luci.lib.cluster_status import ClusterStatus
-from luci.lib.db_helpers import get_cluster_db_obj, get_node_by_host, \
get_agent_for_cluster, get_node_by_name, db_remove_cluster_node +from \
luci.lib.db_helpers import get_cluster_db_obj, get_node_by_host, \
get_agent_for_cluster, get_node_by_name, db_remove_cluster_nodes  from \
luci.lib.ricci_communicator import RicciCommunicator  import luci.lib.ricci_queries \
as rq  import luci.lib.luci_tasks as luci_tasks
@@ -494,9 +494,14 @@ def cluster_node_delete(cluster_name, cluster_model, node_list):
     for node in node_list:
         try:
             cluster_model.deleteNodeByName(node)
-            db_remove_cluster_node(cluster_name, node)
         except Exception, e:
             log.exception('Unable to delete node "%s" from the cluster \
configuration' % node) +
+	try:
+		db_remove_cluster_nodes(cluster_obj, node_list)
+	except Exception, e:
+		log.exception('Unable to delete nodes "%s" from the cluster configuration' % ', \
'.join(node_list)) +
     update_cluster_conf(cluster_model)
 
 def cluster_svc_start(cluster_name, svc_name, target_node=None):


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic