summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2014-06-03 16:41:51 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2014-06-03 16:41:51 +0000
commit11b7c965debe5da58cc8f07d516fcd44aff30389 (patch)
tree8c331090ac5b68622e61d96cb111159f18597cb8
parent64263de0123f9e513a300fd179e5b84384fa5343 (diff)
parent1ab034dc56b8eb3fff8f8f2abf730450048e9dfc (diff)
downloadmorph-11b7c965debe5da58cc8f07d516fcd44aff30389.tar.gz
Merge branch 'baserock/richardmaw/S11159/initramfs-support'
Reviewed-by: Sam Thursfield and Richard Ipsum
-rwxr-xr-xmorphlib/exts/initramfs.write27
-rw-r--r--morphlib/exts/initramfs.write.help35
-rw-r--r--morphlib/exts/kvm.write.help4
-rw-r--r--morphlib/exts/rawdisk.write.help4
-rw-r--r--morphlib/exts/virtualbox-ssh.write.help4
-rw-r--r--morphlib/writeexts.py62
6 files changed, 128 insertions, 8 deletions
diff --git a/morphlib/exts/initramfs.write b/morphlib/exts/initramfs.write
new file mode 100755
index 00000000..815772f2
--- /dev/null
+++ b/morphlib/exts/initramfs.write
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright (C) 2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# =*= License: GPL-2 =*=
+
+set -e
+
+ROOTDIR="$1"
+INITRAMFS_PATH="$2"
+
+(cd "$ROOTDIR" &&
+ find . -print0 |
+ cpio -0 -H newc -o |
+ gzip -c) >"$INITRAMFS_PATH"
diff --git a/morphlib/exts/initramfs.write.help b/morphlib/exts/initramfs.write.help
new file mode 100644
index 00000000..29a9d266
--- /dev/null
+++ b/morphlib/exts/initramfs.write.help
@@ -0,0 +1,35 @@
+help: |
+ Create an initramfs for a system by taking an existing system and
+ converting it to the appropriate format.
+
+ The system must have a `/init` executable as the userland entry-point.
+ This can have a different path, if `rdinit=$path` is added to
+ the kernel command line. This can be added to the `rawdisk`,
+ `virtualbox-ssh` and `kvm` write extensions with the `KERNEL_CMDLINE`
+ option.
+
+ It is possible to use a ramfs as the final rootfs without a `/init`
+ executable, by setting `root=/dev/mem`, or `rdinit=/sbin/init`,
+ but this is beyond the scope for the `initramfs.write` extension.
+
+ The intended use of initramfs.write is to be part of a nested
+ deployment, so the parent system has an initramfs stored as
+ `/boot/initramfs.gz`. See the following example:
+
+ name: initramfs-test
+ kind: cluster
+ systems:
+ - morph: minimal-system-x86_64-generic
+ deploy:
+ system:
+ type: rawdisk
+ location: initramfs-system-x86_64.img
+ DISK_SIZE: 1G
+ HOSTNAME: initramfs-system
+ INITRAMFS_PATH: boot/initramfs.gz
+ subsystems:
+ - morph: initramfs-x86_64
+ deploy:
+ initramfs:
+ type: initramfs
+ location: boot/initramfs.gz
diff --git a/morphlib/exts/kvm.write.help b/morphlib/exts/kvm.write.help
new file mode 100644
index 00000000..8b5053a5
--- /dev/null
+++ b/morphlib/exts/kvm.write.help
@@ -0,0 +1,4 @@
+help: |
+ The INITRAMFS_PATH option can be used to specify the location of an
+ initramfs for syslinux to tell Linux to use, rather than booting
+ the rootfs directly.
diff --git a/morphlib/exts/rawdisk.write.help b/morphlib/exts/rawdisk.write.help
index a514a4e8..298d441c 100644
--- a/morphlib/exts/rawdisk.write.help
+++ b/morphlib/exts/rawdisk.write.help
@@ -5,3 +5,7 @@ help: |
The `location` argument is a pathname to the image to be
created or upgraded.
+
+ The INITRAMFS_PATH option can be used to specify the location of an
+ initramfs for syslinux to tell Linux to use, rather than booting
+ the rootfs directly.
diff --git a/morphlib/exts/virtualbox-ssh.write.help b/morphlib/exts/virtualbox-ssh.write.help
new file mode 100644
index 00000000..8b5053a5
--- /dev/null
+++ b/morphlib/exts/virtualbox-ssh.write.help
@@ -0,0 +1,4 @@
+help: |
+ The INITRAMFS_PATH option can be used to specify the location of an
+ initramfs for syslinux to tell Linux to use, rather than booting
+ the rootfs directly.
diff --git a/morphlib/writeexts.py b/morphlib/writeexts.py
index b4912db1..334dc15c 100644
--- a/morphlib/writeexts.py
+++ b/morphlib/writeexts.py
@@ -120,7 +120,8 @@ class WriteExtension(cliapp.Application):
raise
try:
self.create_btrfs_system_layout(
- temp_root, mp, version_label='factory')
+ temp_root, mp, version_label='factory',
+ disk_uuid=self.get_uuid(raw_disk))
except BaseException, e:
sys.stderr.write('Error creating Btrfs system layout')
self.unmount(mp)
@@ -186,6 +187,13 @@ class WriteExtension(cliapp.Application):
'''Create a btrfs filesystem on the disk.'''
self.status(msg='Creating btrfs filesystem')
cliapp.runcmd(['mkfs.btrfs', '-L', 'baserock', location])
+
+ def get_uuid(self, location):
+ '''Get the UUID of a block device's file system.'''
+ # Requires util-linux blkid; busybox one ignores options and
+ # lies by exiting successfully.
+ return cliapp.runcmd(['blkid', '-s', 'UUID', '-o', 'value',
+ location]).strip()
def mount(self, location):
'''Mount the filesystem so it can be tweaked.
@@ -212,10 +220,12 @@ class WriteExtension(cliapp.Application):
cliapp.runcmd(['umount', mount_point])
os.rmdir(mount_point)
- def create_btrfs_system_layout(self, temp_root, mountpoint, version_label):
+ def create_btrfs_system_layout(self, temp_root, mountpoint, version_label,
+ disk_uuid=None):
'''Separate base OS versions from state using subvolumes.
'''
+ initramfs = self.find_initramfs(temp_root)
version_root = os.path.join(mountpoint, 'systems', version_label)
state_root = os.path.join(mountpoint, 'state')
@@ -238,7 +248,12 @@ class WriteExtension(cliapp.Application):
if self.bootloader_is_wanted():
self.install_kernel(version_root, temp_root)
self.install_syslinux_menu(mountpoint, version_root)
- self.install_extlinux(mountpoint)
+ if initramfs is not None:
+ self.install_initramfs(initramfs, version_root)
+ self.install_extlinux(mountpoint, disk_uuid)
+ else:
+ self.install_extlinux(mountpoint)
+
def create_orig(self, version_root, temp_root):
'''Create the default "factory" system.'''
@@ -322,6 +337,29 @@ class WriteExtension(cliapp.Application):
fstab.write()
return state_dirs_to_create
+ def find_initramfs(self, temp_root):
+ '''Check whether the rootfs has an initramfs.
+
+ Uses the INITRAMFS_PATH option to locate it.
+ '''
+ if 'INITRAMFS_PATH' in os.environ:
+ initramfs = os.path.join(temp_root, os.environ['INITRAMFS_PATH'])
+ if not os.path.exists(initramfs):
+ raise morphlib.Error('INITRAMFS_PATH specified, '
+ 'but file does not exist')
+ return initramfs
+ return None
+
+ def install_initramfs(self, initramfs_path, version_root):
+ '''Install the initramfs outside of 'orig' or 'run' subvolumes.
+
+ This is required because syslinux doesn't traverse subvolumes when
+ loading the kernel or initramfs.
+ '''
+ self.status(msg='Installing initramfs')
+ initramfs_dest = os.path.join(version_root, 'initramfs')
+ cliapp.runcmd(['cp', '-a', initramfs_path, initramfs_dest])
+
def install_kernel(self, version_root, temp_root):
'''Install the kernel outside of 'orig' or 'run' subvolumes'''
@@ -337,20 +375,28 @@ class WriteExtension(cliapp.Application):
def get_extra_kernel_args(self):
return os.environ.get('KERNEL_ARGS', '')
- def install_extlinux(self, real_root):
+ def install_extlinux(self, real_root, disk_uuid=None):
'''Install extlinux on the newly created disk image.'''
self.status(msg='Creating extlinux.conf')
config = os.path.join(real_root, 'extlinux.conf')
- kernel_args = self.get_extra_kernel_args()
+ kernel_args = (
+ 'rw ' # ro ought to work, but we don't test that regularly
+ 'init=/sbin/init ' # default, but it doesn't hurt to be explicit
+ 'rootfstype=btrfs ' # required when using initramfs, also boots
+ # faster when specified without initramfs
+ 'rootflags=subvol=systems/default/run ') # boot runtime subvol
+ kernel_args += 'root=%s ' % ('/dev/sda' if disk_uuid is None
+ else 'UUID=%s' % disk_uuid)
+ kernel_args += self.get_extra_kernel_args()
with open(config, 'w') as f:
f.write('default linux\n')
f.write('timeout 1\n')
f.write('label linux\n')
f.write('kernel /systems/default/kernel\n')
- f.write('append root=/dev/sda '
- 'rootflags=subvol=systems/default/run '
- '%s init=/sbin/init rw\n' % (kernel_args))
+ if disk_uuid is not None:
+ f.write('initrd /systems/default/initramfs\n')
+ f.write('append %s\n' % kernel_args)
self.status(msg='Installing extlinux')
cliapp.runcmd(['extlinux', '--install', real_root])