ONIE x86: major disk partitioning changes

Reviewed by: TBD

This patch implements a more flexible disk partitioning design for x86
systems.  The fundamental changes are:

- Use a single partition for kernel+initramfs and GRUB configuration.
  This partition has the label "ONIE-BOOT".  The "ONIE-CONFIG"
  partition is removed.

- ONIE update now comes in two flavors: update and embed.  'update'
  only updates files in the ONIE-BOOT partition and does not affect
  the partition table or MBR. 'embed' will wipe the disk clean and
  install a new partition table, along with installing GRUB in the MBR
  and installing ONIE.

- To get back to ONIE a NOS now 'chainloads' the ONIE partition.

- replace most onie-boot-XXX tools with a single, simpler
  onie-boot-mode command.

With this patch the ONIE partition is more self-contained and the
installed NOS controls how it manages the MBR and GRUB.

The below examples use GPT as the disk label.  The mechanics for MSDOS
disk labels are nearly the same, the only difference being GPT needs
to create the "BIOS GRUB" partition which MSDOS does not.

Single Partition and Initial Install (embed)
============================================

First let's start with what the hard disk looks like just after ONIE
is installed in the factory.

Before this assume the disk was blank and PXE (or a USB stick) was
used to install ONIE for the first time.

For sake of example assume the hard disk is available as /dev/sda.

+=======================+
|  /dev/sda  MBR        |
|                       |
|  ONIE Installs GRUB   |
+=======================+
|  /dev/sda1 GRUB       |
|                       |
|  BIOS GRUB            |
+=======================+
|  /dev/sda2 ONIE-BOOT  |
|                       |
|  ONIE Installs GRUB   |
+=======================+
|                       |
/  Free Space           /
|                       |
+=======================+

The ramdisk (or netboot or USB stick) boot of ONIE does the following:

- Since the disk is blank we are "embedding" ONIE and need to create
  partition tables.  The installer creates a disk label (either msdos
  or gpt depending on machine config).  gpt in this example.

- Creates needed partitions (two for gpt, one for msdos).  The
  ONIE-BOOT partition is created either way.

- Installs ONIE kernel+initramfs into ONIE-BOOT partition.

- Installs GRUB into /dev/sda2, the ONIE-BOOT partition.  This
  facilitates chainloading ONIE.

- Installs GRUB *again* into /dev/sda, the MBR.  This allows the
  system to boot initially with no NOS installed.

An OS normally installs the GRUB binary into the MBR, i.e. into
/dev/sda (and for GPT also in /dev/sda1).  The grub configuration and
related files go into /dev/sda2, typically mounted as /boot.

A supported option is to install the GRUB binary into a partition,
like /dev/sda2.  Using this approach you can chainload the ONIE OS
from some other OS's GRUB menu.

When ONIE is installed in the factory the ONIE installer will install
the GRUB binaries to *both* /dev/sda and /dev/sda2.  The copy in
/dev/sda is "disposable" and will be over written by the primary OS.
It will only be used to get ONIE started the first time, then the
primary OS installer will take over.

The philosophy is the installed OS "owns" the /dev/sda MBR for
installing the GRUB binaries.  ONIE "owns" everything in /dev/sda2.
As long as the OS installer leaves /dev/sda2 intact we are good.

After a NOS Installer Runs
==========================

Let's continue from the pictures above.  Now assume an OS installer
has run.  That installer is going to create partitions and install its
own version of GRUB (could even be GRUB legacy).  Let's say we
installed CentOS into the remaining free space.

The disk now looks like:

+=======================+
|  /dev/sda  MBR        |
|                       |
|  CentOS Installs GRUB |
+=======================+
|  /dev/sda1 GRUB       |
|                       |
|  BIOS GRUB            |
+=======================+
|  /dev/sda2 ONIE       |
|                       |
|  ONIE Installs GRUB   |
+=======================+
|  /dev/sda3 CentOS     |
|                       |
|                       |
+=======================+

Note: CentOS installed its version of the GRUB binary into /dev/sda,
overwriting what ONIE installed in the factory.  This is OK.

The CentOS GRUB will reference grub config files and modules from
/dev/sda3.  It does not involve ONIE installed on /dev/sda2 at all.

Chainloading and Selecting ONIE Mode
====================================

In order to return to ONIE from the NOS the NOS adds a GRUB menu entry
for chainloading ONIE.  A sample file that can be dropped into
/etc/grub.d is provided in
onie/rootconf/x86_64/sysroot-lib-onie/50_onie_grub.

To select which "mode" to start ONIE in the NOS uses the grub-editenv
command to set the 'onie_mode" variable to one of: install, uninstall,
rescue, update or embed.

The use of grub-reboot is helpful here to reboot and chainload ONIE
for one boot, returning to the default GRUB menu entry after that.

By using grub-editenv the grub.cfg in the ONIE-BOOT partition is now
static and never changes.  This obviates the need for several of the
onie-boot-XXX tools that existed previously.  As such the following
ONIE tools are removed:

  onie-boot-default
  onie-boot-entry-add
  onie-boot-entry-remove
  onie-boot-entry-show
  onie-boot-init
  onie-boot-update

These tools are replaced with 'onie-boot-mode', which is a thin
wrapper around grub-editenv for the ONIE modes described above.  The
demo OS has examples of using this utility.

Updating vs. Embedding ONIE
===========================

This patch introduces two modes of updating ONIE: embed and update.

The 'embed' mechanism is destructive and will wipe out the contents of
the disk, re-partition the disk and install ONIE.  This mode must be
actively selected from the GRUB boot menu, i.e. you must specifically
request this dangerous operation.

The 'onie-self-update' utility, used to update ONIE, now requires the
'-e' option if you intend to embed ONIE.  Otherwise 'update' is
assumed as described next.

The 'update' operation will only update files in the ONIE-BOOT
partition.  It is not destructive nor will it touch the MBR or
partition the disk.  If during the update operation it is detected
that the ONIE-BOOT partition "does not look right", i.e. an external
entity corrupted the partition, the update will fail.  An 'embed'
operation would be required to recover from this case.

This is a departure from the previous update mechanism which would
wipe out and re-partition the disk if anything was out of place.

Testing Done:

All of the following tests were run using two physical x86 systems
(the im_n29xx_t40n machine being one of them) and the virtual
kvm_x86_64 machine.  For each machine the following tests were run
once using GPT and again using MSDOS partition tables.  Do the math,
the following tests were run 6 times.

- Build ONIE with PARTITION_TYPE set to "msdos" and "gpt"

- 'embed' ONIE successfully

- try to 'update' ONIE with a mismatch between partition type,
  i.e. the running system is using gpt and the update image is set for
  msdos or vice versa.  The update fails as the ONIE-BOOT partition
  'does not look right'.

- install the DEMO OS successfully

- from the DEMO OS exercise the install, uninstall, rescue, update and
  embed operations.  The system reboots (chainloads) one time into
  ONIE and performs the operation successfully.

- successfully 'update' ONIE with the demo OS installed.  After the
  update the system reboots back into the demo OS.