#!/bin/bash
# +----------------------------------------------------------------------------------------------------+
# | Name:           instance_monitor.sh                                                                |
# | Autor:          Frank Gerasch                                                                      |
# | Datum:          01.06.2017                                                                         |
# | Typ:            Shell-Script (Bash)                                                                |
# | Version:        Sendmail Version (HTML Mail)                                                       |
# | Funktion:       Ueberwachung von Oracle Instanzen                                                  |
# | Usage:          instance_monitor.sh <ORACLE_SID>                                                   |
# | Voraussetzung:  1. Linux ab Version (getestet mit Red Hat ab Version 5                             |
# |                 2. Mail Transfer Agent (MTA) fuer den Versand von Mails                            |
# |                 3. Mail-Client (sendmail) installiert                                              |
# |                 4. Parameterfile instance_monitor_<ORACLE_SID>.par muss vorhanden sein             |
# |                 5. Datenbankbenutzer instance_monitor mit create session privileg wurde erstellt . |
# |                    Der Benutzer darf kein SYSDBA-Privileg besitzen                                 |     
# +----------------------------------------------------------------------------------------------------+


# KONFIGURATION PFADE und MAILING
#******************************************************

# Path Instance Monitor Home
export WORKDIR=/home/oracle/scripts/instance_monitor   # <- Hier eintragen in welchem Verzeichnis diese Script liegt

# Path Client Oracle Home 
export ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/dbhome_1  # <- Hier ORACLE_HOME des Oracle Clients auf der lokalen Maschine eintragen

# Mailing
export SENDER_ADRESS=instance_check@example.de     # <- Hier den Mail-Absender eintragen (Beispiel: instance_check@example.de)
export RECIPIENT=dba@example.de                    # <- Hier den Mail-Empfaenger fuer die OK-Mails eintragen (Beispiel: dba@example.de)
export REPLYTO='dba@example.de (DBA Support)'      # <- Reply Adresse Mails

#---- DO NOT EDIT BELOW THIS LINE !!-------------------------------------------------------------------------+


# Pruefung Programmausruf und Parameterfile
if [ -z "$1" ]; then
  echo "Error: Argument is missing"
  echo "Usage: instance_monitor.sh <ORACLE_SID>"
else

# Pruefung Parameterfile 
if [ ! -f $WORKDIR/instance_monitor_"`echo $1 | tr [A-Z] [a-z]`".par ]; then
  echo "Error: Parameterfile $WORKDIR/instance_monitor_"`echo $1 | tr [A-Z] [a-z]`".par nicht vorhanden!"
else
  source $WORKDIR/instance_monitor_"`echo $1 | tr [A-Z] [a-z]`".par 

# Setzen weiterer Variablen
cd $WORKDIR
export SENDER="$SENDER_ADRESS (Oracle Instance Monitor)"           # <- Mail-Absender
export PATH=$ORACLE_HOME/bin:$PATH
export MAIL_TEXT=$WORKDIR/mail_text_"`echo $ORACLE_SID | tr [A-Z] [a-z]`".txt  
export FLAG_FILE=$WORKDIR/failed_connect_flag_"`echo $ORACLE_SID | tr [A-Z] [a-z]`".txt
export CONNECT_OUTPUT_FILE=$WORKDIR/sql_connect_output_"`echo $ORACLE_SID | tr [A-Z] [a-z]`".txt
export SCRIPT=$(readlink -f $0)


# Bei temporaeren Fehlern, die moeglicherweise bedingt durch einen Instance-Neustart sind, 
# Pruefung nach 60 Sekunden Wartezeit wiederholen
echo "exit" | $ORACLE_HOME/bin/sqlplus -L -S $CONNECT_STRING > $CONNECT_OUTPUT_FILE
CONNECT_ERROR=`grep 'ORA-' $CONNECT_OUTPUT_FILE | head -n 1 | awk '{print $1}'` >  /dev/null
if [ "$CONNECT_ERROR" = "ORA-01033:" ] || [ "$CONNECT_ERROR" = "ORA-12528:" ]  || [ "$CONNECT_ERROR" = "ORA-12154:" ] || [ "$CONNECT_ERROR" = "ORA-12514:" ] ; then
  sleep 60
fi


# Verbindung zur Datenbankinstanz testen
echo "exit" | $ORACLE_HOME/bin/sqlplus -L -S $CONNECT_STRING > $CONNECT_OUTPUT_FILE
if [ $? -ne 0 ]; then
  CONNECT_STATUS=failed 
  # Pruefung, ob der fehler zuvor schon einmal aufgetreten ist (Flagfile existiert)
  if [ -e $FLAG_FILE ]; then
    FAILURE_REPEATED=yes
  else
    FAILURE_REPEATED=no
    # Error-Flagfile anlegen
    touch $FLAG_FILE
  fi
else  
  CONNECT_STATUS=ok  
fi
    
# Bei erstmaliger fehlerhafter Verbindung, Fehler genauer analysieren und Mailtext erzeugen  
if [ "$CONNECT_STATUS" = "failed" ] && [ "$FAILURE_REPEATED" = "no" ]; then 
  FIRST_FAILED_CONNECT=yes
  
  # Wenn der Test account gesperrt ist
  if [ "$CONNECT_ERROR" = "ORA-28000:" ]; then 
    echo "<b>Keine vollständige Instanzprüfung möglich!</b>" > $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo "<span style=color:#cc0000;><b>Der Account $DB_USER ist in der Datenbank ${ORACLE_SID%[2|1]} gesperrt.</b></span>" >> $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo "Bitte den Grund dafür ermitteln und den Benutzer entsperren (alter user $DB_USER account unlock;)." >> $MAIL_TEXT
  else    
    echo "<b>Die Datenbankinstanz `echo $ORACLE_SID | tr [a-z] [A-Z]` ist nicht verfügbar!</b>" > $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo "Es sind keine Verbindungen mit der auf dem Server $TARGET_HOST befindlichen Datenbankinstanz `echo $ORACLE_SID | tr [a-z] [A-Z]` möglich ($OPERATING_ROLE) !" >> $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo `grep ORA- $CONNECT_OUTPUT_FILE` >> $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo " " >> $MAIL_TEXT
  
    CONNECT_ERROR=`grep 'ORA-' $CONNECT_OUTPUT_FILE | head -n 1 | awk '{print $1}'` >  /dev/null
    
    # Protokoll-Eintrag schreiben
    echo `date +"%d.%m.%Y"` `date +"%H:%M:%S"` CONNECT ERROR `echo $ORACLE_SID | tr [a-z] [A-Z]`, `grep 'ORA-' $CONNECT_OUTPUT_FILE | head -n 1` >> $WORKDIR/connect_protokoll.log
  
    case $CONNECT_ERROR in

      "ORA-12541:")   # Listener nicht erreichbar
      echo "<span style=color:#cc0000;><b>Unter der angegenenen Adresse $TARGET_HOST:$LISTENER_PORT ist kein Listener erreichbar.</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Vermutlich ist der Listener oder Host unten oder es gibt Störungen im Netzwerk.</span>" >> $MAIL_TEXT;;
    
      "ORA-12514:")  # Instance Down
      echo "<span style=color:#cc0000;><b>Die Datenbankinstanz ist vermutlich nicht gestartet und folglich nicht beim Listener registriert.</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Falls die Instanz nicht absichtlich heruntergefahren wurde, ist die Instanz vermutlich aufgrund eines Fehlers unten.</span>" >> $MAIL_TEXT;;
   
      "ORA-01034:")  # Instance Down
      echo "<span style=color:#cc0000;><b>Die Datenbankinstanz ist nicht gestartet.</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Falls die Instanz nicht absichtlich heruntergefahren wurde, ist die Instanz vermutlich wegen eines Fehlers unten.</span>" >> $MAIL_TEXT;;
    
      "ORA-12528:")  # Nomount Status
      echo "<span style=color:#cc0000;><b>Die Datenbankinstanz befindet sich im NOMOUNT Status.</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Falls die Instanz nicht absichtlich in diesen Status versetzt wurde, wurde die Datenbank vermutlich wegen eines Fehlers nicht gemounted.</span>" >> $MAIL_TEXT;;
        
      "ORA-01033:")  # Mount or Nomount Status 
      echo "<span style=color:#cc0000;><b>Die Datenbankinstanz befindet sich im NOMOUNT oder MOUNT Status.</b></span>" >> $MAIL_TEXT 
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Falls die Instanz nicht absichtlich in diese Status versetzt wurde, wurde die Datenbank vermutlich wegen eines Fehlers nicht gemounted und geöffnet.</span>" >> $MAIL_TEXT;; 
    
      "ORA-12526:") # Restricted Mode
      echo "<span style=color:#cc0000;><b>Die Datenbankinstanz befindet sich im RESTRICTED Mode.</b> Es sind nur Verbindungen von Benutzern mit dem Restricted Sessions Privileg möglich.</span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Die Datenbankinstanz wurde vermutlich wegen Wartungsarbeiten (Patching, Upgrade) in diesen Mode versetzt.</span>" >> $MAIL_TEXT;;

      "ORA-28040:") # Alter Client
      echo "<span style=color:#cc0000;><b>Das vom Client genutzte Protokoll wird von der Datenbank nicht unterstützt.</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Vermutlich ist der genutzte Client für die eingesetzte Datenbankversion zu alt</span>" >> $MAIL_TEXT;;
       
      "ORA-00257:")  # Archiver Stuck
      echo "<span style=color:#cc0000;><b>Die Datenbank ist blockiert, da keine Archivelogs mehr geschrieben werden können (Archiver Stuck).</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Wahrscheinlich ist das Filesystem oder ASM Disk Group, in dem die Archivelogs geschrieben werden, voll oder die eingestellte maximale Größe der Flash Recovery Area ist erreicht.</span>" >> $MAIL_TEXT;;

      "ORA-12516:") # Max Processes 
      echo "<span style=color:#cc0000;><b>Wahrscheinlich ist die eingestellte maximale Anzahl der Prozesse innerhalb der Instanz erreicht.</b></span>" >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "<span style=color:#cc0000;>Entweder die Anzahl der Sessions ist aufgrund einer erhöhten Last angestiegen oder es gibt einen Fehler in der Anwendung.</span>" >> $MAIL_TEXT;;
    
      *) 
      echo " " >> $MAIL_TEXT
    esac
  fi
  
  # Leerzeichen am Anfang und Ende einer Zeile entfernen 
  /bin/sed -i  's/[ \t]*$//' $MAIL_TEXT
  /bin/sed -i  's/^[ \t]*//' $MAIL_TEXT
  
else
  FIRST_FAILED_CONNECT=no
fi


# Bei erster erfolgreicher Verbindung nach einer fehlerhaften Verbindung, Mailtext erzeugen  
if [ "$CONNECT_STATUS" = "ok" ] && [ -e $FLAG_FILE ]; then
  FIRST_OK_CONNECT=yes
  echo "<span style=color:#008000;><b>Die Datenbankinstanz `echo $ORACLE_SID | tr [a-z] [A-Z]` ist wieder verfügbar!</b></span>" > $MAIL_TEXT
  echo " " >> $MAIL_TEXT
  echo "Es sind wieder Verbindungen mit der auf dem Server $TARGET_HOST befindlichen Datenbankinstanz `echo $ORACLE_SID | tr [a-z] [A-Z]` möglich ($OPERATING_ROLE)." >> $MAIL_TEXT
  
  # Leerzeichen am Anfang und Ende einer Zeile entfernen 
  /bin/sed -i 's/[ \t]*$//' $MAIL_TEXT
  /bin/sed -i 's/^[ \t]*//' $MAIL_TEXT
   
  # Error-Flagfile loeschen
  rm $FLAG_FILE
  
  # Protokoll-Eintrag schreiben
  echo `date +"%d.%m.%Y"` `date +"%H:%M:%S"` CONNECT OK `echo $ORACLE_SID | tr [a-z] [A-Z]` >> $WORKDIR/connect_protokoll.log
  
else
  FIRST_OK_CONNECT=no
fi



# MAILING BEI FIRST FAILED CONNECT

if [ "$FIRST_FAILED_CONNECT" =  "yes" ];then

  export SUBJECT_WARNUNG="WARNUNG - Instance Status `echo $ORACLE_SID | tr [a-z] [A-Z]` @$TARGET_HOST"  
  
  echo "From: $SENDER" > $WORKDIR/mail_$ORACLE_SID.txt
  echo "To: $RECIPIENT" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Subject: $SUBJECT_WARNUNG" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Reply-to: $REPLYTO">> $WORKDIR/mail_$ORACLE_SID.txt
  echo "MIME-Version: 1.0" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "X-Priority: 1 (Highest)" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "X-MSMail-Priority: High" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Content-Type: text/html; charset=iso-8859-1" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Content-Disposition: inline" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "<html>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "<body>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo '<pre style="font-family:Verdana,Arial Black,Tahoma,Calibri,Cambria;"><span style="font-size:14px;">' >> $WORKDIR/mail_$ORACLE_SID.txt
   
  cat $MAIL_TEXT >> $WORKDIR/mail_$ORACLE_SID.txt
 
  echo " " >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "</pre>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "</body>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "</html>" >> $WORKDIR/mail_$ORACLE_SID.txt
   
  # Versand der Mail mit Sendmail 
  /bin/sed 's/ *$//' $WORKDIR/mail_$ORACLE_SID.txt | /usr/sbin/sendmail -t 
   
  # Mail Log-Eintrag schreiben
  echo `date +"%d.%m.%Y"` `date +"%H:%M"`, Betreff: $SUBJECT_WARNUNG ,Empfaenger: $RECIPIENT >> $WORKDIR/mail.log
fi



# MAILING BEI FIRST OK CONNECT

if [ "$FIRST_OK_CONNECT" =  "yes" ];then
  export SUBJECT_OK="OK - Instance Status `echo $ORACLE_SID | tr [a-z] [A-Z]` @$TARGET_HOST"   
  
  # Building sendmail header
  echo "From: $SENDER" > $WORKDIR/mail_$ORACLE_SID.txt
  echo "To: $RECIPIENT" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Subject: $SUBJECT_OK" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Reply-to: $REPLYTO">> $WORKDIR/mail_$ORACLE_SID.txt
  echo "MIME-Version: 1.0" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Content-Type: text/html; charset=iso-8859-1" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "Content-Disposition: inline" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "<html>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "<body>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo '<pre style="font-family:Verdana,Arial Black,Tahoma,Calibri,Cambria;"><span style="font-size:14px;">' >> $WORKDIR/mail_$ORACLE_SID.txt
       
  cat $MAIL_TEXT >> $WORKDIR/mail_$ORACLE_SID.txt
 
  echo " " >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "</pre>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "</body>" >> $WORKDIR/mail_$ORACLE_SID.txt
  echo "</html>" >> $WORKDIR/mail_$ORACLE_SID.txt
   
  # Versand der Mail mit Sendmail 
  /bin/sed 's/ *$//' $WORKDIR/mail_$ORACLE_SID.txt | /usr/sbin/sendmail -t  
 
  # Mail Log-Eintrag schreiben
  echo `date +"%d.%m.%Y"` `date +"%H:%M"`, Betreff: $SUBJECT_OK, Empfaenger: $RECIPIENT >> mail.log
fi


# HOUSEKEEPING

# mail.log
/usr/bin/find $WORKDIR  -iname "mail.log" -size +10M -print -exec bash -c 'zip -rm "${1%.log}".log.`date '+%Y%m%d%H%M'`.zip "$1"' _ {} \;
/usr/bin/find $WORKDIR  -iname "mail.log.*.zip" -mtime +30 -print -exec rm {} \;

# connect_protokoll.log
/usr/bin/find $WORKDIR  -iname "connect_protokoll.log" -size +10M -print -exec bash -c 'zip -rm "${1%.log}".log.`date '+%Y%m%d%H%M'`.zip "$1"' _ {} \;
/usr/bin/find $WORKDIR  -iname "connect_protokoll.log.*.zip" -mtime +30 -print -exec rm {} \;


fi
fi