#!/bin/bash
#
# Copyright (c) 2016-2024 AstroArch Consulting, Inc. All rights reserved
#
# Create a Base Install to use Ansible for further installs
#
# Target: CentOS/RHEL/Rocky/Fedora/Debian/Ubuntu/MacOS/Alpine
#
###
VERSIONID="2.3.0"

#####
cRun=$0
function version() {
	echo "$0 version is $VERSIONID"
	for x in `ls ${prog}.*`
	do
		. ./$x
		y=`echo $x | awk -F\. '{print $4}'`
		echo -n "	"
		echo -n "$y version "
		eval ${y}_version
	done
}

function colorecho() {
	COLOR=$PURPLE
	if [ Z"$2" = Z"1" ]
	then
		COLOR=$RED
	fi
	echo "${COLOR}${1}${NC}"
}

function checkForUpdate()
{
    oVer=`echo $VERSIONID | sed 's/\.//g'`
    wget -O /tmp/aac-base.install.new https://raw.githubusercontent.com/Texiwill/aac-lib/master/base/aac-base.install >& /dev/null
    nVer=`grep VERSIONID /tmp/aac-base.install.new | head -1 | sed 's/\.//g'| sed 's/VERSIONID=//'|sed 's/\"//g'`
    if [ $nVer -gt $oVer ]
    then
	colorecho "Upgrading $cRun"
	cp /tmp/aac-base.install.new $cRun
	# now do the update of ansible
	$cRun -u 
	colorecho "Restart $cRun"
	exit
    fi
}


function findos() {
	if [ -e /etc/os-release ]
	then
		. /etc/os-release
		theos=`echo $ID | tr [:upper:] [:lower:]`
		if [ Z"$theos" = Z"linuxmint" ]
        	then
            		theos=`echo $ID_LIKE | tr [:upper:] [:lower:]`
        	fi
		VERSION_ID=`echo $VERSION_ID | awk -F. '{print $1}'`
	elif [ -e /etc/centos-release ]
	then
		theos=`cut -d' ' -f1 < /etc/centos-release | tr [:upper:] [:lower:]`
		VERSION_ID=`awk '{print $3}' /etc/centos-release | awk -F. '{print $1}'`
	elif [ -e /etc/redhat-release ]
	then
		theos=`cut -d' ' -f1 < /etc/redhat-release | tr [:upper:] [:lower:]`
		VERSION_ID=`awk '{print $3}' /etc/redhat-release | awk -F. '{print $1}'`
	elif [ -e /etc/fedora-release ]
	then
		theos=`cut -d' ' -f1 < /etc/fedora-release | tr [:upper:] [:lower:]`
		VERSION_ID=`awk '{print $3}' /etc/fedora-release | awk -F. '{print $1}'`
	elif [ -e /etc/debian-release ]
	then
		theos=`cut -d' ' -f1 < /etc/debian-release | tr [:upper:] [:lower:]`
		VERSION_ID=`awk '{print $3}' /etc/debian-release | awk -F. '{print $1}'`
	else
		# Mac OS
		uname -a | grep Darwin  >& /dev/null
		if [ $? -eq 0 ]
		then
			theos="macos"
			VERSION_ID=`sw_vers | grep ProductVersion | cut -d'	' -f2`
		else
			colorecho "Do not know this operating system. LinuxVSM may not work." 1
			theos="unknown"
		fi
	fi
	export VERSION_ID
}

function checkdep() {
	dep=$1
	needdep=0
	if [ Z"$theos" = Z"centos" ] || [ Z"$theos" = Z"redhat" ] || [ Z"$theos" = Z"fedora" ] || [ Z"$theos" = Z"photon" ] || [ Z"$theos" = Z"rocky" ] || [ Z"$theos" = Z"almalinux" ]
	then
		rpm -q $dep >& /dev/null
		if [ $? -ne 0 ]
		then
			echo "Missing Dependency $dep"
			needdep=1
		fi
	elif [ Z"$theos" = Z"debian" ] || [ Z"$theos" = Z"ubuntu" ]
	then
		if [ Z"$dep" != Z"epel-release" ]
		then
			# to remove dep use 'apt-get purge $dep' so dpkg works
			#dpkg -s $dep >& /dev/null
			dpkg-query -W -f='${Status} ${Version}\n' $dep |grep -i '^install' >& /dev/null
			if [ $? -ne 0 ]
			then
				echo "Missing Dependency $dep"
				needdep=1
			fi
		fi
	elif [ Z"$theos" = Z"macos" ]
	then
		which $dep >& /dev/null
		if [ $? -ne 0 ]
		then
			echo "Missing Dependency $dep"
			needdep=1
		fi
	elif [ Z"$theos" = Z"alpine" ]
	then
		apk -e info $dep >& /dev/null
		if [ $? -ne 0 ]
		then
			echo "Missing Dependency $dep"
			needdep=1
		fi
	elif [ Z"$theos" = Z"unknown" ]
	then
		echo "Cannot Check Dependenty $dep"
	fi
}

function installdep() {
	installopts=""
	if [ Z"$1" != Z"" ]
	then
		installopts=$1
	fi
	if [ Z"$theos" = Z"centos" ] || [ Z"$theos" = Z"redhat" ] || [ Z"$theos" = Z"fedora" ] || [ Z"$theos" = Z"photon" ] || [ Z"$theos" = Z"rocky" ] || [ Z"$theos" = Z"almalinux" ]
	then
		if [ Z"$INSTALL" != Z"" ] || [ Z"$DEVEL" != Z"" ]
		then
			if [ $VERSION_ID -lt 8 ] && [ Z"$theos" != Z"photon" ]
			then
				sudo yum -y $installopts install $INSTALL $DEVEL
			else
				sudo dnf -y $installops install $INSTALL $DEVEL
			fi
		fi
		changes=1	
	elif [ Z"$theos" = Z"debian" ] || [ Z"$theos" = Z"ubuntu" ]
	then
		if [ Z"$DINSTALL" != Z"" ] || [ Z"$DDEVEL" != Z"" ]
		then
			which apt-get >& /dev/null
			if [ $? -eq 0 ]
			then
				sudo apt-get install -y $installopts $DINSTALL $DDEVEL
			else
				sudo apt install -y $installopts $DINSTALL $DDEVEL
			fi
			changes=1
		fi
	elif [ Z"$theos" = Z"alpine" ]
	then
		if [ Z"$DINSTALL" != Z"" ] || [ Z"$DDEVEL" != Z"" ]
		then
			sudo apk add $DINSTALL $DDEVEL
		fi
	fi
}

# Dependent on openssl which is installed with Ansible
credfile=.credstore
credname="My VMware"
cdir="/tmp/vsm.$USER"
if [ -e ~/.vsmrc ]; then . ~/.vsmrc; fi
function handlecredstore ()
{
	if [ ! -e $cdir/$credfile ]
	then
		if [ ! -d $cdir ]
		then
			mkdir $cdir
		fi
		if [ ! -d $HOME/.vsm ]
		then
			mkdir $HOME/.vsm
		fi
		chmod 700 $HOME/.vsm

		pbkdf2=''
		openssl enc --help 2>&1 | grep pbkdf2 >& /dev/null
		if [ $? -eq 0 ]
		then
			pbkdf2='-pbkdf2 -iter 1000'
		fi
		if [ ! -e $HOME/.vsm/.key ]
		then
        		openssl rand -base64 64 | tr '\n' ':' > $HOME/.vsm/.key
		fi
		k=`cat $HOME/.vsm/.key`
		if [ Z"$username" = Z"" ]
		then
			echo -n "Enter $credname Username: "
			read username
		fi
		if [ Z"$password" = Z"" ]
		then
			echo -n "Enter $credname Password: "
			read -s password
			echo ""
		fi
		auth=`echo -n "${username}:${password}" |base64`
		# handle storing 'Basic Auth' for reuse
        	echo -n $auth | openssl enc $pbkdf2 -aes-256-cbc -k $k -a -salt -base64 > $cdir/$credfile
		chmod 600 $cdir/$credfile
	fi
}

function call_playbook() {
	us=`id -un`
	if [ Z"$us" = Z"root" ]
	then
		# no need if already root or local installs only
		askpass=""
	fi
	extraargs="$adebug"
	# special case to import passwords, could be more secure
	if [ Z"$choice" = Z"librenms" ]
	then
		# Get mariadb/librenms passwords
		echo -n "Enter mariadb root Password: "
		read -s mariadb_pwd
		echo ""
		echo -n "Enter librenms Password: "
		read -s librenms_pwd
		echo ""
		extraargs="$adebug aac_base_tz=$TZ mariadb_pwd=$mariadb_pwd librenms_pwd=$librenms_pwd"
		askpass="-K"
	elif [ Z"$choice" = Z"mariadb" ]
	then
		# Get mariadb/librenms passwords
		echo -n "Enter mariadb root Password: "
		read -s mariadb_pwd
		echo ""
		extraargs="$adebug aac_base_tz=$TZ mariadb_pwd=$mariadb_pwd"
		askpass="-K"
	elif [ Z"$choice" = Z"smtp" ]
	then
		# Get mariadb/librenms passwords
		echo -n "Enter mariadb root Password: "
		read -s mariadb_pwd
		echo ""
		echo -n "Enter Postfix SQL Password: "
		read -s postfixsql_pwd
		echo ""
		echo -n "Enter Postfix setup Password: "
		read -s postfixadmin_pwd
		echo ""
		extraargs="$adebug aac_base_tz=$TZ mariadb_pwd=$mariadb_pwd postfixadmin_pwd=$postfixadmin_pwd postfixsql_pwd=$postfixsql_pwd"
		askpass="-K"
	elif [ Z"$choice" = Z"pihole" ]
	then
		echo -n "Enter pihole Password: "
		read -s pihole_pwd
		echo ""
		extraargs="$adebug aac_base_tz=$TZ pihole_pwd=$pihole_pwd"
		askpass="-K"
	else
		if [ Z"TZ" != Z"" ]
		then
			extraargs="$adebug aac_base_tz=$TZ"
		fi
	fi
	if [ Z"$choice" = Z"vsm" ]
	then
		choice="LinuxVSM"
	fi
	if [ Z"$choice" = Z"vma" ]
	then
		choice="LinuxVMA"
	fi
	if [ Z"$choice" != Z"" ]
	then
		#fixcompress=0
		# for these we need to handle an existing .vsmrc file 
		# compress=1 could mess up our approach
		#grep "compress=1" $HOME/.vsmrc >& /dev/null
		#if [ $? -eq 0 ]
		#then
		#	# change the compress line to be compress=0
		#	fixcompress=1
		#	cp $HOME/.vsmrc $HOME/.vsmrc.orig
		#	sed 's/compress=1/compress=0/' $HOME/.vsmrc > $HOME/.vsmrc.base
		#	mv $HOME/.vsmrc.base $HOME/.vsmrc
		#fi
		if [ Z"$choice" = Z"vCLI" ] || [ Z"$choice" = Z"ovftool" ] || [ Z"$choice" = Z"LinuxVMA" ]
		then
			# create the LinuxVSM credstore since we use it
			# within the playbook
			handlecredstore
		fi
		if [ Z"$extraargs" != Z"" ]
		then
			ansible-playbook $askpass $vansible --extra-vars="$extraargs" ansible/${choice}.yaml
		else
			ansible-playbook $askpass $vansible ansible/${choice}.yaml
		fi
		#if [ $fixcompress -eq 1 ]
		#then
		#	mv $HOME/.vsmrc.orig $HOME/.vsmrc
		#fi
	fi
}

function menu() {
	all_done=0;
	a=''
	top_pd=`pwd`
	if [ $ansible -eq 1 ]
	then
		if [ -d ansible ]
		then
			a=`find ansible -type f -name '*.yaml' -exec basename {} \; | grep -v aac-base | sed 's/.yaml//g' 2>/dev/null`
		fi
	else
		cd scripts
		a=`ls ${prog}.* 2>/dev/null`
		cd ..
	fi
	if [ Z"$a" = Z"" ]
	then
		all_done=1
	fi
	while [ $all_done != 1 ]
	do
		select choice in $a Exit
		do
			if [ $choice = "Exit" ]
			then
				all_done=1
			else
				echo "Running $choice"
				if [ $ansible -eq 1 ]
				then
					call_playbook
				else
					cd scripts
					installer=`echo $choice | awk -F\. '{print $4}'`
					menu_pd=`pwd`
					. $choice
					$installer
					changes=1
					cd ..
				fi
			fi
			break
		done
	done
	cd $top_pd
}

function startsrv() {
	if [ $VERSION_ID -gt 6 ]
	then
		systemctl enable $1 >& /dev/null
		systemctl restart $1
	else
		service $1 restart
		chkconfig $1 on
	fi
}

function stopsrv() {
	if [ $VERSION_ID -gt 6 ]
	then
		systemctl stop $1 >& /dev/null
		systemctl disable $1 >& /dev/null
	else
		service $1 stop
		chkconfig $1 off
	fi
}

function get_wget() {
	echo "Get wget"
	checkdep wget
	if [ $needdep -eq 1 ]
	then
		if [ Z"$theos" != Z"macos" ]
		then
			echo "Updating Repos"
			if [ -e /usr/bin/yum ]
			then
				yum -q clean all >& /dev/null
				yum -q makecache fast >& /dev/null
			elif [ -e /usr/bin/apt-get ]
			then
				apt-get update
			fi
			echo "Install/update wget"
			INSTALL=wget
			DINSTALL=$INSTALL
			installdep
		else
			checkdep brew
			if [ $needdep -eq 1 ]
			then
				/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
			fi
			brew install wget
		fi
	fi
	# fix for long running playbook issues
	askpass="-K"
}

function tz() {
	echo "Checking Timezone settings"
	checkdep ntp
	if [ $needdep -eq 1 ]
	then
		echo "Install/update ntp"
		INSTALL=ntp
		DINSTALL=$INSTALL
		installdep
	fi
	settz=0
	ls -al /etc/localtime |grep "$TZ" > /dev/null
	if [ $? != 0 ]
	then
		echo "Setting up TZ"
		settz=1
	fi
	if [ $VERSION_ID -gt 6 ]
	then
		if [ $settz -eq 1 ]
		then
			timedatectl set-timezone $TZ
		fi
	else
		if [ $settz -eq 1 ]
		then
			(cd /etc; rm localtime; ln -s /usr/share/zoneinfo/$TZ localtime)
		fi
	fi
	startsrv ntpd
}

function epel() {
	checkdep epel-release
	if [ Z"$theos" = Z"centos" ] || [ Z"$theos" = Z"redhat" ]
	then
		echo "Checking for EPEL repository"
		if [ $needdep -eq 1 ]
		then
			echo "Installing EPEL repository"
			wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-${VERSION_ID}.noarch.rpm
			sudo rpm -ivh epel-release-latest-${VERSION_ID}.noarch.rpm
			askpass=""
		else
			askpass="-K"
		fi
	elif [ Z"$theos" = Z"rocky" ] || [ Z"$theos" = Z"almalinux" ]
	then
		if [ $needdep -eq 1 ]
		then
			INSTALL=epel-release
			DINSTALL=$INSTALL
			installdep
		fi
		askpass="-K"
	else
		askpass="-K"
	fi
}

function ansible() {
	echo "Checking for Ansible"
	if [ Z"$theos" = Z"almalinux" ] || [ Z"$theos" = Z"rocky" ]
	then
		checkdep ansible-core
		checkdep ansible-collection-community-general
	elif [ Z"$theos" = Z"macos" ]
        then
		checkdep ansible-playbook
        else
		checkdep ansible
	fi
	if [ $needdep -eq 1 ]
	then
		if [ Z"$theos" != Z"macos" ]
		then
			if [ Z"$theos" = Z"debian" ] || [ Z"$theos" = Z"ubuntu" ]
			then
				sudo apt-get update
				# needed for WSL and some other things
				if [ $VERSION_ID -lt 20 ]
				then
					sudo apt install dirmngr
					cp /etc/apt/sources.list /tmp/sources.list
					cp /etc/apt/sources.list /tmp/sources.list.orig
					echo "deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main" >> /tmp/sources.list
					sudo cp /tmp/sources.list /etc/apt
					wget -O - "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x93C4A3FD7BB9C367" | sudo apt-key add
					sudo apt update
				fi
			fi
			echo "Installing Ansible"
			INSTALL="ansible"
			DINSTALL="ansible pip"
			if [ Z"$theos" = Z"almalinux" ] || [ Z"$theos" = Z"rocky" ]
			then
				INSTALL="ansible-core"
				DINSTALL="ansible-core pip"
			fi
			installdep
			askpass=""
			if [ Z"$theos" = Z"almalinux" ] || [ Z"$theos" = Z"rocky" ]
			then
				INSTALL="ansible-collection-community-general"
				DINSTALL=$INSTALL
				installdep
				INSTALL="ansible-collection-ansible-posix"
				DINSTALL=$INSTALL
				installdep
				INSTALL="ansible-collection-community-crypto"
				DINSTALL=$INSTALL
				installdep
				INSTALL="ansible-collection-community-mysql"
				DINSTALL=$INSTALL
				installdep
			fi
			if [ Z"$theos" = Z"debian" ]
			then
				pip install markupsafe=2.0.1
			fi
			if [ Z"$theos" = Z"debian" ] || [ Z"$theos" = Z"ubuntu" ]
			then
				sudo cp /tmp/sources.list.orig /etc/apt/sources.list
				rm /tmp/sources.list*
				sudo apt-key del 93C4A3FD7BB9C367
				sudo apt update
			fi
		else
			# MacOS
			#brew install python3
			python3 -m pip install --user --upgrade setuptools
			python3 -m pip install --user --upgrade pip
			python3 -m pip install --user --upgrade ansible
		fi
	else
		askpass="-K"
	fi
	askpass="-K"
}

function selinux() {
	#
	# only install if needed
	echo "Checking for SELinux Policy RPMS"
	if [ Z"$theos" = Z"centos" ] || [ Z"$theos" = Z"redhat" ] || [ Z"$theos" = Z"fedora" ]
	then
		checkdep policycoreutils-python
		if [ $needdep -eq 1 ]
		then
			echo "Installing SELinux Policy RPMS"
			INSTALL="policycoreutils-python setroubleshoot-server"
			DINSTALL=$INSTALL
		fi
	elif [ Z"$theos" = Z"debian" ] || [ Z"$theos" = Z"ubuntu" ]
	then
		checkdep policycoreutils
		if [ $needdep -eq 1 ]
		then
			INSTALL="policycoreutils selinux-utils"
			DINSTALL=$INSTALL
		fi
	fi
	installdep
	echo "If SELinux issues pop up use the following to debug:"
	echo "	sealert -a /var/log/audit/audit.log"
}

function fixselinux() {
	echo "Reset SELinux for dev after installs"
	restorecon -R -v /dev >& /dev/null
}

function usage() {
	# echo "Usage: $prog [--install|-i installer] [--createrepo|-c] [--help|-h] [timezone]"
	echo "Usage: $prog [--install|-i installer] [--update|-u] [-V|--version] [--help|-h][-v|--verbose][--noansible|-n] [--user USER] [--home HOME] [timezone]"
	echo "	-u|--update => Update"
	echo "	-i|--install => Install"
	echo "	-V|--version => version"
	echo "	-v|--verbose => verbose Ansible"
	echo "	-d|--debug => debug Ansible"
	echo "	-n|--noansible => No Ansible, older shell script approach"
	echo "	Last Argument is used to set the timezone"
	echo "	Default timezone $TZ"
	echo "	Available installers are:"
	a=""
        if [ $ansible -eq 1 ]
	then
		a=`find ansible -type f -name '*.yaml' -exec basename {} \; | grep -v aac-base | sed 's/.yaml//g' 2>/dev/null`
	else
		cd scripts
		a=`ls ${prog}.*`
		cd ..
	fi
	for x in $a
	do
		echo -n "		"
		if [ $ansible -eq 1 ]
		then
			echo $x
		else
			echo $x | awk -F\. '{print $4}'
		fi
	done
	exit
}

changes=0
theos=""
needdep=0
findos
myhome=$HOME
myuser=$USER
update=0
prog=$0
installer=""
ansible=1
vansible=""
askpass=""
adebug=""
INSTALL=""
DINSTALL=""
DDEVEL=""
DEVEL=""
TZ='America/Chicago'
# onscreen colors
RED=`tput setaf 1`
PURPLE=`tput setaf 5`
NC=`tput sgr0`
BOLD=`tput smso`
NB=`tput rmso`
TEAL=`tput setaf 6`

while [[ $# -gt 0 ]]
do
	key="$1"
	case "$key" in 
		-i|--install)
			installer=$2
			shift
			;;
		--home)
			myhome=$2
			shift
			;;
		--user)
			myuser=$2
			shift
			;;
		-u|--update)
			update=1
			;;
		-d|--debug)
			adebug="aac_base_debug=1"
			;;
		--version|-V)
			version
			exit
			;;
		--verbose|-v)
			vansible="-vvv"
			;;
		--noansible|-n)
			ansible=0
			;;
		--help|-h) 
			usage
			;;
		*) 
			fgrep "$1" /usr/share/zoneinfo/zone.tab >& /dev/null
			if [ $? -eq 0 ]
			then
				TZ=$1
			else
				echo "Bad Time Zone Specified"
				exit
			fi
			;;
	esac
	shift
done

# MacOS Specific paths
if [ Z"$theos" = Z"macos" ]
then
	if [ -e $HOME/.bash_profile ]
	then
		. $HOME/.bash_profile
	else
		machine=`uname -m`
		if [ Z"$machine" = Z"arm64" ]
		then
			PATH=$PATH:/opt/homebrew/bin:/Users/haletky/Library/Python/3.9/bin
		else
			PATH=$PATH:/Users/haletky/Library/Python/3.9/bin
		fi
		export PATH
	fi
fi
get_wget
checkForUpdate

###
# Update aac-base bits
###
if [ $update -eq 1 ]
then
#	files=`wget -O - https://github.com/Texiwill/aac-lib/tree/master/base |grep aac-base.install | grep span | awk -F\> '{print $3}' |sed 's#</a##g'`
#	for x in $files
#	do
#		wget -O $x https://raw.githubusercontent.com/Texiwill/aac-lib/master/base/$x
#	done
	if [ $ansible -eq 1 ]
	then
		files=`wget -O - https://github.com/Texiwill/aac-lib/tree/master/base/ansible |sed 's/}/}\n/g' |awk -F\" '{print $4}'|grep yaml`
		if [ ! -e ansible ]; then mkdir ansible; fi
		cd ansible
		for x in $files
		do
			wget -O $x https://raw.githubusercontent.com/Texiwill/aac-lib/master/base/ansible/$x
		done
		cd ..
	else
		files=`wget -O - https://github.com/Texiwill/aac-lib/blob/master/base/scripts |grep aac-base.install | grep span | awk -F\> '{print $3}' |sed 's#</a##g'`
		for x in $files
		do
			wget -O $x https://raw.githubusercontent.com/Texiwill/aac-lib/master/base/scripts/$x
		done
	fi
	echo "Update Done - Exiting"
	exit
fi

###
# Get the RHEL/CentOS Version
###
#DNAME=`hostname -d`
RPMLIST=''
if [ $ansible -ne 1 ]
then
	echo "Getting RPMLIST"
	if [ Z"$theos" = Z"centos" ] || [ Z"$theos" = Z"redhat" ] || [ Z"$theos" = Z"fedora" ]
	then
		RPMLIST=`rpm -qa`
	elif [ Z"$theos" = Z"debian" ] || [ Z"$theos" = Z"ubuntu" ]
	then
		RPMLIST=`dpkg -l`
	fi
fi

###
# Now do the base install - just enough for ansible
###
epel
if [ $ansible -eq 1 ]
then
	ansible
else
	tz
	selinux
fi


###
# Run the specific installer or use the menu
###
if [ Z"$installer" != Z"" ]
then
	if [ $ansible -eq 0 ]
	then
		cd scripts
		. ${0}.$installer
		changes=1
		$installer
		cd ..
	else
		choice=$installer
		call_playbook
		if [ $? -eq 0 ]
		then
			colorecho "Installed $installer"
		else
			colorecho "Failed to install $installer." 1
		fi
	fi
else
	menu
fi

###
# General Cleanup
###
if [ $ansible -eq 0 ]
then
	echo "Update SELinux"
	fixselinux
fi