#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

#
# This file is part of Lustre, http://www.lustre.org/
#
# contrib/coverity/coverity-run
#
# Script for running Coverity builds (and setup VMs)
# to upload to https://scan.coverity.com/projects/lustre
#
# Author: Timothy Day <timday@amazon.com>
#

#
# Output list of all commands
#
function cr_list() {
	less -F <<EOF
Usage: ${0##*/} [options]
Helper for running Coverity builds for Lustre
	setup         Test that ssh is working and setup needed VMs.
	install       Install packages needed for build.
	build         Build Lustre and dependencies. The users should
		      validate the everything builds correctly.
	run           Run Coverity scan. You must provide the path
		      to the Coverity tool tarball using the COV_PATH
		      env variable. This can be downloaded from the
		      Coverity website.
	clean         Remove build/VM artifacts.
	all           Run all of the above steps in order.
	list          List all possible commands.

The commands should be run in the following order:

	setup -> install -> build -> run -> clean

To run this locally, both Vagrant and the 'libvirt' provider must be
used. Otherwise, any remote host can be used. After the scan is run,
there will be a tar file generated. This should be uploaded to Coverity
via the web portal using the Lustre version output during the
'run' step as the software version.
EOF
	exit
}

#
# Create VM using Vagrant.
#
function cr_setup() {
	if [[ "$COV_SSH" =~ "vagrant" ]]; then
		vagrant up
		vagrant reload
		vagrant ssh-config > vagrant-ssh.config
	fi

	ssh "$COV_SSH" "$COV_HOST" "uname -r"
}

#
# Setup node to build Lustre and run Coverity
#
function cr_install() {
	# Setup host
	ssh "$COV_SSH" "$COV_HOST" <<EOF
# Repo setup (for CentOS)
sudo sed -i -e "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-*
sudo sed -i -e "s|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*

# Add repos
sudo dnf update -y
sudo dnf config-manager --set-enabled powertools
sudo dnf config-manager --add-repo=https://downloads.whamcloud.com/public/e2fsprogs/latest/el8
sudo dnf install -d1 -y --enablerepo=*rhel-*rhui-*rpms libyaml-devel || true
sudo dnf install -d1 -y --enablerepo=?ower?ools libyaml-devel || true
sudo dnf install -y --enablerepo=*rhel-*rhui-*rpms libnl3-devel libmount-devel || true

# General kernel tools
sudo dnf groupinstall -y 'Development Tools'

# Debug info (needed for ldiskfs)
sudo dnf install -y --enablerepo=*debug* kernel-debuginfo

# Install Lustre/ZFS dependencies and tools
sudo dnf install -y --nogpgcheck git libyaml-devel libnl3-devel libmount-devel \
          wget ncurses-devel bc kernel kernel-devel openssl-devel \
          binutils-devel lsof crash kexec-tools perf psmisc e2fsprogs-devel \
          elfutils-libelf-devel libudev-devel libattr-devel libaio-devel libuuid-devel \
          libblkid-devel libtirpc-devel libffi-devel ncompress python3-cffi python3-devel
sudo dnf install -y dwarves python3-packaging || true
EOF
}

#
# Perform a test build of ZFS and Lustre. User must
# validate that correct modules get built.
#
function cr_build() {
	# Build ZFS
	ssh "$COV_SSH" "$COV_HOST" <<EOF
# Grab repo
rm -rf ~/zfs
git clone https://github.com/openzfs/zfs.git

# Build
cd ~/zfs
git checkout -b coverity-run zfs-2.1.11
sh autogen.sh
./configure
make -s -j\$(nproc)

# Install
sudo make install
EOF

	# Build Lustre
	ssh "$COV_SSH" "$COV_HOST" <<EOF
# Grab repo
rm -rf ~/lustre-release
git clone git://git.whamcloud.com/fs/lustre-release.git

# Build
cd ~/lustre-release
git checkout origin/master-next
./autogen.sh
./configure
make -s -j\$(nproc)

# Report
echo "KERNEL MODULES BUILT:"
find . -name *.ko
EOF
}

#
# Run coverity scan. 'setup' and 'build' must have been
# run beforehand. Automatically copies the tar file that
# should be uploaded to Coverity along with the Lustre
# version.
#
# The build is run sequentially, due to limitations with
# cov-build.
#
function cr_run() {
	# Copy build tool to VM
	scp "$COV_SSH" "$COV_PATH" "$COV_HOST":~

	# Run scan
	ssh "$COV_SSH" "$COV_HOST" <<EOF
# Get coverity tool
cd ~
tar xf *.tar.gz

# Clean and run
cd ~/lustre-release
make clean
"\$(find ~ -name cov-build)" --dir cov-int make
tar czvf "lustre-coverity-\$(date +"%m-%d-%Y").tgz" cov-int

# Report
echo "KERNEL MODULES BUILT:"
find . -name *.ko
echo "LUSTRE VERSION:"
cat LUSTRE-VERSION-FILE
EOF

	# Grab scan results
	scp "$COV_SSH" "$COV_HOST":~/lustre-release/*.tgz .
}

#
# Destroy Vagrant VM.
#
function cr_clean() {
	if [[ "$COV_SSH" =~ "vagrant" ]]; then
		vagrant destroy
		rm -f vagrant-ssh.config
	fi
}

#
# Run all steps in the correct order.
#
function cr_all() {
	cr_setup
	cr_install
	cr_build
	cr_run
	cr_clean
}

# Run as root or with sudo
if [[ "$EUID" -ne 0 ]]; then
	echo "Please run as root or with sudo."
	exit
fi

# Check if COV_PATH is defined
if [[ -z ${COV_PATH+x} ]]; then
	echo "Provide the path to the Coverity tool tarball using COV_PATH."
	exit
fi

# Check if COV_SSH is defined
if [[ -z ${COV_SSH+x} || -z ${COV_HOST+x} ]]; then
	export COV_SSH="-F vagrant-ssh.config"
	export COV_HOST="default"
	echo "Defaulting to Vagrant."

	# Check if vagrant is actually installed
	if ! command -v vagrant 2>&1 >/dev/null; then
		echo "Vagrant could not be found."
		exit 1
	fi
fi

# Process options
for arg in "$@"; do
	shift
	case "$arg" in
		setup) cr_setup;;
		install) cr_install;;
		build) cr_build;;
		run) cr_run;;
		clean) cr_clean;;
		all) cr_all;;
		list) cr_list;;
		*) cr_list;;
	esac
done
