#!/bin/bash
set -u

# Usage (bash syntax):
# ./os_tweaks.sh 2>&1 | tee /tmp/os_tweaks.log

# This script checks, and if need be sets, certain OS parameters per
# Perforce recommendations: http://answers.perforce.com/articles/KB/3005#LINUX

# Following is a sample manual session:
# ROOT@perforce1:/root cat /sys/kernel/mm/transparent_hugepage/khugepaged/defrag
# [yes] no
# ROOT@perforce1:/root cat /sys/kernel/mm/transparent_hugepage/defrag
# [always] madvise never
# ROOT@perforce1:/root cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never
# ROOT@perforce1:/root echo no > /sys/kernel/mm/transparent_hugepage/khugepaged/defrag
# ROOT@perforce1:/root echo never > /sys/kernel/mm/transparent_hugepage/defrag
# ROOT@perforce1:/root echo never > /sys/kernel/mm/transparent_hugepage/enabled
# ROOT@perforce1:/root cat /sys/kernel/mm/transparent_hugepage/khugepaged/defrag
# yes [no]
# ROOT@perforce1:/root cat /sys/kernel/mm/transparent_hugepage/defrag
# always madvise [never]
# ROOT@perforce1:/root cat /sys/kernel/mm/transparent_hugepage/enabled
# always madvise [never]

function bail () { echo -e "\nError: ${1:-Unknown Error}\n"; exit ${2:-1}; }

declare -i i=0
declare -a Files
declare -i ChangesNeeded=0
declare -a CurrentValues
declare -a CorrectValues
declare CurrentValue
declare Version=1.0.1

# Static Data
Files[0]=/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
Files[1]=/sys/kernel/mm/transparent_hugepage/defrag
Files[2]=/sys/kernel/mm/transparent_hugepage/enabled

CorrectValues[0]="no"
CorrectValues[1]="never"
CorrectValues[2]="never"

# Usage Verification.

[[ -r /etc/redhat-release ]] || bail "This is only tested on RHEL/CentOS."
[[ -n "$(grep '(Santiago)' /etc/redhat-release)" ]] || bail "This is only tested on RHEL/CentOS 6 (Santiago)."
[[ $(whoami) == root ]] || bail "This must be run as root."

echo -e "\nStarted ${0##*/} v$Version at $(date) on $(hostname --fqdn).\n"

while [[ $i -lt ${#Files[*]} ]]; do
   if [[ -r ${Files[$i]} ]]; then
      CurrentValue=$(cat ${Files[$i]})
      CurrentValue=${CurrentValue#*\[}
      CurrentValue=${CurrentValue%\]*}
      CurrentValues[$i]=$CurrentValue
   else
      bail "Expected file does not exist: ${Files[$i]}"
   fi

   echo -n -e "File:        : ${Files[$i]}\nCurrent Value: ${CurrentValues[$i]}\nCorrect Value: ${CorrectValues[$i]}"

   if [[ "$CurrentValue" == "${CorrectValues[$i]}" ]]; then
      echo -e " (OK)\n"
   else
      echo -e " (Needs to be adjusted)\n"
      ChangesNeeded=$((ChangesNeeded+1))
   fi

   i=$((i+1))
done

if [[ $ChangesNeeded -eq 0 ]]; then
   echo -e "Verified: No changes to the OS parameters checked by this script are needed.\n"
   exit 0
else
   echo -e "Detected $ChangesNeeded of ${#Files[*]} OS parameters needing to be updated.\n"
fi

echo -e "Making updates.\n"
i=0
while [[ $i -lt ${#Files[*]} ]]; do
   CurrentValue=$(cat ${Files[$i]})
   CurrentValue=${CurrentValue#*\[}
   CurrentValue=${CurrentValue%\]*}

   [[ "$CurrentValue" == "${CorrectValues[$i]}" ]] && continue

   echo -e "Setting value to ${CorrectValues[$i]} in ${Files[$i]}"
   echo ${CorrectValues[$i]} > ${Files[$i]} || bail  "Failed to set value in ${Files[$i]}."

   i=$((i+1))
done

echo -e "\nRechecking files after making updates.\n"
i=0
ChangesNeeded=0

while [[ $i -lt ${#Files[*]} ]]; do
   CurrentValue=$(cat ${Files[$i]})
   CurrentValue=${CurrentValue#*\[}
   CurrentValue=${CurrentValue%\]*}

   echo -n -e "File:        : ${Files[$i]}\nCurrent Value: $CurrentValue\nCorrect Value: ${CorrectValues[$i]}"

   if [[ "$CurrentValue" == "${CorrectValues[$i]}" ]]; then
      echo -e " (OK)\n"
   else
      echo -e " (Still needs to be adjusted)\n"
      ChangesNeeded=$((ChangesNeeded+1))
   fi

   i=$((i+1))
done

if [[ $ChangesNeeded -eq 0 ]]; then
   echo -e "Done. All OS parameters needing updates have been made.\n"
else
   bail "Some OS parameter updates failed.  See output above.\n"
fi

