#!/bin/bash
#
# cs_prepare_esxvm
#
# (c) 2014 SUSE Linux GmbH, Germany. Author: L.Pinne.
# GNU Public License. No warranty.
#
# Version: 2014-05-08 14:17
#

EXE=${0}

CFG="/etc/ClusterTools2/cs_prep_esxvm"
test -s $CFG && source $CFG

TMP="/tmp/$RANDOM"
ERR="/dev/null"
SFX=$(basename $EXE)

test -z "${BAK}" &&\
	BAK="/var/adm/backup/${SFX}-$(date +%Y%m%d-%H%M%S)"
test -z "${SRVC_OK}" &&\
	SRVC_OK="
ntp
sshd
boot.sysstat
vmware-tools
"
# TODO vmware-tools?
test -z "${SRVC_NO}" &&\
	SRVC_NO="
boot.multipath
multipathd
microcode.ctl
irq_balancer
alsasound
smartd
mcelog
fbset
openais
splash
splash_early
ipmi
ipmievd
powerd
auditd
SuSEfirewall2_setup
SuSEfirewall2_init
"
test -z "${RLVL_OK}" &&\
	RLVL_OK="3"
# TODO SLES for SAP?
test -z "${PROD_OK}" &&\
	PROD_OK="
SUSE_SLES
"
# TODO SLES for VMware?
test -z "${PROD_NO}" &&\
	PROD_NO="
"
test -z "${PTRN_OK}" &&\
	PTRN_OK="
Minimal
base
"
test -z "${PTRN_NO}" &&\
	PTRN_NO="
apparmor
gnome
kde
Dom0
Dom0_KVM
kvm_server
xen_server
"
test -z "${PCKG_OK}" &&\
	PCKG_OK="
sysstat
kernel-default-base
kernel-default
"
test -z "${PCLT_OK}" &&\
	PCLT_OK="
corosync
cluster-glue
crmsh
libcorosync4
libglue2
libpacemaker3
ldirectord
openais
libopenais3
pacemaker
resource-agents
ocfs2-kmp-default
ocfs2-tools
ocfs2-tools-o2cb
drbd
drbd-pacemaker
drbd-kmp-default
drbd-utils
drbd-udev
drbd-bash-completion
sbd
ClusterTools2
"
# TODO with and w/o cluster
test -z "${PCKG_NO}" &&\
	PCKG_NO="
"
test -z "${ELVT_OK}" &&\
	ELVT_OK="noop"
test -z "${ELVT_NO}" &&\
	ELVT_NO="cfq"
test -z "${SYCT_OK}" &&\
	SYCT_OK="
vm.swappiness=40
vm.dirty_bytes=1073741824
vm.dirty_background_bytes=134217728
vm.zone_reclaim_mode=0
"


function filesystem() {
 case $1 in
 apply)
	# TODO /etc/fstab noatime,data=writeback
	# TODO tune2fs -c0 -i0
	# TODO xfs, ocfs2

	echo nop
 ;;
 list)
	# TODO xfs, ocfs2

	echo "=== $FUNCNAME ==="

	echo
	grep -v "^#" /etc/fstab

	# TODO autofs
	# echo
	# grep -v "^#" /etc/auto.*
	echo
	mount | awk '{print $1}' | while read; do
		echo -e "\n$REPLY"
		tune2fs -l $REPLY 2>$ERR |\
		awk '( $0~/Block size:/ || $0~/Maximum mount count:/ || $0~/Check interval:/ || $0~/Filesystem features:/ || $0~/Filesystem flags:/ || $0~/Block count:/ || $0~/Inode count:/ ) { print }'
	done 
	# TODO hide pseudo filesystems
 ;;
 esac
}


function ntpconf() {
 case $1 in
 apply)
	# TODO error handling, useful rerturn codes $RC
	FIL="/etc/ntp.conf"
	cp -a $FIL ${FIL}.$SFX || exit 1
	# TODO
	cat >$FIL <<EOF
# /etc/ntp.conf
tinker panic 0
EOF
	sed -e s/^server.127.127.1.0//g -e s/^fudge.127.127.1.0//g <${FIL}.$SFX >>$FIL

	/etc/init.d/ntp restart
	/sbin/chkconfig on
 ;;
 list)
	echo "=== $FUNCNAME ==="

	FIL="/etc/ntp.conf"
	echo -n "chkconfig: "
	/sbin/chkconfig ntp
	echo
	/etc/init.d/ntp status
	echo
	/usr/sbin/ntpq -p
	echo
	echo "$FIL:"
	grep -v "^#" $FIL | tr -s "\n"
	echo
 ;;
 esac
}


function elevator() {
 case $1 in
 apply)
	# TODO $RC
	# TODO also look into udev rules	

	FIL="/etc/sysconfig/bootloader"
	cp -a $FIL ${FIL}.$SFX || exit 1
	sed s/showopts\"$/showopts\ elevator=noop\ cgroup_disable=memory\"/ <${FIL}.$SFX >$FIL

	FIL="/boot/grub/menu.lst"
	cp -a $FIL ${FIL}.$SFX || exit 1
	sed s/showopts\ vga=/showopts\ elevator=noop\ cgroup_disable=memory\ vga=/ <${FIL}.$SFX >$FIL

	find /sys -name "scheduler" | while read; do echo noop >$REPLY; done
 ;;
 list)
	echo "=== $FUNCNAME ==="
	
	FIL="/etc/sysconfig/bootloader"
	echo "$FIL:"
	grep "DEFAULT_APPEND=" $FIL
	echo

	FIL="/boot/grub/menu.lst"
	echo "$FIL:"
	grep showopts $FIL | grep -v x11failsafe | grep -v "vmlinuz.*xen"
	echo
	find /sys -name "scheduler" | while read; do echo -n "$REPLY: "; cat $REPLY; done | grep -v "none$"
	echo
 ;;
 esac
}


function inittab() {
 case $1 in
 apply)
	# TODO $RC
	FIL="/etc/inittab"
	/sbin/runlevel >/root/runlevel.$SFX
	cp -a $FIL ${FIL}.$SFX || exit 1
	sed s/^id:.:initdefault:/id:${RLVL_OK}:initdefault:/ <${FIL}.$SFX >$FIL 

	/sbin/telinit ${RLVL_OK}
 ;;
 list)
	echo "=== $FUNCNAME ==="

	FIL="/etc/inittab"

	echo -n "runlevel: "
	/sbin/runlevel
	echo	
	echo "$FIL:"
	grep "^id:.:" $FIL
	echo
 ;;
 esac
}


function services() {
	# TODO $RC
 case $1 in
 apply)
	/sbin/chkconfig -A >/root/chkconfig-a.$SFX || exit 1
	for f in $SRVC_NO; do
		/sbin/chkconfig $f off
		/etc/init.d/$f stop
	done
	for f in $SRVC_OK; do
		/sbin/chkconfig $f on
		/etc/init.d/$f start
	done
 ;;
 list)
	echo "=== $FUNCNAME ==="

	for f in $SRVC_NO; do
                /sbin/chkconfig $f
        done
	echo
	for f in $SRVC_OK; do
                /sbin/chkconfig $f
        done
	echo
 ;;
 esac
}


function syscontr() {
 case $1 in
 apply)
	# TODO $RC

	/sbin/sysctl -e -a >/root/sysctl-a.$SFX 2>$ERR

	FIL="/etc/sysctl.conf"
	cp -a $FIL ${FIL}.$SFX || exit 1

	# TODO TID if RAM > 4GB
	# TODO numa and cstate settings
	# TODO transparent hugepages, hugepages
	# TODO use SYCT_OK
	cat >$FIL <<EOF
# /etc/sysctl.conf
vm.swappiness = 40
#vm.dirty_bytes = 1073741824 
#vm.dirty_background_bytes = 134217728
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5
#
EOF
	cat ${FIL}.$SFX |\
		grep -v "vm.dirty.*ratio" |\
		grep -v "vm.dirty.*bytes" |\
		grep -v "vm.swappiness" >>$FIL

	/sbin/sysctl -e -p $FIL 2>$ERR 1>&2
 ;;
 list)
	echo "=== $FUNCNAME ==="

	FIL="/etc/sysctl.conf"
	for f in $SYCT_OK ; do
		S=$( echo $f | awk -F= '{print $1}' )
		/sbin/sysctl $S
	done
	echo
	echo "$FIL:"
	grep -v "^#" $FIL
	echo
 ;;
 esac
}


function products() {
 case $1 in
 apply)
	echo nop
 ;;
 list)
	echo "=== $FUNCNAME ==="
	mkdir $TMP || exit 1
	cd $TMP
	# outputs looks like sam-20140505-12:43.report
	FIL="cs_sam.report"
	SOPT="--no-rpm-verify --no-rpm-verify-md5 --skip-unmatched-prod"	
	# TODO sam how to handle user input prompt?
	# TODO sam Unsatisfied dependencies:
	sam $SOPT >$FIL 2>$ERR
	awk '$1=="Product:"{print "prod: "$2,"vers: "$3,"sp: "$4,"arch: "$6}
		$1=="Baseproduct:"{print "base_prod: "$2}
		$1=="Packages"&&$2=="not" {print "3rd-party: "$6} 
		$1=="Unsupported"&&$2=="SUSE/Novell" {print "unsupported: "$4}' $FIL 
	# TODO add-on products
	cd $OLDPWD || exit 1 
	rm -rf $TMP
 ;;
 esac
}


function patterns() {
 case $1 in
 apply)
	# TODO $RC
	# TODO check

	zypper se -t pattern | grep "^i" >/root/zypper-se-tpattern.$SFX || exit 1
	for f in $PTRN_OK; do
			zypper in -t pattern $f 
	done
 ;;
 list)
	echo "=== $FUNCNAME ==="
	zypper se -t pattern | grep "^i"
 ;;
 esac
}


function packages() {
 case $1 in
 apply)
	# TODO $RC
	# TODO check
	rpm -qa >/root/rpm-qa.$SFX || exit 1
	zypper refs -r | exit 1
	# TODO -y ?
	zypper -q -n --no-gpg-checks in -l --no-recommends $PCKG_OK
	zypper -q -n --no-gpg-checks in -l --no-recommends $PCLT_OK
 ;;
 list)
	echo "=== $FUNCNAME ==="
	zypper se $PCKG_OK 2>$ERR #| grep "|.package$" 
	zypper se $PCLT_OK 2>$ERR #| grep "|.package$"
 ;;
 esac
}


function backup() {
	# TODO use functions check option
	# TODO error handling, useful return code
	mkdir $TMP
	cd $TMP || exit 1

	/sbin/sysctl -e -a >${TMP}/sysctl-a.$SFX 2>$ERR
	/sbin/runlevel >${TMP}/runlevel.$SFX
	rpm -qa >${TMP}/rpm-qa.$SFX
	zypper se -t pattern | grep "^i" >${TMP}/zypper-se-tpattern.$SFX
	cp -a /boot/grub/menu.lst ${TMP}/
	tar czf ${TMP}/etc.tgz /etc/ >$ERR 2>&1

	cd $OLDPWD
	tar czf ${BAK}.tgz $TMP >$ERR 2>&1; RC=$? && rm -rf $TMP
	echo "RC: $RC"
	ls -l ${BAK}.tgz
}


function hardware() {
 case $1 in
 apply)
	echo nop
 ;;
 list)
	echo "=== $FUNCNAME ==="
	# TODO check vmxnet3, pvscsi, memcrtl
	# TODO check hwinfo for PV hardware and VMware BIOS
	# TODO check modules.d/*
	# TODO check NUMA topology, CPU count, RAM size
	# TODO LUNs visible, to decide if pvscsi useful or not? 
	echo "not implemented yet"
 ;;
 esac
}


function help() {
	echo "usage: $(basename $0) [OPTION]"
	echo
	echo " --save		save current settings, call first of all"
	echo " --list		list current settings, not fully implemented"
	echo " --preview	preview recommended settings"
	echo " --apply	apply recommended settings, call only once"
	echo " --help		show help"
	echo " --version	show version"
	echo
	echo "This script could apply changes only once on each VM."
	exit
}


# main()

case $1 in
	-v|--version)
		echo -n "$(basename $EXE) "
		head -11 $EXE | grep "^# Version: "
		exit
	;;
	-a|--apply)
		# TODO select functions
		# Makes no sense: products apply
		# patterns apply?
		packages apply
		ntpconf apply
		inittab apply	
		services apply
		elevator apply
		# TODO filesystem apply
		syscontr apply
	;;
	-l|--list)
		products list
		# patterns list
		packages list
		ntpconf list 
		inittab list
		services list
		elevator list
		# TODO filesystem list
		syscontr list
	;;
	-s|save)
		backup
	;;
	-p|preview)
		# TODO hardcoded settings?
		echo
		#echo "patterns:        $PROD_OK"
		#echo "patterns:	$PTRN_OK"
		echo "packages:	$PCKG_OK"
		echo "inittab:	$RLVL_OK"
		echo
		echo "services:	$SRVC_OK"
		echo "services_NOT:	$SRVC_NO"
		echo "elevator:	$ELVT_OK"
		# TODO filesystem
		echo
		echo "syscontr: $SYCT_OK"
	;;
	-t|--test)
		#products list
		#patterns list
		#packages list	
		#ntpconf list
		#inittab list
		#services list
		#elevator list
		filesystem list
		#syscontr list
	;;
	*)
		help
	;;
esac
#
