#!/bin/bash

#--------------------------
# Set Defaults
#--------------------------

RSPM_BASE="${RSPM_BASE:-/opt/rstudio-pm}"
RSPM_LOG="${RSPM_LOG:-/var/log/rstudio/rstudio-pm/rstudio-pm.log}"
RSPM_CONFIG_DIR="${RSPM_CONFIG_DIR:-/etc/rstudio-pm}"
OUTPUT_FILE="${OUTPUT_FILE:-./rspm_diagnostics-report.txt}"

#--------------------------
# Helper Functions
#--------------------------

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

}

print_constants () {
  echo "Using:"
  echo "RSPM_BASE=$RSPM_BASE"
  echo "RSPM_LOG=$RSPM_LOG"
  echo "RSPM_CONFIG_DIR=$RSPM_CONFIG_DIR"
  echo "RSPM_CLI=$RSPM_CLI"
  echo "RSPM_LIC=$RSPM_LIC"
  echo "RSPM_DATADIR=$RSPM_DATADIR"
}

scruburl () {
  # extract the protocol
  proto="$(echo $1 | grep :// | sed -e's,^\(.*://\).*,\1,g')"

  # remove the protocol
  url=$(echo $1 | sed -e s,$proto,,g)

  # extract the user (if any)
  user="$(echo $url | grep @ | cut -d@ -f1)"

  # extract the host and port
  hostport=$(echo $url | sed -e s,$user@,,g | cut -d/ -f1)

  # extract the path (if any)
  path="$(echo $url | grep / | cut -d/ -f2-)"
    if [[ -n "$user" ]]; then
          echo "$proto[REDACTED]@$hostport/$path"
    else
          echo "$proto$hostport/$path"
    fi
}

gather_info () {

  date
  add_label "Constants"
  print_constants

  add_label "Detect OS"
  OS='cat /etc/*-release'
  DISTRO=$($OS | grep DISTRIB_ID | cut -f2 -d "=")
  if test -f /etc/SuSE-release
  then
   DISTRO="SUSE"
  fi
  if [[ $(cat /etc/os-release | grep -e "^CPE_NAME\=*" | cut -f 2 -d '=') == "\"cpe:/o:opensuse:leap:15.0\"" ]]
  then
   DISTRO="SUSE"
  fi
  if [[ $(cat /etc/os-release | grep -e "^CPE_NAME\=*" | cut -f 2 -d '=') == "\"cpe:/o:suse:sles:15\"" ]]
  then
   DISTRO="SUSE"
  fi
  if [[ -f /etc/centos-release || -f /etc/redhat-release ]]
  then
   DISTRO="RedHat"
  fi
  [ -z $DISTRO ] && { DISTRO="RedHat"; echo "Distribution unable to be determined; RedHat set as default."; }
  $OS
  uname -a

  add_label "CPU model"
  lscpu

  add_label "Mounts"
  mount

  add_label "NFS Mounts"
  if mount | grep -q nfs; then
    mount | grep nfs
    if mount | grep nfs | grep -q -v "lookupcache=pos"; then
      echo "WARNING: NFS mounts do not have recommended mount option lookupcache=pos. If the mount is used for the data directory, this can cause serious performance issues."
    fi
  else
    echo "No NFS mounts found"
  fi

  add_label "System disk space"
  df -h

  add_label "System memory usage"
  free -h

  add_label "Non-kernel processes"
  ps auxf | grep -v ']$'

  add_label "Posit Package Manager"
  echo "Status of rstudio-pm package:"
  case $DISTRO in
    "RedHat" | "CentOS")
      yum info rstudio-pm
      ;;
    "Ubuntu" | "Debian")
       dpkg -s rstudio-pm
      ;;
    "SUSE")
      zypper info rstudio-pm
      ;;
  esac
  echo ""
  echo "rstudio-pm version"
  cat $RSPM_BASE/VERSION
  echo ""
  echo "rstudio-pm status"
  # cribbed from RSP rstudio-server command
  INIT_SYSTEM=`cat /proc/1/comm 2>/dev/null`
  if test "$INIT_SYSTEM" = "systemd"
  then
     systemctl status rstudio-pm
  else
     status rstudio-pm
  fi

  add_label "Posit PM config files"
  for f in $(ls $RSPM_CONFIG_DIR)
  do
    # Skip binaries files and rspm_diagnostics-report.txt
    if [[ ${f##*.} == rpm ]] || [[ ${f##*.} == deb ]] || [[ ${f##*.} == gz ]] || [[ ${f} == rspm_diagnostics-report.txt ]] ; then
        continue
    fi
    # Exclude files larger than 1MB (1048576 bytes)
    if [[ $(stat -c%s "$RSPM_CONFIG_DIR/$f") -gt 1048576 ]]; then
        continue
    fi

    # Read line by line and if we see a URL, scrub it
    echo "$f:"
    while read l; do
        for w in $l; do
            (echo "$w" | grep -Eq '(https:\/\/|http:\/\/|postgres:\/\/)') && echo "$(scruburl $w) " | tr -d '\n' || echo "$w " | tr -d '\n'
        done
        echo ""
    done < $RSPM_CONFIG_DIR/$f
    echo ""
  done


  add_label "License manager status"
  STATUS=$(timeout 1 bash -c '(echo > /dev/tcp/www.wyday.com/443) > /dev/null 2>&1' && echo "up" || echo "down")
  echo "Port Status: $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:"

  $RSPM_LIC status
  echo "Offline license status:"
  $RSPM_LIC status-offline
  # TODO enhance to check with --proxy flag, if need be

  add_label "Posit PM Log"
  cat $RSPM_LOG


  add_label "Network connections"
  echo "http_proxy env var: $http_proxy"
  echo "https_proxy / HTTPS_PROXY env var: $https_proxy $HTTPS_PROXY"
  echo "all_proxy / ALL_PROXY env var: $all_proxy $ALL_PROXY"
  INIT_SYSTEM=`cat /proc/1/comm 2>/dev/null`
  if test "$INIT_SYSTEM" = "systemd"; then
    echo "systemd Environment:"
    systemctl show --property=Environment rstudio-pm
  fi
  STATUS=$(timeout 1 bash -c '(echo > /dev/tcp/rspm-sync.rstudio.com/443) > /dev/null 2>&1' && echo "up" || echo "down")
  echo "Port Status: $STATUS"
  if ping -c 1 rspm-sync.rstudio.com &> /dev/null; then
    echo "ping to https://rspm-sync.rstudio.com  successful"
  else
    echo "ping to https://rspm-sync.rstudio.com unsuccessful"
  fi


  add_label "Check RSPM CLI"
  echo "CLI permissions:"
  ls -al $RSPM_CLI
  echo ""
  echo "CLI accessible:"
  $RSPM_CLI --help
  echo ""
  echo "CLI 'list' results:"
  $RSPM_CLI list
  echo ""
  echo "CLI 'list git-builders' results:"
  $RSPM_CLI list git-builders
  echo ""
  echo "CLI 'list git-builds' results:"
  $RSPM_CLI list git-builds --all
  echo ""
  echo "CLI 'list blocklist-rules' results:"
  $RSPM_CLI list blocklist-rules


  add_label "Check RSPM Data Directory"
  ls -al $RSPM_DATADIR

  date
}

end_msg() {
  echo ""
  echo "All done! Output file is here: $OUTPUT_FILE"
  echo ""
  echo "If you plan to send the output file to Posit Support, you are welcome"
  echo "to sanitize any data that you feel is sensitive, but please let us know that you"
  echo "have done so."
  echo ""
  echo "Weird results? Run the command with --help to see arguments you may need to set"
  echo ""
}

help() {
  echo "Posit Package Manager Diagnostics Script"
  echo ""
  echo "This script must be run as root"
  echo ""
  echo "Arguments:"
  echo "Can be set using short or long flags, or by environment variable."
  echo "Sample command:  OUTPUT_FILE='./diagnostics.txt' /opt/rstudio-pm/bin/run-diagnostics -i /opt/rstudio-pm"
  echo ""
  echo "-i --installdir RSPM_BASE       The location where RSPM was installed,   default: $RSPM_BASE"
  echo "-l --logpath    RSPM_LOG        The path to the RSPM log file,           default: $RSPM_LOG"
  echo "-c --configdir  RSPM_CONFIG_DIR The location of the RSPM config file,    default: $RSPM_CONFIG_DIR"
  echo "-o --outputfile OUTPUT_FILE     Where to save the diagnostic output,     default: $OUTPUT_FILE"
}

check_access() {
 config_file="$RSPM_CONFIG_DIR/rstudio-pm.gcfg"
 if ! test -r $config_file; then
   echo "Diagnostics script must be run as root or the Package Manager service account (typically rstudio-pm)"
   exit 1
 fi
}

# -------------
# argument parser (cribbed from the driver installer)
# -------------

getoptlong="outputfile:,logpath:,installdir:,configdir:,help"
getoptshort="o:,l:,i:,c:,h"
args=$(getopt -l "$getoptlong" -o "$getoptshort" -- "$@")
if [ $? -ne 0 ]
then
    exit 0
fi

eval set -- "$args"

while [ $# -ge 1 ]; do
  case "$1" in
    --)
      break
      ;;
    -o|--outputfile)
      OUTPUT_FILE="$2"
      shift
      ;;
    -l|--logpath)
      RSPM_LOG="$2"
      shift
      ;;
    -i|--installdir)
      RSPM_BASE="$2"
      shift
      ;;
    -c|--configdir)
      RSPM_CONFIG_DIR="$2"
      shift
      ;;
    -h|--help)
      help;
      exit 0
      ;;
  esac
  shift
done

#-------------------
# Computed Variables
#-------------------

RSPM_CLI="$RSPM_BASE/bin/rspm"
RSPM_LIC="$RSPM_BASE/bin/license-manager"
RSPM_DATADIR="$(cat $RSPM_CONFIG_DIR/rstudio-pm.gcfg | sed -En 's/^DataDir[[:space:]]*=[[:space:]]*(.*)$/\1/p')"
if test "$RSPM_DATADIR" = ""
then
  RSPM_DATADIR="/var/lib/rstudio-pm"
fi

#-------------------
# Run!
#-------------------
print_constants
check_access
gather_info &> $OUTPUT_FILE
end_msg
