-#!/bin/sh
+#!/bin/bash
-# Copyright (C) 2007 Google Inc.
+# Copyright (C) 2007, 2008, 2009, 2012 Google Inc.
#
# 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
set -e
-# Customize this if you need another mirror, or set to empty to get the
-# node's sources.list
-MIRROR="http://ftp.debian.org/debian"
-DPKG_ARCH="`dpkg --print-architecture`"
-CACHE_FILE="cache-${DPKG_ARCH}.tar"
+# minimum device size is 256 MB, but we use 255 to account for
+# potential rounding
+declare -ri MIN_DEV_SIZE=$((255*1048576))
-TEMP=`getopt -o i:b:s: -n '$0' -- "$@"`
+. common.sh
-if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+if [ "$GENERATE_CACHE" = "yes" -a ! -d "$CACHE_DIR" ]; then
+ mkdir -p "$CACHE_DIR"
+fi
-# Note the quotes around `$TEMP': they are essential!
-eval set -- "$TEMP"
+DPKG_ARCH=${ARCH:-`dpkg --print-architecture`}
+CACHE_FILE="$CACHE_DIR/cache-${SUITE}-${DPKG_ARCH}.tar"
-while true; do
- case "$1" in
- -i) instance=$2; shift 2;;
+# If the target device is not a real block device we'll first losetup it.
+# This is needed for file disks.
+if [ ! -b $blockdev ]; then
+ ORIGINAL_BLOCKDEV=$blockdev
+ blockdev=$(losetup -sf $blockdev)
+ CLEANUP+=("losetup -d $blockdev")
+fi
- -b) blockdev=$2; shift 2;;
+DEVICE_SIZE=$(blockdev --getsize64 $blockdev)
+if [ "$DEVICE_SIZE" -lt $MIN_DEV_SIZE ]; then
+ echo "Device size is too small ($((DEVICE_SIZE/1048576)) MB)" 1>&2
+ echo "Required size is at least 256MB" 1>&2
+ exit 1
+fi
- -s) swapdev=$2; shift 2;;
+if [ "$PARTITION_STYLE" = "none" ]; then
+ filesystem_dev=$blockdev
+elif [ "$PARTITION_STYLE" = "msdos" ]; then
+ # Create one big partition, and make it bootable
+ format_disk0 $blockdev
+ filesystem_dev=$(map_disk0 $blockdev)
+ CLEANUP+=("unmap_disk0 $blockdev")
+else
+ echo "Unknown partition style $PARTITION_STYLE" 1>&2
+ exit 1
+fi
- --) shift; break;;
+mke2fs -Fjqt $OSP_FILESYSTEM $filesystem_dev
+root_uuid=$($VOL_ID $filesystem_dev )
- *) echo "Internal error!"; exit 1;;
- esac
-done
-if [ -z "$instance" -o -z "$blockdev" -o -z "$swapdev" ]; then
- echo "Missing -i or -b or -s argument!"
- exit 1
+if [ -n "$swapdev" ]; then
+ mkswap $swapdev
+ swap_uuid=$($VOL_ID $swapdev || true )
fi
-mkswap $swapdev
-mke2fs -Fjq $blockdev
TMPDIR=`mktemp -d` || exit 1
-trap "umount $TMPDIR; rmdir $TMPDIR" EXIT
-mount $blockdev $TMPDIR
+CLEANUP+=("rmdir $TMPDIR")
+
+mount $filesystem_dev $TMPDIR
+CLEANUP+=("umount $TMPDIR")
# remove the cache file if it's old (> 2 weeks) and writable by the owner (the
# default due to the standard umask)
-if [ -f "$CACHE_FILE" ]; then
- find "$CACHE_FILE" -perm -0200 -daystart -mtime +14 -print0 | \
- xargs -r0 rm -f
+if [ "$CLEAN_CACHE" -a -d "$CACHE_DIR" ]; then
+ find "$CACHE_DIR" -name 'cache-*.tar' -type f \
+ -daystart -mtime "+${CLEAN_CACHE}" -print0 | \
+ xargs -r0 rm -f
fi
if [ -f "$CACHE_FILE" ]; then
- tar xf "$CACHE_FILE" -C $TMPDIR
+ tar xf "$CACHE_FILE" -C $TMPDIR
else
- # On i386, we need the xen-specific library
- if [ "$DPKG_ARCH" = "i386" ]; then
- EXTRAPKG="linux-image-xen-686 libc6-xen"
- elif [ "$DPKG_ARCH" = "amd64" ]; then
- EXTRAPKG="linux-image-xen-amd64"
- fi
-
- debootstrap --include="$EXTRAPKG" etch $TMPDIR $MIRROR
-
- # remove the downloaded debs, as they are no longer needed
- find "$TMPDIR/var/cache/apt/archives" -type f -name '*.deb' -print0 | \
- xargs -r0 rm -f
-
- # remove the persistent-net rules, otherwise it will remember the node's
- # interfaces as eth0, eth1, ...
-
- rm -f "$TMPDIR/etc/udev/rules.d/z25_persistent-net.rules"
-
- if [ ! -e no_cache ]; then
- TMP_CACHE=`mktemp "${CACHE_FILE}.XXXXXX"`
- tar cf "$TMP_CACHE" -C $TMPDIR .
- mv -f "$TMP_CACHE" "$CACHE_FILE"
- fi
+ if [ "$PROXY" ]; then
+ export http_proxy="$PROXY"
+ export https_proxy="$PROXY"
+ fi
+ # INCLUDE will be empty if EXTRA_PKGS is null/empty, otherwise we
+ # build the full parameter format from it
+ INCLUDE=${EXTRA_PKGS:+"--include=$EXTRA_PKGS"}
+ COMP=${COMPONENTS:+"--components=$COMPONENTS"}
+ debootstrap \
+ --arch "$DPKG_ARCH" \
+ $INCLUDE \
+ $COMP \
+ "$SUITE" $TMPDIR $MIRROR
+
+ # remove the downloaded debs, as they are no longer needed
+ find "$TMPDIR/var/cache/apt/archives" -type f -name '*.deb' -print0 | \
+ xargs -r0 rm -f
+
+ # remove the persistent-net rules, otherwise it will remember the node's
+ # interfaces as eth0, eth1, ...
+ rm -f "$TMPDIR/etc/udev/rules.d/z25_persistent-net.rules"
+
+ if [ "$GENERATE_CACHE" = "yes" ]; then
+ TMP_CACHE=`mktemp "${CACHE_FILE}.XXXXXX"`
+ tar cf "$TMP_CACHE" -C $TMPDIR .
+ mv -f "$TMP_CACHE" "$CACHE_FILE"
+ fi
fi
+# reset the root password
+chroot $TMPDIR passwd -d root
+
cp -p /etc/hosts $TMPDIR/etc/hosts
cp -p /etc/resolv.conf $TMPDIR/etc/resolv.conf
echo $instance > $TMPDIR/etc/hostname
cat > $TMPDIR/etc/fstab <<EOF
# /etc/fstab: static file system information.
#
-# <file system> <mount point> <type> <options> <dump> <pass>
-/dev/sda / ext3 defaults 0 1
-/dev/sdb swap swap defaults 0 0
-proc /proc proc defaults 0 0
+# <file system> <mount point> <type> <options> <dump> <pass>
+UUID=$root_uuid / ext3 defaults 0 1
+proc /proc proc defaults 0 0
+EOF
+
+[ -n "$swapdev" -a -n "$swap_uuid" ] && cat >> $TMPDIR/etc/fstab <<EOF
+UUID=$swap_uuid swap swap defaults 0 0
EOF
cat > $TMPDIR/etc/network/interfaces <<EOF
iface lo inet loopback
EOF
-umount $TMPDIR
-rmdir $TMPDIR
+# for kvm, we should only activate a serial console if the
+# 'serial_console' parameter is set; for xen-pvm though, we should
+# always define a serial console
+SERIAL_PORT=""
+if [ "$INSTANCE_HV_serial_console" = "True" ]; then
+ SERIAL_PORT="ttyS0"
+elif [ "$HYPERVISOR" = "xen-pvm" ]; then
+ SERIAL_PORT="hvc0"
+fi
+
+if [ -n "$SERIAL_PORT" ]; then
+ if [ -e $TMPDIR/etc/inittab ]; then
+ # debian
+ echo "T0:23:respawn:/sbin/getty $SERIAL_PORT 38400" >> $TMPDIR/etc/inittab
+ elif [ -e $TMPDIR/etc/init ]; then
+ # ubuntu (eg. karmic)
+ cat > $TMPDIR/etc/init/${SERIAL_PORT}.conf <<EOF
+start on stopped rc RUNLEVEL=[2345]
+stop on runlevel [!2345]
+
+respawn
+exec /sbin/getty -8 38400 $SERIAL_PORT
+EOF
+ elif [ -e $TMPDIR/etc/event.d ]; then
+ # ubuntu (eg. intrepid)
+ cat > $TMPDIR/etc/event.d/${SERIAL_PORT}.conf <<EOF
+start on stopped rc2
+start on stopped rc3
+start on stopped rc4
+start on stopped rc5
+
+stop on runlevel 0
+stop on runlevel 1
+stop on runlevel 6
+
+respawn
+exec /sbin/getty 38400 ${SERIAL_PORT}
+EOF
+ fi
+fi
+
+RUN_PARTS=`which run-parts`
+
+if [ -n "$RUN_PARTS" -a -n "$CUSTOMIZE_DIR" -a -d "$CUSTOMIZE_DIR" ]; then
+ TARGET=$TMPDIR
+ BLOCKDEV=$blockdev
+ FSYSDEV=$filesystem_dev
+ export TARGET SUITE ARCH PARTITION_STYLE EXTRA_PKGS BLOCKDEV FSYSDEV
+ $RUN_PARTS $CUSTOMIZE_DIR
+fi
+
+# execute cleanups
+cleanup
trap - EXIT
exit 0