#!/bin/bash

#
# template script for generating openmandriva container for LXC
#

#
# lxc: linux Container library

# Authors:
# Alexander Khryukin <alexander@mezon.ru>
# Vokhmin Alexey V   <avokhmin@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#

# Detect use under userns (unsupported)
for arg in "$@"; do
    [ "$arg" = "--" ] && break
    if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
        echo "This template can't be used for unprivileged containers." 1>&2
        echo "You may want to try the \"download\" template instead." 1>&2
        exit 1
    fi
done

# Make sure the usual locations are in PATH
export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin

#Configurations
#distro=cooker
hostarch=$(uname -m)
# Allow the cache base to be set by environment variable
cache_base="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/openmandriva/$arch}"
default_path=@LXCPATH@
default_profile=default
lxc_network_type=veth
lxc_network_link=br0

# is this openmandriva?
[ -f /etc/mandriva-release ] && is_openmandriva=true

configure_openmandriva()
{
mkdir -p ${rootfs_path}/etc/sysconfig/network-scripts/

   # configure the network using the dhcp
    cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=dhcp
NM_CONTROLLED=no
HOSTNAME=${utsname}
EOF

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

echo "${utsname}" > ${rootfs_path}/etc/hostname

    # set minimal hosts
    cat <<EOF > $rootfs_path/etc/hosts
127.0.0.1 localhost.localdomain localhost $utsname
::1                 localhost6.localdomain6 localhost6
EOF
}

populate_dev()
{
    echo -n "Create devices in /dev/"
    dev_path="${rootfs_path}/dev"
    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 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
    mkdir -m 755 ${dev_path}/net
    mknod -m 666 ${dev_path}/net/tun c 10 200

}

set_guest_root_password()
{
    [ -z "$root_password" ] && return # pass is empty, abort

    echo " - setting guest root password.."
    echo "root passwd is: $root_password"
    echo "root:$root_password" | chroot "$rootfs_path" chpasswd
    echo "done."
}

create_chroot_openmandriva()
{
    # check the mini openmandriva was not already downloaded
    INSTALL_ROOT=$cache/cache
    mkdir -p $INSTALL_ROOT
    if [ $? -ne 0 ]; then
        echo "Failed to create '$INSTALL_ROOT' directory"
        return 1
    fi
    # package list to install
    PKG_LIST="basesystem-minimal locales locales-en initscripts urpmi cronie dhcp-client kbd"
    # download a mini openmandriva into a cache
    echo "Downloading openmandriva minimal ..."
    URPMI="/usr/sbin/urpmi.addmedia --urpmi-root $INSTALL_ROOT main http://abf.rosalinux.ru/downloads/$release/repository/$arch/main/release"
    echo $URPMI
    URPMI_BASE="/usr/sbin/urpmi --no-suggests --no-verify-rpm --ignorearch --root $INSTALL_ROOT --urpmi-root $INSTALL_ROOT --auto $PKG_LIST"
    $URPMI
    $URPMI_BASE
    # We're splitting the old loop into two loops plus a directory retrival.
    # First loop...  Try and retrive a mirror list with retries and a slight
    # delay between attempts...
    if [ $? -ne 0 ]; then
        echo "Failed to download the rootfs, aborting."
        return 1
    fi

    mv "$INSTALL_ROOT" "$cache/rootfs"
    echo "Download complete."

    return 0

}

copy_openmandriva()
{

    echo -n "Copying rootfs to $rootfs_path ..."
    mkdir -p $rootfs_path
    rsync -SHaAX $cache/rootfs/ $rootfs_path/
    return 0
}

update_openmandriva()
{
    echo "automated update in progress..."
    urpmi --root $cache/rootfs --urpmi-root $cache/rootfs --auto --auto-update --ignorearch
}

configure_openmandriva_systemd()
{
    chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/proc-sys-fs-binfmt_misc.automount
    chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/systemd-udevd.service
    chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/systemd-udevd-control.socket
    chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/systemd-udevd-kernel.socket
    # remove numlock service
    # KDGKBLED: Inappropriate ioctl for device
    rm -f ${rootfs_path}/etc/systemd/system/getty@.service.d/enable-numlock.conf

    unlink ${rootfs_path}/etc/systemd/system/default.target
    chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
    sed -i 's!ConditionPathExists=/dev/tty0!ConditionPathExists=|/dev/tty0\nConditionVirtualization=|lxc!' \
	    ${rootfs_path}/lib/systemd/system/getty\@.service
}


install_openmandriva()
{
    mkdir -p @LOCALSTATEDIR@/lock/subsys/
    (
        flock -x 9
        if [ $? -ne 0 ]; then
            echo "Cache repository is busy."
            return 1
        fi

        echo "Checking cache download in $cache/rootfs ... "
        if [ ! -e "$cache/rootfs" ]; then
            echo $cache/rootfs
            create_chroot_openmandriva
            if [ $? -ne 0 ]; then
                echo "Failed to download 'openmandriva basesystem-minimal'"
                return 1
            fi
        else
            echo "Cache found. Updating..."
            update_openmandriva
            if [ $? -ne 0 ]; then
                echo "Failed to update 'openmandriva base', continuing with last known good cache"
            else
                echo "Update finished"
            fi
        fi

        echo "Copy $cache/rootfs to $rootfs_path ... "
        copy_openmandriva
        if [ $? -ne 0 ]; then
            echo "Failed to copy rootfs"
            return 1
        fi
        return 0
    ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-openmandriva

    return $?
}

copy_configuration()
{

    mkdir -p $config_path
    grep -q "^lxc.rootfs.path" $config_path/config 2>/dev/null || echo "lxc.rootfs.path = $rootfs_path" >> $config_path/config
    cat <<EOF >> $config_path/config
lxc.uts.name = $name
lxc.tty.max = 4
lxc.pty.max = 1024
lxc.cap.drop = sys_module mac_admin mac_override sys_time
lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed

# When using LXC with apparmor, uncomment the next line to run unconfined:
#lxc.apparmor.profile = unconfined

#networking
lxc.net.0.type = $lxc_network_type
lxc.net.0.flags = up
lxc.net.0.link = $lxc_network_link
lxc.net.0.name = eth0
lxc.net.0.mtu = 1500
EOF
if [ ! -z ${ipv4} ]; then
    cat <<EOF >> $config_path/config
lxc.net.0.ipv4.address = $ipv4
EOF
fi
if [ ! -z ${gw} ]; then
    cat <<EOF >> $config_path/config
lxc.net.0.ipv4.gateway = $gw
EOF
fi
if [ ! -z ${ipv6} ]; then
    cat <<EOF >> $config_path/config
lxc.net.0.ipv6.address = $ipv6
EOF
fi
if [ ! -z ${gw6} ]; then
    cat <<EOF >> $config_path/config
lxc.net.0.ipv6.gateway = $gw6
EOF
fi
    cat <<EOF >> $config_path/config
#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 10:135 rwm
EOF

    if [ $? -ne 0 ]; then
        echo "Failed to add configuration"
        return 1
    fi

    return 0
}

clean()
{

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

    # lock, so we won't purge while someone is creating a repository
    (
        flock -x 9
        if [ $? != 0 ]; then
            echo "Cache repository is busy."
            exit 1
        fi

        echo -n "Purging the download cache for OpenMandriva-$release..."
        rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
        exit 0
    ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-openmandriva
}

usage()
{
    cat <<EOF
usage:
    $1 -n|--name=<container_name>
        [-p|--path=<path>] [-c|--clean] [-R|--release=<openmandriva2013.0/rosa2012.1/cooker/ release>]
        [-4|--ipv4=<ipv4 address>] [-6|--ipv6=<ipv6 address>]
        [-g|--gw=<gw address>] [-d|--dns=<dns address>]
        [-P|--profile=<name of the profile>] [--rootfs=<path>]
        [-A|--arch=<arch of the container>]
        [-h|--help]
Mandatory args:
  -n,--name         container name, used to as an identifier for that container from now on
Optional args:
  -p,--path         path to where the container rootfs will be created, defaults to @LXCPATH@. The container config will go under @LXCPATH@ in that case
  -c,--clean        clean the cache
  -R,--release      openmandriva2013.0/cooker/rosa2012.1 release for the new container. if the host is OpenMandriva, then it will default to the host's release.
  -4,--ipv4         specify the ipv4 address to assign to the virtualized interface, eg. 192.168.1.123/24
  -6,--ipv6         specify the ipv6 address to assign to the virtualized interface, eg. 2003:db8:1:0:214:1234:fe0b:3596/64
  -g,--gw           specify the default gw, eg. 192.168.1.1
  -G,--gw6          specify the default gw, eg. 2003:db8:1:0:214:1234:fe0b:3596
  -d,--dns          specify the DNS server, eg. 192.168.1.2
  -P,--profile      Profile name is the file name in /etc/lxc/profiles contained packages name for install to cache.
  -A,--arch         Define what arch the container will be [i586,x86_64,armv7l,armv7hl]
  ---rootfs         rootfs path
  -h,--help         print this help
EOF
    return 0
}

options=$(getopt -o hp:n:P:cR:4:6:g:d:A -l help,rootfs:,path:,name:,profile:,clean:,release:,ipv4:,ipv6:,gw:,dns:,arch: -- "$@")
if [ $? -ne 0 ]; then
    usage $(basename $0)
    exit 1
fi
eval set -- "$options"

release=${release:-"cooker"}
if [ -f /etc/lsb-release ]; then
    . /etc/lsb-release
    if [ "$DISTRIB_ID" = "OpenMandrivaLinux" ]; then
        release=openmandriva2013.0
    elif [ "$DISTRIB_ID" = "RosaDesktop.Fresh" ]; then
        release=rosa2012.1
    else
        echo "This is not an OpenMandriva or ROSA release"
        exit 1
    fi
fi

while true
do
    case "$1" in
        -h|--help)      usage $0 && exit 0;;
        -p|--path)      path=$2; shift 2;;
        --rootfs)       rootfs_path=$2; shift 2;;
        -n|--name)      name=$2; shift 2;;
        -P|--profile)   profile=$2; shift 2;;
        -c|--clean)     clean=1; shift 1;;
        -R|--release)   release=$2; shift 2;;
        -A|--arch)      arch=$2; shift 2;;
        -4|--ipv4)      ipv4=$2; shift 2;;
        -6|--ipv6)      ipv6=$2; shift 2;;
        -g|--gw)        gw=$2; shift 2;;
        -d|--dns)       dns=$2; shift 2;;
        --)             shift 1; break ;;
        *)              break ;;
    esac
done

arch=${arch:-$hostarch}

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

if [ -z "${utsname}" ]; then
    utsname=${name}
fi

type urpmi >/dev/null 2>&1
if [ $? -ne 0 ]; then
    echo "'urpmi' command is missing"
    exit 1
fi

if [ -z "$path" ]; then
    path=$default_path
fi

if [ -z "$profile" ]; then
    profile=$default_profile
fi

if [ $hostarch = "i586" -a $arch = "x86_64" ]; then
     echo "can't create x86_64 container on i586"
     exit 1
fi

if [ -z "$ipv4" -a -z "$ipv6" ]; then
    BOOTPROTO="dhcp"
else
    BOOTPROTO="static"
fi

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

# check for 'lxc.rootfs.path' passed in through default config by lxc-create
if [ -z "$rootfs_path" ]; then
    if grep -q '^lxc.rootfs.path' $path/config 2>/dev/null ; then
        rootfs_path=$(awk -F= '/^lxc.rootfs.path =/{ print $2 }' $path/config)
    else
        rootfs_path=$path/$name/rootfs
    fi
fi

config_path=$default_path/$name
cache=$cache_base/$release/$arch/$profile

if [ ! -f $config_path/config ]; then
    echo "A container with that name exists, chose a different name"
    exit 1
fi

install_openmandriva
if [ $? -ne 0 ]; then
    echo "failed to install openmandriva"
    exit 1
fi

configure_openmandriva
if [ $? -ne 0 ]; then
    echo "failed to configure openmandriva for a container"
    exit 1
fi

# If the systemd configuration directory exists - set it up for what we need.
if [ -d ${rootfs_path}/etc/systemd/system ]
then
    configure_openmandriva_systemd
fi

populate_dev
if [ $? -ne 0 ]; then
    echo "failed to populated /dev/ devices"
    exit 1
fi

set_guest_root_password
if [ $? -ne 0 ]; then
    echo "failed to configure password for chroot"
    exit 1
fi

copy_configuration
if [ $? -ne 0 ]; then
    echo "failed write configuration file"
    exit 1
fi

if [ ! -z "$clean" ]; then
    clean || exit 1
    exit 0
fi
echo "container rootfs and config created"
