#!/bin/sh
# autopkgtest-build-lxd is part of autopkgtest
# autopkgtest is a tool for testing Debian binary packages
#
# autopkgtest is Copyright (C) 2006-2015 Canonical Ltd.
#
# Build or update an LXD image autopkgtest/<distro>/<release>/<arch> with
# autopkgtest customizations from an arbitrary existing image.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# See the file CREDITS for a full list of credits information (often
# installed as /usr/share/doc/autopkgtest/CREDITS).
set -eu

# generate temporary container name
generate_container_name() {
    while true; do
        CONTAINER=$(mktemp autopkgtest-prepare-XXX -u)
        lxc info "$CONTAINER" >/dev/null 2>&1 || break
    done
}

# detect apt proxy
proxy_detect() {
    # support backwards compatible env var too
    AUTOPKGTEST_APT_PROXY=${AUTOPKGTEST_APT_PROXY:-${ADT_APT_PROXY:-}}
    if [ -z "$AUTOPKGTEST_APT_PROXY" ]; then
        RES=`apt-config shell proxy Acquire::http::Proxy`
        eval $RES
        if echo "${proxy:-}" | egrep -q '(localhost|127\.0\.0\.[0-9]*)'; then
            # translate proxy address to one that can be accessed from the
            # running container
            local bridge_interface=$(lxc profile show default | sed -n '/parent:/ { s/^.*: *//; p; q }') || true
            if [ -n "$bridge_interface" ]; then
                local bridge_ip=$(ip -4 a show dev "$bridge_interface" | awk '/ inet / {sub(/\/.*$/, "", $2); print $2}') || true
                if [ -n "$bridge_ip" ]; then
                    AUTOPKGTEST_APT_PROXY=$(echo "$proxy" | sed -r "s#localhost|127\.0\.0\.[0-9]*#$bridge_ip#")
                fi
            fi
            if [ -n "$AUTOPKGTEST_APT_PROXY" ]; then
                echo "Detected local apt proxy, using $AUTOPKGTEST_APT_PROXY as container proxy"
            fi
        elif [ -n "${proxy:-}" ]; then
            AUTOPKGTEST_APT_PROXY="$proxy"
            echo "Using $AUTOPKGTEST_APT_PROXY as container proxy"
        fi
    fi
}

setup() {
    # set up apt proxy for the container
    if [ -n "$AUTOPKGTEST_APT_PROXY" ] && [ "$AUTOPKGTEST_APT_PROXY" != "none" ]; then
        echo "Acquire::http::Proxy \"$AUTOPKGTEST_APT_PROXY\";" | lxc file push - "$CONTAINER/etc/apt/apt.conf.d/01proxy"
        # work around LP#1548878
        lxc exec "$CONTAINER" -- chmod 644 /etc/apt/apt.conf.d/01proxy
    fi

    sleep 5
    if lxc exec "$CONTAINER" -- systemctl mask serial-getty@getty.service; then
       lxc exec "$CONTAINER" -- reboot
    fi

    # wait until it is booted: lxc exec works and we get a numeric runlevel
    timeout=60
    while [ $timeout -ge 0 ]; do
        timeout=$((timeout - 1))
        sleep 1
        O=`lxc exec "$CONTAINER" runlevel 2>/dev/null </dev/null` || continue
        [ "$O" = "${O%[0-9]}" ] || break
    done
    [ $timeout -ge 0 ] || {
        echo "Timed out waiting for container to boot" >&2
        exit 1
    }

    # wait until a systemd based container has networking
    if ! echo '[ ! -d /run/systemd/system ] || systemctl start network-online.target' | timeout 60 lxc exec "$CONTAINER" -- sh -e; then
        echo "Timed out waiting for container to start network-online.target" >&2
        exit 1
    fi

    ARCH=$(lxc exec "$CONTAINER" -- dpkg --print-architecture </dev/null)
    DISTRO=$(lxc exec "$CONTAINER" -- sh -ec 'lsb_release -si 2>/dev/null || . /etc/os-release; echo "${NAME% *}"' </dev/null)
    CRELEASE=$(lxc exec "$CONTAINER" -- sh -ec 'lsb_release -sc 2>/dev/null || awk "/^deb/ {sub(/\\[.*\\]/, \"\", \$0); print \$3; exit}" /etc/apt/sources.list' </dev/null)
    echo "Container finished booting. Distribution $DISTRO, release $CRELEASE, architecture $ARCH"
    RELEASE=${RELEASE:-${CRELEASE}}

    if [ -z "${AUTOPKGTEST_KEEP_APT_SOURCES:-}" ] && [ -n "${AUTOPKGTEST_APT_SOURCES_FILE:-}" ]; then
        # Transfer the apt sources from the host system to the environment
        AUTOPKGTEST_APT_SOURCES="$(cat "$AUTOPKGTEST_APT_SOURCES_FILE")"
        unset AUTOPKGTEST_APT_SOURCES_FILE
    fi

    # find setup-testbed script
    for script in $(dirname $(dirname "$0"))/setup-commands/setup-testbed \
                  /usr/share/autopkgtest/setup-commands/setup-testbed; do
        if [ -r "$script" ]; then
            echo "Running setup script $script..."
            lxc exec "$CONTAINER" -- env \
                AUTOPKGTEST_KEEP_APT_SOURCES="${AUTOPKGTEST_KEEP_APT_SOURCES:-}" \
                AUTOPKGTEST_APT_SOURCES="${AUTOPKGTEST_APT_SOURCES:-}" \
                MIRROR="${MIRROR:-}" \
                RELEASE="${RELEASE}" \
                sh < "$script"
            break
        fi
    done
    lxc stop "$CONTAINER"
}

#
# main
#

if [ -z "${1:-}" ]; then
    echo "Usage: $0 <image>" >&2
    exit 1
fi
IMAGE="$1"
CONTAINER=''
trap '[ -z "$CONTAINER" ] || lxc delete -f "$CONTAINER"' EXIT INT QUIT PIPE

proxy_detect
generate_container_name
# we must redirect stdin when calling lxc launch due to lp #1845037
lxc launch "$IMAGE" "$CONTAINER" < /dev/null
setup

# if there already is a published image, get its fingerprint to clean it up
# afterwards
DISTROLC=$(echo "$DISTRO" | tr '[:upper:]' '[:lower:]')
ALIAS="autopkgtest/$DISTROLC/$RELEASE/$ARCH"
DESCRIPTION="autopkgtest $DISTRO $RELEASE $ARCH"

lxc publish "$CONTAINER" --alias "$ALIAS" --public description="$DESCRIPTION" distribution="$DISTROLC" release="$RELEASE" architecture="$ARCH"

# clean up old images
for i in $(lxc image list | grep "$DESCRIPTION" | grep -v "$ALIAS" | cut -d'|' -f3); do
    echo "Removing previous image $i"
    lxc image delete "$i"
done
