2013-05-09 16:34:53 +00:00
|
|
|
# vim: syntax=sh ts=4 sts=4 sw=2:et
|
2012-11-15 03:20:32 +00:00
|
|
|
# Copyright 2012 Hewlett-Packard Development Company, L.P.
|
|
|
|
# All Rights Reserved.
|
2013-01-25 22:23:56 +00:00
|
|
|
#
|
2012-11-15 03:20:32 +00:00
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
|
|
# not use this file except in compliance with the License. You may obtain
|
|
|
|
# a copy of the License at
|
2013-01-25 22:23:56 +00:00
|
|
|
#
|
2012-11-15 03:20:32 +00:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2013-01-25 22:23:56 +00:00
|
|
|
#
|
2012-11-15 03:20:32 +00:00
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
# License for the specific language governing permissions and limitations
|
|
|
|
# under the License.
|
|
|
|
|
2013-05-02 21:02:38 +00:00
|
|
|
function tmpfs_check() {
|
|
|
|
[ "$DIB_NO_TMPFS" == "0" ] || return 1
|
|
|
|
[ -r /proc/meminfo ] || return 1
|
|
|
|
total_kB=$(awk '/^MemTotal/ { print $2 }' /proc/meminfo)
|
2013-08-26 11:57:34 +00:00
|
|
|
# tmpfs uses by default 50% of the available RAM, so the RAM should be at least
|
|
|
|
# the double of the minimum tmpfs size required
|
2014-09-30 12:52:46 +00:00
|
|
|
RAM_NEEDED=$(($DIB_MIN_TMPFS * 2))
|
2013-08-26 11:57:34 +00:00
|
|
|
[ $total_kB -lt $(($RAM_NEEDED*1024*1024)) ] || return 0
|
|
|
|
echo "Not enough RAM to use tmpfs for build. ($total_kB < ${RAM_NEEDED}G)"
|
2013-05-02 21:02:38 +00:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2012-11-09 18:18:08 +00:00
|
|
|
function mk_build_dir () {
|
2013-07-31 18:26:05 +00:00
|
|
|
TMP_BUILD_DIR=$(mktemp -t -d --tmpdir=${TMP_DIR:-/tmp} image.XXXXXXXX)
|
2014-05-01 09:22:15 +00:00
|
|
|
TMP_IMAGE_DIR=$(mktemp -t -d --tmpdir=${TMP_DIR:-/tmp} image.XXXXXXXX)
|
2012-11-09 18:18:08 +00:00
|
|
|
[ $? -eq 0 ] || die "Failed to create tmp directory"
|
2013-07-31 18:26:05 +00:00
|
|
|
export TMP_BUILD_DIR
|
2013-05-02 21:02:38 +00:00
|
|
|
if tmpfs_check ; then
|
2014-03-26 10:06:54 +00:00
|
|
|
sudo mount -t tmpfs tmpfs $TMP_BUILD_DIR
|
2014-05-01 09:22:15 +00:00
|
|
|
sudo mount -t tmpfs tmpfs $TMP_IMAGE_DIR
|
2013-05-02 21:02:38 +00:00
|
|
|
fi
|
2014-05-01 09:22:15 +00:00
|
|
|
sudo chown $(id -u):$(id -g) $TMP_BUILD_DIR $TMP_IMAGE_DIR
|
2014-10-11 00:01:37 +00:00
|
|
|
trap trap_cleanup EXIT
|
2012-11-09 18:18:08 +00:00
|
|
|
echo Building in $TMP_BUILD_DIR
|
2014-05-01 09:22:15 +00:00
|
|
|
export TMP_IMAGE_PATH=$TMP_IMAGE_DIR/image.raw
|
2014-10-01 19:34:21 +00:00
|
|
|
export OUT_IMAGE_PATH=$TMP_IMAGE_PATH
|
2012-11-09 18:18:08 +00:00
|
|
|
export TMP_HOOKS_PATH=$TMP_BUILD_DIR/hooks
|
|
|
|
}
|
|
|
|
|
2014-03-25 01:16:06 +00:00
|
|
|
function finish_image () {
|
2014-06-26 06:22:31 +00:00
|
|
|
if [ -f $1 -a ${OVERWRITE_OLD_IMAGE:-0} -eq 0 ]; then
|
2014-05-13 13:57:35 +00:00
|
|
|
old_image="${1%.*}"-$(date +%Y.%m.%d-%H.%M.%S).${1##*.}
|
2014-06-26 06:22:31 +00:00
|
|
|
echo "Old image found. Renaming it to $old_image"
|
2014-05-13 13:57:35 +00:00
|
|
|
mv "$1" "$old_image"
|
|
|
|
fi
|
|
|
|
|
2014-10-01 19:34:21 +00:00
|
|
|
mv $OUT_IMAGE_PATH $1
|
2014-03-25 01:16:06 +00:00
|
|
|
echo "Image file $1 created..."
|
|
|
|
}
|
|
|
|
|
2012-11-09 18:18:08 +00:00
|
|
|
function save_image () {
|
2014-06-26 06:22:31 +00:00
|
|
|
finish_image $1
|
2012-11-09 18:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function generate_hooks () {
|
|
|
|
mkdir -p $TMP_HOOKS_PATH
|
2013-06-20 02:58:14 +00:00
|
|
|
for _ELEMENT in $IMAGE_ELEMENT ; do
|
2014-05-02 17:10:33 +00:00
|
|
|
for dir in ${ELEMENTS_PATH//:/ } ; do
|
2014-10-08 07:53:31 +00:00
|
|
|
[ -d $dir/$_ELEMENT ] || continue
|
2013-02-25 09:17:32 +00:00
|
|
|
cp -t $TMP_HOOKS_PATH -a $dir/$_ELEMENT/* ;
|
|
|
|
break
|
|
|
|
done
|
2012-11-09 18:18:08 +00:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2012-12-14 07:17:00 +00:00
|
|
|
# Call the supplied break-in routine if the named point is listed in the break
|
|
|
|
# list.
|
|
|
|
# $1 the break point.
|
|
|
|
# $2.. what to call if a break is needed
|
|
|
|
function check_break () {
|
2014-04-03 22:49:18 +00:00
|
|
|
if echo "${break:-}" | egrep -e "(,|^)$1(,|$)" -q; then
|
2012-12-14 07:17:00 +00:00
|
|
|
echo "Starting debug shell. Exit to resume building." >&2
|
|
|
|
echo At stage $1 >&2
|
|
|
|
shift
|
|
|
|
"$@"
|
|
|
|
echo "Resuming" >&2
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2012-11-30 20:47:57 +00:00
|
|
|
# Check that a real element has been chosen (prevents foot-guns)
|
|
|
|
function check_element () {
|
2012-11-09 18:18:08 +00:00
|
|
|
[ -d $TMP_HOOKS_PATH ] || generate_hooks
|
|
|
|
}
|
|
|
|
|
2012-11-11 22:47:26 +00:00
|
|
|
# Run a hook, looking for a regex in its stdout, and eval the matched lines.
|
|
|
|
# $1 is the hook to run
|
|
|
|
# $2 is the regex to look for
|
|
|
|
function eval_run_d () {
|
|
|
|
local TEMP=`run_d $1`
|
|
|
|
echo "$TEMP"
|
2012-11-12 00:45:57 +00:00
|
|
|
if [ `echo "$TEMP" | grep -s "$2"` ]; then
|
|
|
|
TEMP=`echo "$TEMP" | grep "$2"`
|
|
|
|
eval "$TEMP"
|
|
|
|
fi
|
2012-11-11 22:47:26 +00:00
|
|
|
}
|
2012-11-17 02:30:15 +00:00
|
|
|
|
|
|
|
# Usage: map_nbd $image
|
|
|
|
# Returns nbd device path
|
|
|
|
function map_nbd {
|
2013-12-09 12:58:25 +00:00
|
|
|
(lsmod | grep '^nbd ' >/dev/null) || sudo modprobe nbd max_part=16
|
2012-11-17 02:30:15 +00:00
|
|
|
|
2013-01-25 22:23:56 +00:00
|
|
|
if [[ $(qemu-nbd --help | grep cache) == *writeback* ]] ; then
|
2012-11-17 02:30:15 +00:00
|
|
|
CACHE="--cache=writeback"
|
2013-01-25 22:23:56 +00:00
|
|
|
else
|
2012-11-17 02:30:15 +00:00
|
|
|
echo "Warning: qemu-nbd without --cache=writeback is /slow/."
|
|
|
|
CACHE=""
|
|
|
|
fi
|
|
|
|
NBD_DEV=
|
|
|
|
for i in `seq 0 15`; do
|
|
|
|
if [ ! -e /sys/block/nbd$i/pid ]; then
|
|
|
|
NBD_DEV=/dev/nbd$i
|
|
|
|
# Connect to nbd and wait till it is ready
|
|
|
|
sudo qemu-nbd -c $NBD_DEV $CACHE $1
|
|
|
|
if ! timeout 60 sh -c "while ! [ -e /sys/block/nbd$i/pid ]; do sleep 1; done"; then
|
|
|
|
echo "Couldn't connect $NBD_DEV"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
if [ -z "$NBD_DEV" ]; then
|
|
|
|
echo "No free NBD slots"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# Delete and unmount the working dir used in extracting kernel/initrd
|
|
|
|
function unmount_qcow_image () {
|
|
|
|
sudo umount $WORK_DIR || true
|
2013-12-09 12:58:25 +00:00
|
|
|
sudo qemu-nbd -d $NBD_DEV >/dev/null || true
|
2012-11-17 02:30:15 +00:00
|
|
|
sudo rm -rf $WORK_DIR
|
|
|
|
|
|
|
|
trap - SIGHUP SIGINT SIGTERM EXIT
|
|
|
|
}
|
|
|
|
|
|
|
|
function mount_qcow_image() {
|
|
|
|
trap unmount_qcow_image SIGHUP SIGINT SIGTERM EXIT
|
|
|
|
|
|
|
|
WORK_DIR=$(mktemp -d)
|
|
|
|
map_nbd $1
|
2012-11-22 03:00:53 +00:00
|
|
|
if [ -e "${NBD_DEV}p1" ]; then
|
|
|
|
sudo mount ${NBD_DEV}p1 $WORK_DIR
|
|
|
|
else
|
|
|
|
sudo mount ${NBD_DEV} $WORK_DIR
|
|
|
|
fi
|
2012-11-17 02:30:15 +00:00
|
|
|
}
|
2013-05-06 16:11:49 +00:00
|
|
|
|
|
|
|
function cleanup_dirs () {
|
|
|
|
sudo rm -rf $TMP_BUILD_DIR/built
|
|
|
|
sudo rm -rf $TMP_BUILD_DIR/mnt
|
2014-05-01 09:22:15 +00:00
|
|
|
sudo umount -f $TMP_BUILD_DIR $TMP_IMAGE_DIR || true
|
|
|
|
rm -rf $TMP_BUILD_DIR $TMP_IMAGE_DIR
|
2013-05-06 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
2014-07-16 06:59:49 +00:00
|
|
|
# Run a directory of hooks outside the target (that is, no chrooting).
|
2013-05-06 16:11:49 +00:00
|
|
|
function run_d() {
|
|
|
|
check_element
|
|
|
|
check_break before-$1 bash
|
|
|
|
if [ -d ${TMP_HOOKS_PATH}/$1.d ] ; then
|
2014-06-14 00:38:16 +00:00
|
|
|
dib-run-parts ${TMP_HOOKS_PATH}/$1.d
|
2013-05-06 16:11:49 +00:00
|
|
|
fi
|
|
|
|
check_break after-$1 bash
|
|
|
|
}
|
|
|
|
|
2013-05-09 16:34:53 +00:00
|
|
|
function detach_loopback() {
|
|
|
|
local loopdev=$1
|
2013-08-15 16:35:07 +00:00
|
|
|
|
|
|
|
# Remove the map if it exists
|
|
|
|
# If setup on a rhel or derivative the map was created with kpartx not losetup
|
|
|
|
# and subsequently needs to be removed.
|
|
|
|
loopdev_name=$(echo $loopdev | sed 's/\/dev\///g')
|
|
|
|
mapper_name=$(sudo dmsetup ls | grep $loopdev_name | awk '{ print $1 }')
|
|
|
|
if [ "$mapper_name" ]; then
|
|
|
|
sudo dmsetup remove $mapper_name
|
|
|
|
fi
|
|
|
|
|
2013-05-09 16:34:53 +00:00
|
|
|
# loopback dev may be tied up a bit by udev events triggered by partition events
|
|
|
|
for try in $(seq 10 -1 1) ; do
|
2014-10-06 18:04:06 +00:00
|
|
|
if ! sudo losetup $loopdev || sudo losetup -d $loopdev ; then
|
2013-05-09 16:34:53 +00:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
echo $loopdev may be busy, sleeping up to $try more seconds...
|
|
|
|
sleep 1
|
|
|
|
done
|
|
|
|
echo Gave up trying to detach $loopdev
|
|
|
|
return 1
|
|
|
|
}
|
2013-06-20 03:48:37 +00:00
|
|
|
|
|
|
|
function arg_to_elements() {
|
|
|
|
for arg do IMAGE_ELEMENT="$IMAGE_ELEMENT $arg" ; done
|
|
|
|
|
|
|
|
if [ "$SKIP_BASE" != "1" ]; then
|
|
|
|
IMAGE_ELEMENT="base $IMAGE_ELEMENT"
|
|
|
|
fi
|
2013-07-01 16:20:15 +00:00
|
|
|
if [ "$IS_RAMDISK" == "1" ]; then
|
2014-09-26 05:12:32 +00:00
|
|
|
IMAGE_ELEMENT="$RAMDISK_ELEMENT $IMAGE_ELEMENT"
|
2013-07-01 16:20:15 +00:00
|
|
|
fi
|
2013-06-20 03:48:37 +00:00
|
|
|
echo "Building elements: $IMAGE_ELEMENT"
|
|
|
|
|
2014-05-30 19:38:17 +00:00
|
|
|
IMAGE_ELEMENT=$($SCRIPT_HOME/element-info --expand-dependencies $IMAGE_ELEMENT)
|
|
|
|
export IMAGE_ELEMENT
|
2013-06-20 03:48:37 +00:00
|
|
|
|
|
|
|
echo "Expanded element dependencies to: $IMAGE_ELEMENT"
|
|
|
|
}
|
2013-06-20 04:47:22 +00:00
|
|
|
|
|
|
|
function create_base () {
|
|
|
|
mkdir $TMP_BUILD_DIR/mnt
|
|
|
|
export TMP_MOUNT_PATH=$TMP_BUILD_DIR/mnt
|
|
|
|
# Copy data in to the root.
|
|
|
|
TARGET_ROOT=$TMP_MOUNT_PATH run_d root
|
Move /tmp/ccache setup to base element
Commit c7d80dd (Cleanup mount points automatically) removed the unmount
of $TMP_MOUNT_PATH/tmp/ccache in run_d_in_target() and moved the
"rm /tmp/ccache" to elements/base/finalise.d/02-remove-ccache. There
are two problems with this:
1) Not unmounting at the end of run_d_in_target() results in tmp/ccache
being bind mounted muliple times on top of itself (three times, if you
just run `disk-image-create base`). It is eventually unmounted, but
somehow the auto unmount code is confused, and tries to unmount it
one more time than it was mounted, which results in an error like
"umount: /tmp/image.THQkZxQa/mnt/tmp/ccache: not mounted".
This doesn't actually break anything, but it's a little messy.
2) "rm /tmp/ccache" in elements/base/finalise.d/02-remove-ccache never
succeeds in removing /tmp/ccache, because that hook is invoked by
run_d_in_target(), *while* /tmp/ccache is mounted.
This present commit solves the above by moving the ccache setup glue out
of img-functions and into the base element's root.d. This has the
following implications:
1) lib/img-functions is a little cleaner.
2) /tmp/ccache is available in the chroot during the root, extra-data,
pre-install, install and post-install stages. It is not available
during block-device, finalise and cleanup stages as it will have been
automatically unmounted by then.
3) /tmp/ccache won't be setup if you're building an image that doesn't
include the base element.
Change-Id: Ief4c0a6f4ec622db6c6f652776215684178d8943
2013-10-08 12:53:16 +00:00
|
|
|
if [ -z "$(ls $TMP_MOUNT_PATH | grep -v '^lost+found\|tmp$')" ] ; then
|
2013-11-26 18:59:14 +00:00
|
|
|
# No root element copied in. Note the test above allows
|
|
|
|
# root.d elements to put things in /tmp
|
2014-04-30 15:59:49 +00:00
|
|
|
echo "Failed to deploy the root element."
|
2013-11-26 18:59:14 +00:00
|
|
|
exit 1
|
2013-06-20 04:47:22 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
# Configure Image
|
|
|
|
# Setup resolv.conf so we can chroot to install some packages
|
|
|
|
if [ -L $TMP_MOUNT_PATH/etc/resolv.conf ] || [ -f $TMP_MOUNT_PATH/etc/resolv.conf ] ; then
|
|
|
|
sudo mv $TMP_MOUNT_PATH/etc/resolv.conf $TMP_MOUNT_PATH/etc/resolv.conf.ORIG
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Recreate resolv.conf
|
|
|
|
sudo touch $TMP_MOUNT_PATH/etc/resolv.conf
|
|
|
|
sudo chmod 777 $TMP_MOUNT_PATH/etc/resolv.conf
|
|
|
|
# use system configured resolv.conf if available to support internal proxy resolving
|
2014-07-01 09:27:41 +00:00
|
|
|
if [ -e /etc/resolv.conf ]; then
|
2013-06-20 04:47:22 +00:00
|
|
|
cat /etc/resolv.conf > $TMP_MOUNT_PATH/etc/resolv.conf
|
|
|
|
else
|
|
|
|
echo nameserver 8.8.8.8 > $TMP_MOUNT_PATH/etc/resolv.conf
|
|
|
|
fi
|
|
|
|
mount_proc_dev_sys
|
|
|
|
}
|
|
|
|
|
|
|
|
function mount_proc_dev_sys () {
|
|
|
|
# supporting kernel file systems
|
|
|
|
sudo mount -t proc none $TMP_MOUNT_PATH/proc
|
|
|
|
sudo mount --bind /dev $TMP_MOUNT_PATH/dev
|
2013-10-08 10:41:18 +00:00
|
|
|
sudo mount --bind /dev/pts $TMP_MOUNT_PATH/dev/pts
|
2013-06-20 04:47:22 +00:00
|
|
|
sudo mount -t sysfs none $TMP_MOUNT_PATH/sys
|
|
|
|
}
|
|
|
|
|
2013-12-24 08:24:59 +00:00
|
|
|
function unmount_dir () {
|
|
|
|
local pattern="$1" mnts=""
|
|
|
|
if [ -n "$pattern" ]; then
|
|
|
|
mnts=`awk '{print $2}' < /proc/mounts | grep "^$pattern" | sort -r`
|
|
|
|
fi
|
|
|
|
if [ -n "$mnts" ]; then
|
|
|
|
sudo umount -fl $mnts || true
|
|
|
|
fi
|
|
|
|
}
|