From d04aaa2f5268739ab69f96e993c09a7c0003c68c Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Mon, 18 May 2009 19:21:44 +0200
Subject: [PATCH] Add -H/-B startup parameters to gnt-instance

This patch modifies the start instance script, opcode and logical unit
to support temporary startup parameters.

Different from 1.2, where only the kernel arguments were supporting
changes (and thus xen-pvm specific), this version supports changing all
hypervisor and backend parameters (with appropriate checks).

This is much more flexible, and allows for example:
  - start with different, temporary kernel
  - start with different memory size

Note: in later versions, this should be extended to cover disk
parameters as well (e.g. start with drbd without flushes, start with
drbd in async mode, etc.).

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>
---
 lib/cmdlib.py         | 31 ++++++++++++++++++++++++++++++-
 lib/opcodes.py        |  2 +-
 man/gnt-instance.sgml | 22 +++++++++++++++++++++-
 scripts/gnt-instance  | 13 ++++++++++++-
 4 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index ff6dbc359..1a9e85f9f 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2761,6 +2761,34 @@ class LUStartupInstance(LogicalUnit):
     assert self.instance is not None, \
       "Cannot retrieve locked instance %s" % self.op.instance_name
 
+    # extra beparams
+    self.beparams = getattr(self.op, "beparams", {})
+    if self.beparams:
+      if not isinstance(self.beparams, dict):
+        raise errors.OpPrereqError("Invalid beparams passed: %s, expected"
+                                   " dict" % (type(self.beparams), ))
+      # fill the beparams dict
+      utils.ForceDictType(self.beparams, constants.BES_PARAMETER_TYPES)
+      self.op.beparams = self.beparams
+
+    # extra hvparams
+    self.hvparams = getattr(self.op, "hvparams", {})
+    if self.hvparams:
+      if not isinstance(self.hvparams, dict):
+        raise errors.OpPrereqError("Invalid hvparams passed: %s, expected"
+                                   " dict" % (type(self.hvparams), ))
+
+      # check hypervisor parameter syntax (locally)
+      cluster = self.cfg.GetClusterInfo()
+      utils.ForceDictType(self.hvparams, constants.HVS_PARAMETER_TYPES)
+      filled_hvp = cluster.FillDict(cluster.hvparams[instance.hypervisor],
+                                    instance.hvparams)
+      filled_hvp.update(self.hvparams)
+      hv_type = hypervisor.GetHypervisor(instance.hypervisor)
+      hv_type.CheckParameterSyntax(filled_hvp)
+      _CheckHVParams(self, instance.all_nodes, instance.hypervisor, filled_hvp)
+      self.op.hvparams = self.hvparams
+
     _CheckNodeOnline(self, instance.primary_node)
 
     bep = self.cfg.GetClusterInfo().FillBE(instance)
@@ -2789,7 +2817,8 @@ class LUStartupInstance(LogicalUnit):
 
     _StartInstanceDisks(self, instance, force)
 
-    result = self.rpc.call_instance_start(node_current, instance, None, None)
+    result = self.rpc.call_instance_start(node_current, instance,
+                                          self.hvparams, self.beparams)
     msg = result.RemoteFailMsg()
     if msg:
       _ShutdownInstanceDisks(self, instance)
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 5be660bdc..535db910d 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -382,7 +382,7 @@ class OpStartupInstance(OpCode):
   """Startup an instance."""
   OP_ID = "OP_INSTANCE_STARTUP"
   OP_DSC_FIELD = "instance_name"
-  __slots__ = ["instance_name", "force"]
+  __slots__ = ["instance_name", "force", "hvparams", "beparams"]
 
 
 class OpShutdownInstance(OpCode):
diff --git a/man/gnt-instance.sgml b/man/gnt-instance.sgml
index 176f70c0d..edf267eec 100644
--- a/man/gnt-instance.sgml
+++ b/man/gnt-instance.sgml
@@ -1127,7 +1127,7 @@ instance5: 11225
         <para>
           Show detailed information about the given instance(s). This is
           different from <command>list</command> as it shows detailed data
-          about the instance's disks (especially useful for the drbd disk 
+          about the instance's disks (especially useful for the drbd disk
           template).
         </para>
 
@@ -1314,6 +1314,9 @@ instance5: 11225
             <arg>--all</arg>
           </group>
           <sbr>
+          <arg>-H <option>key=value...</option></arg>
+          <arg>-B <option>key=value...</option></arg>
+          <sbr>
           <arg>--submit</arg>
           <sbr>
           <arg choice="opt"
@@ -1382,6 +1385,23 @@ instance5: 11225
           instance will be affected.
         </para>
 
+        <para>
+          The <option>-H</option> and <option>-B</option> options
+          specify extra, temporary hypervisor and backend parameters
+          that can be used to start an instance with modified
+          parameters. They can be useful for quick testing without
+          having to modify an instance back and forth, e.g.:
+          <screen>
+# gnt-instance start -H root_args="single" instance1
+# gnt-instance start -B memory=2048 instance2
+          </screen>
+          The first form will start the instance
+          <userinput>instance1</userinput> in single-user mode, and
+          the instance <userinput>instance2</userinput> with 2GB of
+          RAM (this time only, unless that is the actual instance
+          memory size already).
+        </para>
+
         <para>
           The <option>--submit</option> option is used to send the job to
           the master daemon but not wait for its completion. The job
diff --git a/scripts/gnt-instance b/scripts/gnt-instance
index 62a1f038e..7b93e3bc1 100755
--- a/scripts/gnt-instance
+++ b/scripts/gnt-instance
@@ -710,6 +710,11 @@ def StartupInstance(opts, args):
   for name in inames:
     op = opcodes.OpStartupInstance(instance_name=name,
                                    force=opts.force)
+    # do not add these parameters to the opcode unless they're defined
+    if opts.hvparams:
+      op.hvparams = opts.hvparams
+    if opts.beparams:
+      op.beparams = opts.beparams
     jex.QueueJob(name, op)
   jex.WaitOrShow(not opts.submit_only)
   return 0
@@ -1472,8 +1477,14 @@ commands = {
                m_node_opt, m_pri_node_opt, m_sec_node_opt,
                m_clust_opt, m_inst_opt,
                SUBMIT_OPT,
+               keyval_option("-H", "--hypervisor", type="keyval",
+                             default={}, dest="hvparams",
+                             help="Temporary hypervisor parameters"),
+               keyval_option("-B", "--backend", type="keyval",
+                             default={}, dest="beparams",
+                             help="Temporary backend parameters"),
                ],
-            "<instance>", "Starts an instance"),
+              "<instance>", "Starts an instance"),
 
   'reboot': (RebootInstance, ARGS_ANY,
               [DEBUG_OPT, m_force_multi,
-- 
GitLab