summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2014-03-18 16:42:03 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2014-03-20 16:33:34 +0000
commitfcf5150e927147bbce338a61101ccbb3d760f07c (patch)
tree371099eaffd417f61878f0c756a50964c35ba2b6
parent31aadea7e49617a783f924fe373e642c88157a2b (diff)
downloaddefinitions-baserock/richardmaw/S10721-img-pkg.tar.gz
Add write extension for making a package that allows deferred instansiationbaserock/richardmaw/S10721-img-pkg
This is a write extension for making a package that can be used to install the produced system. Ideally we'd instead have Baserock everywhere to do the deployment, but we need to support this workflow until that is possible. It gets configured with a script templates that get filled in with the paths to the rootfs tarball as @@ROOTFS_TAR_PATH@@, script directory as @@SCRIPT_DIR@@ and copied boot-files as @@IMAGE_DIR@@. Scripts to include are specified as a relative path to your morphologies repository, separated by : characters in the INCLUDE_SCRIPTS variable. If another separator is convenient, it can be specified in the INCLUDE_SCRIPTS_SEPARATOR variable, which has the same semantics as the shell IFS variable. Other files needed to create the disk image, such as bootloader image files can be specified in BOOTLOADER_BLOBS, relative to the root of the rootfs, separated with similar rules to INCLUDE_SCRIPTS. The name of the rootfs tarball, the scripts subdirectory and the bootloader blobs subdirectory can be changed with the ROOTFS_TAR, SCRIPT_SUBDIR and IMAGE_SUBDIR variables, but the default should be sufficient. The compression of the rootfs tarball, and the package tarball can be specified by specifying a shell command that reads the uncompressed tarball from stdin and writes to stdout in the ROOTFS_COMPRESS and OUTPUT_COMPRESS variables.
-rw-r--r--imgpkg.morph12
-rwxr-xr-ximgpkg.write142
-rw-r--r--imgpkg/common.sh.in71
-rw-r--r--imgpkg/disk-install.sh.in47
-rw-r--r--imgpkg/make-disk-image.sh.in33
5 files changed, 305 insertions, 0 deletions
diff --git a/imgpkg.morph b/imgpkg.morph
new file mode 100644
index 00000000..a7018459
--- /dev/null
+++ b/imgpkg.morph
@@ -0,0 +1,12 @@
+name: imgpkg
+kind: cluster
+description: |
+ Packaged system and script for installing it, for deferred instansiation.
+systems:
+- morph: base-system-x86_32-generic
+ deploy:
+ imgpkg:
+ type: imgpkg
+ location: imgpkg.tar
+ BOOTLOADER_BLOBS: "/usr/share/syslinux/mbr.bin"
+ INCLUDE_SCRIPTS: "imgpkg/make-disk-image.sh.in:imgpkg/disk-install.sh.in:imgpkg/common.sh.in"
diff --git a/imgpkg.write b/imgpkg.write
new file mode 100755
index 00000000..c911c89b
--- /dev/null
+++ b/imgpkg.write
@@ -0,0 +1,142 @@
+#!/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 =*=
+#
+#
+# This is a write extension for making a package that can be used to
+# install the produced system. Ideally we'd instead have Baserock
+# everywhere to do the deployment, but we need to support this workflow
+# until that is possible.
+#
+# It gets configured with a script templates that get filled in with the
+# paths to the rootfs tarball as @@ROOTFS_TAR_PATH@@, script directory as
+# @@SCRIPT_DIR@@ and copied boot-files as @@IMAGE_DIR@@.
+#
+# Scripts to include are specified as a relative path to your morphologies
+# repository, separated by : characters in the INCLUDE_SCRIPTS variable.
+# If another separator is convenient, it can be specified in the
+# INCLUDE_SCRIPTS_SEPARATOR variable, which has the same semantics as the
+# shell IFS variable.
+#
+# Other files needed to create the disk image, such as bootloader image
+# files can be specified in BOOTLOADER_BLOBS, relative to the root of the
+# rootfs, separated with similar rules to INCLUDE_SCRIPTS.
+#
+# The name of the rootfs tarball, the scripts subdirectory and the
+# bootloader blobs subdirectory can be changed with the ROOTFS_TAR,
+# SCRIPT_SUBDIR and IMAGE_SUBDIR variables, but the default should be
+# sufficient.
+#
+# The compression of the rootfs tarball, and the package tarball can be
+# specified by specifying a shell command that reads the uncompressed
+# tarball from stdin and writes to stdout in the ROOTFS_COMPRESS and
+# OUTPUT_COMPRESS variables.
+
+set -eu
+
+die(){
+ echo "$@" >&2
+ exit 1
+}
+
+warn(){
+ echo "$@" >&2
+}
+
+info(){
+ echo "$@" >&2
+}
+
+shellescape(){
+ echo "'$(echo "$1" | sed -e "s/'/'\\''/g")'"
+}
+
+sedescape(){
+ # Escape the passed in string so it can be safely interpolated into
+ # a sed expression as a literal value.
+ echo "$1" | sed -e 's/[\/&]/\\&/g'
+}
+
+ROOTDIR="$1"
+OUTPUT_TAR="$2"
+td="$(mktemp -d)"
+IMAGE_SUBDIR="${IMAGE_SUBDIR-image_files}"
+SCRIPT_SUBDIR="${SCRIPT_SUBDIR-tools}"
+ROOTFS_TAR="${ROOTFS_TAR-rootfs.tar}"
+
+install_script(){
+ local source_file="$1"
+ local output_dir="$2"
+ local target_file="$output_dir/$SCRIPT_SUBDIR/$(basename "$source_file" .in)"
+ local find_script_dir='"$(readlink -f "$(dirname "$0")")"'
+ local image_dir="$find_script_dir/../$(shellescape "$IMAGE_SUBDIR")"
+ local rootfs_tar_path="$image_dir/$(shellescape "$ROOTFS_TAR")"
+ sed -e "s/@@SCRIPT_DIR@@/$(sedescape "$find_script_dir")/g" \
+ -e "s/@@IMAGE_DIR@@/$(sedescape "$image_dir")/g" \
+ -e "s/@@ROOTFS_TAR_PATH@@/$(sedescape "$rootfs_tar_path")/g" \
+ "$source_file" \
+ | install -D -m 755 /proc/self/fd/0 "$target_file"
+}
+
+install_scripts(){
+ local output_dir="$1"
+ (
+ IFS="${INCLUDE_SCRIPTS_SEPATATOR-:}"
+ for script in $INCLUDE_SCRIPTS; do
+ local script_path="$(pwd)/$script"
+ if [ ! -e "$script_path" ]; then
+ warn Script "$script" not found, ignoring
+ continue
+ fi
+ install_script "$script" "$output_dir"
+ done
+ )
+}
+
+install_bootloader_blobs(){
+ local output_dir="$1"
+ local image_dir="$output_dir/$IMAGE_SUBDIR"
+ (
+ IFS="${BOOTLOADER_BLOBS_SEPATATOR-:}"
+ for blob in $BOOTLOADER_BLOBS; do
+ local blob_path="$ROOTDIR/$blob"
+ if [ ! -e "$blob_path" ]; then
+ warn Bootloader blob "$blob" not found, ignoring
+ continue
+ fi
+ install -D -m644 "$blob_path" "$image_dir/$(basename "$blob_path")"
+ done
+ )
+}
+
+output_dir="$(basename "$OUTPUT_TAR")"
+for ext in .xz .bz2 .gzip .gz .tgz .tar; do
+ output_dir="${output_dir%$ext}"
+done
+
+info Installing scripts
+install_scripts "$td/$output_dir"
+
+info Installing bootloader blobs
+install_bootloader_blobs "$td/$output_dir"
+
+info Writing rootfs tar to "$IMAGE_SUBDIR/$ROOTFS_TAR"
+tar -C "$ROOTDIR" -c . \
+| sh -c "${ROOTFS_COMPRESS-cat}" >"$td/$output_dir/$IMAGE_SUBDIR/$ROOTFS_TAR"
+
+info Writing image package tar to "$OUTPUT_TAR"
+tar -C "$td" -c "$output_dir" | sh -c "${OUTPUT_COMPRESS-cat}" >"$OUTPUT_TAR"
diff --git a/imgpkg/common.sh.in b/imgpkg/common.sh.in
new file mode 100644
index 00000000..08473a6b
--- /dev/null
+++ b/imgpkg/common.sh.in
@@ -0,0 +1,71 @@
+#!/bin/false
+
+status(){
+ echo "$@"
+}
+
+info(){
+ echo "$@" >&2
+}
+
+warn(){
+ echo "$@" >&2
+}
+
+extract_rootfs(){
+ tar -C "$1" -xf @@ROOTFS_TAR_PATH@@ .
+}
+
+make_disk_image(){
+ truncate --size "$1" "$2"
+}
+
+format_disk(){
+ local disk="$1"
+ mkfs.ext4 -F -L rootfs "$disk"
+}
+
+install_fs_config(){
+ local mountpoint="$1"
+ local rootdisk="${2-/dev/vda}"
+ cat >>"$mountpoint/etc/fstab" <<EOF
+$rootdisk / ext4 rw,errors=remount-ro 0 0
+EOF
+ install -D -m 644 /proc/self/fd/0 "$mountpoint/boot/extlinux.conf" <<EOF
+DEFAULT baserock
+LABEL baserock
+SAY Booting Baserock
+LINUX /boot/vmlinuz
+APPEND root=$rootdisk
+EOF
+}
+
+install_bootloader(){
+ local disk="$1"
+ local mountpoint="$2"
+ dd if=@@IMAGE_DIR@@/mbr.bin conv=notrunc bs=440 count=1 of="$disk"
+ extlinux --install "$mountpoint/boot"
+}
+
+loop_file(){
+ losetup --show --find "$1"
+}
+unloop_file(){
+ #losetup --detach "$1"
+ # unlooping handled by umount -d, for busybox compatibility
+ true
+}
+
+temp_mount(){
+ local mp="$(mktemp -d)"
+ if ! mount "$@" "$mp"; then
+ rmdir "$mp"
+ return 1
+ fi
+ echo "$mp"
+}
+untemp_mount(){
+ # Unmount and detach in one step for busybox compatibility
+ umount -d "$1"
+ rmdir "$1"
+}
diff --git a/imgpkg/disk-install.sh.in b/imgpkg/disk-install.sh.in
new file mode 100644
index 00000000..60b3f465
--- /dev/null
+++ b/imgpkg/disk-install.sh.in
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+set -eu
+
+usage(){
+ cat <<EOF
+usage: $0 DISK [TARGET_DISK]
+
+DISK: Where the disk appears on your development machine
+TARGET_DISK: What the disk will appear as on the target machine
+EOF
+}
+
+. @@SCRIPT_DIR@@/common.sh
+
+if [ "$#" -lt 1 -o "$#" -gt 2 ]; then
+ usage
+ exit 1
+fi
+
+DISK="$1"
+TARGET_DISK="${1-/dev/sda}"
+
+status Formatting "$DISK" as ext4
+format_disk "$DISK"
+(
+ info Mounting "$DISK"
+ MP="$(temp_mount -t ext4 "$DISK")"
+ info Mounted "$DISK" to "$MP"
+ set +e
+ (
+ set -e
+ info Copying rootfs onto disk
+ extract_rootfs "$MP"
+ info Configuring disk paths
+ install_fs_config "$MP" "$TARGET_DISK"
+ info Installing bootloader
+ install_bootloader "$DISK" "$MP"
+ )
+ ret="$?"
+ if [ "$ret" != 0 ]; then
+ warn Filling rootfs failed with "$ret"
+ fi
+ info Unmounting "$DISK" from "$MP" and removing "$MP"
+ untemp_mount "$MP"
+ exit "$ret"
+)
diff --git a/imgpkg/make-disk-image.sh.in b/imgpkg/make-disk-image.sh.in
new file mode 100644
index 00000000..29a0e13a
--- /dev/null
+++ b/imgpkg/make-disk-image.sh.in
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+usage(){
+ cat <<EOF
+usage: $0 FILENAME SIZE [TARGET_DISK]
+
+FILENAME: Location to write the disk image to
+SIZE: Size to create the disk image with
+TARGET_DISK: What the disk will appear as on the target machine
+EOF
+}
+
+. @@SCRIPT_DIR@@/common.sh
+
+if [ "$#" -lt 2 -o "$#" -gt 3 ]; then
+ usage
+ exit 1
+fi
+
+DISK_IMAGE="$1"
+DISK_SIZE="$2"
+TARGET_DISK="${3-/dev/vda}"
+
+make_disk_image "$DISK_SIZE" "$DISK_IMAGE"
+
+(
+ LOOP="$(loop_file "$DISK_IMAGE")"
+ set +e
+ @@SCRIPT_DIR@@/disk-install.sh "$DISK_IMAGE" "$TARGET_DISK"
+ ret="$?"
+ unloop_file "$LOOP"
+ exit "$ret"
+)