#!/usr/bin/env bash

# Script should be run as root user
if [[ $EUID -ne 0 ]]; then
   echo "Diagnostics script must be run as root" 
   exit 1
fi

DATE="$(date +"%y%m%d%H%M%S")"
OUTPUT_FILE="/tmp/rstudio-diagnostics/rsp-diagnostics-report-${DATE}.txt"
mkdir -p /tmp/rstudio-diagnostics

add_label () {
  echo ""
  echo "-------------------------------"
  echo "$1"
  echo "-------------------------------"

}

# 'find' instead of 'ls' allows us to filter out directory results.
# '-maxdepth 1' keeps the scope to the parent directory, in keeping with the functionality delivered by 'ls'.
# 'while IFS= read -r' allows for handling of whitespace characters in filenames, along with backslash characters.
# Redirecting stderr to '/dev/null' results in a less noisy diagnostics report.
cat_config () {
  find "$1/" -maxdepth 1 ! -type d | while IFS= read -r f
  do
    echo "$f:" | cat -v
    cat "$f" 2> /dev/null
    echo ""
  done
}

gather_info () {
  date
  echo "Server name:"
  hostname
  add_label "Detect OS"
  OS='cat /etc/*-release'
  DISTRO=$($OS | grep DISTRIB_ID | cut -f2 -d "=")
  [ -z $DISTRO ] && { DISTRO="RedHat"; echo "Distribution unable to be determined; RedHat set as default."; }
  $OS
  uname -a
  echo "Mount point space usage:"
  df -h
  echo "Mount point inode usage:"
  df -i

  add_label "R Installation"
  echo "which R: $(which R)"
  echo "which gcc: $(which gcc)"
  if [[ "$(which R 2> /dev/null)" ]] && [[ "$(R RHOME 2> /dev/null)" ]] ; then
    R_HOME=$(R RHOME)
    echo "R_HOME: $R_HOME"
    R --version

    add_label "R config files"

    # Parse contents of r-versions to detect all R_HOME paths and store in array
    R_CONFIG_DIR=($(cat /var/lib/rstudio-server/r-versions | grep R_HOME | cut -d '"' -f4))

    # append /etc to each directory in array
    R_CONFIG_DIR=( "${R_CONFIG_DIR[@]/%//etc}" )

    for m in "${R_CONFIG_DIR[@]}"
    do
      find "${m}/" -maxdepth 1 ! -type d | while IFS= read -r f
      do
        echo "$f:"
        cat "$f" 2> /dev/null
        echo ""
      done
    done
  else
    echo "R not found."
  fi

  add_label "RStudio Server"
  echo "Status of rstudio-server package:"
  case $DISTRO in
    "RedHat" | "CentOS")
      yum info rstudio-server
      ;;
    "Ubuntu" | "Debian")
       dpkg -s rstudio-server
      ;;
    "SUSE")
      zypper info rstudio-server
      ;;
  esac
  echo ""
  echo "rstudio-server version, status, and verify-installation"
  rstudio-server version
  rstudio-server status
  rstudio-server verify-installation

  echo ""
  echo "rstudio-launcher version and status"
  rstudio-launcher version
  rstudio-launcher status

  add_label "RStudio Server config files"
  RSP_CONFIG_DIR="/etc/rstudio"
  cat_config "$RSP_CONFIG_DIR"
  
  cat /etc/profile
  cat /etc/environment
  cat /etc/security/pam_env.conf  

  cat /etc/pam.conf
  PAM_CONFIG_DIR="/etc/pam.d"
  cat_config "$PAM_CONFIG_DIR"

  LB_SCRIPT="/usr/lib/rstudio-server/bin/rserver-balancer"
  if [ -f "$LB_SCRIPT" ]; then
    add_label "Custom load-balancing script"
    cat "$LB_SCRIPT"
  fi

  add_label "License manager status"
  if ping -c 1 www.wyday.com &> /dev/null; then
    echo "ping to www.wyday.com successful"
  else
    echo "ping to www.wyday.com unsuccessful"
  fi
  echo "Online license status:"
  rstudio-server license-manager status
  echo "Offline license status:"
  rstudio-server license-manager status-offline

  add_label "Machine environment"
  env
  echo ""
  echo "ldd rserver"
  ldd /usr/lib/rstudio-server/bin/rserver
  echo "ldd rsession"
  ldd /usr/lib/rstudio-server/bin/rsession

  add_label "R environment outside RStudio (default R)"
  echo "Sys.info:"
  Rscript -e 'Sys.info()'
  echo "sessionInfo:"
  Rscript -e 'sessionInfo()'
  echo "Sys.getEnv:"
  Rscript -e 'Sys.getenv()'
  echo ".libPaths:"
  Rscript -e '.libPaths()'
  echo "R_HOME"
  echo $R_HOME

  if [ -f "/var/log/messages" ]; then
    SYS_LOG_PATH="/var/log/messages"
  elif [ -f "/var/log/syslog" ]; then
    SYS_LOG_PATH="/var/log/syslog"
  fi

  add_label "RStudio messages in the system log"
  if [ -f "$SYS_LOG_PATH" ]; then
    cat "$SYS_LOG_PATH" | grep "\(rstudio-server\|rstudio-session\|rserver-monitor\)"
  fi

  add_label "RStudio Server log"
  RSP_LOG_PATH="/var/lib/rstudio-server/monitor/log/rstudio-server.log"
  if [ -f "$RSP_LOG_PATH" ]; then
    cat "$RSP_LOG_PATH"
  fi

  add_label "Job Launcher logs in the system log"
  if [ -f "$SYS_LOG_PATH" ]; then
    cat "$SYS_LOG_PATH" | grep "rstudio\(-.*\)\?-launcher"
  fi

  add_label "Job Launcher debug logs"
  LAUNCHER_CONF_FILE="/etc/rstudio/launcher.conf"
  LAUNCHER_SCRATCH_PATH="/var/lib/rstudio-launcher"
  declare -a LAUNCHER_CONF_FILES
  cat $LAUNCHER_CONF_FILE | while read LINE; do
    if [[ $LINE =~ "scratch-path" ]]; then
      scratchPath=$(echo $LINE | sed -n /^scratch-path=/s/^scratch-path=//p)
      if [ -z "$scratchPath" ]; then
        continue
      fi
      LAUNCHER_SCRATCH_PATH="${scratchPath}"
    elif [[ $LINE =~ "config-file" ]]; then
      configFile=$(echo $LINE | sed -n /^config-file=/s/^config-file=//p)
      if [ -z "$configFile" ]; then
        continue
      fi
      LAUNCHER_CONF_FILES+=("${configFile}")
    fi
  done
  
  LAUNCHER_LOG_FILES=($(find $LAUNCHER_SCRATCH_PATH -name "*.log"))
  for LOG_FILE in "${LAUNCHER_LOG_FILES[@]}"; do 
    add_label $LOG_FILE
    cat $LOG_FILE
  done

  for CONF_FILE in "${LAUNCHER_CONF_FILES[@]}"; do
    cat $CONF_FILE | while read LINE; do
      if [[ $LINE =~ "scratch-path" ]]; then
        scratchPath=$(echo $LINE | sed -n /^scratch-path=/s/^scratch-path=//p)
        if [ -z "$scratchPath" ]; then
          continue
        fi
        PLUGIN_LOG_FILES=($(find $scratchPath -name "*.log"))
        for LOG_FILE in "${PLUGIN_LOG_FILES[@]}"; do 
          add_label $LOG_FILE
          cat $LOG_FILE
        done
      fi
    done
  done

  add_label "Java environment"
  echo "whereis: $(whereis java)"
  echo "version: $(java -version)"
  echo ""
  echo "JAVA_HOME"
  echo $JAVA_HOME
  echo ""
  echo "PATH"
  echo $PATH
  echo ""
  echo "Get status of JVM"
  [ $(which jps) >/dev/null ] && jps -lvm || echo "jps is not available to get further information."
  echo "** Compare this data to the contents of the $R_CONFIG_DIR/javaconf file above."

  add_label "Network connections"
  echo "http_proxy env var: $http_proxy"
  echo "all_proxy env var: $all_proxy"
  if ping -c 1 www.google.com &> /dev/null; then
    echo "ping to www.google.com successful"
  else
    echo "ping to www.google.com unsuccessful"
  fi
  echo "GET headers:"
  curl -vs www.google.com 1> /dev/null
  echo ""
  echo "Check websocket handshake headers:"
  PORT=$(sed -nE 's/^www-port[^{0-9}]+//p' < /etc/rstudio/rserver.conf)
  [ -z $PORT ] && PORT=8787
  curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: localhost:$PORT" -H "Origin: localhost:$PORT" http://localhost:$PORT
  date

}

gather_info &> $OUTPUT_FILE
echo ""
echo "All done! Output file is here: $OUTPUT_FILE"
echo ""
echo "If you plan to send the output file to RStudio Support, you are welcome to sanitize any data that you feel is sensitive, but please let us know that you have done so."
echo ""

if [ "$(stat -c '%s' $OUTPUT_FILE)" -gt 52428800 ]; then
  echo "Please note: Generated report is large; consider compressing and using our Support Upload tool to submit this file:"
  echo "http://apps.rstudio.com/SupportUpload/"
  echo "Please let us know you have done this, along with the name of the uploaded file."
  echo ""
fi
