From 8fbf5ac7fadafe22dcbaa25d557954eed54509ad Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Wed, 30 Sep 2009 17:25:29 +0100
Subject: [PATCH] LUSetNodeParams: Don't break config on mc demotion.

If --force is used to demote an MC, but then there are not enough MCs in
the cluster, the configuration gets corrupted until a node is promoted.

In order to avoid that we only allow demotion with --force if the node
is offlined or drained at the same time, and we don't have any other
node available to promote.

Signed-off-by: Guido Trotter <ultrotter@google.com>
Reviewed-by: Olivier Tharan <olive@google.com>
---
 lib/cmdlib.py | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 3f36b0a04..e1056903c 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2970,14 +2970,21 @@ class LUSetNodeParams(LogicalUnit):
         raise errors.OpPrereqError("The master role can be changed"
                                    " only via masterfailover")
 
-    if ((self.op.master_candidate == False or self.op.offline == True or
-         self.op.drained == True) and node.master_candidate):
+    # Boolean value that tells us whether we're offlining or draining the node
+    offline_or_drain = self.op.offline == True or self.op.drained == True
+
+    if (node.master_candidate and
+        (self.op.master_candidate == False or offline_or_drain)):
       cp_size = self.cfg.GetClusterInfo().candidate_pool_size
-      num_candidates, _, _ = self.cfg.GetMasterCandidateStats()
-      if num_candidates <= cp_size:
+      mc_now, mc_should, mc_max = self.cfg.GetMasterCandidateStats()
+      if mc_now <= cp_size:
         msg = ("Not enough master candidates (desired"
-               " %d, new value will be %d)" % (cp_size, num_candidates-1))
-        if self.op.force:
+               " %d, new value will be %d)" % (cp_size, mc_now-1))
+        # Only allow forcing the operation if it's an offline/drain operation,
+        # and we could not possibly promote more nodes.
+        # FIXME: this can still lead to issues if in any way another node which
+        # could be promoted appears in the meantime.
+        if self.op.force and offline_or_drain and mc_should == mc_max:
           self.LogWarning(msg)
         else:
           raise errors.OpPrereqError(msg)
-- 
GitLab