From 8d8c4eff2135d74b919c3c56dbb51027b76aa680 Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Wed, 20 Oct 2010 20:13:49 +0200
Subject: [PATCH] gnt-instance reinstall: Allow overriding OS parameters

This allows OS installation scripts to make use of special parameters,
e.g. to retain some data on reinstallation.

The RAPI resource is not updated as it takes all parameters via the
query string and encoding arbitrary data in a query string is tricky.
The resource will need to be changed to use the POST body instead.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/cmdlib.py         | 17 ++++++++++++++++-
 lib/opcodes.py        |  2 +-
 lib/rpc.py            |  7 ++++---
 man/gnt-instance.sgml |  6 ++++--
 scripts/gnt-instance  |  5 +++--
 5 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index b47e764cb..6b887b5a6 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -4672,6 +4672,7 @@ class LUReinstallInstance(LogicalUnit):
     _PInstanceName,
     ("os_type", None, ht.TMaybeString),
     ("force_variant", False, ht.TBool),
+    ("osparams", None, ht.TOr(ht.TDict, ht.TNone)),
     ]
   REQ_BGL = False
 
@@ -4709,6 +4710,18 @@ class LUReinstallInstance(LogicalUnit):
       # OS verification
       pnode = _ExpandNodeName(self.cfg, instance.primary_node)
       _CheckNodeHasOS(self, pnode, self.op.os_type, self.op.force_variant)
+      instance_os = self.op.os_name
+    else:
+      instance_os = instance.os
+
+    nodelist = list(instance.all_nodes)
+
+    if self.op.osparams:
+      i_osdict = _GetUpdatedParams(instance.osparams, self.op.osparams)
+      _CheckOSParams(self, True, nodelist, instance_os, i_osdict)
+      self.os_inst = i_osdict # the new dict (without defaults)
+    else:
+      self.os_inst = None
 
     self.instance = instance
 
@@ -4721,6 +4734,7 @@ class LUReinstallInstance(LogicalUnit):
     if self.op.os_type is not None:
       feedback_fn("Changing OS to '%s'..." % self.op.os_type)
       inst.os = self.op.os_type
+      # Write to configuration
       self.cfg.Update(inst, feedback_fn)
 
     _StartInstanceDisks(self, inst, None)
@@ -4728,7 +4742,8 @@ class LUReinstallInstance(LogicalUnit):
       feedback_fn("Running the instance OS create scripts...")
       # FIXME: pass debug option from opcode to backend
       result = self.rpc.call_instance_os_add(inst.primary_node, inst, True,
-                                             self.op.debug_level)
+                                             self.op.debug_level,
+                                             osparams=self.os_inst)
       result.Raise("Could not install OS for instance %s on node %s" %
                    (inst.name, inst.primary_node))
     finally:
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 48677063c..652f9a133 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -492,7 +492,7 @@ class OpReinstallInstance(OpCode):
   """Reinstall an instance's OS."""
   OP_ID = "OP_INSTANCE_REINSTALL"
   OP_DSC_FIELD = "instance_name"
-  __slots__ = ["instance_name", "os_type", "force_variant"]
+  __slots__ = ["instance_name", "os_type", "force_variant", "osparams"]
 
 
 class OpRemoveInstance(OpCode):
diff --git a/lib/rpc.py b/lib/rpc.py
index f64848b23..ffe64c3eb 100644
--- a/lib/rpc.py
+++ b/lib/rpc.py
@@ -433,7 +433,7 @@ class RpcRunner(object):
     @type bep: dict or None
     @param bep: a dictionary with overridden backend parameters
     @type osp: dict or None
-    @param osp: a dictionary with overriden os parameters
+    @param osp: a dictionary with overridden os parameters
     @rtype: dict
     @return: the instance dict, with the hvparams filled with the
         cluster defaults
@@ -752,14 +752,15 @@ class RpcRunner(object):
                                  shutdown_timeout])
 
   @_RpcTimeout(_TMO_1DAY)
-  def call_instance_os_add(self, node, inst, reinstall, debug):
+  def call_instance_os_add(self, node, inst, reinstall, debug, osparams=None):
     """Installs an OS on the given instance.
 
     This is a single-node call.
 
     """
     return self._SingleNodeCall(node, "instance_os_add",
-                                [self._InstDict(inst), reinstall, debug])
+                                [self._InstDict(inst, osp=osparams),
+                                 reinstall, debug])
 
   @_RpcTimeout(_TMO_SLOW)
   def call_instance_run_rename(self, node, inst, old_name, debug):
diff --git a/man/gnt-instance.sgml b/man/gnt-instance.sgml
index 5a4c2e6f6..565b22a35 100644
--- a/man/gnt-instance.sgml
+++ b/man/gnt-instance.sgml
@@ -1651,6 +1651,8 @@ instance5: 11225
             <arg>--secondary</arg>
             <arg>--all</arg>
           </group>
+          <sbr>
+          <arg choice="opt">-O <replaceable>OS_PARAMETERS</replaceable></arg>
           <arg>--submit</arg>
           <arg choice="opt" rep="repeat"><replaceable>instance</replaceable></arg>
         </cmdsynopsis>
@@ -1665,7 +1667,8 @@ instance5: 11225
         <para>
           The <option>--select-os</option> option switches to an
           interactive OS reinstall. The user is prompted to select the OS
-          template from the list of available OS templates.
+          template from the list of available OS templates. OS parameters
+          can be overridden using <option>-O</option>.
         </para>
 
         <para>
@@ -1687,7 +1690,6 @@ instance5: 11225
           <command>gnt-job info</command>.
         </para>
 
-
       </refsect3>
 
       <refsect3>
diff --git a/scripts/gnt-instance b/scripts/gnt-instance
index bb236e888..691d08ea8 100755
--- a/scripts/gnt-instance
+++ b/scripts/gnt-instance
@@ -572,7 +572,8 @@ def ReinstallInstance(opts, args):
   for instance_name in inames:
     op = opcodes.OpReinstallInstance(instance_name=instance_name,
                                      os_type=os_name,
-                                     force_variant=opts.force_variant)
+                                     force_variant=opts.force_variant,
+                                     osparams=opts.osparams)
     jex.QueueJob(instance_name, op)
 
   jex.WaitOrShow(not opts.submit_only)
@@ -1459,7 +1460,7 @@ commands = {
     [FORCE_OPT, OS_OPT, FORCE_VARIANT_OPT, m_force_multi, m_node_opt,
      m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, m_node_tags_opt,
      m_pri_node_tags_opt, m_sec_node_tags_opt, m_inst_tags_opt, SELECT_OS_OPT,
-     SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
+     SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT, OSPARAMS_OPT],
     "[-f] <instance>", "Reinstall a stopped instance"),
   'remove': (
     RemoveInstance, ARGS_ONE_INSTANCE,
-- 
GitLab