Run functions while (some) daemons are stopped
authorHelga Velroyen <helgav@google.com>
Tue, 9 Jun 2015 09:10:04 +0000 (11:10 +0200)
committerHelga Velroyen <helgav@google.com>
Mon, 6 Jul 2015 10:45:49 +0000 (12:45 +0200)
For the new renew-crypto operation, we need to run
functions while most of the daemons are stopped,
except for WConfd. This refactors our code a bit
and generalizes the method that runs functions
while *all* daemons are stopped to one that
accepts a list of daemons to not be stopped.

Signed-off-by: Helga Velroyen <helgav@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>

lib/cli.py
lib/pathutils.py
src/Ganeti/Constants.hs

index c51c2a5..657308e 100644 (file)
@@ -267,6 +267,7 @@ __all__ = [
   "JobSubmittedException",
   "ParseTimespec",
   "RunWhileClusterStopped",
+  "RunWhileDaemonsStopped",
   "SubmitOpCode",
   "SubmitOpCodeToDrainedQueue",
   "SubmitOrSend",
@@ -2935,12 +2936,12 @@ def GenericInstanceCreate(mode, opts, args):
   return 0
 
 
-class _RunWhileClusterStoppedHelper(object):
-  """Helper class for L{RunWhileClusterStopped} to simplify state management
+class _RunWhileDaemonsStoppedHelper(object):
+  """Helper class for L{RunWhileDaemonsStopped} to simplify state management
 
   """
   def __init__(self, feedback_fn, cluster_name, master_node,
-               online_nodes, ssh_ports):
+               online_nodes, ssh_ports, exclude_daemons):
     """Initializes this class.
 
     @type feedback_fn: callable
@@ -2953,6 +2954,10 @@ class _RunWhileClusterStoppedHelper(object):
     @param online_nodes: List of names of online nodes
     @type ssh_ports: list
     @param ssh_ports: List of SSH ports of online nodes
+    @type exclude_daemons: list of string
+    @param exclude_daemons: list of daemons to shutdown
+    @param exclude_daemons: list of daemons that will be restarted after
+                            all others are shutdown
 
     """
     self.feedback_fn = feedback_fn
@@ -2966,6 +2971,8 @@ class _RunWhileClusterStoppedHelper(object):
     self.nonmaster_nodes = [name for name in online_nodes
                             if name != master_node]
 
+    self.exclude_daemons = exclude_daemons
+
     assert self.master_node not in self.nonmaster_nodes
 
   def _RunCmd(self, node_name, cmd):
@@ -3017,6 +3024,13 @@ class _RunWhileClusterStoppedHelper(object):
         for node_name in self.online_nodes:
           self.feedback_fn("Stopping daemons on %s" % node_name)
           self._RunCmd(node_name, [pathutils.DAEMON_UTIL, "stop-all"])
+          # Starting any daemons listed as exception
+          for daemon in self.exclude_daemons:
+            if (daemon in constants.DAEMONS_MASTER and
+                node_name != self.master_node):
+              continue
+            self.feedback_fn("Starting daemon '%s' on %s" % (daemon, node_name))
+            self._RunCmd(node_name, [pathutils.DAEMON_UTIL, "start", daemon])
 
         # All daemons are shut down now
         try:
@@ -3029,18 +3043,31 @@ class _RunWhileClusterStoppedHelper(object):
       finally:
         # Start cluster again, master node last
         for node_name in self.nonmaster_nodes + [self.master_node]:
+          # Stopping any daemons listed as exception.
+          # This might look unnecessary, but it makes sure that daemon-util
+          # starts all daemons in the right order.
+          for daemon in self.exclude_daemons:
+            if (daemon in constants.DAEMONS_MASTER and
+                node_name != self.master_node):
+              continue
+            self.feedback_fn("Stopping daemon '%s' on %s" % (daemon, node_name))
+            self._RunCmd(node_name, [pathutils.DAEMON_UTIL, "stop", daemon])
           self.feedback_fn("Starting daemons on %s" % node_name)
           self._RunCmd(node_name, [pathutils.DAEMON_UTIL, "start-all"])
+
     finally:
       # Resume watcher
       watcher_block.Close()
 
 
-def RunWhileClusterStopped(feedback_fn, fn, *args):
+def RunWhileDaemonsStopped(feedback_fn, exclude_daemons, fn, *args):
   """Calls a function while all cluster daemons are stopped.
 
   @type feedback_fn: callable
   @param feedback_fn: Feedback function
+  @type exclude_daemons: list of string
+  @param exclude_daemons: list of daemons that are NOT stopped. If None,
+                          all daemons will be stopped.
   @type fn: callable
   @param fn: Function to be called when daemons are stopped
 
@@ -3060,9 +3087,24 @@ def RunWhileClusterStopped(feedback_fn, fn, *args):
   del cl
 
   assert master_node in online_nodes
+  if exclude_daemons is None:
+    exclude_daemons = []
+
+  return _RunWhileDaemonsStoppedHelper(
+      feedback_fn, cluster_name, master_node, online_nodes, ssh_ports,
+      exclude_daemons).Call(fn, *args)
+
+
+def RunWhileClusterStopped(feedback_fn, fn, *args):
+  """Calls a function while all cluster daemons are stopped.
 
-  return _RunWhileClusterStoppedHelper(feedback_fn, cluster_name, master_node,
-                                       online_nodes, ssh_ports).Call(fn, *args)
+  @type feedback_fn: callable
+  @param feedback_fn: Feedback function
+  @type fn: callable
+  @param fn: Function to be called when daemons are stopped
+
+  """
+  RunWhileDaemonsStopped(feedback_fn, None, fn, *args)
 
 
 def GenerateTable(headers, fields, separator, data,
index 0e02142..203df47 100644 (file)
@@ -132,7 +132,7 @@ NODED_CERT_MODE = 0440
 RESTRICTED_COMMANDS_LOCK_FILE = LOCK_DIR + "/ganeti-restricted-commands.lock"
 
 #: Lock file for watcher, locked in shared mode by watcher; lock in exclusive
-# mode to block watcher (see L{cli._RunWhileClusterStoppedHelper.Call}
+# mode to block watcher (see L{cli._RunWhileDaemonsStoppedHelper.Call}
 WATCHER_LOCK_FILE = LOCK_DIR + "/ganeti-watcher.lock"
 
 #: Status file for per-group watcher, locked in exclusive mode by watcher
index d31189a..3e8dd54 100644 (file)
@@ -375,6 +375,11 @@ rapi = Runtime.daemonName GanetiRapi
 kvmd :: String
 kvmd = Runtime.daemonName GanetiKvmd
 
+-- Set of daemons which only run on the master.
+-- Keep in sync with the 'daemon-util' script.
+daemonsMaster :: FrozenSet String
+daemonsMaster = ConstantUtils.mkSet [wconfd, luxid, rapi]
+
 daemons :: FrozenSet String
 daemons =
   ConstantUtils.mkSet