#!/bin/bash
# +----------------------------------------------------------------------------------------------------+
# | Name:           instance_monitor.sh                                                                |
# | Autor:          Frank Gerasch                                                                      |
# | Datum:          01.06.2017                                                                         |
# | Typ:            Shell-Script (Bash)                                                                |
# | Version:        Mailx Version                                                                      |
# | 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 eingerichtet               |
# |                 3. Mail-Client (mailx) 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 Programmaufruf 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 "Keine vollstaendige Instanzpruefung moeglich!" > $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo "Der Account $DB_USER ist in der Datenbank ${ORACLE_SID%[2|1]} gesperrt." >> $MAIL_TEXT
    echo " " >> $MAIL_TEXT
    echo "Bitte den Grund dafuer ermitteln und den Benutzer entsperren (alter user $DB_USER account unlock;)." >> $MAIL_TEXT
  else    
    echo "Die Datenbankinstanz `echo $ORACLE_SID | tr [a-z] [A-Z]` ist nicht verfuegbar!" > $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]` moeglich ($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 "Unter der angegenenen Adresse $TARGET_HOST:$LISTENER_PORT ist kein Listener erreichbar." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Vermutlich ist der Listener oder Host unten oder es gibt Stoerungen im Netzwerk." >> $MAIL_TEXT;;
    
      "ORA-12514:")  # Instance Down
      echo "Die Datenbankinstanz ist vermutlich nicht gestartet und folglich nicht beim Listener registriert." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Falls die Instanz nicht absichtlich heruntergefahren wurde, ist die Instanz vermutlich aufgrund eines Fehlers unten." >> $MAIL_TEXT;;
   
      "ORA-01034:")  # Instance Down
      echo "Die Datenbankinstanz ist nicht gestartet." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Falls die Instanz nicht absichtlich heruntergefahren wurde, ist die Instanz vermutlich wegen eines Fehlers unten." >> $MAIL_TEXT;;
    
      "ORA-12528:")  # Nomount Status
      echo "Die Datenbankinstanz befindet sich im NOMOUNT Status." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Falls die Instanz nicht absichtlich in diesen Status versetzt wurde, wurde die Datenbank vermutlich wegen eines Fehlers nicht gemounted." >> $MAIL_TEXT;;
        
      "ORA-01033:")  # Mount or Nomount Status 
      echo "Die Datenbankinstanz befindet sich im NOMOUNT oder MOUNT Status." >> $MAIL_TEXT 
      echo " " >> $MAIL_TEXT
      echo "Falls die Instanz nicht absichtlich in diese Status versetzt wurde, wurde die Datenbank vermutlich wegen eines Fehlers nicht gemounted und geoeffnet." >> $MAIL_TEXT;; 
    
      "ORA-12526:") # Restricted Mode
      echo "Die Datenbankinstanz befindet sich im RESTRICTED Mode. Es sind nur Verbindungen von Benutzern mit dem Restricted Sessions Privileg moeglich." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Die Datenbankinstanz wurde vermutlich wegen Wartungsarbeiten (Patching, Upgrade) in diesen Mode versetzt." >> $MAIL_TEXT;;

      "ORA-28040:") # Alter Client
      echo "Das vom Client genutzte Protokoll wird von der Datenbank nicht unterstuetzt." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Vermutlich ist der genutzte Client fuer die eingesetzte Datenbankversion zu alt" >> $MAIL_TEXT;;
       
      "ORA-00257:")  # Archiver Stuck
      echo "Die Datenbank ist blockiert, da keine Archivelogs mehr geschrieben werden koennen (Archiver Stuck)." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Wahrscheinlich ist das Filesystem oder ASM Disk Group, in dem die Archivelogs geschrieben werden, voll oder die eingestellte maximale Groeße der Flash Recovery Area ist erreicht." >> $MAIL_TEXT;;

      "ORA-12516:") # Max Processes 
      echo "Wahrscheinlich ist die eingestellte maximale Anzahl der Prozesse innerhalb der Instanz erreicht." >> $MAIL_TEXT
      echo " " >> $MAIL_TEXT
      echo "Entweder die Anzahl der Sessions ist aufgrund einer erhoehten Last angestiegen oder es gibt einen Fehler in der Anwendung." >> $MAIL_TEXT;;
    
      *) 
      echo " " >> $MAIL_TEXT
    esac
  fi
  
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 "Die Datenbankinstanz `echo $ORACLE_SID | tr [a-z] [A-Z]` ist wieder verfuegbar" > $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]` moeglich ($OPERATING_ROLE)." >> $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"  
  cat $MAIL_TEXT > $WORKDIR/mail_$ORACLE_SID.txt
   
  # Versand der Mail mit Sendmail 
  cat | /bin/mailx -s "$(echo -e "$SUBJECT_WARNUNG \nFrom: $SENDER \nImportance: High")" -S replyto="$REPLYTO" $RECIPIENT < $WORKDIR/mail_$ORACLE_SID.txt
  
  # 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"   
  
       
  cat $MAIL_TEXT > $WORKDIR/mail_$ORACLE_SID.txt
    
  # Versand der Mail mit Sendmail 
  /bin/mailx -s "$(echo -e "$SUBJECT_OK \nFrom: $SENDER ")" -S replyto="$REPLYTO" $RECIPIENT < $WORKDIR/mail_$ORACLE_SID.txt
  
  # 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