From 25c5878d35bab020b3b0c79d7f536bf1ed0635f8 Mon Sep 17 00:00:00 2001
From: Alexander Schreiber <als@google.com>
Date: Fri, 11 Jan 2008 12:13:22 +0000
Subject: [PATCH] Support selecting the boot device order for HVM.

This patch adds support for specifying and changing the boot device order for
HVM instances. The boot device order specification is ignored for non HVM
instances.

Reviewed-by: iustinp
---
 lib/cmdlib.py         | 24 +++++++++++++++++-
 lib/constants.py      |  1 +
 lib/hypervisor.py     |  5 +++-
 lib/opcodes.py        |  4 +--
 man/gnt-instance.sgml | 59 ++++++++++++++++++++++++++++++++++++++++++-
 scripts/gnt-instance  | 19 +++++++++++---
 tools/burnin          |  3 ++-
 7 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index a625dcde4..bb998063e 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -3049,6 +3049,12 @@ class LUCreateInstance(LogicalUnit):
                                  " destination node '%s'" %
                                  (self.op.bridge, pnode.name))
 
+    # boot order verification
+    if self.op.hvm_boot_order is not None:
+      if len(self.op.hvm_boot_order.strip("acdn")) != 0:
+             raise errors.OpPrereqError("invalid boot order specified,"
+                                        " must be one or more of [acdn]")
+
     if self.op.start:
       self.instance_status = 'up'
     else:
@@ -3092,6 +3098,7 @@ class LUCreateInstance(LogicalUnit):
                             network_port=network_port,
                             kernel_path=self.op.kernel_path,
                             initrd_path=self.op.initrd_path,
+                            hvm_boot_order=self.op.hvm_boot_order,
                             )
 
     feedback_fn("* creating instance disks...")
@@ -4110,8 +4117,9 @@ class LUSetInstanceParms(LogicalUnit):
     self.bridge = getattr(self.op, "bridge", None)
     self.kernel_path = getattr(self.op, "kernel_path", None)
     self.initrd_path = getattr(self.op, "initrd_path", None)
+    self.hvm_boot_order = getattr(self.op, "hvm_boot_order", None)
     all_parms = [self.mem, self.vcpus, self.ip, self.bridge, self.mac,
-                 self.kernel_path, self.initrd_path]
+                 self.kernel_path, self.initrd_path, self.hvm_boot_order]
     if all_parms.count(None) == len(all_parms):
       raise errors.OpPrereqError("No changes submitted")
     if self.mem is not None:
@@ -4163,6 +4171,14 @@ class LUSetInstanceParms(LogicalUnit):
     else:
       self.do_initrd_path = False
 
+    # boot order verification
+    if self.hvm_boot_order is not None:
+      if self.hvm_boot_order != constants.VALUE_DEFAULT:
+        if len(self.hvm_boot_order.strip("acdn")) != 0:
+          raise errors.OpPrereqError("invalid boot order specified,"
+                                     " must be one or more of [acdn]"
+                                     " or 'default'")
+
     instance = self.cfg.GetInstanceInfo(
       self.cfg.ExpandInstanceName(self.op.instance_name))
     if instance is None:
@@ -4200,6 +4216,12 @@ class LUSetInstanceParms(LogicalUnit):
     if self.do_initrd_path:
       instance.initrd_path = self.initrd_path
       result.append(("initrd_path", self.initrd_path))
+    if self.hvm_boot_order:
+      if self.hvm_boot_order == constants.VALUE_DEFAULT:
+        instance.hvm_boot_order = None
+      else:
+        instance.hvm_boot_order = self.hvm_boot_order
+      result.append(("hvm_boot_order", self.hvm_boot_order))
 
     self.cfg.AddInstance(instance)
 
diff --git a/lib/constants.py b/lib/constants.py
index 47db98e5e..81876dd1d 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -159,4 +159,5 @@ HYPER_TYPES = frozenset([HT_XEN_PVM30, HT_FAKE, HT_XEN_HVM31])
 HTS_REQ_PORT = frozenset([HT_XEN_HVM31])
 
 HT_HVM_VNC_BASE_PORT = 5900
+HT_HVM_DEFAULT_BOOT_ORDER = 'dc'
 VNC_PASSWORD_FILE = _autoconf.SYSCONFDIR + "/ganeti/vnc-cluster-password"
diff --git a/lib/hypervisor.py b/lib/hypervisor.py
index d3b7e8709..e77e4b8d8 100644
--- a/lib/hypervisor.py
+++ b/lib/hypervisor.py
@@ -596,7 +596,10 @@ class XenHvmHypervisor(XenHypervisor):
       config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
     else:
       config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
-    config.write("boot = 'dc'\n")
+    if instance.hvm_boot_order is None:
+      config.write("boot = '%s'\n" % constants.HT_HVM_DEFAULT_BOOT_ORDER)
+    else:
+      config.write("boot = '%s'\n" % instance.hvm_boot_order)
     config.write("sdl = 0\n")
     config.write("vnc = 1\n")
     config.write("vnclisten = '0.0.0.0'\n")
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 3aa3a2cdf..73afaf8c7 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -165,7 +165,7 @@ class OpCreateInstance(OpCode):
     "disk_template", "snode", "swap_size", "mode",
     "vcpus", "ip", "bridge", "src_node", "src_path", "start",
     "wait_for_sync", "ip_check", "mac",
-    "kernel_path", "initrd_path",
+    "kernel_path", "initrd_path", "hvm_boot_order",
     ]
 
 
@@ -265,7 +265,7 @@ class OpSetInstanceParms(OpCode):
   OP_ID = "OP_INSTANCE_SET_PARMS"
   __slots__ = [
     "instance_name", "mem", "vcpus", "ip", "bridge", "mac",
-    "kernel_path", "initrd_path",
+    "kernel_path", "initrd_path", "hvm_boot_order",
     ]
 
 
diff --git a/man/gnt-instance.sgml b/man/gnt-instance.sgml
index a96fd8f21..36a6c1468 100644
--- a/man/gnt-instance.sgml
+++ b/man/gnt-instance.sgml
@@ -69,6 +69,7 @@
           <arg>-o <replaceable>os-type</replaceable></arg>
           <arg>-b <replaceable>bridge</replaceable></arg>
           <arg>--mac <replaceable>MAC-address</replaceable></arg>
+          <arg>--hvm-boot-order <replaceable>boot-order</replaceable></arg>
           <sbr>
           <arg>--kernel <group choice="req">
               <arg>default</arg>
@@ -146,6 +147,55 @@
           this cluster.
         </para>
 
+        <para>
+          The <option>--hvm-boot-order</option> option specifies the
+          boot device order for Xen HVM instances. The boot order is a
+          string of letters listing the boot devices, with valid
+          device letters being:
+        </para>
+
+        <para>
+          <variablelist>
+            <varlistentry>
+              <term>a</term>
+              <listitem>
+                <para>
+                  floppy drive
+                </para>
+              </listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>c</term>
+              <listitem>
+                <para>
+                  hard disk
+                </para>
+              </listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>d</term>
+              <listitem>
+                <para>
+                  CDROM drive
+                </para>
+              </listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>n</term>
+              <listitem>
+                <para>
+                  network boot (PXE)
+                </para>
+              </listitem>
+            </varlistentry>
+          </variablelist>
+        </para>
+
+        <para>
+          The option is only relevant for Xen HVM instances and
+          ignored by all other instances types.
+        </para>
+
         <para>
           The <option>--kernel</option> options allows the instance to
           use a custom kernel (if a filename is passed) or to use the
@@ -439,6 +489,7 @@
           <arg choice="opt">-i <replaceable>ip</replaceable></arg>
           <arg choice="opt">-b <replaceable>bridge</replaceable></arg>
           <arg choice="opt">--mac <replaceable>MAC-address</replaceable></arg>
+          <arg>--hvm-boot-order <replaceable>boot-order</replaceable></arg>
           <sbr>
           <arg>--kernel <group choice="req">
               <arg>default</arg>
@@ -466,10 +517,16 @@
         </para>
 
         <para>
-          The <option>--kernel</option> and <option>--initrd</option>
+          The <option>--kernel</option>, <option>--initrd</option>
+          and <option>--hvm-boot-order</option>
           options are described in the <command>add</command> command.
         </para>
 
+        <para>
+          Additionally, the HVM boot order can be reset to the default
+          values by using <option>--hvm-boot-order=default</option>.
+        </para>
+
         <para>
           All the changes take effect at the next restart. If the
           instance is running, there is no effect on the instance.
diff --git a/scripts/gnt-instance b/scripts/gnt-instance
index f230714f0..d89cce9fe 100755
--- a/scripts/gnt-instance
+++ b/scripts/gnt-instance
@@ -255,7 +255,8 @@ def AddInstance(opts, args):
                                 wait_for_sync=opts.wait_for_sync,
                                 mac=opts.mac,
                                 kernel_path=kernel_path,
-                                initrd_path=initrd_path)
+                                initrd_path=initrd_path,
+                                hvm_boot_order=opts.hvm_boot_order)
   SubmitOpCode(op)
   return 0
 
@@ -669,18 +670,23 @@ def SetInstanceParms(opts, args):
 
   """
   if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
-          opts.kernel_path or opts.initrd_path):
+          opts.kernel_path or opts.initrd_path or opts.hvm_boot_order):
     logger.ToStdout("Please give at least one of the parameters.")
     return 1
 
   kernel_path = _TransformPath(opts.kernel_path)
   initrd_path = _TransformPath(opts.initrd_path)
+  if opts.hvm_boot_order.lower() == 'default':
+    hvm_boot_order = constants.VALUE_DEFAULT
+  else:
+    hvm_boot_order = opts.hvm_boot_order
 
   op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
                                   vcpus=opts.vcpus, ip=opts.ip,
                                   bridge=opts.bridge, mac=opts.mac,
                                   kernel_path=opts.kernel_path,
-                                  initrd_path=opts.initrd_path)
+                                  initrd_path=opts.initrd_path,
+                                  hvm_boot_order=hvm_boot_order)
   result = SubmitOpCode(op)
 
   if result:
@@ -771,6 +777,9 @@ add_opts = [
               help="Path to the instances' initrd (or 'none', or 'default')",
               default=None,
               type="string", metavar="<FILENAME>"),
+  make_option("--hvm-boot-order", dest="hvm_boot_order",
+              help="boot device order for HVM (one or more of [acdn])",
+              default=None, type="string", metavar="<BOOTORDER>"),
   ]
 
 commands = {
@@ -878,6 +887,10 @@ commands = {
                           help="Path to the instances' initrd (or 'none', or"
                           " 'default')", default=None,
                           type="string", metavar="<FILENAME>"),
+              make_option("--hvm-boot-order", dest="hvm_boot_order",
+                          help="boot device order for HVM"
+                          "(either one or more of [acdn] or 'default')",
+                          default=None, type="string", metavar="<BOOTORDER>"),
               ],
              "<instance>", "Alters the parameters of an instance"),
   'shutdown': (ShutdownInstance, ARGS_ANY,
diff --git a/tools/burnin b/tools/burnin
index 4ded7492a..2b5203c2c 100755
--- a/tools/burnin
+++ b/tools/burnin
@@ -203,7 +203,8 @@ class Burner(object):
                                     wait_for_sync=True,
                                     mac="auto",
                                     kernel_path=None,
-                                    initrd_path=None)
+                                    initrd_path=None,
+                                    hvm_boot_order=None)
       Log("- Add instance %s on node %s" % (instance, pnode))
       self.ExecOp(op)
       self.to_rem.append(instance)
-- 
GitLab