From 3a5ba66a752d7f3341d1b76a55bed609114760d8 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Mon, 8 Dec 2008 11:46:51 +0000
Subject: [PATCH] gnt-node modify: add the offline attribute

This patch changes gnt-node modify and the associated opcode/lu to allow
modification of the node offline attribute.

Setting a node into offline mode automatically demotes it from the
master role.

Reviewed-by: ultrotter
---
 lib/cmdlib.py    | 36 +++++++++++++++++++++++++++---------
 lib/opcodes.py   |  1 +
 scripts/gnt-node | 19 +++++++++++++++----
 3 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 552477f45..0d119b97b 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2123,9 +2123,13 @@ class LUSetNodeParams(LogicalUnit):
     if node_name is None:
       raise errors.OpPrereqError("Invalid node name '%s'" % self.op.node_name)
     self.op.node_name = node_name
-    if not hasattr(self.op, 'master_candidate'):
+    _CheckBooleanOpField(self.op, 'master_candidate')
+    _CheckBooleanOpField(self.op, 'offline')
+    if self.op.master_candidate is None and self.op.offline is None:
       raise errors.OpPrereqError("Please pass at least one modification")
-    self.op.master_candidate = bool(self.op.master_candidate)
+    if self.op.offline == True and self.op.master_candidate == True:
+      raise errors.OpPrereqError("Can't set the node into offline and"
+                                 " master_candidate at the same time")
 
   def ExpandNames(self):
     self.needed_locks = {locking.LEVEL_NODE: self.op.node_name}
@@ -2139,6 +2143,7 @@ class LUSetNodeParams(LogicalUnit):
     env = {
       "OP_TARGET": self.op.node_name,
       "MASTER_CANDIDATE": str(self.op.master_candidate),
+      "OFFLINE": str(self.op.offline),
       }
     nl = [self.cfg.GetMasterNode(),
           self.op.node_name]
@@ -2150,34 +2155,47 @@ class LUSetNodeParams(LogicalUnit):
     This only checks the instance list against the existing names.
 
     """
-    force = self.force = self.op.force
+    node = self.node = self.cfg.GetNodeInfo(self.op.node_name)
 
-    if self.op.master_candidate == False:
+    if ((self.op.master_candidate == False or self.op.offline == True)
+        and node.master_candidate):
+      # we will demote the node from master_candidate
       if self.op.node_name == self.cfg.GetMasterNode():
         raise errors.OpPrereqError("The master node has to be a"
-                                   " master candidate")
+                                   " master candidate and online")
       cp_size = self.cfg.GetClusterInfo().candidate_pool_size
       node_info = self.cfg.GetAllNodesInfo().values()
-      num_candidates = len([node for node in node_info
-                            if node.master_candidate])
+      num_candidates, _ = self.cfg.GetMasterCandidateStats()
       if num_candidates <= cp_size:
         msg = ("Not enough master candidates (desired"
                " %d, new value will be %d)" % (cp_size, num_candidates-1))
-        if force:
+        if self.op.force:
           self.LogWarning(msg)
         else:
           raise errors.OpPrereqError(msg)
 
+    if (self.op.master_candidate == True and node.offline and
+        not self.op.offline == False):
+      raise errors.OpPrereqError("Can't set an offline node to"
+                                 " master_candidate")
+
     return
 
   def Exec(self, feedback_fn):
     """Modifies a node.
 
     """
-    node = self.cfg.GetNodeInfo(self.op.node_name)
+    node = self.node
 
     result = []
 
+    if self.op.offline is not None:
+      node.offline = self.op.offline
+      result.append(("offline", str(self.op.offline)))
+      if self.op.offline == True and node.master_candidate:
+        node.master_candidate = False
+        result.append(("master_candidate", "auto-demotion due to offline"))
+
     if self.op.master_candidate is not None:
       node.master_candidate = self.op.master_candidate
       result.append(("master_candidate", str(self.op.master_candidate)))
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 958ee4261..fbce4249b 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -326,6 +326,7 @@ class OpSetNodeParams(OpCode):
     "node_name",
     "force",
     "master_candidate",
+    "offline",
     ]
 
 # instance opcodes
diff --git a/scripts/gnt-node b/scripts/gnt-node
index cf9677af2..306597696 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -379,14 +379,22 @@ def SetNodeParams(opts, args):
   @return: the desired exit code
 
   """
-  if opts.master_candidate is None:
+  if opts.master_candidate is None and opts.offline is None:
     ToStderr("Please give at least one of the parameters.")
     return 1
 
-  candidate = opts.master_candidate == 'yes'
+  if opts.master_candidate is not None:
+    candidate = opts.master_candidate == 'yes'
+  else:
+    candidate = None
+  if opts.offline is not None:
+    offline = opts.offline == 'yes'
+  else:
+    offline = None
   op = opcodes.OpSetNodeParams(node_name=args[0],
-                              master_candidate=candidate,
-                              force=opts.force)
+                               master_candidate=candidate,
+                               offline=offline,
+                               force=opts.force)
 
   # even if here we process the result, we allow submit only
   result = SubmitOrSend(op, opts)
@@ -444,6 +452,9 @@ commands = {
               make_option("-C", "--master-candidate", dest="master_candidate",
                           choices=('yes', 'no'), default=None,
                           help="Set the master_candidate flag on the node"),
+              make_option("-O", "--offline", dest="offline",
+                          choices=('yes', 'no'), default=None,
+                          help="Set the offline flag on the node"),
               ],
              "<instance>", "Alters the parameters of an instance"),
   'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
-- 
GitLab