#!/bin/bash

#
# template script for generating Oracle Linux container for LXC
# based on lxc-fedora
#

#
# lxc: linux Container library

# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>
# Ramez Hanna <rhanna@informatiq.org>

# Modified for Oracle Linux 4
# wim coekaerts <wim.coekaerts@oracle.com>

# This library 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.

# This library 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
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#Configurations

# hardcoded right now. So this script assumes that you have a valid base 
# template in /container/ol4-template on a btrfs volume
template_path=/container/ol4-template

# destination of the snapshot (for now same fs)
container_path=/container

#we compile lxc with /etc/lxc as config path
default_path=/etc/lxc

# just for testing right now. virbr0 comes up in a default environment
lxc_network_type=veth
lxc_network_link=virbr0

# is this Oracle Linux
[ -f /etc/oracle-release ] && is_ol=true

# ok so the configure function takes rootfs_patch
# and then goes and fixes it up to be a container

configure_ol4()
{
    # disable selinux in oracle linux container
    mkdir -p $rootfs_path/selinux
    echo 0 > $rootfs_path/selinux/enforce

   # configure the network using the dhcp
   # right now I am just setting hostname to container name for convenience
   # note that template configure for oracle vm templates will run at first boot anyway
    cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=${name}
NM_CONTROLLED=no
TYPE=Ethernet
MTU=${MTU}
EOF

    # set the hostname
    cat <<EOF > ${rootfs_path}/etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=${name}
EOF

    # set minimal hosts
    cat <<EOF > $rootfs_path/etc/hosts
127.0.0.1 localhost $name
EOF

    # disable ipv6
    cat << EOF >> $rootfs_path/etc/modprobe.d/blacklist
blacklist ipv6
blacklist net-pf-10
EOF

    cat <<EOF > $rootfs_path/etc/fstab
proc            /proc         proc    nodev,noexec,nosuid 0 0
devpts          /dev/pts      devpts defaults 0 0
sysfs           /sys          sysfs defaults  0 0
EOF

    # disable unneeded services for a container

    sed -i 's|IPTABLES_MODULES=".*|IPTABLES_MODULES="no"|' ${rootfs_path}/etc/sysconfig/iptables-config
    sed -i 's|IPTABLES_MODULES_UNLOAD=".*|IPTABLES_MODULES_UNLOAD="no"|' ${rootfs_path}/etc/sysconfig/iptables-config
    sed -i 's|.*sbin.start_udev.*||' ${rootfs_path}/etc/rc.sysinit
    sed -i 's|.*sbin.start_udev.*||' ${rootfs_path}/etc/rc.d/rc.sysinit

    # keep fastboot

    sed -i 's|rm -f /fastboot|rm -f |' ${rootfs_path}/etc/rc.sysinit
    sed -i 's|rm -f /fastboot|rm -f |' ${rootfs_path}/etc/rc.d/rc.sysinit

    chroot ${rootfs_path} chkconfig network on
    chroot ${rootfs_path} chkconfig acpid off
    chroot ${rootfs_path} chkconfig kudzu off
    chroot ${rootfs_path} chkconfig microcode_ctl off
    chroot ${rootfs_path} chkconfig autofs off
    chroot ${rootfs_path} chkconfig hidd off
    chroot ${rootfs_path} chkconfig auditd off
    chroot ${rootfs_path} chkconfig iptables off
    chroot ${rootfs_path} chkconfig isdn off
    chroot ${rootfs_path} chkconfig sendmail off
    chroot ${rootfs_path} chkconfig gpm off
    chroot ${rootfs_path} chkconfig ntpd off
    chroot ${rootfs_path} chkconfig dund off
    chroot ${rootfs_path} chkconfig apmd off
    chroot ${rootfs_path} chkconfig cpuspeed off
    chroot ${rootfs_path} chkconfig pcmcia off
    chroot ${rootfs_path} chkconfig irqbalance off
    touch ${rootfs_path}/fastboot
 
    # create required devices - important

    dev_path="${rootfs_path}/dev"
    # FIXME don't really want to do a blind rm -rf need to check rootfs_path != /
    rm -rf $dev_path
    mkdir -p $dev_path
    mknod -m 666 ${dev_path}/null c 1 3
    mknod -m 666 ${dev_path}/zero c 1 5
    mknod -m 666 ${dev_path}/random c 1 8
    mknod -m 666 ${dev_path}/urandom c 1 9
    mkdir -m 755 ${dev_path}/pts
    mkdir -m 1777 ${dev_path}/shm
    mknod -m 666 ${dev_path}/tty c 5 0
    mknod -m 666 ${dev_path}/tty0 c 4 0
    mknod -m 666 ${dev_path}/tty1 c 4 1
    mknod -m 666 ${dev_path}/tty2 c 4 2
    mknod -m 666 ${dev_path}/tty3 c 4 3
    mknod -m 666 ${dev_path}/tty4 c 4 4
    mknod -m 666 ${dev_path}/tty5 c 4 5
    mknod -m 666 ${dev_path}/tty6 c 4 6
    mknod -m 600 ${dev_path}/console c 5 1
    mknod -m 666 ${dev_path}/full c 1 7
    mknod -m 600 ${dev_path}/initctl p
    mknod -m 666 ${dev_path}/ptmx c 5 2

    return 0
}

# FIX ME - need to support filesystem copy (tar) next to snapshots as well
# right now just assuming a btrfs volume in /container

copy_ol()
{
   btrfs subvolume snapshot $template_path $container_path/$name
   return $?
}

install_ol()
{

	echo "Cloning base template $template_path to $container_path/$name ..."
	copy_ol
	if [ $? -ne 0 ]; then
	    echo "Failed to clone template"
	    return 1
	fi

	return 0

}

# this creates an lxc config file for use

copy_configuration()
{

    mkdir -p $config_path
    cat <<EOF >> $config_path/config
lxc.utsname = $name
lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = $rootfs_path
lxc.mount  = $config_path/fstab
#networking
lxc.network.type = $lxc_network_type
lxc.network.flags = up
lxc.network.link = $lxc_network_link
lxc.network.name = eth0
lxc.network.mtu = 1500
#cgroups
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

    cat <<EOF > $config_path/fstab
proc            $rootfs_path/proc         proc    nodev,noexec,nosuid 0 0
devpts          $rootfs_path/dev/pts      devpts defaults 0 0
sysfs           $rootfs_path/sys          sysfs defaults  0 0
EOF
    if [ $? -ne 0 ]; then
	echo "Failed to add configuration"
	return 1
    fi

    return 0
}

usage()
{
    cat <<EOF
usage:
    $1 -n|--name=<container_name>
        [-c|--clean]
        [-h|--help]
Mandatory args:
  -n,--name         Container name
Optional args:
  -h,--help         print this help
EOF
    return 0
}

options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release: -- "$@")
if [ $? -ne 0 ]; then
    usage $(basename $0)
    exit 1
fi
eval set -- "$options"

while true
do
    case "$1" in
	-h|--help)      usage $0 && exit 0;;
	-p|--path)      path=$2; shift 2;;
	-n|--name)      name=$2; shift 2;;
	--)             shift 1; break ;;
        *)              break ;;
    esac
done

# some sanity testing

if [ ! -d $template_path ]; then
    echo "$template_path does not exist ..."
    echo "Set up a container template first ..."
    exit 1
fi

if [ ! -d $container_path ]; then
    echo "$container_path does not exist ..."
    exit 1
fi

x=`df -T $container_path | grep btrfs > /dev/null`
ret=$?

if [ $ret -ne 0 ]; then
    echo "$container_path has to be a btrfs volume ..."
    exit 1
fi

if [ ! -z "$clean" -a -z "$path" ]; then
    clean || exit 1
    exit 0
fi

path=$default_path

if [ -z "$release" ]; then
    if [ "$is_ol" ]; then
        release=$(cat /etc/oracle-release |awk '/^Oracle/ {print $3}')
    else
        echo "This is not an Oracle Linux host and release missing."
    fi
fi

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


rootfs_path=$container_path/$name
config_path=$default_path/$name

revert()
{
    echo "Interrupted, so cleaning up"
    lxc-destroy -n $name
    # maybe was interrupted before copy config
    rm -rf $path/$name
    rm -rf $default_path/$name
    echo "exiting..."
    exit 1
}

trap revert SIGHUP SIGINT SIGTERM

copy_configuration
if [ $? -ne 0 ]; then
    echo "Failed to create configuration file ..."
    exit 1
fi

install_ol
if [ $? -ne 0 ]; then
    echo "Failed to clone Oracle Linux 4 template ..."
    exit 1
fi

configure_ol4
if [ $? -ne 0 ]; then
    echo "Failed to configure Oracle Linux 4 container"
    exit 1
fi


if [ ! -z $clean ]; then
    clean || exit 1
    exit 0
fi
echo "Container created : $container_path/$name ..."
echo "Container template source : $template_path"
echo "Container config : $default_path/$name"
echo "Network : eth0 (veth) on virbr0"
