
#################################################################
#
# Docker specific functions.
#
# Author: TODO
#
################################################################
#
# Copyright (c) 2017 SUSE Linux Products GmbH
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or 3 as
# published by the Free Software Foundation.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING); if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
################################################################

recipe_setup_docker() {
    TOPDIR="/usr/src/packages"
    mkdir -p "$BUILD_ROOT$TOPDIR/SOURCES"
    mkdir -p "$BUILD_ROOT$TOPDIR/SOURCES/packages"

    echo "Copying packages"
    for package in $(find repos -name \*.rpm); do
        cp $package "$BUILD_ROOT$TOPDIR/SOURCES/packages/"
    done

    # Exclude the "repos" directory which was handled above
    find . -maxdepth 1 ! -name "repos" ! -name '.' -exec cp -rp -t $BUILD_ROOT$TOPDIR/SOURCES/ {} \+
}

recipe_prepare_docker() {
    :
}

docker_umount_setup() {
    if test -z "$BUILD_ROOT" -o "$BUILD_ROOT" = / ; then
	return
    fi
    mount --make-rslave "$BUILD_ROOT/sys/fs/cgroup" 2>/dev/null
    umount -n -R $BUILD_ROOT/sys/fs/cgroup 2>/dev/null
    # get rid of the bind mount
    umount -n $BUILD_ROOT/dev/shm 2>/dev/null
    umount -n -l $BUILD_ROOT
}

docker_mount_setup() {
    if test -z "$BUILD_ROOT" -o "$BUILD_ROOT" = / ; then
	return
    fi
    test -d /sys/fs/cgroup || cleanup_and_exit 1 "/sys/fs/cgroup does not exist"

    # make build root a mount point
    mount --rbind --make-private "$BUILD_ROOT" "$BUILD_ROOT"
    mount --make-rprivate "$BUILD_ROOT"

    if ! test -e $BUILD_ROOT/sys/block; then
	mkdir -p $BUILD_ROOT/sys
	mount -n -tsysfs sys $BUILD_ROOT/sys
    fi
    mount --rbind /sys/fs/cgroup "$BUILD_ROOT/sys/fs/cgroup"
    mount --make-rslave "$BUILD_ROOT/sys/fs/cgroup"

    # work around docker pivot root failure (to be investigated)
    export DOCKER_RAMDISK=true
}

# Variables:
# $BUILD_ROOT is the chroot
# $TOPDIR/SOURCES includes the docker sources
# $TOPDIR/$DOCKERIMAGE_ROOT where docker will be called
# $RECIPEFILE the name of the Dockerfile

recipe_build_docker() {
    touch $BUILD_ROOT/etc/resolv.conf
    chmod 755 $BUILD_ROOT/$TOPDIR/SOURCES/obs_pkg_mgr

    base_image_path=$(find containers -regextype egrep -regex ".*\.(tgz|tar|tar\.xz|tar\.gz)$" -print -quit)
    test -f "$base_image_path" || cleanup_and_exit 1 "base image not found"

    # load needed kernel modules
    modprobe bridge br_netfilter
    modprobe nf_nat
    modprobe xt_conntrack
    modprobe ip_tables

    docker_mount_setup

    echo "Starting container daemon"
    chroot $BUILD_ROOT /usr/sbin/containerd --listen unix:///run/containerd/containerd.sock &
    echo "Starting docker daemon"
    chroot $BUILD_ROOT /usr/bin/dockerd --containerd /run/containerd/containerd.sock --add-runtime oci=/usr/bin/docker-runc &
    echo "Waiting for docker daemon to start"
    for i in 1 2 3 4 5 6 7 8 9 10 ; do
        chroot $BUILD_ROOT docker version >/dev/null 2>&1 && break
        sleep 1
    done
    if ! chroot $BUILD_ROOT docker version >/dev/null 2>&1 ; then
	docker_umount_setup
        cleanup_and_exit 1 "Docker is dead"
    fi

    echo "Loading base image"
    if test -L "$base_image_path" ; then
	# copy into build root
	cp -L "$base_image_path" "$base_image_path.lnk"
	mv "$base_image_path.lnk" "$base_image_path"
    fi

    # Inspect the content of the image to decide if this is a layered image
    # or a filesystem one. We need to know if we will "docker load" it or
    # "docker import" it.
    if tar -tf $base_image_path | grep "^manifest.json" -q; then
        echo "Layered image found"
        chroot $BUILD_ROOT docker load --input $TOPDIR/SOURCES/$base_image_path
    else
        echo "Filesystem image found"
        desired_tag=$(grep "^\s*FROM" Dockerfile | cut -d" " -f2)
        chroot $BUILD_ROOT docker import $TOPDIR/SOURCES/$base_image_path "$desired_tag"
    fi

    # Start the local zypper repository
    # TODO [TBD] Should we inject the OBS_REPOSITORY_URL in the Dockerfile as described in
    # the following link or is this a user's responsibility?
    #  https://github.com/SUSE/cloudfoundry/blob/NativeDockerInOBS_research_results/NativeDockerInOBS.md
    # TODO [TBD] What about SLES? Are dependencies fetched automatically from osc/OBS?
    #  What about registration?

    # This is where we copied the downloaded dependencies in the setup method above.
    REPOPATH=$TOPDIR/SOURCES/packages
    # Prepare the zypper repository
    # TODO: Handle other distribution repositories as well (deb, arch etc)
    chroot $BUILD_ROOT createrepo $REPOPATH >/dev/null
    # TODO Add Python as a default building dependency.
    chroot $BUILD_ROOT bash -c "cd $REPOPATH && python -m SimpleHTTPServer 8080 &"

    # Build the repository url
    
    if test -x /sbin/ip ; then
        REPO_URL=$(ip addr show docker0 | sed -n -e 's@.*inet \([^ /]*\).*@\1@p')
    else
        REPO_URL=$(ifconfig docker0 | sed -n -e 's@.*inet addr:\([^ /]*\).*@\1@p')
    fi
    if test -z "$REPO_URL" ; then
        echo "network setup error, no docker0 interface?"
        cleanup_build_processes
        BUILD_SUCCEEDED=false
        return
    fi
    REPO_URL="http://$REPO_URL:8080"

    # Create the needed file to publish the generated image
    IMAGE_NAME=
    TAG=
    if [ -f "TAG" ] && [ $(cat TAG | grep ":") ]; then
        IMAGE_NAME=$(cat TAG | cut -d":" -f1)
        TAG=$(cat TAG | cut -d":" -f2)
    fi

    if [ -z "$IMAGE_NAME" ] || [ -z "$TAG" ]; then
        echo "TAG file missing of contents invalid (use image_name:tag format)"
        cleanup_build_processes
        BUILD_SUCCEEDED=false
        return
    fi

    # Use tag to generate the filename for the image
    FILENAME="$IMAGE_NAME:$TAG"
    FILENAME="${FILENAME//[\/:]/-}"

    echo "Building image"
    if ! chroot $BUILD_ROOT docker build -t "$IMAGE_NAME:$TAG" --build-arg OBS_REPOSITORY_URL=$REPO_URL $TOPDIR/SOURCES/ ; then
        echo "Docker build command failed"
        cleanup_build_processes
        BUILD_SUCCEEDED=false
        return
    fi

    # Save the resulting image to a tarball.
    mkdir -p $BUILD_ROOT$TOPDIR/DOCKER
    if ! chroot $BUILD_ROOT docker save --output "$TOPDIR/DOCKER/$FILENAME.tar" "$IMAGE_NAME:$TAG" ; then
        echo "Docker save command failed"
        cleanup_build_processes
        BUILD_SUCCEEDED=false
        return
    fi
    
    # Create containerinfo
    perl -I$BUILD_DIR -MBuild::Docker -e Build::Docker::showcontainerinfo "$BUILD_ROOT/$TOPDIR/SOURCES/$RECIPEFILE" "$FILENAME.tar" "$IMAGE_NAME:$TAG" containers/annotation> "$BUILD_ROOT$TOPDIR/DOCKER/$FILENAME.containerinfo"

    cleanup_build_processes
    BUILD_SUCCEEDED=true
}

cleanup_build_processes() {
    echo "Stopping local repository server"
    kill $(pgrep -f "python -m SimpleHTTPServer 8080")
    echo "Stopping the docker daemon"
    kill $(pidof dockerd)
    kill $(pidof containerd)
    docker_umount_setup
}

recipe_resultdirs_docker() {
    echo DOCKER
}

# Local Variables:
# mode: Shell-script
# End:
