#!/bin/bash
#
# This script builds a precompiled version of sysdig-probe for a bunch of kernels
# The precompiled binary is then obtained at runtime by sysdig-probe-loader
# Ideally, the community should expand this stuff with better support
#
set -euo pipefail

#
# For continuous integration log purposes, wget prints its own output to stderr
# so it can be convenient to redirect it to a file. This can be done directly
# at runtime.
#

PROBE_NAME=$1
PROBE_VERSION=$2
REPOSITORY_NAME=$3
BASEDIR=$(pwd)
ARCH=$(uname -m)

if [ ! -d $BASEDIR/output ]; then
	mkdir $BASEDIR/output
fi

function build_probe {
	if [ "$PROBE_NAME" = "sysdig-probe" ]; then
		build_sysdig
	elif [ "$PROBE_NAME" = "sysdigcloud-probe" ]; then
		build_sysdigcloud
	else
		exit 1
	fi
}

function build_sysdig {

	if [ ! -f $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko ] || [ ! -f $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH_ORIG.ko ]; then

		echo Building $PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko [${FUNCNAME[1]}]

		if [ ! -d sysdig ]; then
			git clone git@github.com:draios/sysdig.git
		fi

		cd sysdig
		git checkout master
		git pull
		git checkout $PROBE_VERSION
		make -C driver clean || true
		rm -rf build || true
		mkdir build
		cd build
		cmake -DCMAKE_BUILD_TYPE=Release -DSYSDIG_VERSION=$PROBE_VERSION ..
		make configure_driver
		make driver
		strip -g driver/$PROBE_NAME.ko

		KO_VERSION=$(/sbin/modinfo driver/$PROBE_NAME.ko | grep vermagic | tr -s " " | cut -d " " -f 2)
		if [ "$KO_VERSION" != "$KERNEL_RELEASE" ]; then
			echo "Corrupted probe, KO_VERSION " $KO_VERSION ", KERNEL_RELEASE " $KERNEL_RELEASE
			exit 1
		fi

		cp driver/$PROBE_NAME.ko $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko
		cp driver/$PROBE_NAME.ko $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH_ORIG.ko
	else
		echo Skipping $PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko \(already built\)
	fi

	cd $BASEDIR
}

function build_sysdigcloud {

	if [ ! -f $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko ] || [ ! -f $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH_ORIG.ko ]; then

		echo Building $PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko [${FUNCNAME[1]}]

		if [ ! -d sysdig ]; then
			git clone git@github.com:draios/sysdig.git
		fi

		if [ ! -d agent ]; then
			git clone git@github.com:draios/agent.git
		fi

		cd sysdig
		git checkout master
		git pull
		git checkout agent/$PROBE_VERSION
		make -C driver clean || true
		rm -rf build || true
		cd ..
		cd agent
		git checkout master
		git pull
		git checkout $PROBE_VERSION
		rm -rf build || true
		mkdir build
		cd build
		cmake -DCMAKE_BUILD_TYPE=Release -DAGENT_VERSION=$PROBE_VERSION ..
		make configure_driver
		make driver
		strip -g driver/$PROBE_NAME.ko

		KO_VERSION=$(/sbin/modinfo driver/$PROBE_NAME.ko | grep vermagic | tr -s " " | cut -d " " -f 2)
		if [ "$KO_VERSION" != "$KERNEL_RELEASE" ]; then
			echo "Corrupted probe, KO_VERSION " $KO_VERSION ", KERNEL_RELEASE " $KERNEL_RELEASE
			exit 1
		fi

		cp driver/$PROBE_NAME.ko $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko
		cp driver/$PROBE_NAME.ko $BASEDIR/output/$PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH_ORIG.ko
	else
		echo Skipping $PROBE_NAME-$PROBE_VERSION-$ARCH-$KERNEL_RELEASE-$HASH.ko \(already built\)
	fi

	cd $BASEDIR
}

function coreos_build {
	VERSION_URL=$1
	VERSION_NUMBER=$(echo $VERSION_URL | grep -o '[0-9][0-9][0-9]\.[0-9]\.[0-9]')
	COREOS_DIR="coreos-"$VERSION_NUMBER

	if [ ! -d $COREOS_DIR ]; then
		mkdir $COREOS_DIR
	fi

	cd $COREOS_DIR

	if [ ! -f config_orig ]; then
		wget ${VERSION_URL}coreos_developer_container.bin.bz2
		bunzip2 coreos_developer_container.bin.bz2
		sudo kpartx -asv coreos_developer_container.bin
		LOOPDEV=$(sudo kpartx -asv coreos_developer_container.bin | cut -d\  -f 3)
		sudo mkdir /tmp/loop || true
		sudo mount /dev/mapper/$LOOPDEV /tmp/loop
		cp /tmp/loop/usr/boot/config-* .
		sudo umount /tmp/loop
		sudo kpartx -dv coreos_developer_container.bin
		rm -rf coreos_developer_container.bin
		cp config-* config_orig
	fi

	KERNEL_RELEASE=$(ls config-* | sed s/config-//)
	VANILLA=$(echo $KERNEL_RELEASE | sed s/[-+].*// | sed s/\.0$//)
	MAJOR=$(echo $KERNEL_RELEASE | head -c1)
	EXTRAVERSION=$(echo $KERNEL_RELEASE | sed s/[^-+]*//)
	TGZ_NAME=linux-${VANILLA}.tar.xz
	DIR_NAME=linux-${VANILLA}
	KERNEL_URL=https://www.kernel.org/pub/linux/kernel/v${MAJOR}.x/$TGZ_NAME
	
	if [ ! -f $TGZ_NAME ]; then
		wget $KERNEL_URL
	fi

	if [ ! -d $DIR_NAME ]; then
		tar xf $TGZ_NAME
		cd $DIR_NAME
		make distclean
		sed -i "s/^EXTRAVERSION.*/EXTRAVERSION = $EXTRAVERSION/" Makefile
		cp ../config_orig .config
		make modules_prepare
		mv .config ../config
		cd ..
	fi

	HASH=$(md5sum config | cut -d' ' -f1)
	HASH_ORIG=$(md5sum config_orig | cut -d' ' -f1)

	cd $BASEDIR

	export KERNELDIR=$BASEDIR/$COREOS_DIR/$DIR_NAME
	build_probe
}

function boot2docker_build {
	CONFIGURATION_NAME=$1
	KERNEL_RELEASE=$2
	KERNEL_URL=$3
	KERNEL_CONFIG=$4
	AUFS_REPO=$5
	AUFS_BRANCH=$6
	AUFS_COMMIT=$7
	TGZ_NAME=$(echo $KERNEL_URL | awk -F"/" '{print $NF }')
	DIR_NAME=$(echo $TGZ_NAME | sed 's/.tar.xz//')

	if [ ! -d $CONFIGURATION_NAME ]; then
		mkdir $CONFIGURATION_NAME
	fi

	cd $CONFIGURATION_NAME

	if [ ! -f $TGZ_NAME ]; then
		echo Downloading $TGZ_NAME [Boot2Docker]
		wget $KERNEL_URL
	fi

	if [ ! -d $DIR_NAME ]; then
		tar xf $TGZ_NAME
		cd $DIR_NAME
		make distclean
		git clone -b "$AUFS_BRANCH" "$AUFS_REPO" aufs-standalone
		cd aufs-standalone 
		git checkout -q "$AUFS_COMMIT"
		cd ..
		cp -r aufs-standalone/Documentation . 
		cp -r aufs-standalone/fs .
		cp -r aufs-standalone/include/uapi/linux/aufs_type.h include/uapi/linux/
		set -e && for patch in \
			aufs-standalone/aufs*-kbuild.patch \
			aufs-standalone/aufs*-base.patch \
			aufs-standalone/aufs*-mmap.patch \
			aufs-standalone/aufs*-standalone.patch \
			aufs-standalone/aufs*-loopback.patch \
		; do \
	        patch -p1 < "$patch"; \
		done
		wget -O .config $KERNEL_CONFIG
		cp .config ../config-orig
		make olddefconfig
		make modules_prepare
		mv .config ../config
		cd ..
	fi

	HASH=$(md5sum config | cut -d' ' -f1)
	HASH_ORIG=$(md5sum config-orig | cut -d' ' -f1)

	cd $BASEDIR

	export KERNELDIR=$BASEDIR/$CONFIGURATION_NAME/$DIR_NAME
	build_probe
}

function ubuntu_build {

	URL=$1
	DEB=$(echo $URL | grep -o '[^/]*$')
	KERNEL_RELEASE_FULL=$(echo $DEB | grep -E -o "[0-9]{1}\.[0-9]+\.[0-9]+-[0-9]+\.[0-9]+")		# ex. 3.13.0-24.47
	KERNEL_RELEASE=$(echo $KERNEL_RELEASE_FULL | grep -E -o "[0-9]{1}\.[0-9]+\.[0-9]+-[0-9]+")	# ex. 3.13.0-24
	KERNEL_UPDATE=$(echo $KERNEL_RELEASE_FULL | grep -E -o "[0-9]+$")							# ex. 47

	if [ ! -d $KERNEL_RELEASE ]; then
		mkdir $KERNEL_RELEASE
	fi

	cd $KERNEL_RELEASE

	if [ ! -d $KERNEL_UPDATE ]; then
		mkdir $KERNEL_UPDATE
	fi

	cd $KERNEL_UPDATE

	if [ ! -f $DEB ]; then
		echo Downloading $DEB [Ubuntu]
		wget $URL
		dpkg -x $DEB ./
	fi

	NUM_DEB=$(ls linux-*.deb -1 | wc -l)

	if [ $NUM_DEB -eq 3 ]; then

		local KERNEL_FOLDER=$KERNEL_RELEASE
		KERNEL_RELEASE=$(ls -1 linux-image-* | grep -E -o "[0-9]{1}\.[0-9]+\.[0-9]+-[0-9]+-[a-z]+")

		HASH=$(md5sum boot/config-$KERNEL_RELEASE | cut -d' ' -f1)
		HASH_ORIG=$HASH

		cd $BASEDIR
		
		export KERNELDIR=$BASEDIR/$KERNEL_FOLDER/$KERNEL_UPDATE/usr/src/linux-headers-$KERNEL_RELEASE
		build_probe
	fi

	cd $BASEDIR
}

function rhel_build {

	#
	# The function just requires the rpm url
	#

	# Get all the parameters needed
	URL=$1
	RPM=$(echo $URL | grep -o '[^/]*$')
	KERNEL_RELEASE=$(echo $RPM | awk 'match($0, /[^kernel\-(core\-|devel\-)?].*[^(\.rpm)]/){ print substr($0, RSTART, RLENGTH) }')

	if [ ! -d $KERNEL_RELEASE ]; then
		mkdir $KERNEL_RELEASE
	fi

	cd $KERNEL_RELEASE

	if [ ! -f $RPM ]; then
		echo Downloading $RPM [RHEL and CentOS]
		wget $URL
		rpm2cpio $RPM | cpio -idm
	fi

	NUM_RPM=$(ls kernel-*.rpm -1 | wc -l)

	if [ $NUM_RPM -eq 2 ]; then

		#echo Building $KERNEL_RELEASE

		HASH=$(md5sum boot/config-$KERNEL_RELEASE | cut -d' ' -f1)
		HASH_ORIG=$HASH

		cd $BASEDIR

		export KERNELDIR=$BASEDIR/$KERNEL_RELEASE/usr/src/kernels/$KERNEL_RELEASE
		build_probe
	fi

	cd $BASEDIR
}

#
# Ubuntu build
#

echo Building Ubuntu
DIR=$(dirname $(readlink -f $0))
URLS="$($DIR/kernel-crawler.py Ubuntu)"

for URL in $URLS
do
	ubuntu_build $URL
done

#
# RHEL build
#

echo Building RHEL
DIR=$(dirname $(readlink -f $0))
URLS="$($DIR/kernel-crawler.py CentOS)"

for URL in $URLS
do
	rhel_build $URL
done

#
# Fedora build
#

echo Building Fedora
DIR=$(dirname $(readlink -f $0))
URLS="$($DIR/kernel-crawler.py Fedora)"

for URL in $URLS
do
	rhel_build $URL
done

#
# CoreOS build
#
echo Building CoreOS
DIR=$(dirname $(readlink -f $0))
URLS="$($DIR/kernel-crawler.py CoreOS)"

for URL in $URLS
do
	coreos_build $URL
done

#
# boot2docker build
#
echo Building boot2docker

# tracepoints only enabled >= 1.7.0
boot2docker_build boot2docker-1.7.0 4.0.5-boot2docker https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.5.tar.xz https://raw.githubusercontent.com/boot2docker/boot2docker/v1.7.0/kernel_config https://github.com/sfjro/aufs4-standalone aufs4.0 a8c8a849e236d7f7fa121c8344899a796ccf7b8f
boot2docker_build boot2docker-1.7.1 4.0.7-boot2docker https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.7.tar.xz https://raw.githubusercontent.com/boot2docker/boot2docker/v1.7.1/kernel_config https://github.com/sfjro/aufs4-standalone aufs4.0 e274de9419a0c135179244e45f3991fe5dc70b03
boot2docker_build boot2docker-1.8.0 4.0.9-boot2docker https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.9.tar.xz https://raw.githubusercontent.com/boot2docker/boot2docker/v1.8.0/kernel_config https://github.com/sfjro/aufs4-standalone aufs4.0 e274de9419a0c135179244e45f3991fe5dc70b03
boot2docker_build boot2docker-1.8.1 4.0.9-boot2docker https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.9.tar.xz https://raw.githubusercontent.com/boot2docker/boot2docker/v1.8.1/kernel_config https://github.com/sfjro/aufs4-standalone aufs4.0 e274de9419a0c135179244e45f3991fe5dc70b03

#
# Upload modules
#
aws s3 sync ./output/ s3://download.draios.com/$REPOSITORY_NAME/sysdig-probe-binaries/ --acl public-read

echo "Success."
