#!/bin/bash
## kola:
##   # Increase timeout since this test has a lot of I/O and involves rebasing
##   timeoutMin: 20
##   # We've seen some OOM when 1024M is used:
##   # https://github.com/coreos/fedora-coreos-tracker/issues/1506
##   minMemory: 2048
##   # We do a bunch of copies/rebuilds of the whole OS.
##   minDisk: 20
##   # Needs internet access as we fetch files from koji
##   tags: "needs-internet platform-independent"
##   description: Verify that build of a container image with a new kernel
##     and reboot into it succeeds.

#
# Copyright (C) 2023 Red Hat, Inc.
#
# 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 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.

set -euxo pipefail

# shellcheck disable=SC1091
. "$KOLA_EXT_DATA/commonlib.sh"

cd $(mktemp -d)

# TODO: It'd be much better to test this via a registry

# define OS ID in order to assign appropriate kernel later
OS_ID=$(. /etc/os-release; echo $ID)
baseimage="localhost/coreos-base:latest"
imagespec="containers-storage:${baseimage}"
derivedimage="localhost/coreos-derived:latest"
derived_imagespec="containers-storage:${derivedimage}"
arch=$(arch)


build_base_image() {
    # Take the existing ostree commit, and export it to a container image
    rpm-ostree status --json > status.json
    checksum=$(jq -r '.deployments[0].checksum' < status.json)
    v0=$(jq -r '.deployments[0].version' < status.json)
    imgref=$(jq -r '.deployments[0]["container-image-reference"]' < status.json)
    encapsulate_args=()
    # A hack...if we're booted into a container, then we need to fake things out
    # for the merge commit to turn it back into an image.  What we *really* want
    # here obviously is seamless support for re-serializing a container from
    # the ostree storage, but right now we're not doing the tar-split stuff.
    if [[ "$imgref" != null ]]; then
      encapsulate_args+=("--label" "ostree.bootable=true")
    fi
    ostree container encapsulate "${encapsulate_args[@]}" --repo=/ostree/repo ${checksum} "${imagespec}"
}

build_derived_image() {
    # do the container build in a temporary context directory
    contextdir=$(mktemp -d)
    pushd ${contextdir}

	running_kver=$(rpm -q kernel --qf '%{EVR}')
    case "$OS_ID" in
      rhcos|scos|rhel|centos)
        # Use the matching CentOS Stream version based on RHEL/SCOS major version
        if match_maj_ver "10"; then
            cs_mirror="https://mirror.stream.centos.org/10-stream/BaseOS/${arch}/os"
        elif match_maj_ver "9"; then
            cs_mirror="https://mirror.stream.centos.org/9-stream/BaseOS/${arch}/os"
        else
            fatal "Unhandled major RHEL/SCOS VERSION"
        fi
        # we're probably already on CentOS and running the latest kernel. so
        # here we need to instead pick whatever the latest that's *not* the same
        dnf_opts="--repofrompath=tmp,${cs_mirror} --disablerepo=* --enablerepo tmp"
        kver=$(dnf repoquery $dnf_opts kernel --qf '%{EVR}' | \
                  grep -v "${running_kver}" | tail -n1)
        dnf download $dnf_opts --resolve kernel-{,core-,modules-,modules-core-,modules-extra-}$kver
        ;;
      fedora)
        VERSION_ID=$(. /etc/os-release; echo $VERSION_ID)
        previous_version_id=$((VERSION_ID - 1))
        # Workaround https://github.com/coreos/fedora-coreos-tracker/issues/2113
        # with the skip_system_repo_lock=true setting in dnf configuration file.
        printf "[main]\nskip_system_repo_lock=true" > dnf_config
        dnf download --config=dnf_config --releasever "${previous_version_id}" \
          --resolve --disablerepo=* --enablerepo=updates --enablerepo=fedora kernel-core kernel
        kver=$(rpm -qp --qf '%{EVR}' ./kernel-core*rpm)
		if [[ "${kver}" ==  "${running_kver}" && "$(get_fcos_stream)" == "rawhide" ]]; then
			ok "Skipping: no kernel other than the running one (${running_kver}) found"
			exit 0
		fi
        ;;
      *)
        echo "Unknown OS_ID: ${OS_ID}"
        exit 1
        ;;
    esac

    # we only want to query repos once but need the info on multiple boots, so write out state to /var
    echo "$kver" > /var/kola-kernel.evr

    cat > Containerfile << EOF
FROM $baseimage
# Disable yum repos since we are overriding local files and we don't
# want to reach out to the repos. This is done in a way such that if
# there are no repo files (i.e. like on RHCOS) then it succeeds anyway.
RUN ls /etc/yum.repos.d/*.repo 2>/dev/null | xargs --no-run-if-empty sed -i s/enabled=1/enabled=0/
RUN rpm-ostree override replace /tmp/buildcontext/*rpm && \
    rpm-ostree cleanup -m && \
    ostree container commit
EOF
    podman build --volume $PWD:/tmp/buildcontext:z -t "${derived_imagespec}" --squash .
    popd
}

case "${AUTOPKGTEST_REBOOT_MARK:-}" in
  "")
    # First thing, let's create the base and derived images
    build_base_image
    build_derived_image

    # Since we're switching OS update streams, turn off zincati
    systemctl mask --now zincati

    # Rebase a few times to test the mechanisms
    #
    # This one keeps --experimental, but we also test without it below
    rpm-ostree rebase --experimental "ostree-unverified-image:${imagespec}"
    ostree container image list --repo=/ostree/repo | tee imglist.txt
    # Test rebasing back to ostree https://github.com/coreos/rpm-ostree/issues/3677
    rpm-ostree rebase "$checksum"
    rpm-ostree rebase "ostree-unverified-image:${imagespec}"
    /tmp/autopkgtest-reboot 1
    ;;
  1)
    # Now test rebasing to the derived kernel-replaced image
    rpm-ostree --version
    rpm-ostree rebase "ostree-unverified-image:$derived_imagespec"
    ostree container image list --repo=/ostree/repo
    /tmp/autopkgtest-reboot 2
    ;;
  2)
    kver="$(cat /var/kola-kernel.evr).${arch}" # expected
    un=$(uname -r)                             # detected
    if test "$un" != "$kver"; then
      echo "Expected kernel $kver but found $un"
      exit 1
    else
      echo "Kernel switch to $un was successful"
    fi
    test -f /usr/lib/modules/$kver/initramfs.img
    test -f /usr/lib/modules/$kver/vmlinuz
    ;;
  *)
    echo "Unknown AUTOPKGTEST_REBOOT_MARK: ${AUTOPKGTEST_REBOOT_MARK:-}"
    exit 1
    ;;
esac
