#!/bin/bash
# set -ex

CACHE="/var/cache/lxc/ubuntu"

NAME="ubuntu"
CONFFILE="lxc.conf"
MNTFILE=
TMPMNTFILE=
UTSNAME=
IPV4="172.20.0.21"
GATEWAY="172.20.0.1"
MTU="1500"

# These paths are within the container so do not need to obey configure prefixes
INTERFACES="/etc/network/interfaces"
INITTAB="/etc/inittab"
HOSTNAME="/etc/hostname"
FSTAB="/etc/fstab"
SSHD_CONFIG="/etc/ssh/sshd_config"
PROFILE="/etc/profile"

################################################################################
#                    ubuntu custom configuration files
################################################################################

# custom selinux

write_ubuntu_selinux() {
    mkdir -p $ROOTFS/selinux
    echo 0 > $ROOTFS/selinux/enforce
}

# custom fstab

write_ubuntu_fstab() {
cat <<EOF > $ROOTFS/$FSTAB
tmpfs  /dev/shm   tmpfs  defaults  0 0
EOF
}

# custom inittab

write_ubuntu_inittab() {
cat <<EOF > $ROOTFS/$INITTAB
id:3:initdefault:
si::sysinit:/etc/init.d/rcS
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
1:2345:respawn:/sbin/getty 38400 console
c1:12345:respawn:/sbin/getty 38400 tty1 linux
c2:12345:respawn:/sbin/getty 38400 tty2 linux
c3:12345:respawn:/sbin/getty 38400 tty3 linux
c4:12345:respawn:/sbin/getty 38400 tty4 linux
EOF
}

# custom network configuration

write_ubuntu_network() {
cat <<EOF > $ROOTFS/$INTERFACES
auto eth0 lo
iface eth0 inet static
address $IPV4
netmask 255.255.255.0
broadcast 0.0.0.0
mtu $MTU
up route add default gw $GATEWAY
iface lo inet loopback
EOF
}

# custom hostname

write_ubuntu_hostname() {
cat <<EOF > $ROOTFS/$HOSTNAME
$UTSNAME
EOF
}

# custom sshd configuration file

write_ubuntu_sshd_config() {
cat <<EOF > $ROOTFS/$SSHD_CONFIG
Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 768
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords yes
ChallengeResponseAuthentication no
EOF
}

reconfigure_ubuntu_packages() {
    chroot $ROOTFS /usr/sbin/dpkg-reconfigure locales
}

disable_ubuntu_services() {
    chroot $ROOTFS /usr/sbin/update-rc.d -f umountfs remove
    chroot $ROOTFS /usr/sbin/update-rc.d -f hwclock.sh remove
    chroot $ROOTFS /usr/sbin/update-rc.d -f hwclockfirst.sh remove
}


################################################################################
#                        lxc configuration files
################################################################################

write_lxc_configuration() {
cat <<EOF > $CONFFILE
lxc.utsname = $UTSNAME
lxc.tty = 4
lxc.pts = 1024
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.mtu = $MTU
lxc.mount = $TMPMNTFILE
lxc.rootfs = $ROOTFS
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
EOF
}

write_lxc_mounts() {

    TMPMNTFILE=$(mktemp lxc.XXXXXXXXXX)

    if [ ! -z "$MNTFILE" ]; then
	cp $MNTFILE $TMPMNTFILE
    fi
}

collect_information() {
    # choose a container name, default is 'ubuntu'
    echo -n "What is the name for the container ? [$NAME] "
    read _NAME_

    if [ ! -z "$_NAME_" ]; then
	NAME=$_NAME_
    fi

    # choose a hostname, default is the container name
    echo -n "What hostname do you wish for this container ? [$NAME] "
    read _UTSNAME_

    if [ ! -z "$_UTSNAME_" ]; then
	UTSNAME=$_UTSNAME_
    else
	UTSNAME=$NAME
    fi

    # choose an ipv4 address, better to choose the same network than
    # your host
    echo -n "What IP address do you wish for this container ? [$IPV4] "
    read _IPV4_

    if [ ! -z "$_IPV4_" ]; then
	IPV4=$_IPV4_
    fi

    # choose the gateway ip address
    echo -n "What is the gateway IP address ? [$GATEWAY] "
    read _GATEWAY_

    if [ ! -z "$_GATEWAY_" ]; then
	GATEWAY=$_GATEWAY_
    fi

    # choose the MTU size
    echo -n "What is the MTU size ? [$MTU] "
    read _MTU_

    if [ ! -z "$_MTU_" ]; then
	MTU=$_MTU_
    fi

    ROOTFS="./rootfs.$NAME"
    # choose the rootfs
    echo -n "Specify the location of the rootfs [$ROOTFS] "
    read _ROOTFS_

    if [ ! -z "$_ROOTFS_" ]; then
	ROOTFS=$_ROOTFS_
    fi

    echo -n "Specify the location for an extra fstab file [(none)] "
    read _MNTFILE_

    if [ ! -z "$_MNTFILE_" ]; then
	MNTFILE=$_MNTFILE_
    fi
}

install_ubuntu()
{
    # check if the rootfs does already exist
    if [ ! -e "$ROOTFS" ]; then
	    mkdir -p /var/lock/subsys/
	(
	    flock -n -x 200 


	    RES=$?
	    if [ "$RES" != "0" ]; then
		echo "Cache repository is busy."
		break
	    fi

	    echo "Choose your architecture"
	    select ARCH in amd64 i386; do
		echo "Architecture $ARCH selected"
		break;
	    done

	    # check the mini ubuntu was not already downloaded
	    echo -n "Checking cache download ..."
	    if [ ! -e "$CACHE/rootfs-$ARCH" ]; then
		
		echo "not cached"
		
		mkdir -p "$CACHE/partial-$ARCH"
		
	        # download a mini ubuntu into a cache
		echo "Downloading ubuntu minimal ..."
		echo debootstrap --verbose --variant=minbase --arch=$ARCH --include ifupdown,locales,net-tools,iproute,openssh-server karmic $CACHE/partial-$ARCH http://archive.sigma-com.net/ubuntu
		debootstrap --verbose --variant=minbase --arch=$ARCH --include ifupdown,locales,net-tools,iproute,openssh-server karmic $CACHE/partial-$ARCH http://archive.sigma-com.net/ubuntu
		
		RESULT=$?
		if [ "$RESULT" != "0" ]; then
		    echo "Failed to download the rootfs, aborting."
		    exit 1
		fi
		mv "$CACHE/partial-$ARCH" "$CACHE/rootfs-$ARCH"
		echo "Download complete."
	    else
		echo "Found."
	    fi
	    
            # make a local copy of the miniubuntu
	    echo -n "Copying rootfs ..."
	    cp -a $CACHE/rootfs-$ARCH $ROOTFS && echo "Done." || exit
	) 200> "/var/lock/subsys/lxc"
    fi

}

create() {

    collect_information

    install_ubuntu

    write_lxc_mounts

    write_lxc_configuration

    write_ubuntu_inittab

    write_ubuntu_hostname

    write_ubuntu_fstab

    write_ubuntu_network

    write_ubuntu_sshd_config

    write_ubuntu_selinux

    reconfigure_ubuntu_packages

    disable_ubuntu_services

    /usr/bin/lxc-create -n $NAME -f $CONFFILE
    RES=$?

    # remove the configuration files
    rm -f $CONFFILE
    rm -f $TMPMNTFILE

    if [ "$RES" != "0" ]; then
	echo "Failed to create '$NAME'"
	exit 1
    fi

    echo "Done."
    echo -e "\nYou can run your container with the 'lxc-start -n $NAME'\n"
}

destroy() {

    echo -n "What is the name for the container ? [$NAME] "
    read _NAME_

    if [ ! -z "$_NAME_" ]; then
	NAME=$_NAME_
    fi

    /usr/bin/lxc-destroy -n $NAME
    RETVAL=$?
    if [ ! $RETVAL -eq 0 ]; then
	echo "Failed to destroyed '$NAME'"
	return $RETVAL;
    fi

    ROOTFS="./rootfs.$NAME"

    echo -n "Shall I remove the rootfs [y/n] ? "
    read
    if [ "$REPLY" = "y" ]; then
	rm -rf $ROOTFS
    fi

    return 0
}

help() {
    cat <<EOF

This script is a helper to create ubuntu system containers.

The script will create the container configuration file following
the informations submitted interactively with 'lxc-ubuntu create'

The first creation will download, with debootstrap, a ubuntu
minimal and store it into a cache.

The script will copy from the cache the root filesystem to the
current directory.

If there is a problem with the container, (bad configuration for 
example), you can destroy the container with 'lxc-ubuntu destroy'
but without removing the rootfs and recreate it again with
'lxc-ubuntu create'.

If you want to create another ubuntu container, call the 'lxc-ubuntu
 create' again, specifying another name and new parameters.

At any time you can purge the ubuntu cache download by calling 
'lxc-ubuntu purge'

Have fun :)

EOF
}

purge() {

    if [ ! -e $CACHE ]; then
	exit 0
    fi

    # lock, so we won't purge while someone is creating a repository
    (
	flock -n -x 200 

	RES=$?
	if [ "$RES" != "0" ]; then
	    echo "Cache repository is busy."
	    exit 1
	fi

	echo -n "Purging the download cache..."
	rm --preserve-root --one-file-system -rf $CACHE && echo "Done." || exit 1
	exit 0

    ) 200> "/var/lock/subsys/lxc"
}

if [ "$(id -u)" != "0" ]; then
	echo "This script should be run as 'root'"
	exit 1
fi 

case "$1" in
    create)
	create;;
    destroy)
	destroy;;
    help)
	help;;
    purge)
	purge;;
    *)
	echo "Usage: $0 {create|destroy|purge|help}"
	exit 1;;
esac
