#!/bin/sh
# Copyright:
#   (c) 2013-2016, Thomas Goirand <zigo@debian.org>
#   (c) 2015-2016, Bastian Blank
# License: Apache 2.0, see LICENSE.txt for details.

set -e

export DEBIAN_FRONTEND=noninteractive

if [ "$UNSHARED" != true ] ; then
	exec env UNSHARED=true unshare --mount --pid --fork --mount-proc "$0" "$@"
fi

LC_ALL=C
export LC_ALL

# Parse input parameters
usage() {
	echo "Usage: $0 --release|-r <jessie|wheezy|stretch|buster|bullseye|booksworm|sid> [options]
Options are:
 --minimal|-m
 --azure|-az
 --boot-manager|-bm <grub|syslinux> (default: grub)
 --debootstrap-url|-u <debootstrap-mirror> (default: http://deb.debian.org/debian)
 --sources.list-mirror|-s <source-list-mirror> (default: http://deb.debian.org/debian)
 --extra-packages|-e <package>,<package>,...
 --hook-script|-hs <hook-script>
 --image-size|-is <image-size> (default: 2G)
 --automatic-resize|-ar
 --automatic-resize-space|-ars <suplementary-space> (default: 50M)
 --login|-l <userlogin> (default: debian)
 --password|-p <root-password> (dangerous option: avoid it if possible)
 --boot-type|-bt <boot type> (default: mbr)
 --architecture|-a <architecture> (default: amd64)
 --dest-hdd <dest-hdd>
 --no-cloud-init
 --root-ssh-key <path-to-id_rsa.pub>
 --permit-ssh-as-root
 --no-remove-host-keys (no effect if not generating a VM image using --dest-hdd)
 --hostname <hostname>
 --static-iface type=<normal,bond,bondvlan,bondvlanbridge>,iface0=eth0,addr=<CIDR-address><:gateway>[,iface1=eth1][,vlannum=85][,bridgename=br85] (can be specified multiple times)
       type= Type of setup (ie: normal, bonding, binding with vlan, bonding with vlan and bridging)
     iface0= Name of the first interface.
     iface1= Name of the 2nd interface (only useful when using bridging)
       addr= Ip address in CIDR format, eventually postfixed with :gateway
    vlannum= Number of the vlan
 bridgename= Name of the bridge
        dns= Address of the DNS servers, separated by :
 dns-search= Search namespace in resolv.conf
        mtu= MTU for this network setup
      ovsbr= Name of the OVS bridge to use
 vmnet_addr= IP address of the VM trafic network
 vmnet_vlan= Number of the vlan for the VM trafic network
  extra_ovs=yes will Bridge a br-ex to the iface / bond
 --reboot-after-install
 --install-nonfree-repo (installs contrib and non-free)
 --postinstall-packages <packages> (useful for non-free/contrib)
 --security-mirror <security-mirror-url>
 --pre-reboot-hook <pre-reboot-script>
 --add-serial-getty <serial-console-dev>
 --xfsformat <sda,sdb,...> will format /dev/sda and /dev/sdb in XFS (useful for Swift stores)
 --vgcreate <sda,sdb,...> will prepare /dev/sda and /dev/sdb volume group (useful for Cinder LVM volume groups)
 --no-cloud-kernel
For more info: man $0"
	exit 1
}

EXTRA=yes
AZURE=no
BOOTMANAGER=grub
BOOTTYPE=mbr
ARCH=amd64
REAL_HARDWARE=no
DEST_HDD=vda
CLOUD_INIT=yes
REBOOT_AFTER_INSTALL=no
INSTALL_NONFREE_REPO=no
REMOVE_HOST_KEYS=yes
SECURITY_MIRROR_URL=http://security.debian.org/debian-security
PERMIT_SSH_AS_ROOT=no
SERIAL_CONSOLE=no
XFSFORMAT=""
CLOUD_KERNEL=yes
for i in $@ ; do
	case "${1}" in
	"--extra-packages"|"-e")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the extra packages"
			usage
		fi
		EXTRA_PACKAGES=${2}
		shift
		shift
	;;
	"--debootstrap-url"|"-u")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the debootstrap URL"
			usage
		fi
		DEB_MIRROR=${2}
		shift
		shift
	;;
	"--minimal"|"-m")
		EXTRA=no
		shift
	;;
	"--azure"|"-az")
		AZURE=yes
		shift
	;;
	"--boot-manager"|"-bm")
		if [ "${2}" != "grub" ] && [ "${2}" != "syslinux" ] ; then
			echo "No recognized parameter defining the boot manager"
			usage
		fi
		BOOTMANAGER=${2}
		shift
		shift
	;;
	"--boot-type"|"-bt")
		if [ "${2}" != "mbr" ] && [ "${2}" != "uefi" ] ; then
			echo "No recognized parameter defining the boot type"
			usage
		fi
		BOOTTYPE=${2}
		shift
		shift
	;;
	"--architecture"|"-a")
		if [ "${2}" != "amd64" ] && [ "${2}" != "arm64" ] ; then
			echo "No recognized parameter defining the architecture (currently support amd64 and arm64)"
			usage
		fi
		ARCH=${2}
		shift
		shift
	;;
	"--automatic-resize"|"-ar")
		AUTOMATIC_RESIZE=yes
		shift
	;;
	"--automatic-resize-space"|"-ars")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the suplementary space"
			usage
		fi
		AUTOMATIC_RESIZE_SPACE=${2}
		shift
		shift
	;;
	"--image-size"|"-is")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the image size"
			usage
		fi
		IMAGE_SIZE=${2}
		shift
		shift
	;;
	"--hook-script"|"-hs")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the hook script"
			usage
		fi
		if ! [ -x "${2}" ] ; then
			echo "Hook script not executable"
		fi
		HOOK_SCRIPT=${2}
		shift
		shift
	;;
	"--sources.list-mirror"|"-s")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the hook script"
			usage
		fi
		SOURCE_LIST_MIRROR=${2}
		shift
		shift
	;;
	"--release"|"-r")
		if [ "${2}" = "wheezy" ] || [ "${2}" = "jessie" ] || [ "${2}" = "stretch" ] || [ "${2}" = "buster" ] || [ "${2}" = "bullseye" ] || [ "${2}" = "booksworm" ] || [ "${2}" = "sid" ] ; then
			RELEASE=${2}
			shift
			shift
		else
			echo "Release not recognized."
			usage
		fi
	;;
	"--login"|"-l")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the user login"
			usage
		fi
		USER_LOGIN=${2}
		shift
		shift
	;;
	"--password"|"-p")
		if [ -z "${2}" ] ; then
			echo "No parameter defining the root password"
			usage
		fi
		ROOT_PASSWORD=${2}
		shift
		shift
	;;
	"--root-ssh-key")
		if [ -z "${2}" ] ; then
			echo "No parameter for the id_rsa.pub"
			usage
		fi
		ROOT_SSH_KEY=${2}
		shift
		shift
	;;
	"--no-remove-host-keys")
		REMOVE_HOST_KEYS=no
		shift
	;;
	"--permit-ssh-as-root")
		PERMIT_SSH_AS_ROOT=yes
		shift
	;;
	"--output"|"-o")
		if [ -z "${2}" ] ; then
			echo "No output file specified"
			usage
		fi
		OUTPUT=${2}
		shift
		shift
	;;
	"--dest-hdd")
		if [ -z "${2}" ] ; then
			echo "No dest hdd specified"
			usage
		fi
		REAL_HARDWARE=yes
		DEST_HDD=${2}
		shift
		shift
	;;
	"--no-cloud-init")
		CLOUD_INIT=no
		shift
	;;
	"--hostname")
		if [ -z "${2}" ] ; then
			echo "No hostname specified"
			usage
		fi
		HOSTNAME=${2}
		shift
		shift
	;;
	"--static-iface")
		if [ -z "${2}" ] ; then
			echo "No IP specified"
			usage
		fi
		if [ -z "${STATIC_ETH}" ] ; then
			STATIC_ETH=${2}
		else
			STATIC_ETH="${STATIC_ETH} ${2}"
		fi
		shift
		shift
	;;
	"--reboot-after-install")
		REBOOT_AFTER_INSTALL=yes
		shift
	;;
	"--install-nonfree-repo")
		INSTALL_NONFREE_REPO=yes
		shift
	;;
	"--postinstall-packages")
		if [ -z "${2}" ] ; then
			echo "No postinstall packages specified"
			usage
		fi
		POSTINSTALL_PACKAGES=${2}
		shift
		shift
	;;
	"--security-mirror")
		if [ -z "${2}" ] ; then
			echo "No security mirror specified"
			usage
		fi
		SECURITY_MIRROR_URL="${2}"
		shift
		shift
	;;
	"--pre-reboot-hook")
		if [ -z "${2}" ] ; then
			echo "No pre-reboot hook script specified"
			usage
		fi
		PRE_REBOOT_HOOK_SCRIPT="${2}"
		shift
		shift
	;;
	"--add-serial-getty")
		if [ -z "${2}" ] ; then
			echo "No serial port specified."
			usage
		fi
		SERIAL_CONSOLE=yes
		SERIAL_CONSOLE_DEV="${2}"
		shift
		shift
	;;
	"--xfsformat")
		if [ -z "${2}" ] ; then
			echo "No device specifed for --xfsformat."
			usage
		fi
		XFSFORMAT="${2}"
		shift
		shift
	;;
	"--vgcreate")
		if [ -z "${2}" ] ; then
			echo "No device specifed for --vgcreate."
			usage
		fi
		VGCREATE="${2}"
		shift
		shift
	;;
	"--no-cloud-kernel")
		CLOUD_KERNEL=no
		shift
	;;
	*)
	;;
	esac
done

if [ -z "${RELEASE}" ] ; then
	echo "Release not recognized: please specify the -r parameter."
	usage
fi
case "${RELEASE}" in
	"wheezy")
		RELEASE_NUM=7
	;;
	"jessie")
		RELEASE_NUM=8
	;;
	"stretch")
		RELEASE_NUM=9
	;;
	"buster")
		RELEASE_NUM=10
	;;
	"bullseye")
		RELEASE_NUM=11
	;;
	"booksworm")
		RELEASE_NUM=12
	;;
	"sid")
		RELEASE_NUM=10
	;;
esac

if [ -z "${DEB_MIRROR}" ] ; then
	DEB_MIRROR=http://deb.debian.org/debian
fi
if [ -z "${EXTRA_PACKAGES}" ] ; then
	EXTRA_PACKAGES=bash-completion,joe,most,screen,less,vim,bzip2,nano
fi
if [ -z "${SOURCE_LIST_MIRROR}" ] ; then
	SOURCE_LIST_MIRROR=http://deb.debian.org/debian
fi
if [ -z "${IMAGE_SIZE}" ] ; then
	IMAGE_SIZE=2
fi
if [ -z "${AUTOMATIC_RESIZE_SPACE}" ] ; then
	AUTOMATIC_RESIZE_SPACE=50
fi
if [ -z "${USER_LOGIN}" ] ; then
	USER_LOGIN=debian
fi
if [ -z "${OUTPUT}" ] ; then
	OUTPUT=debian-${RELEASE}-$(TZ=UTC date '+%Y%m%d%H%M')-${ARCH}
fi

if [ "${BOOTTYPE}" = "uefi" ] && [ "${BOOTMANAGER}" != "grub" ] ; then
	echo "uefi boot type is only compatible with grub"
	usage
fi

if [ "${ARCH}" = "arm64" ] ; then
	if [ "${BOOTMANAGER}" != "grub" ] || [ "${BOOTTYPE}" != "uefi" ] ; then
		echo "arm64 depends on using grub and uefi"
		usage
	fi
fi

if [ -n "${SERIAL_CONSOLE_DEV}" ] ; then
	CONSOLE=${SERIAL_CONSOLE_DEV}
else
	CONSOLE=ttyS0
	if [ "${ARCH}" = "arm64" ] ; then
		CONSOLE=ttyAMA0
	fi
fi

if [ "${BOOTMANAGER}" = "grub" ] ; then
	if [ "${BOOTTYPE}" = "uefi" ] ; then
		BOOT_MGR_PKG="grub-efi-${ARCH}"
		if [ "${ARCH}" = "arm64" ] ; then
			GRUB_TARGET="arm64-efi"
		else
			GRUB_TARGET="x86_64-efi"
		fi
	else
		BOOT_MGR_PKG="grub-pc"
		GRUB_TARGET="i386-pc"
	fi
else
	BOOT_MGR_PKG="extlinux"
fi

IF_PKG=""
if echo "${STATIC_ETH}" | grep -q bond ; then
	IF_PKG="${IF_PKG},ifenslave,ethtool"
fi

if echo "${STATIC_ETH}" | grep -q bridge ; then
	IF_PKG="${IF_PKG},bridge-utils"
fi

if echo "${STATIC_ETH}" | grep -q vlan ; then
	IF_PKG="${IF_PKG},vlan"
fi

NEEDED_PACKAGES=sudo,adduser,locales,${BOOT_MGR_PKG},openssh-server,euca2ools,file,kbd,aptitude,file${IF_PKG}
if [ "${RELEASE}" = "wheezy" ] ; then
	# These are needed by cloud-init and friends, and since we don't want backports of them,
	# but just normal packages from Wheezy, we resolve dependencies by hand, prior to using
	# apt-get -t wheezy-backports install cloud-init cloud-utils cloud-initramfs-growroot
	NEEDED_PACKAGES=${NEEDED_PACKAGES},python,python-paramiko,python-argparse,python-cheetah,python-configobj,python-oauth,python-software-properties,python-yaml,python-boto,python-prettytable,initramfs-tools,python-requests,acpid,acpi-support-base,ntp
else
	if [ "${RELEASE}" = "jessie" ] ; then
		if [ "${CLOUD_INIT}" = "yes" ] ; then
			NEEDED_PACKAGES=${NEEDED_PACKAGES},cloud-initramfs-growroot
		fi
	fi
	NEEDED_PACKAGES=${NEEDED_PACKAGES},dbus,ntp,unscd
	if [ "${CLOUD_INIT}" = "yes" ] ; then
		NEEDED_PACKAGES=${NEEDED_PACKAGES},cloud-init,cloud-utils,resolvconf
	fi
fi

# This is a workaround for python3-cryptography failing to install
if [ "${RELEASE_NUM}" -ge 9 ] ; then
	NEEDED_PACKAGES=${NEEDED_PACKAGES},python3-cffi-backend
fi

if [ ${EXTRA} = "no" ] ; then
	PKG_LIST=${NEEDED_PACKAGES}
else
	PKG_LIST=${NEEDED_PACKAGES},${EXTRA_PACKAGES}
fi
if ! [ `whoami` = "root" ] ; then
	echo "You have to be root to run this script"
	exit 1
fi
if [ "${REAL_HARDWARE}" = "no" ] ; then
	RAW_NAME=${OUTPUT}.raw
	QCOW2_NAME=${OUTPUT}.qcow2
	rm -f ${RAW_NAME}
	qemu-img create ${RAW_NAME} ${IMAGE_SIZE}G
else
	RAW_NAME=/dev/${DEST_HDD}
fi

set -x

######################################
### Prepare the HDD (format, ext.) ###
######################################
PARTED=/sbin/parted

if [ "${BOOTTYPE}" = "mbr" ] ; then
	${PARTED} -s ${RAW_NAME} mktable msdos
	${PARTED} -s -a optimal ${RAW_NAME} mkpart primary ext4 1Mi 100%
	${PARTED} -s ${RAW_NAME} set 1 boot on
	install-mbr --force ${RAW_NAME}

	if [ "${REAL_HARDWARE}" = "no" ] ; then
		RESULT_KPARTX=$(kpartx -asv ${RAW_NAME} 2>&1)
		if echo "${RESULT_KPARTX}" | grep "^add map" ; then
			LOOP_DEVICE=$(echo ${RESULT_KPARTX} | cut -d" " -f3)
			LOOPRAW_DEVICE=${LOOP_DEVICE%p*}
			echo "kpartx mounted using: ${LOOP_DEVICE} via ${LOOPRAW_DEVICE}"
		else
			echo "It seems kpartx didn't mount the image correctly: exiting."
			exit 1
		fi
	fi
else # uefi
	${PARTED} -s ${RAW_NAME} mktable gpt
	${PARTED} -s -a optimal ${RAW_NAME} mkpart ESP fat32 1Mi 101Mi
	${PARTED} -s -a optimal ${RAW_NAME} -- mkpart ROOT ext4 102Mi -64s
	${PARTED} -s ${RAW_NAME} set 1 esp on

	if [ "${REAL_HARDWARE}" = "no" ] ; then
		RESULT_KPARTX=$(kpartx -asv ${RAW_NAME} 2>&1 | tail -1)
		if echo "${RESULT_KPARTX}" | grep "^add map" ; then
			LOOP_DEVICE=$(echo ${RESULT_KPARTX} | cut -d" " -f3)
			LOOPRAW_DEVICE=${LOOP_DEVICE%p*}
			echo "kpartx mounted using: ${LOOP_DEVICE} via ${LOOPRAW_DEVICE}"
		else
			echo "It seems kpartx didn't mount the image correctly: exiting."
			exit 1
		fi
		LOOP_DEVICE_ESP="${LOOPRAW_DEVICE}"p1
	fi
fi

cleanup(){
	error=$?
	[ ! -d "${MOUNT_DIR}" ] && return
	if [ "$error" -gt 0 ]; then
		echo
		echo "Error $error"
	else
		echo "Finished."
	fi

	set +e

	sync
	chroot ${MOUNT_DIR} umount /proc || true
	chroot ${MOUNT_DIR} umount /sys || true
	chroot ${MOUNT_DIR} umount /dev || true
	umount -l ${MOUNT_DIR}
	rmdir ${MOUNT_DIR}

	if [ "${REAL_HARDWARE}" = "no" ] ; then
		kpartx -d ${RAW_NAME}
	fi
	exit $error
}
trap "cleanup" EXIT TERM INT

if [ "${REAL_HARDWARE}" = "no" ] ; then
	DEST_PART=/dev/mapper/${LOOP_DEVICE}
	DEST_PART_ESP=/dev/mapper/${LOOP_DEVICE_ESP}
else
	if [ "${BOOTTYPE}" = "mbr" ] ; then
		DEST_PART=/dev/${DEST_HDD}1
	else
		DEST_PART_ESP=/dev/${DEST_HDD}1
		DEST_PART=/dev/${DEST_HDD}2
	fi
fi

mkfs.ext4 -F ${DEST_PART}
UUID=$(blkid -o value -s UUID ${DEST_PART})

# No fsck because of X days without checks
tune2fs -i 0 ${DEST_PART}

MOUNT_DIR=`mktemp -d -t build-debimg.XXXXXX`

mount ${DEST_PART} ${MOUNT_DIR}
if [ "${BOOTTYPE}" = "uefi" ] ; then
	mkfs.vfat ${DEST_PART_ESP}
	UUID_ESP=$(blkid -o value -s UUID ${DEST_PART_ESP})
	mkdir -p ${MOUNT_DIR}/boot/efi
	mount ${DEST_PART_ESP} ${MOUNT_DIR}/boot/efi
fi

debootstrap --verbose \
	--include=${PKG_LIST} \
	${RELEASE} ${MOUNT_DIR} ${DEB_MIRROR}


if [ -n "${XFSFORMAT}" ] ; then
	XFS_HDDS=$(echo ${XFSFORMAT} | tr , " ")
	for i in ${XFS_HDDS} ; do
		if [ -x /sbin/mkfs.xfs ] ; then
			echo "===> Formating /dev/${i}"
			mkfs.xfs -f /dev/${i}
		else
			echo "===> Could not find mkfs.xfs, so wont format /dev/${i}"
		fi
	done
fi

if [ -n "${VGCREATE}" ] ; then
	if [ -x /sbin/lvcreate ] ; then
		VG_HDDS=$(echo ${VGCREATE} | tr , " ")
		VG_DEVS=""
		for i in ${VG_HDDS} ; do
			echo "===> Creating PV for /dev/${i}"
			pvcreate -ff -y /dev/${i}
			VG_DEVS="${VG_DEVS} /dev/${i}"
		done
		if [ -x /sbin/vgcreate ] ; then
			vgcreate ocivg0 ${VG_DEVS}
			vgchange -a y ocivg0
		else
			echo "===> Could not find vgcreate, so wont create volume groups."
		fi
	else
		echo "===> Could not find pvcreate, so wont create volume groups."
	fi
fi

############################
### Customize the distro ###
############################
### Customize: access to the VM ###
# # # # # # # # # # # # # # # # # #
# Setup default root password to what has been set on the command line
if [ -n "${ROOT_PASSWORD}" ] ; then
	chroot ${MOUNT_DIR} sh -c "echo root:${ROOT_PASSWORD} | chpasswd"
fi

if [ -n "${ROOT_SSH_KEY}" ] ; then
	mkdir -p ${MOUNT_DIR}/root/.ssh
	chmod 700 ${MOUNT_DIR}/root/.ssh
	cat <${ROOT_SSH_KEY} >${MOUNT_DIR}/root/.ssh/authorized_keys
	chmod 600 ${MOUNT_DIR}/root/.ssh/authorized_keys
fi

if [ "${CLOUD_INIT}" = "yes" ] ; then
	# Add a default user which is used by cloud-init by default.
	# This isn't needed for at least stretch and on, because cloud-init
	# creates the user, and it's best to give users a choice to overwrite it.
	if [ "${RELEASE}" = "wheezy" ] || [ "${RELEASE}" = "jessie" ] ; then
		chroot ${MOUNT_DIR} adduser --gecos Cloud-init-user --disabled-password --quiet ${USER_LOGIN}
	fi

	# Adds the "debian" user to sudoers, since that is the way
	# cloud-init grant access
	mkdir -p ${MOUNT_DIR}/etc/sudoers.d
	echo "${USER_LOGIN} ALL = NOPASSWD: ALL" >${MOUNT_DIR}/etc/sudoers.d/debian-cloud-init
	chmod 0440 ${MOUNT_DIR}/etc/sudoers.d/debian-cloud-init
fi

### Customize: misc stuff ###
# # # # # # # # # # # # # # #
# Setup fstab
echo "# /etc/fstab: static file system information.
UUID=${UUID}	/	ext4	errors=remount-ro	0	1
" > ${MOUNT_DIR}/etc/fstab
if [ "${BOOTTYPE}" = "uefi" ] ; then
	echo "UUID=${UUID_ESP}	/boot/efi	vfat	errors=remount-ro	0	0" >> ${MOUNT_DIR}/etc/fstab
fi
mount -t proc proc ${MOUNT_DIR}/proc

if [ "${REAL_HARDWARE}" = "no" ] ; then
	echo "# disable pc speaker
	blacklist pcspkr" >${MOUNT_DIR}/etc/modprobe.d/blacklist.conf
fi

# No clear for the tty1 console
if [ "${RELEASE}" = "wheezy" ] ; then
	sed -i "s#1:2345:respawn:/sbin/getty 38400 tty1#1:2345:respawn:/sbin/getty --noclear 38400 tty1#" ${MOUNT_DIR}/etc/inittab
else
	# XXX: the serial port on Microsoft Azure plattform can't cope with
	# lots of data, keep this option disabled.
	#echo ForwardToConsole=yes >> ${MOUNT_DIR}/etc/systemd/journald.conf
	:
fi

if [ "${SERIAL_CONSOLE}" = "yes" ] ; then
	PROC_MANUFACTURER=$(dmidecode -s processor-manufacturer | head -n 1)
	if [ "${REAL_HARDWARE}" = "yes" ] && [ "${PROC_MANUFACTURER}" = "QEMU" ] ; then
		echo "Probably setting-up on a virtualized OCI PoC: will not setup getty on ttyS1."
	else
		mkdir -p ${MOUNT_DIR}/etc/systemd/system/getty.target.wants
		echo "#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Serial Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
BindsTo=dev-%i.device
After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target
After=rc-local.service

# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
# getty.target didn't actually pull it in.
Before=getty.target
IgnoreOnIsolate=yes

# IgnoreOnIsolate causes issues with sulogin, if someone isolates
# rescue.target or starts rescue.service from multi-user.target or
# graphical.target.
Conflicts=rescue.service
Before=rescue.service

[Service]
# The '-o' option value tells agetty to replace 'login' arguments with an
# option to preserve environment (-p), followed by '--' for safety, and then
# the entered username.
ExecStart=-/sbin/agetty --keep-baud 115200,38400,9600 %I \$TERM
Type=idle
Restart=always
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes

[Install]
WantedBy=getty.target
" >${MOUNT_DIR}/etc/systemd/system/serial-getty@${SERIAL_CONSOLE_DEV}.service
		ln -s ../serial-getty@${SERIAL_CONSOLE_DEV}.service ${MOUNT_DIR}/etc/systemd/system/getty.target.wants/serial-getty@${SERIAL_CONSOLE_DEV}.service
	fi
fi

# If running on real hardware, hard-wire eth names in udev rules,
# because they can change over time, especially since OCI potentially removes
# some drivers from the initrd.
if [ "${REAL_HARDWARE}" = "yes" ] ; then
	mkdir -p ${MOUNT_DIR}/etc/udev/rules.d
	echo "# Persistent-net rules written by openstack-debian-images" >${MOUNT_DIR}/etc/udev/rules.d/70-persistent-net.rules
	for i in $(ip link show | grep -v '^ ' | grep -v 'lo:' | cut -d' ' -f2 | cut -d: -f1) ; do
	        MAC_ADDR=$(ip link show dev $i | grep 'link/ether' | awk '{print $2}')
	        ETH_SPEED=$(( $(lshw -class network 2>/dev/null -json | jq '.[] | select(.serial|test("'${MAC_ADDR}'")) | .capacity') / 1000000))
	        if [ "${ETH_SPEED}" = 10000 ] ; then
			NICE_SPEED="10 Gbits/s"
	        elif [ "${ETH_SPEED}" = 1000 ] ; then
			NICE_SPEED="1 Gbits/s"
	        elif [ "${ETH_SPEED}" = 100 ] ; then
			NICE_SPEED="100 Mbits/s"
	        elif [ "${ETH_SPEED}" = 10 ] ; then
			NICE_SPEED="10 Mbits/s"
	        else
			NICE_SPEED="unrecognized speed"
	        fi
		echo "# ${i}: ${NICE_SPEED}
"'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="'${MAC_ADDR}'", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="'${i}'"'"
">>${MOUNT_DIR}/etc/udev/rules.d/70-persistent-net.rules
	done
fi

# We do it *after* the debootstrap, as otherwise it fails with
# systemd-shim conflicting with systemd-sysv.
chroot ${MOUNT_DIR} apt-get update
chroot ${MOUNT_DIR} apt-get install -y -o Dpkg::Options::="--force-confnew" locales-all libpam-systemd


# Turn off console blanking which is *very* annoying
# and increase KEYBOARD_DELAY because it can be annoying
# over network.
# Note: /etc/kbd/config is gone away from Stretch, but
# we still need to fix it for previous Debian releases.
# In stretch and beyond, consoleblank=0 in the kernel
# command line should be enough (TODO: check for that fact).
if [ -e ${MOUNT_DIR}/etc/kbd/config ] ; then
	sed -i s/^BLANK_TIME=.*/BLANK_TIME=0/ ${MOUNT_DIR}/etc/kbd/config
	sed -i s/^POWERDOWN_TIME=.*/POWERDOWN_TIME=0/ ${MOUNT_DIR}/etc/kbd/config
	sed -i 's/^[ \t#]KEYBOARD_DELAY=.*/KEYBOARD_DELAY=1000/' ${MOUNT_DIR}/etc/kbd/config
fi

if [ "${REAL_HARDWARE}" = "no" ] && [ "${REMOVE_HOST_KEYS}" = "yes" ] ; then
	rm -f ${MOUNT_DIR}/etc/ssh/ssh_host_*
fi

if [ "${PERMIT_SSH_AS_ROOT}" = "yes" ] ; then
	sed -i 's|[#]*PermitRootLogin.*|PermitRootLogin yes|' ${MOUNT_DIR}/etc/ssh/sshd_config
fi

if [ "${REAL_HARDWARE}" = "no" ] ; then
	rm -f ${MOUNT_DIR}/etc/udev/rules.d/70-persistent-net.rules
	rm -f ${MOUNT_DIR}/lib/udev/write_net_rules
fi

# Setup networking
ENI=${MOUNT_DIR}/etc/network/interfaces


# First, always add the loopback
echo "# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback
" > ${ENI}
if [ -n "${STATIC_ETH}" ] ; then
	BOND_NUMBER=0
	for i in ${STATIC_ETH} ; do
		SE_TYPE=""
		SE_IFACE0=""
		SE_IFACE1=""
		SE_ADDR=""
		SE_GW=""
		SE_VLANNUM=""
		SE_BRNAME=""
		SE_DNS=""
		SE_DNSSEARCH=""
		SE_MTU=""
		SE_OVSBR=""
		SE_VMNET_ADDR=""
		SE_VMNET_VLAN=""
		SE_EXTRA_OVS="no"
		ETH_PARAMS=$(echo ${i} | tr , " ")
		for ETH_PARAM in ${ETH_PARAMS} ; do
			ETH_PDIR=$(echo ${ETH_PARAM} | cut -d= -f1)
			ETH_PVAL=$(echo ${ETH_PARAM} | cut -d= -f2)
			case "${ETH_PDIR}" in
			"type")
				SE_TYPE=${ETH_PVAL}
			;;
			"iface0")
				SE_IFACE0=${ETH_PVAL}
			;;
			"iface1")
				SE_IFACE1=${ETH_PVAL}
			;;
			"addr")
				SE_ADDR=$( echo ${ETH_PVAL} | cut -d: -f1)
				SE_GW=$( echo ${ETH_PVAL} | cut -d: -f2)
			;;
			"vlannum")
				SE_VLANNUM=${ETH_PVAL}
			;;
			"bridgename")
				SE_BRNAME=${ETH_PVAL}
			;;
			"dns")
				SE_DNS=${ETH_PVAL}
				SE_ALL_NS=$(echo ${SE_DNS} | tr : " ")
			;;
			"dns-search")
				SE_DNSSEARCH=${ETH_PVAL}
			;;
			"mtu")
				SE_MTU=${ETH_PVAL}
			;;
			"ovsbr")
				SE_OVSBR=${ETH_PVAL}
			;;
			"vmnet_addr")
				SE_VMNET_ADDR=${ETH_PVAL}
			;;
			"vmnet_vlan")
				SE_VMNET_VLAN=${ETH_PVAL}
			;;
			"extra_ovs")
				SE_EXTRA_OVS="yes"
			;;
			*)
				echo "Unrecognized parameter"
			;;
			esac
		done
		IFACE_ADDR=$(echo ${SE_ADDR} | cut -d/ -f1)
		IFACE_NETWORK=$(ipcalc ${SE_ADDR} | grep '^Network:' | awk '{print $2}' | cut -d/ -f1)
		IFACE_BROADCAST=$(ipcalc ${SE_ADDR} | grep '^Broadcast:' | awk '{print $2}')
		IFACE_NETMASK=$(ipcalc ${SE_ADDR} | grep '^Netmask:' | awk '{print $2}')
		if [ -n "${SE_VMNET_ADDR}" ] ; then
			VMNET_IFACE_ADDR=$(echo ${SE_VMNET_ADDR} | cut -d/ -f1)
			VMNET_IFACE_NETWORK=$(ipcalc ${SE_VMNET_ADDR} | grep '^Network:' | awk '{print $2}' | cut -d/ -f1)
			VMNET_IFACE_BROADCAST=$(ipcalc ${SE_VMNET_ADDR} | grep '^Broadcast:' | awk '{print $2}')
			VMNET_IFACE_NETMASK=$(ipcalc ${SE_VMNET_ADDR} | grep '^Netmask:' | awk '{print $2}')
		fi

		case "${SE_TYPE}" in
		"normal")
			if [ -n "${SE_OVSBR}" ] ; then
				INTERFACE=${SE_OVSBR}
				echo "# Interface ${SE_OVSBR}" >> ${ENI}
				echo "allow-ovs ${SE_OVSBR}" >> ${ENI}
			else
				INTERFACE=${SE_IFACE0}
				echo "# Interface ${INTERFACE}" >> ${ENI}
				echo "allow-hotplug ${INTERFACE}" >> ${ENI}
			fi
			echo "iface ${INTERFACE} inet static" >> ${ENI}
			if [ -n "${SE_OVSBR}" ] ; then
				echo "	ovs_type OVSBridge" >> ${ENI}
				echo "	ovs_ports ${SE_IFACE0}" >> ${ENI}
			fi
			echo "	address ${IFACE_ADDR}" >> ${ENI}
			echo "	network ${IFACE_NETWORK}" >> ${ENI}
			echo "	netmask ${IFACE_NETMASK}" >> ${ENI}
			echo "	broadcast ${IFACE_BROADCAST}" >> ${ENI}
			if [ -n "${SE_GW}" ] ; then
				echo "	gateway ${SE_GW}" >> ${ENI}
			fi
			if [ "${SE_MTU}" ] ; then
				echo "	mtu ${SE_MTU}" >> ${ENI}
			fi
			if [ -n "${SE_DNS}" ] ; then
				echo "	dns-nameservers ${SE_ALL_NS}" >> ${ENI}
			fi
			if [ -n "${SE_DNSSEARCH}" ] ; then
				echo "	dns-search ${SE_DNSSEARCH}" >> ${ENI}
			fi
			echo "" >> ${ENI}
			if [ -n "${SE_OVSBR}" ] ; then
				echo "allow-${SE_OVSBR} ${SE_IFACE0}" >> ${ENI}
				echo "iface ${SE_IFACE0} inet manual" >> ${ENI}
				echo "	ovs_bridge ${SE_OVSBR}" >> ${ENI}
				echo "	ovs_type OVSPort" >> ${ENI}
				echo "" >> ${ENI}
			fi
		;;
		"bond")
			INTERFACE=bond${BOND_NUMBER}
			BOND_NUMBER=$(( ${BOND_NUMBER} + 1 ))
			# Iface 0
			echo "# Interface ${SE_IFACE0}" >> ${ENI}
			echo "auto ${SE_IFACE0}" >> ${ENI}
			echo "iface ${SE_IFACE0} inet manual" >> ${ENI}
			echo "	bond-master ${INTERFACE}" >> ${ENI}
			echo "" >> ${ENI}
			# Iface 1
			echo "# Interface ${SE_IFACE1}" >> ${ENI}
			echo "auto ${SE_IFACE1}" >> ${ENI}
			echo "iface ${SE_IFACE1} inet manual" >> ${ENI}
			echo "	bond-master ${INTERFACE}" >> ${ENI}
			echo "" >> ${ENI}
			# Bridge
			echo "# Interface ${INTERFACE}" >> ${ENI}
			echo "auto ${INTERFACE}" >> ${ENI}
			echo "iface ${INTERFACE} inet static" >> ${ENI}
			echo "	address ${IFACE_ADDR}" >> ${ENI}
			echo "	network ${IFACE_NETWORK}" >> ${ENI}
			echo "	netmask ${IFACE_NETMASK}" >> ${ENI}
			echo "	broadcast ${IFACE_BROADCAST}" >> ${ENI}
			if [ -n "${SE_GW}" ] ; then
				echo "	gateway ${SE_GW}" >> ${ENI}
			fi
			if [ "${SE_MTU}" ] ; then
				echo "	mtu ${SE_MTU}" >> ${ENI}
			fi
			if [ -n "${SE_DNS}" ] ; then
				echo "	dns-nameservers ${SE_ALL_NS}" >> ${ENI}
			fi
			if [ -n "${SE_DNSSEARCH}" ] ; then
				echo "	dns-search ${SE_DNSSEARCH}" >> ${ENI}
			fi
			echo "	bond-mode 802.3ad" >> ${ENI}
			echo "	bond-miimon 100" >> ${ENI}
			echo "	bond-lacp-rate 1" >> ${ENI}
			echo "	bond-slaves ${SE_IFACE0} ${SE_IFACE1}" >> ${ENI}
			echo "	bond_xmit_hash_policy layer3+4" >> ${ENI}
			echo "" >> ${ENI}
		;;
		"bondvlan")
			INTERFACE=bond${BOND_NUMBER}
			BOND_NUMBER=$(( ${BOND_NUMBER} + 1 ))

			# Iface 0
			echo "# Interface ${SE_IFACE0}" >> ${ENI}
			echo "auto ${SE_IFACE0}" >> ${ENI}
			echo "iface ${SE_IFACE0} inet manual" >> ${ENI}
			echo "	bond-master ${INTERFACE}" >> ${ENI}
			echo "" >> ${ENI}
			# Iface 1
			echo "# Interface ${SE_IFACE1}" >> ${ENI}
			echo "auto ${SE_IFACE1}" >> ${ENI}
			echo "iface ${SE_IFACE1} inet manual" >> ${ENI}
			echo "	bond-master ${INTERFACE}" >> ${ENI}
			echo "" >> ${ENI}

			# Bonding interface
			echo "# Interface ${INTERFACE}" >> ${ENI}
			echo "auto ${INTERFACE}" >> ${ENI}
			echo "iface ${INTERFACE} inet manual" >> ${ENI}
			if [ -n "${SE_DNS}" ] ; then
				echo "	dns-nameservers ${SE_ALL_NS}" >> ${ENI}
			fi
			if [ -n "${SE_DNSSEARCH}" ] ; then
				echo "	dns-search ${SE_DNSSEARCH}" >> ${ENI}
			fi
			echo "	bond-mode 802.3ad" >> ${ENI}
			echo "	bond-miimon 100" >> ${ENI}
			echo "	bond-lacp-rate 1" >> ${ENI}
			echo "	bond-slaves ${SE_IFACE0} ${SE_IFACE1}" >> ${ENI}
			echo "	bond_xmit_hash_policy layer3+4" >> ${ENI}
			if [ "${SE_EXTRA_OVS}" = "yes" ] ; then
				echo "	up ifup br-ex" >> ${ENI}
			fi
			if [ -n "${SE_MTU}" ] ; then
				echo "	mtu 9000" >> ${ENI}
			fi
			echo "" >> ${ENI}

			# Eventual OVS bridge, plus vlan device using the bond interface
			if [ -n "${SE_OVSBR}" ] ; then
                                echo "# Interface ${SE_OVSBR}" >> ${ENI}
                                echo "allow-ovs ${SE_OVSBR}" >> ${ENI}
				echo "iface ${SE_OVSBR} inet static" >> ${ENI}
			else
				echo "# Interface vlan${SE_VLANNUM}" >> ${ENI}
				echo "auto vlan${SE_VLANNUM}" >> ${ENI}
				echo "iface vlan${SE_VLANNUM} inet static" >> ${ENI}
				echo "	vlan-raw-device ${INTERFACE}" >> ${ENI}
				echo "	pre-up ip link set up dev ${SE_IFACE0}" >> ${ENI}
				echo "	pre-up ip link set up dev ${SE_IFACE1}" >> ${ENI}
			fi

			echo "	address ${IFACE_ADDR}" >> ${ENI}
			echo "	network ${IFACE_NETWORK}" >> ${ENI}
			echo "	netmask ${IFACE_NETMASK}" >> ${ENI}
			echo "	broadcast ${IFACE_BROADCAST}" >> ${ENI}
			if [ -n "${SE_GW}" ] ; then
				echo "	gateway ${SE_GW}" >> ${ENI}
			fi
			if [ -n "${SE_MTU}" ] ; then
				echo "	mtu 9000" >> ${ENI}
			fi
			echo "" >>${ENI}


			if [ -n "${SE_VMNET_ADDR}" ] ; then
				echo "# Interface vlan${SE_VMNET_VLAN}" >> ${ENI}
				echo "auto vlan${SE_VMNET_VLAN}" >> ${ENI}
				echo "iface vlan${SE_VMNET_VLAN} inet static" >> ${ENI}
				echo "	vlan-raw-device ${INTERFACE}" >> ${ENI}
				echo "	pre-up ip link set up dev ${SE_IFACE0}" >> ${ENI}
				echo "	pre-up ip link set up dev ${SE_IFACE1}" >> ${ENI}
				echo "	address ${VMNET_IFACE_ADDR}" >> ${ENI}
				echo "	network ${VMNET_IFACE_NETWORK}" >> ${ENI}
				echo "	netmask ${VMNET_IFACE_NETMASK}" >> ${ENI}
				echo "	broadcast ${VMNET_IFACE_BROADCAST}" >> ${ENI}
				if [ -n "${SE_MTU}" ] ; then
					echo "	mtu 9000" >> ${ENI}
				fi
				echo "" >>${ENI}

				if [ "${SE_EXTRA_OVS}" = "yes" ] ; then
	                                echo "auto br-ex" >> ${ENI}
					echo "iface br-ex inet manual" >> ${ENI}
					echo "	ovs_type OVSBridge" >> ${ENI}
					echo "	ovs_ports ${INTERFACE}" >> ${ENI}
					echo "	up ovs-vsctl add-port br-ex ${INTERFACE}" >> ${ENI}
					echo "" >> ${ENI}
				fi
			fi

			if [ -n "${SE_OVSBR}" ] ; then
				echo "# Interface vlan${SE_VLANNUM}" >> ${ENI}
				echo "auto vlan${SE_VLANNUM}" >> ${ENI}
				echo "iface vlan${SE_VLANNUM} inet manual" >> ${ENI}
				echo "	vlan-raw-device ${INTERFACE}" >> ${ENI}
				echo "  pre-up ip link set up dev ${SE_IFACE0}" >> ${ENI}
				echo "  pre-up ip link set up dev ${SE_IFACE1}" >> ${ENI}
			fi
			echo "" >> ${ENI}
		;;
		"bondvlanbridge")
			INTERFACE=bond${BOND_NUMBER}
			BOND_NUMBER=$(( ${BOND_NUMBER} + 1 ))
			# Iface 0
			echo "# Interface ${SE_IFACE0}" >> ${ENI}
			echo "auto ${SE_IFACE0}" >> ${ENI}
			echo "iface ${SE_IFACE0} inet manual" >> ${ENI}
			echo "	bond-master ${INTERFACE}" >> ${ENI}
			echo "" >> ${ENI}
			# Iface 1
			echo "# Interface ${SE_IFACE1}" >> ${ENI}
			echo "auto ${SE_IFACE1}" >> ${ENI}
			echo "iface ${SE_IFACE1} inet manual" >> ${ENI}
			echo "	bond-master ${INTERFACE}" >> ${ENI}
			echo "" >> ${ENI}
			# Bond iface
			echo "# Interface ${INTERFACE}" >> ${ENI}
			echo "auto ${INTERFACE}" >> ${ENI}
			echo "iface ${INTERFACE} inet manual" >> ${ENI}
			echo "	bond-mode 802.3ad" >> ${ENI}
			echo "	bond-miimon 100" >> ${ENI}
			echo "	bond-lacp-rate 1" >> ${ENI}
			echo "	bond-slaves ${SE_IFACE0} ${SE_IFACE1}" >> ${ENI}
			echo "	bond_xmit_hash_policy layer3+4" >> ${ENI}
			if [ -n "${SE_MTU}" ] ; then
				echo "	mtu 9000" >> ${ENI}
			fi
			echo "" >> ${ENI}
			# Vlan
			echo "# Interface vlan${SE_VLANNUM}" >> ${ENI}
			echo "auto vlan${SE_VLANNUM}" >> ${ENI}
			echo "iface vlan${SE_VLANNUM} inet manual" >> ${ENI}
			echo "	vlan-raw-device ${INTERFACE}" >> ${ENI}
			if [ -n "${SE_MTU}" ] ; then
				echo "	mtu 9000" >> ${ENI}
			fi
			echo "" >> ${ENI}
			# Bridge
			echo "# Interface ${SE_BRNAME}" >> ${ENI}
			echo "auto ${SE_BRNAME}" >> ${ENI}
			echo "iface ${SE_BRNAME} inet static" >> ${ENI}
			echo "	bridge_ports vlan${SE_VLANNUM}" >> ${ENI}
			echo "	bridge_maxwait 0" >> ${ENI}
			echo "  pre-up ip link set up dev ${SE_IFACE0}" >> ${ENI}
			echo "  pre-up ip link set up dev ${SE_IFACE1}" >> ${ENI}
			echo "	address ${IFACE_ADDR}" >> ${ENI}
			echo "	network ${IFACE_NETWORK}" >> ${ENI}
			echo "	netmask ${IFACE_NETMASK}" >> ${ENI}
			echo "	broadcast ${IFACE_BROADCAST}" >> ${ENI}
			if [ -n "${SE_GW}" ] ; then
				echo "	gateway ${SE_GW}" >> ${ENI}
			fi
			if [ -n "${SE_DNS}" ] ; then
				echo "	dns-nameservers ${SE_ALL_NS}" >> ${ENI}
			fi
			if [ -n "${SE_DNSSEARCH}" ] ; then
				echo "	dns-search ${SE_DNSSEARCH}" >> ${ENI}
			fi
			if [ -n "${SE_MTU}" ] ; then
				echo "	mtu 9000" >> ${ENI}
			fi
			echo "" >> ${ENI}
		;;
		esac
	done
	if echo "${STATIC_ETH}" | grep -q bond ; then
		mkdir -p ${MOUNT_DIR}/etc/modprobe.d
		echo "options bonding mode=4" >${MOUNT_DIR}/etc/modprobe.d/bonding.conf
	fi
else
# If no --static-iface param is set, then DHCP by default
	echo "# The normal eth0
allow-hotplug eth0
iface eth0 inet dhcp

# Additional interfaces, just in case we're using
# multiple networks
allow-hotplug eth1
iface eth1 inet dhcp

allow-hotplug eth2
iface eth2 inet dhcp

# Set this one last, so that cloud-init or user can
# override defaults.
source /etc/network/interfaces.d/*
" >> ${MOUNT_DIR}/etc/network/interfaces
fi

# Setup the default hostname (will be set by cloud-init at boot,
# though for installing real hardware, we do care)
if [ -z "${HOSTNAME}" ] ; then
	HOSTNAME="debian.example.com"
fi
echo "${HOSTNAME}" >${MOUNT_DIR}/etc/hostname
echo "127.0.0.1	localhost
127.0.1.1	${HOSTNAME}

::1	localhost ip6-localhost ip6-loopback
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
" >${MOUNT_DIR}/etc/hosts

# This should be a correct default everywhere
if [ "${INSTALL_NONFREE_REPO}" = yes ] ; then
	NON_FREE=" contrib non-free"
else
	NON_FREE=""
fi
echo "deb ${SOURCE_LIST_MIRROR} ${RELEASE} main${NON_FREE}
deb-src ${SOURCE_LIST_MIRROR} ${RELEASE} main${NON_FREE}" >${MOUNT_DIR}/etc/apt/sources.list

if [ "${RELEASE}" != "sid" ] && [ "${RELEASE}" != "unstable" ] ; then
	echo "deb ${SOURCE_LIST_MIRROR} ${RELEASE}-updates main${NON_FREE}
deb-src ${SOURCE_LIST_MIRROR} ${RELEASE}-updates main${NON_FREE}
deb ${SECURITY_MIRROR_URL} ${RELEASE}/updates main${NON_FREE}
deb-src ${SECURITY_MIRROR_URL} ${RELEASE}/updates main${NON_FREE}
" >>${MOUNT_DIR}/etc/apt/sources.list
fi

if [ "${RELEASE}" = "wheezy" ] ; then
	echo "deb ${SOURCE_LIST_MIRROR} wheezy-backports main${NON_FREE}
deb-src ${SOURCE_LIST_MIRROR} wheezy-backports main${NON_FREE}
" >>${MOUNT_DIR}/etc/apt/sources.list
fi

if [ "${RELEASE}" = "jessie" ] && [ "${AZURE}" = "yes" ] ; then
	echo "deb ${SOURCE_LIST_MIRROR} jessie-backports main${NON_FREE}
deb-src ${SOURCE_LIST_MIRROR} jessie-backports main${NON_FREE}
deb ${SOURCE_LIST_MIRROR}-azure jessie-backports main${NON_FREE}
deb-src ${SOURCE_LIST_MIRROR}-azure jessie-backports main${NON_FREE}
" >>${MOUNT_DIR}/etc/apt/sources.list
fi

if [ "${AZURE}" = "yes" ] ; then
	chroot ${MOUNT_DIR} apt-key add - <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1

mQENBFYWcbkBCADKvo4KT/ic3wb4AoNFtWvoS1Ae3NFcvM/6WR/n9BTsayOlnjDu
EFh7yH16nIhuO5pZFocY+32BWMEmiK6/0pkk1lB9+XfNB8yqDCJ/ItzADfuKQv6g
smfx4tLa1Vj+jUbrgiIG7MYTCPlpkSuPA+FgntlR4JBxOy2g4fqqp3of+xM8tfSN
4I7/g1989YU9EQN53c1HGLdsc5x5Y5Kezd46H4IK5oyri7BaG4zRzpJLYa4yxB2W
re+HXP0a5SN/zQq1oq8pvkPubEBPKhdypZzzoHWPkZqXh1pHsMMNRkwsLW/3iwzE
IjDKrbdILz3/b+iLLIvYo9RlTycRO0XeS/B3ABEBAAG0UkRlYmlhbiBmb3IgQXp1
cmUgQXJjaGl2ZSBBdXRvbWF0aWMgU2lnbmluZyBLZXkgKDgvamVzc2llKSA8bWlj
cm9zb2Z0QGNyZWRhdGl2LmNvbT6JAT4EEwECACgFAlYWcbkCGwMFCQPCZwAGCwkI
BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEAbqSemobK1/2c8H/1j4HK/izt7aw7Kk
g+ChRDhltb4LiYTZNgHaBnLGkKewkA1vYIHQjdu/pVnJjh1JzvOBFV+rhJ4Cc60D
s4JDqkrl8LpA4jsLb/PW1bRtbW92mPfhWgjyWs6S2tRBsBy1m2+SLZKeaDUq/PCD
VnaClzDh2fQYimI8IQk5U/u8VHXtDm3qYQSq7dJMTTnDcBC1oCjEYN+uPm9M+tUI
ik2hIE4VmjIXYTQVTa1lD+qyJvZ9hCsBUxAGllFpcWlyexN5orer6c+30XY/0Y4i
Q+zzVPrp1s6MgM9F8ofgd2+MhL57fwyj2A+Tbyzm7xYhzPPMx/mopo4pi884+5lo
FY6A20E=
=X0jG
-----END PGP PUBLIC KEY BLOCK-----
EOF
fi

chroot ${MOUNT_DIR} apt-get update
if [ "${AZURE}" = "yes" ] ; then
	chroot ${MOUNT_DIR} apt-get install -y -o Dpkg::Options::="--force-confnew" debian-azure-archive-keyring unscd
	chroot ${MOUNT_DIR} apt-get update
fi

if [ -n "${POSTINSTALL_PACKAGES}" ] ; then
	chroot ${MOUNT_DIR} apt-get install -y -o Dpkg::Options::="--force-confnew"  $(echo ${POSTINSTALL_PACKAGES} | tr "," " ")
fi

# Run dist-upgrade here - some security updates may involve installing
# packages with new names, like kernels with a new ABI chroot
chroot ${MOUNT_DIR} apt-get --no-install-recommends dist-upgrade -y -o Dpkg::Options::="--force-confnew" 

########################
### Install a kernel ###
########################
if [ "${RELEASE_NUM}" -ge 10 ] && [ "${ARCH}" = "amd64" ] ; then
	if [ "${REAL_HARDWARE}" = "no" ] && [ "${CLOUD_KERNEL}" = "yes" ] ; then
		KERNEL_PACKAGE_NAME=linux-image-cloud-${ARCH}
	else
		KERNEL_PACKAGE_NAME=linux-image-${ARCH}
	fi
else
	KERNEL_PACKAGE_NAME=linux-image-${ARCH}
fi
chroot ${MOUNT_DIR} apt-get install -y -o Dpkg::Options::="--force-confnew" ${KERNEL_PACKAGE_NAME}

###########################################
### Remove older releases of the kernel ###
###########################################
# Specifically remove all but the highest-versioned kernel
# image. Let's not waste space on older kernels we won't use...
OLD_KERNELS=$(COLUMNS=200 chroot ${MOUNT_DIR} dpkg -l | awk '/^ii  linux-image-[0-9]/ {print $2}' | sort -u | head -n -1)
NUM_KERNELS=$(echo $OLD_KERNELS | wc -w)
if [ $NUM_KERNELS -gt 0 ]; then
    echo "Removing old kernels: $OLD_KERNELS"
    chroot ${MOUNT_DIR} apt-get remove --purge -y $OLD_KERNELS
fi

# And run autoremove to remove any dependencies that might have been
# brought in too
echo "Running apt-get autoremove:"
chroot ${MOUNT_DIR} apt-get autoremove -y

# Setup cloud-init, cloud-utils and cloud-initramfs-growroot
# These are only available from backports in Wheezy
if [ "${RELEASE}" = "wheezy" ] ; then
	chroot ${MOUNT_DIR} apt-get -t wheezy-backports install -y -o Dpkg::Options::="--force-confnew" cloud-init cloud-utils cloud-initramfs-growroot
	cat > ${MOUNT_DIR}/etc/apt/preferences.d/linux.pref <<EOF
Package: linux-image-${ARCH} initramfs-tools
Pin: release n=wheezy-backports
Pin-Priority: 500
EOF
fi

##########################
### Install cloud init ###
##########################
if [ "${CLOUD_INIT}" = "yes" ] ; then
	if [ "${AZURE}" = "yes" ] ; then
		echo "# to update this file, run dpkg-reconfigure cloud-init
datasource_list: [Azure]" >${MOUNT_DIR}/etc/cloud/cloud.cfg.d/90_dpkg.cfg
	else
		# DigitalOcean is available in cloud-init only starting on Jessie and on
		# (ie: cloud-init >= 0.7.6)
		if ! [ "${RELEASE}" = "wheezy" ] ; then
			DIGITAL_OCEAN_SOURCE="DigitalOcean, "
		else
			DIGITAL_OCEAN_SOURCE=""
		fi
		echo "# to update this file, run dpkg-reconfigure cloud-init
datasource_list: [ NoCloud, AltCloud, ConfigDrive, OpenStack, CloudStack, ${DIGITAL_OCEAN_SOURCE} Ec2, MAAS, OVF, GCE, None ]" >${MOUNT_DIR}/etc/cloud/cloud.cfg.d/90_dpkg.cfg
	fi

	# Needed to have automatic mounts of /dev/vdb
	echo "mount_default_fields: [~, ~, 'auto', 'defaults,nofail', '0', '2']" >>${MOUNT_DIR}/etc/cloud/cloud.cfg
	echo "manage_etc_hosts: true" >>${MOUNT_DIR}/etc/cloud/cloud.cfg

	# Set the cloud init default user (required for the keypair to be put in the right home directory)
	sed -i "s/name: debian/name: ${USER_LOGIN}/" ${MOUNT_DIR}/etc/cloud/cloud.cfg
fi

if [ "${AZURE}" = "yes" ] ; then
	unshare --pid --fork --mount-proc chroot ${MOUNT_DIR} apt-get install -y -o Dpkg::Options::="--force-confnew" waagent
	rm -f ${MOUNT_DIR}/var/log/waagent.log
fi

# Setting-up initramfs
chroot ${MOUNT_DIR} update-initramfs -u

rm ${MOUNT_DIR}/var/cache/apt/archives/*.deb

# Set console for emergency and rescue shells
SYSTEMD_DIR="${MOUNT_DIR}/etc/systemd/system/"
for service in emergency.service rescue.service ; do
	mkdir "${SYSTEMD_DIR}/${service}.d"
	echo '[Service]
ExecStart=
ExecStart=-/bin/sh -c "/sbin/sulogin /dev/tty0; /bin/systemctl --fail --no-block default"' > "${SYSTEMD_DIR}/${service}.d/console.conf"
done

###################################
### Setting-up extlinux or grub ###
###################################
mkdir -p ${MOUNT_DIR}/boot/extlinux 
if [ "${RELEASE}" = "wheezy" ] ; then
	append="rootdelay=30"
fi
KERNEL_PARAMS="nosplash text biosdevname=0 net.ifnames=0 console=tty0 console=$CONSOLE,115200 earlyprintk=$CONSOLE,115200 consoleblank=0 systemd.show_status=true $append"
if [ "${BOOTMANAGER}" = "grub" ] ; then
	sed -i -e 's|^[ #\t]*GRUB_CMDLINE_LINUX_DEFAULT[ #\t]*=.*|GRUB_CMDLINE_LINUX_DEFAULT="'"${KERNEL_PARAMS}"'"|' ${MOUNT_DIR}/etc/default/grub
	echo "
# openstack-debian-images disables OS prober to avoid
# loopback detection which breaks booting
GRUB_DISABLE_OS_PROBER=true" >>${MOUNT_DIR}/etc/default/grub

	if [ "${SERIAL_CONSOLE}" = "yes" ] ; then
		echo "GRUB_TERMINAL=serial
GRUB_SERIAL_COMMAND=\"serial --unit=1 --speed=115200 --word=8 --parity=no --stop=1\"
" >>${MOUNT_DIR}/etc/default/grub
	fi

	# Tell grub about our loopback devices first
	mkdir -p ${MOUNT_DIR}/boot/grub
	mount --bind /dev ${MOUNT_DIR}/dev
	mount --bind /proc ${MOUNT_DIR}/proc
	mount --bind /sys ${MOUNT_DIR}/sys
	echo "grub-efi-${ARCH} grub2/force_efi_extra_removable boolean true" | chroot ${MOUNT_DIR} debconf-set-selections
	chroot ${MOUNT_DIR} grub-mkconfig -o /boot/grub/grub.cfg
	# Run grub from the chroot, pointing to the bind mounted /dev device.
	if [ "${REAL_HARDWARE}" = "no" ] ; then
		GRUB_DESTINATION_DEV=/dev/${LOOPRAW_DEVICE}
	else
		GRUB_DESTINATION_DEV=/dev/${DEST_HDD}
	fi
	chroot ${MOUNT_DIR} grub-install --target=${GRUB_TARGET} --no-nvram --force-extra-removable --no-floppy --modules="part_msdos part_gpt" --grub-mkdevicemap=/boot/grub/device.map ${GRUB_DESTINATION_DEV}
	# Run grub from the host, pointing to the guest installation
	#grub-install --no-floppy --modules=part_msdos --grub-mkdevicemap=${MOUNT_DIR}/boot/grub/device.map --root-directory=${MOUNT_DIR} /dev/${LOOPRAW_DEVICE}
	umount ${MOUNT_DIR}/sys
	umount ${MOUNT_DIR}/dev
	umount ${MOUNT_DIR}/proc
else
	KERNEL_PARAMS="initrd=/initrd.img root=UUID=${UUID} ${KERNEL_PARAMS} ro"
	echo "default linux
timeout 1
label linux
kernel /vmlinuz
append ${KERNEL_PARAMS}" > ${MOUNT_DIR}/boot/extlinux/extlinux.conf
	extlinux --install ${MOUNT_DIR}/boot/extlinux
fi

###################
### HOOK SCRIPT ###
###################
if [ -x ${HOOK_SCRIPT} ] ; then
	export BODI_CHROOT_PATH=${MOUNT_DIR}
	export BODI_RELEASE=${RELEASE}
	${HOOK_SCRIPT}
fi

##########################
### Unmount everything ###
##########################

cleanup(){
	# refine cleanup everything was ok
	echo "Finished."
} 

sync
chroot ${MOUNT_DIR} umount /proc || true
chroot ${MOUNT_DIR} umount /sys || true
chroot ${MOUNT_DIR} umount /boot/efi || true

# Defrag the filesystem to allow for better size reduction below
e4defrag ${DEST_PART} > /dev/null
umount ${MOUNT_DIR}

# Run FSCK so that resize can work
fsck.ext4 -f ${DEST_PART} || true

if [ "${AUTOMATIC_RESIZE}" = "yes" ] ; then
	resize2fs -M /dev/mapper/${LOOP_DEVICE}
	FS_BLOCKS=`tune2fs -l /dev/mapper/${LOOP_DEVICE} | awk '/Block count/{print $3}'`
	WANTED_SIZE=`expr $FS_BLOCKS '*' 4 '/' 1024 + ${AUTOMATIC_RESIZE_SPACE}` # Add ${AUTOMATIC_RESIZE_SPACE}M
	resize2fs /dev/mapper/${LOOP_DEVICE} ${WANTED_SIZE}M
	FINAL_FS_BLOCKS=`tune2fs -l /dev/mapper/${LOOP_DEVICE} | awk '/Block count/{print $3}'`	
fi

sync
if [ "${REAL_HARDWARE}" = "no" ] ; then
	kpartx -d ${RAW_NAME}
fi
rmdir ${MOUNT_DIR}

if [ "${AUTOMATIC_RESIZE}" = "yes" ] ; then
	if [ "${BOOTTYPE}" = "mbr" ] ; then
		# some blocks for mbr and multiple block size (4k)
		FINAL_IMG_SIZE=`expr '(' $FINAL_FS_BLOCKS + 258 ')' '*' 4 '/' 1024`
		# Rebuild a smaller partition table
		${PARTED} -s ${RAW_NAME} rm 1
		${PARTED} -s ${RAW_NAME} mkpart primary ext4 1Mi ${FINAL_IMG_SIZE}Mi
		${PARTED} -s ${RAW_NAME} set 1 boot on
		# Add 2M for the 1M at the beginning of the partition and some additional space
		truncate -s `expr 3 + ${FINAL_IMG_SIZE}`M ${RAW_NAME}
		install-mbr ${RAW_NAME}
	else # uefi
		# Work out the sizes of the new image
		# 1M for the GPT header, and alignment padding
		# 100M for the ESP
		# $FINAL_FS_BLOCKS for the root partition
		FINAL_IMG_SIZE=$((1 + 100 + $((${FINAL_FS_BLOCKS} * 4 / 1024)) + 1))
		# Rebuild a smaller partition table
		${PARTED} -s ${RAW_NAME} rm 2
		${PARTED} -s -a optimal ${RAW_NAME} -- mkpart ROOT ext4 102Mi -64s
		# Add 1M padding
		truncate -s $((1 + ${FINAL_IMG_SIZE}))M ${RAW_NAME}
	fi
fi

if [ "${REAL_HARDWARE}" = "no" ] ; then
	if ! [ "${AZURE}" = "yes" ] ; then
		QEMU_VERSION=`qemu-img --help | head -n 1 | cut -d" " -f3 | cut -d"," -f1`
		if dpkg --compare-versions ${QEMU_VERSION} gt 1.0 ; then
			OTHER_QEMU_IMG_OPTIONS=" -o compat=0.10"
		else
			OTHER_QEMU_IMG_OPTIONS=""
		fi

		qemu-img convert -c -f raw ${RAW_NAME}${OTHER_QEMU_IMG_OPTIONS} -O qcow2 ${QCOW2_NAME}
	fi
fi

if [ "${REBOOT_AFTER_INSTALL}" = "yes" ] ; then
	if [ -x "${PRE_REBOOT_HOOK_SCRIPT}" ] ; then
		${PRE_REBOOT_HOOK_SCRIPT}
	fi
	echo "Rebooting computer in 5 seconds ..."
	sleep 5
	shutdown -r now
fi
