From b31c867624dbd02a5ddb86daaa166b9cb581f110 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Tue, 2 Dec 2008 05:05:01 +0000
Subject: [PATCH] Add a gnt-node modify operation

This patch adds the OpCode, LogicalUnit and gnt-node command for
modifying node parameters, more specifically the master candidate flag
for a node.

Reviewed-by: imsnah
---
 lib/cmdlib.py    | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/mcpu.py      |  1 +
 lib/opcodes.py   | 10 ++++++++
 scripts/gnt-node | 37 +++++++++++++++++++++++++++
 4 files changed, 113 insertions(+)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index c0021093a..491e695f8 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1959,6 +1959,71 @@ class LUAddNode(LogicalUnit):
       self.context.AddNode(new_node)
 
 
+class LUSetNodeParams(LogicalUnit):
+  """Modifies the parameters of a node.
+
+  """
+  HPATH = "node-modify"
+  HTYPE = constants.HTYPE_NODE
+  _OP_REQP = ["node_name"]
+  REQ_BGL = False
+
+  def CheckArguments(self):
+    node_name = self.cfg.ExpandNodeName(self.op.node_name)
+    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'):
+      raise errors.OpPrereqError("Please pass at least one modification")
+    self.op.master_candidate = bool(self.op.master_candidate)
+
+  def ExpandNames(self):
+    self.needed_locks = {locking.LEVEL_NODE: self.op.node_name}
+
+  def BuildHooksEnv(self):
+    """Build hooks env.
+
+    This runs on the master node.
+
+    """
+    env = {
+      "OP_TARGET": self.op.node_name,
+      "MASTER_CANDIDATE": str(self.op.master_candidate),
+      }
+    nl = [self.cfg.GetMasterNode(),
+          self.op.node_name]
+    return env, nl, nl
+
+  def CheckPrereq(self):
+    """Check prerequisites.
+
+    This only checks the instance list against the existing names.
+
+    """
+    force = self.force = self.op.force
+
+    return
+
+  def Exec(self, feedback_fn):
+    """Modifies a node.
+
+    """
+    node = self.cfg.GetNodeInfo(self.op.node_name)
+
+    result = []
+
+    if self.op.master_candidate is not None:
+      node.master_candidate = self.op.master_candidate
+      result.append(("master_candidate", str(self.op.master_candidate)))
+
+    # this will trigger configuration file update, if needed
+    self.cfg.Update(node)
+    # this will trigger job queue propagation or cleanup
+    self.context.ReaddNode(node)
+
+    return result
+
+
 class LUQueryClusterInfo(NoHooksLU):
   """Query cluster configuration.
 
diff --git a/lib/mcpu.py b/lib/mcpu.py
index 9804d2ddf..fc9fcf3e2 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -54,6 +54,7 @@ class Processor(object):
     opcodes.OpQueryNodes: cmdlib.LUQueryNodes,
     opcodes.OpQueryNodeVolumes: cmdlib.LUQueryNodeVolumes,
     opcodes.OpRemoveNode: cmdlib.LURemoveNode,
+    opcodes.OpSetNodeParams: cmdlib.LUSetNodeParams,
     # instance lu
     opcodes.OpCreateInstance: cmdlib.LUCreateInstance,
     opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance,
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 5807922d1..c0b88a91a 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -312,6 +312,16 @@ class OpQueryNodeVolumes(OpCode):
   __slots__ = ["nodes", "output_fields"]
 
 
+class OpSetNodeParams(OpCode):
+  """Change the parameters of a node."""
+  OP_ID = "OP_NODE_SET_PARAMS"
+  OP_DSC_FIELD = "node_name"
+  __slots__ = [
+    "node_name",
+    "force",
+    "master_candidate",
+    ]
+
 # instance opcodes
 
 class OpCreateInstance(OpCode):
diff --git a/scripts/gnt-node b/scripts/gnt-node
index 1b20a66f8..6e2d686b2 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -365,6 +365,35 @@ def ListVolumes(opts, args):
   return 0
 
 
+def SetNodeParams(opts, args):
+  """Modifies a node.
+
+  @param opts: the command line options selected by the user
+  @type args: list
+  @param args: should contain only one element, the node name
+  @rtype: int
+  @return: the desired exit code
+
+  """
+  if opts.master_candidate is None:
+    ToStderr("Please give at least one of the parameters.")
+    return 1
+
+  candidate = opts.master_candidate == 'yes'
+  op = opcodes.OpSetNodeParams(node_name=args[0],
+                              master_candidate=candidate,
+                              force=opts.force)
+
+  # even if here we process the result, we allow submit only
+  result = SubmitOrSend(op, opts)
+
+  if result:
+    ToStdout("Modified node %s", args[0])
+    for param, data in result:
+      ToStdout(" - %-5s -> %s", param, data)
+  return 0
+
+
 commands = {
   'add': (AddNode, ARGS_ONE,
           [DEBUG_OPT,
@@ -408,6 +437,14 @@ commands = {
            " The default field list is"
            " (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
            ),
+  'modify': (SetNodeParams, ARGS_ONE,
+             [DEBUG_OPT, FORCE_OPT,
+              SUBMIT_OPT,
+              make_option("-C", "--master-candidate", dest="master_candidate",
+                          choices=('yes', 'no'), default=None,
+                          help="Set the master_candidate flag on the node"),
+              ],
+             "<instance>", "Alters the parameters of an instance"),
   'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT],
              "<node_name>", "Removes a node from the cluster"),
   'volumes': (ListVolumes, ARGS_ANY,
-- 
GitLab