#!/bin/bash
#
# Lenovo automated Linux Bundle installer
#
# Version 1.2 - 2024-08-13
versionInfo="yum_bundle_install.sh v1.2 2024-08-13"

cleanup()
{
	echo "Cleaning Up"

	rm -rf `echo $baseurl | rev | cut -c 2- | cut -d'/' -f 2- | rev` Lenovo_Install/repos Lenovo_Install/*_$server_mt* /etc/yum.repos.d/lenovo.repo /etc/zypp/repos.d/lenovo.repo

	if [[ -f /etc/yum.repos.d/lenovo.repo.tmp ]]; then
		mv /etc/yum.repos.d/lenovo.repo.tmp /etc/yum.repos.d/lenovo.repo 
	fi

	if [[ -f /etc/zypp/repos.d/lenovo.repo.tmp ]]; then
		mv /etc/zypp/repos.d/lenovo.repo.tmp /etc/zypp/repos.d/lenovo.repo 
	fi

	if [[ -f /etc/yum.conf.tmp ]]; then
		mv /etc/yum.conf.tmp /etc/yum.conf
	fi

	exit $error
}



# Program Start
tgz="Empty"
url="Empty"
update_source="tbd"
keyfile="In-Bundle"
assumeyes="no"
selectiveInstall="yes"
help="no"
error="0"
version="no"
keepconfig="no"
deleteconfig="no"
while [[ "$#" > 0 ]]; do 
	case $1 in
  		-b|--bundle) tgz="$2"; shift; update_source="bundle";;
		-u|--url) url="$2"; shift; update_source="url";;
		-l|--lenovo) lenovoRelease="$2"; shift; update_source="lenovo";;
  		-y|--assumeyes) assumeyes="yes";;
		-k|--keyfile) keyfile="$2"; shift;;
		-a|--allpackages) selectiveInstall="no";;
		-h|--help) help="yes";;
		-V|--version) version="yes";;
		-K|--keepconfig) keepconfig="yes";;
		-d|--deleteconfig) deleteconfig="yes";; 
  		*) echo "Unknown parameter passed: $1"; help="yes"; error="1";;
	esac; shift; 
done

echo -e "\nLenovo DataCenter Group - Linux Update Bundle standalone application.  \nVersion: `echo $versionInfo | cut -d' ' -f 2-`"
if [[ "$version" = "yes" ]]; then
	exit $error
fi

if [[ "$update_source" = "tbd" ]]; then
	if [[ "$help" = "no" ]]; then
		echo -e "\nMust specify update source (--bundle, --url or --lenovo) \nHere's --help information:"
		help="yes"
		error="2"
	fi
fi

if [[ "$help" = "yes" ]]; then
	echo -e "\nHelper application to configure & apply Lenovo DataCenter Linux Update Bundles."
        echo -e "Home Page:https://linux.lenovo.com/yum"
	echo -e "\nCommands: "
	echo -e " -b, --bundle    Download available tgz file at the bottom of the bundle release's home page"
	echo -e " -u, --url       URL of a file server,only support a repication of the lenovo bundle is available on a local intranet file server". 
        echo -e " -l, --lenovo    Please refer to home page to get the release name,default release name is latest" 
        echo -e "\nExamples:"
        echo -e " yum_bundle_install.sh -b Lenovo_YUM_Repo_2023_10_11.tgz    Download tgz file from https://linux.lenovo.com/yum/2023_10"
        echo -e " yum_bundle_install.sh -l latest                            Use lenovo latest version as the yum repository"
        echo -e " yum_bundle_install.sh -l                                   Same as command:yum_bundle_install.sh -l latest "
        echo -e " yum_bundle_install.sh -l 2023_10                           Use release version \"2023_10\" as the yum repository"
        echo -e " yum_bundle_install.sh -u http://ip/2023_10_16              Use intranet file server http://ip/2023_10_16 as the repository"
	echo -e "\nOptions:"
	echo -e " -k, --keyfile          Public Keyfile (default: Keyfile stored in bundle)"
	echo -e " -a, --allpackages      Installs all packages qualified for server vs just packages for devices installed on server"
	echo -e " -y, --assumeyes        Answers yes to yum/zypper install/update questions"
	echo -e " -h, --help             Show this screen"
	echo -e " -V, --version          Show version"
	echo -e " -K, --keepconfig       Keeps lenovo.repo config file default for -u or -l install method"
	echo -e " -d, --deleteconfig     Delete lenovo.repo config file.default for -b install method"
	exit $error
fi

if [[ "$update_source" = "bundle" ]]; then
	echo -e "\n(Bundle File: $tgz) (Keyfile: $keyfile) (Assume Yes? $assumeyes) (Selective Install? $selectiveInstall)\n "
elif [[ "$update_source" = "url" ]]; then
	echo -e "\n(Bundle URI: $url) (Keyfile: $keyfile) (Assume Yes? $assumeyes) (Selective Install? $selectiveInstall)\n "
elif [[ "$update_source" = "lenovo" ]]; then
	echo -e "\n(Bundle URI: Lenovo Repository) (Keyfile: $keyfile) (Assume Yes? $assumeyes) (Selective Install? $selectiveInstall)\n "
#	echo -e "\n --url and --lenovo bundle sources not yet supported"
#	echo -e "Check https://www.github.com/Lenovo/BundleTools for updates."
#	exit 3
fi


mkdir -p Lenovo_Install/debug
debugFile="Lenovo_Install/debug/debug_`date +%Y%m%d%H%M`"
echo "000-Program Start:  $versionInfo" > $debugFile
#### Determine Server Machine Type

server_mt=`dmidecode -t 1 | grep "SKU Number" | cut -d " " -f 3 | cut -c 1-4`
if [[ "$server_mt" = "LENO" ]]; then
        server_mt=`dmidecode -t 1 | grep "SKU Number" |cut -d _ -f 3`
fi
echo "010-Server mt query:  $server_mt (`dmidecode -t 1`)" >> $debugFile

vm="no"
#### Virtual Machine Test Mode Enablement #####
## Comment Section out to disable KVM/VMware Virtual Machine Testing ##
if [[ "$server_mt" = "Stan" ]]  || [[ "$server_mt" = "VMwa" ]]; then
	server_mt="6241"  # Lenovo Server Machine Type 6241 = System x3850 X5 (supports all Linux Distros)
	vm="yes"
	echo "015-VM Test mode:  Enabled" >> $debugFile
fi
#### End of Vitural Machine Test Section #####

#### Determine Linux Distro
linux_distro="unknown"


if [[ -f /etc/centos-release ]]; then
	centos_release=`rpm -qf /etc/centos-release`
	if [[ "`echo $centos_release | fgrep -c ".el7."`" = "1" ]]; then
		linux_distro="RHEL`echo $centos_release | cut -d- -f 3-4 | cut -d. -f 1 | tr "-" "."`"
	elif [[ "`echo $centos_release | fgrep -c ".el6."`" = "1" ]]; then
		linux_distro="RHEL`echo $centos_release | cut -d- -f 3-4 | cut -d. -f 1 | tr "-" "."`"
	fi
	echo "015-CentOS Distro discovered: rpm -qf /etc/centos-release = $centos_release" >> $debugFile

elif [[ -f /etc/redhat-release ]]; then
	redhat_release=`rpm -qf /etc/redhat-release`
	if [[ "`echo $redhat_release | fgrep -c ".el6."`" = "1" ]]; then
	 	linux_distro="RHEL`echo $redhat_release | cut -d- -f 5 | cut -d. -f 1-2`"
	elif [[ "`echo $redhat_release | fgrep -c ".el7."`" = "1" ]]; then
	 	linux_distro="RHEL`echo $redhat_release | cut -d- -f 4`"
	elif [[ "`echo $redhat_release | fgrep -c ".el8."`" = "1" ]]; then
                linux_distro="RHEL`echo $redhat_release | cut -d- -f 3`"
	elif [[ "`echo $redhat_release | fgrep -c ".el9."`" = "1" ]]; then
                linux_distro="RHEL`echo $redhat_release | cut -d- -f 3`"
	elif [[ "`echo $redhat_release | fgrep -c ".el10."`" = "1" ]]; then
                linux_distro="RHEL`echo $redhat_release | cut -d- -f 3`"
	fi
	echo "015-RHEL Distro discovered: rpm -qf /etc/redhat-release = $redhat_release" >> $debugFile

elif [[ -f /etc/SuSE-release ]]; then
	sles_release=`rpm -qf /etc/SuSE-release`
	if [[ "`echo $sles_release | cut -d- -f 3`" = "11.4" ]]; then
		if [[ "`rpm -qa | grep -c ^kernel-xen-base`" != "0" ]]; then
			linux_distro="SLES11SP4_XEN"
		else
			linux_distro="SLES11SP4_Default"
		fi
		echo "015-SLES11 Distro discovered: rpm -qf /etc/SuSE-release = $sles_release" >> $debugFile

	elif [[ "`echo $sles_release | cut -d- -f 3 | cut -d. -f 1`" = "12" ]]; then
		 linux_distro="SLES12SP`echo $sles_release | cut -d- -f 3 | cut -d. -f 2`"
		 echo "015-SLES12 Distro discovered: rpm -qf /etc/SuSE-release = $sles_release" >> $debugFile
	elif [[ "`echo $sles_release | cut -d- -f 3 | cut -d. -f 1`" = "15" ]]; then
                 linux_distro="SLES15SP`echo $sles_release | cut -d- -f 3 | cut -d. -f 2`"
                 echo "015-SLES15 Distro discovered: rpm -qf /etc/SuSE-release = $sles_release" >> $debugFile
	fi
elif [[ -f /etc/issue ]]; then
	is_SLE15=`cat /etc/issue | grep -c "SUSE Linux Enterprise Server 15"`
	if [[ "$is_SLE15" = "1" ]]; then
		sp="SP0"
		for SP in `cat /etc/issue | grep "SUSE Linux Enterprise Server 15"`; do
			if [[ "$SP" =~ "SP" ]]; then
				sp=$SP
			fi
		done
		linux_distro="SLES15"$sp
		echo -e "015-SLES15 Distro discovered: cat /etc/issue | grep \"SUSE Linux Enterprise Server 15\" = `cat /etc/issue | grep "SUSE Linux Enterprise Server 15"`" >> $debugFile
	fi
fi

echo "020- Server/OS Discovery complete.  Server MT:$server_mt  Linux Distro:$linux_distro" >> $debugFile
echo "Server/OS Discovery complete.  Server MT:$server_mt  Linux Distro:$linux_distro"

###  Device Agentless Software IDs  ###

### Tested on CentOS 7

softwareIDsTXT="Lenovo_Install/debug/pci_softwareIDs.txt"

if [[ "$vm" = "no" ]]; then
	cat /dev/null > $softwareIDsTXT.tmp

	for device in `lspci | cut -d' ' -f 1 | grep 0$`; do
                lspci -vv -n -s $device 2>/dev/null | grep "Subsystem" | cut -d: -f 2- | xargs | tr -d ':' >> $softwareIDsTXT.tmp 
		#lspci -vv -n -s $device | grep "Subsystem" | cut -d: -f 2- | xargs | tr -d ':' >> $softwareIDsTXT.tmp
	done

	cat $softwareIDsTXT.tmp | awk 'NF' | sort | uniq | tr '[:lower:]' '[:upper:]' > $softwareIDsTXT

else

	cp testpci.txt $softwareIDsTXT

fi

echo -e "\n\n040-Discovered PCIe SoftwareID" >> $debugFile
cat $softwareIDsTXT >> $debugFile
echo -e "040-End of PCIe SoftwareID List\n\n" >> $debugFile

echo -e "050-Starting YUM config creation" >> $debugFile

if [[ "$update_source" = "bundle" ]]; then

	echo -e "\n\n030-Starting TGZ repositiory extraction" >> $debugFile
	tar -xvzf $tgz -C Lenovo_Install --wildcards *_$server_mt*/$linux_distro* */repos/$linux_distro*  >> $debugFile
	sleep 60
	echo -e "030-Completed TGZ repositiory extraction\n\n" >> $debugFile

	baseurl=`pwd`"/Lenovo_Install/"`ls Lenovo_Install/ | grep $server_mt`"/"$linux_distro"/" 

	if [[ ! -d $baseurl"repodata" ]]; then 
		echo "STOP ERROR: Required Directory "$server_mt"/"$linux_distro" not discovered"
		echo "055-STOP ERROR: Required Directory "$baseurl"/repodata not found" >> $debugFile
		exit 
	fi

	if [[ "$selectiveInstall" = "yes" ]]; then
		cp `ls $baseurl/repodata/*groups.xml | head -n 1` Lenovo_Install/debug/groups.xml
	fi

	echo -e "060-Starting key prep" >> $debugFile

	if [[ "$keyfile" = "In-Bundle" ]]; then
		keyfile=$baseurl"repodata/repomd.xml.key"
	fi
	baseurl="file://$baseurl"
else
	if [[ "$update_source" = "lenovo" ]]; then
		if [ -z $lenovoRelease ]; then
			lenovoRelease="latest"
		fi
		url="https://linux.lenovo.com/yum/$lenovoRelease"
	fi
	curl -s -L $url > Lenovo_Install/debug/repo-list.html 
	mtdisto=`cat Lenovo_Install/debug/repo-list.html | grep $server_mt | grep $linux_distro | head -n 1 | cut -d'"' -f2 | cut -d/ -f 1-2`
	baseurl=$url"/$mtdisto"
	if [[ "$selectiveInstall" = "yes" ]]; then
		echo -e "Downloading Lenovo Group Data File...\n"
		curl -s -L $baseurl/repodata > Lenovo_Install/debug/repodata.dir.txt
		for quote in {1..20}; do
			groupfile=`cat Lenovo_Install/debug/repodata.dir.txt | fgrep groups.xml | fgrep -v xml.gz | cut -d'"' -f $quote`
			if [[ "`echo $groupfile | grep -c xml$`" = "1" ]]; then
				break
			fi
		done
		if [[ "`echo $groupfile | grep -c xml$`" != "1" ]]; then
			echo "Can not find group file,please check your bundle or URL"
			exit 5
		fi
		curl -s -L $baseurl/repodata/$groupfile > Lenovo_Install/debug/groups.xml
		echo -e "\nGroup Data File Download complete.\n"
	fi
	if [[ "$keyfile" = "In-Bundle" ]]; then
		echo -e "Downloading Public Key...\n"
		curl -L -s $baseurl/repodata/repomd.xml.key > Lenovo_Install/debug/repomd.xml.key
		keyfile=`pwd`"/Lenovo_Install/debug/repomd.xml.key"
		echo -e "\nPublic Key Download complete.\n"
	fi
fi


echo "Loading authenticity key into RPM keychain"
gpg --quiet --with-fingerprint $keyfile  >> $debugFile
echo "Key digital fingerprint:"
tail -n 2 $debugFile
echo -e "\n"

rpm --import $keyfile

if [[ -d /etc/pki/rpm-gpg/ ]]; then
	cp $keyfile /etc/pki/rpm-gpg/
fi

echo -e "060-Completed key prep" >> $debugFile

if [[ "`echo $linux_distro | cut -c 1-4`" = "SLES" ]]; then
	
	echo -e "070-Starting YUM update" >> $debugFile

	echo "[lenovo]" > lenovo.repo
	echo "name=Lenovo YUM Updates Repository" >> lenovo.repo
	echo "enabled=1" >> lenovo.repo
	echo "autorefresh=1" >> lenovo.repo
	echo "baseurl="$baseurl >> lenovo.repo
	echo "Type=rpm-md" >> lenovo.repo 
	echo "gpgcheck=1" >> lenovo.repo
	echo "keeppackages=0" >> lenovo.repo

	if [[ -f /etc/zypp/repos.d/lenovo.repo ]]; then
		mv /etc/zypp/repos.d/lenovo.repo /etc/zypp/repos.d/lenovo.repo.tmp
	fi

	mv lenovo.repo /etc/zypp/repos.d/lenovo.repo

	echo -e "\n080-zypper config file:  /etc/zypp/repos.d/lenovo.repo" >> $debugFile
	cat /etc/zypp/repos.d/lenovo.repo >> $debugFile
	echo -e "080-END zypper config file.\n" >> $debugFile

	if [[ "$selectiveInstall" = "yes" ]]; then
		cat /dev/null > installrpms.txt
		cat Lenovo_Install/debug/groups.xml | grep "^<name>" | grep -v LenovoUpdates | cut -c 7-14 |  tr '[:lower:]' '[:upper:]' | sort | uniq > Lenovo_Install/debug/available.softwareIDs.txt
		grep -f Lenovo_Install/debug/available.softwareIDs.txt Lenovo_Install/debug/pci_softwareIDs.txt > Lenovo_Install/debug/installable_softwareIDs.txt
		for device in `cat Lenovo_Install/debug/installable_softwareIDs.txt`; do
			cat Lenovo_Install/debug/groups.xml | grep -A20 "<name>$device</name>" > group_data.tmp
			cat group_data.tmp | head -n `cat group_data.tmp | grep -n "</packagelist>" | head -n 1 | cut -d: -f 1` > group_data.tmp
			cat group_data.tmp | grep "<packagereq" | cut -d '>' -f 2 | cut -d '<' -f 1 >> installrpms.txt
		done
		
		installList=`cat installrpms.txt | tr '\n' ' '`
		rm -rf group_data.tmp installrpms.txt
	else
		installList="ALL"
	fi


	echo -e "080-Starting zypper update" >> $debugFile
	

	if [[ "$installList" = "" ]]; then
		echo "Warning: Appears that no updates in bundle applies to server configuration"
		error="171"
		cleanup
	fi

	echo -e "081-zypper Command:  zypper $zypperArgs install --from lenovo $installList" >> $debugFile
	echo -e "\nStarting zypper update:\n"
	if [[ "$installList" = "ALL" ]]; then
		zypper $zypperArgs install --from lenovo '*'
	else
		zypper $zypperArgs install --from lenovo -n $installList
	fi

	if [[ "$keepconfig" = "no" ]]; then
		cleanup
	fi

else # Start RHEL/CentOS Updates Section

	echo -e "070-Starting YUM update" >> $debugFile

	echo "[lenovo]" > lenovo.repo
	echo "name=Lenovo YUM Updates Repository" >> lenovo.repo
	echo "baseurl="$baseurl >> lenovo.repo
	echo "enabled=1" >> lenovo.repo
	echo "gpgcheck=1" >> lenovo.repo
	echo "gpgkey=file://"$baseurl"repodata/repomd.xml.key" >> lenovo.repo

	if [[ -f /etc/yum.repos.d/lenovo.repo ]]; then
		mv /etc/yum.repos.d/lenovo.repo /etc/yum.repos.d/lenovo.repo.tmp
	fi

	mv lenovo.repo /etc/yum.repos.d/lenovo.repo

	echo -e "\n080-YUM config file:  /etc/yum.repos.d/lenovo.repo" >> $debugFile
	cat /etc/yum.repos.d/lenovo.repo >> $debugFile
	echo -e "080-END YUM config file.\n" >> $debugFile

	if [[ "$selectiveInstall" = "yes" ]]; then
		cat Lenovo_Install/debug/groups.xml | grep "^<name>" | grep -v LenovoUpdates | cut -c 7-14 |  tr '[:lower:]' '[:upper:]' | sort | uniq > Lenovo_Install/debug/available.softwareIDs.txt
		grep -f Lenovo_Install/debug/available.softwareIDs.txt Lenovo_Install/debug/pci_softwareIDs.txt > Lenovo_Install/debug/installable_softwareIDs.txt
		yum grouplist > Lenovo_Install/debug/available_groups.txt
		installGroupList=""
		echo "Installing/Updating:"
		for device in `cat Lenovo_Install/debug/installable_softwareIDs.txt`; do
			if [[ "`cat Lenovo_Install/debug/available_groups.txt | grep -c $device`" = "1" ]]; then
				update_desc=`yum groupinfo $device | grep Description | cut -d: -f 2-`
				echo -e "\t$update_desc (softwareID: $device)"
				installGroupList=$installGroupList$device" "
			fi
		done
		echo -e "\n"
	else
		installGroupList="LenovoUpdates"
	fi



	yumArgs=""
	if [[ "$assumeyes" = "yes" ]]; then
		yumArgs="-y"
	fi

	echo -e "080-Starting YUM update" >> $debugFile
	echo -e "081-YUM Command:  yum $yumArgs groupinstall $installGroupList" >> $debugFile

	if [[ "$installGroupList" = "" ]]; then
		echo "Warning: Appears that no updates in bundle applies to server configuration"
		error="171"
		cleanup
	fi

	#yum groups mark convert >> $debugFile
	yum clean all >> $debugFile
	cp /etc/yum.conf /etc/yum.conf.tmp
	echo "group_command=compat" >> /etc/yum.conf
	echo -e "\nStarting YUM update:\n"
	yum $yumArgs groupinstall $installGroupList

	if [[ "$keepconfig" = "no" ]]; then
		cleanup
	fi
fi
