Pages

Tuesday, December 1, 2015

RMAN Backup. Example of backup code

backup.ini
RMAN_BACKUP_DIR=/backup/ora_online
RMAN_RETENTION_REDUNDANCY=1
RMAN_GENERAL_LOG=/etc/sh/backup/log/backup_general.log
RMAN_ARCH_BACKUP_THRESHOLD=20
RMAN_ARCH_DELETE_THRESHOLD=10
#RMAN_READRATE=4

REPORT_SMTP_SERVER=x.y.z.w
REPORT_SMTP_TO=user@someplace.com

backuptab
#@ backuptab file format:
#@
#@ sid:backup-type:arch-dest
#@
#@ sid         - name of sid to backup
#@ backup-type - F (full) or I (incremental, NYI)
#@ arch-dest   - a comma-separated archive destination locations
igt:F:/oracle_db/db2/db_igt/arch
gin:F:/cygdrive/m/oracle_db/db2/db_gin/arch 


backupFunctions.sh
#!/bin/bash
#@ backupFunctions
#@
#@ this script is used by other backup scripts to load common functions.
#@
#@ available functions:
#@  createTmpFile     - generates a name for a temporary file
#@  getBackupLogName  - translates the backup log name to the appropriate
#@                      platform (windows vs. *nix)
#@  getFromIni        - retrieves a parameter from the backup.ini file
#@  getOsFilename     - translates a filename to a platform specific form
#@  getRmanScriptName - translates the rman script name to the appropriate
#@                      platform (windows vs. *nix)
#@  loadOracle        - loads the oracle environment variable for a specific
#@                      instance
#@  setSymbols        - sets symbols for common execution files such as awk,
#@                      and rman for the specific platofrm (gawk vs. awk, etc.)
#@  showVersion       - display the version number of the running script
#@                      according to the Revision cvs parameter
#@
# written by Amir Kibbar
#
# $Revision: 543 $
#
# Changelog:
# +-------------+------+-------------------------------------------------------+
# | 12-DEC-2004 | Amir | Initial version                                       |
# +-------------+------+-------------------------------------------------------+

showVersion() {
  version=`grep "# \\$Revision" $0 | awk -F"$" '{print $2}' | cut -d " " -f2`
  echo "$FACILITY version $version"
  exit
}

createTmpFile() {
  if [ $OS = "SunOS" ]; then
    # the sleep here is to make sure the filename is unique. Solaris does not
    # support milliseconds
    sleep 1
    tmpFile="/tmp/rman_$$`date '+%M%S'`"
    touch $tmpFile
  elif [ ! -x /usr/bin/mktemp -a ! -x /bin/mktemp ]; then
    tmpFile="/tmp/rman_$$`date +%s`"
    touch $tmpFile
  else
    tmpFile=`mktemp /tmp/rman_XXXXXX`
  fi
}

getFromIni() {
  local param=$1
  iniValue=`grep -v "#" $BACKUPINI | grep $param`
  if [ -n "$iniValue" ]; then
    iniValue=`echo $iniValue | cut -d= -f2`
  fi
}

loadOracle() {
  local oraSid=$1
  echo $FACILITY `date` INFO- loading Oracle env for $oraSid
  . $ORASH/oracle_login.sh $oraSid

  FACILITY=`basename $0 .sh`\:

  if [ -z "$ORACLE_ENV_DEFINED" ]; then
    echo "$FACILITY `date` ERR- can't load Oracle env for $oraSid"
    exit
  fi
}

setSymbols() {
  if [ -z "$ORACLE_HOME" -a -n "$CYG_ORACLE_HOME" ]; then
    RMAN=$CYG_ORACLE_HOME/bin/rman
  else
    RMAN=$ORACLE_HOME/bin/rman
  fi

  AWK=awk
  GREP=grep
  PATH_SEP=/
  LINE_SEP=\\n
  OS=`uname | cut -d_ -f1`
  SUDO=sudo
  
  if [ $OS = "Linux" ]; then
    DF="df -klP"
  elif [ $OS = "SunOS" ]; then 
    AWK=/usr/sfw/bin/gawk
    DF="df -k"
    GREP="ggrep"
  elif [ $OS = "CYGWIN" ]; then
    DF="df -k"
    PATH_SEP=\\
    LINE_SEP=\\r\\n
    SUDO=false
  fi
}

getOsFilename() {
  if [ $OS = "CYGWIN" ]; then
    filename=`cygpath -w $1`
  else
    filename=$1
  fi
}

getRmanScriptName() {
  local tmpFile=$1

  getOsFilename $tmpFile
  rmanScript=$filename
}

getBackupLogName() {
  local backupDest=$1

  getOsFilename $backupDest
  backupLog=$filename
}

if [ "$1" = "--help" ]; then
  setSymbols
  grep ^"#@" $0 | $AWK -F "#@" '{print $2}'

fi 


rmanBackup.sh
#!/bin/bash
#@ rmanBackup [-h | -v] | [[-tab backuptab] [-ini backup.ini] instance-name]
#@
#@ backs up a database instance using rman
#@
#@ -h              - this message
#@ -v              - display version number
#@ instance-name   - name of instance to backup.
#@                   Default: ORACLE_SID
#@ -tab backuptab  - use backuptab at the specified location.
#@                   Default: BACKUPTAB
#@ -ini backup.ini - use backup.ini at the specified location.
#@                   Default: BACKUPINI
#@
#@
#
# written by Amir Kibbar
#
# $Revision: 243 $
#
# Changelog:
# +-------------+------+-------------------------------------------------------+
# | 12-DEC-2004 | Amir | Initial version                                       |
# +-------------+------+-------------------------------------------------------+

BACKUPTAB=$BACKUP_ROOT/backuptab
BACKUPINI=$BACKUP_ROOT/backup.ini
FACILITY=`basename $0 .sh`\:
DATE=`date`
sid=$ORACLE_SID

. $BACKUP_ROOT/internal/backupFunctions.sh

usage() {
  grep ^"#@" $0 | awk -F "#@" '{sub("ORACLE_SID",ORACLE_SID,$2); sub("BACKUPTAB",BACKUPTAB,$2); sub("BACKUPINI",BACKUPINI,$2); print $2}' ORACLE_SID=$ORACLE_SID BACKUPTAB=$BACKUPTAB BACKUPINI=$BACKUPINI

  echo
  grep ^"#@" $BACKUPTAB | awk -F "#@" '{print $2}'
  exit
}

while [ -n "$1" ]; do
  case "$1" in
    -h)
      usage
      ;;
    -v)
      showVersion
      ;;
    -tab)
      shift
      BACKUPTAB=$1
      if [ -z "$BACKUPTAB" ]; then
        echo $FACILITY `date` ERR- must specify backuptab location
        exit
      fi
      ;;
   -ini) 
      shift
      BACKUPINI=$1
      if [ -z "$BACKUPINI" ]; then
        echo "$FACILITY `date` ERR- must specify backup.ini location"
        exit
      fi
      ;;
    *)
      sid=$1
      ;;
  esac
  shift
done

if [ ! -r $BACKUPTAB ]; then
  echo "$FACILITY `date` ERR- can't read $BACKUPTAB. Permission denied or file not found"
  exit
fi

if [ ! -r $BACKUPINI ]; then
  echo "$FACILITY `date` ERR- can't read $BACKUPINI. Permission denied or file not found"
  exit
fi

if [ -z "$sid" ]; then
  echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` ERR- must specify ORACLE_SID"
  exit
fi

loadOracle $sid
tabLine=`grep $sid $BACKUPTAB`
backupType=`echo $tabLine | cut -d: -f2`

getFromIni RMAN_GENERAL_LOG
generalLog=$iniValue

case $backupType in
  F)
  echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- executing Oracle full backup using rman for sid: $sid" | tee -a $generalLog
  $BACKUP_ROOT/internal/fullRmanBackup.sh $sid $BACKUPTAB $BACKUPINI 
esac


fullRmanBackup.sh
#!/bin/bash
#@ fullRmanBackup [-h | -v] sid backuptab backupini
#@
#@ backs up a database instance using rman with the full-backup scheme. This
#@ script is an internal script, and is only intended to be run from the
#@ backup.sh script. However, it is possible to run this script on its own,
#@ just make sure the parameters are passed correctly - it does not verify them
#@
#@ -h        - this message
#@ -v        - display version
#@ sid       - Oracle sid to backup
#@ backuptab - backuptab location
#@ backupini - backupini location
#@
#@
#
# written by Amir Kibbar
#
# $Revision: 7026 $
#
# Changelog:
# +-------------+------+-------------------------------------------------------+
# | 12-DEC-2004 | Amir | Initial version                                       |
# +-------------+------+-------------------------------------------------------+
# | 31-JAN-2010 |Yossi | Adapt to streams; write more to log; keep logs longer |
# +-------------+------+-------------------------------------------------------+

FACILITY=`basename $0 .sh`\:
. $BACKUP_ROOT/internal/backupFunctions.sh

setSymbols

usage() {
  grep ^"#@" $0 | $AWK -F "#@" '{print $2}'

  exit
}

if [ "$1" = "-h" ]; then
  usage
fi

if [ "$1" = "-v" ]; then
  showVersion
fi

sid=$1
shift
BACKUPTAB=$1
shift
BACKUPINI=$1
shift

getFromIni RMAN_BACKUP_DIR
backupDestRoot=$iniValue

getFromIni RMAN_RETENTION_REDUNDANCY
retentionRedundancy=$iniValue

getFromIni RMAN_GENERAL_LOG
generalLog=$iniValue

getFromIni RMAN_READRATE
readRate=$iniValue

echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- rman backup started for instance $sid" | tee -a $generalLog

#echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- creating backup destination"
TIMESTAMP=`date +%Y%m%d_%H%M`
backupDest=$backupDestRoot/$TIMESTAMP
#echo $backupDest
mkdir -p $backupDest

# this is done to allow oracle to write in the backup dest, even if the running
# user is not oracle
#echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- setting acls" | tee -a $backupLog
$SUDO $INFRA_ROOT/bin/set_rman_perm.sh

if [ ! -d $backupDestRoot/for_backup/log ]; then
  mkdir -p $backupDestRoot/for_backup/log
fi

if [ $OS = "CYGWIN" ]; then
  rmanBackupDest=`cygpath -w $backupDest`
  pathSep=\\
  lineSep=\\r\\n
else
  rmanBackupDest=$backupDest
  pathSep=/
  lineSep=\\n
fi

createTmpFile 

#echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- creating rman script"

# the current backup script only backs up using autobackup because of rman
# bug #4110708

# We aim to backup all archivelog needed for restore.
# using sysdate-10/1440 (10 mins) might miss some archives for long running backup
# Instead we take timestamp at the beginning of backup session. 
BACKUP_TIMESTAMP="TO_DATE('`date +%Y:%m:%d:%H:%M`','YYYY:MM:DD:HH24:MI')-10/1400"

echo "run {" >> $tmpFile
echo "  configure controlfile autobackup on;" >> $tmpFile
echo "  configure backup optimization on;" >> $tmpFile
echo "  set controlfile autobackup format for device type disk to '${rmanBackupDest}${pathSep}%F';" >> $tmpFile
echo "  allocate channel 'dev_0' type disk format = '${rmanBackupDest}${pathSep}dbf_%d_%T_%U';" >> $tmpFile
if [ -n "$readRate" ]; then
  echo "  set limit channel 'dev_0' readrate=$readRate;" >> $tmpFile
fi
echo "  backup full database;" >> $tmpFile
#echo "  backup current controlfile format '${rmanBackupDest}${pathSep}ctl_%d_%T_%U';" >> $tmpFile
#echo "  backup spfile format '${rmanBackupDest}${pathSep}spfile_%d_%T_%U' ;" >> $tmpFile
echo "  backup archivelog from time = \"$BACKUP_TIMESTAMP\" format '${rmanBackupDest}${pathSep}arch_%d_%T_%U';" >> $tmpFile
echo "  release channel 'dev_0';" >> $tmpFile
echo "}" >> $tmpFile

#echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- running rman script"

getRmanScriptName $tmpFile

getBackupLogName $backupDestRoot/backup.log

if [ -f $backupLog ]; then
#  echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- rotating backup log"

  for ((i=$retentionRedundancy ; i>0 ; --i )) do
    let c=i-1
    if [ -f ${backupLog}.${c} ]; then
      \mv -f ${backupLog}.${c} ${backupLog}.${i}
    fi
  done
  \mv -f $backupLog ${backupLog}.1
fi

echo "backup $backupDest" >> $backupLog

$RMAN target / @ $rmanScript >> $backupLog
\rm -f $tmpFile

echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- rman target backup has finished" >> $backupLog 

# move backup to the for_backup directory
echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- moving finished backup to for_backup" >> $backupLog
\mv $backupDest $backupDestRoot/for_backup/$TIMESTAMP

createTmpFile 
obsoleteFile=$tmpFile.obsolete

# get the obsolete directories list
echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- obtaining obsolete directories list" >> $backupLog
$RMAN target / << zZ | tee -a $backupLog > $obsoleteFile
report obsolete redundancy = $retentionRedundancy;
exit;
zZ

dirList=`cat $obsoleteFile | grep "Backup Piece" | $AWK '{print $5}' | $AWK -F"$PATH_SEP" '{print $(NF-1)}' | sort | uniq`

# Moving backup directories containing obsolete files from the for_backup to root directory
# It maybe that directory was already moved in previous run of the script
# as the data files and control file backup kits were obsolete but archives were still required,
# thus the backup directory is already located at the root dir. 
for currDir in $dirList ; do
  if [ -a $backupDestRoot/for_backup/$currDir ]; then
    echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- moving $currDir from for_backup to backup root" >> $backupLog
    \mv $backupDestRoot/for_backup/$currDir $backupDestRoot/
  fi
done

\rm -f $obsoleteFile

# this is required again to allow a user other than oracle that is running the
# script to delete the files that rman create. These files are always created
# owned by oracle:dba
#echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- setting acls" | tee -a $backupLog
$SUDO $INFRA_ROOT/bin/set_rman_perm.sh

#check if oracle streams capture is defined on the DB
sqlplus /nolog << EOD  | grep -qi -e "streams0streams"
connect /
select 'streams'||count(*)||'streams' from  dba_capture;
exit
EOD

streams_status=$?

echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- deleting obsolete backup sets" >> $backupLog
if [ $streams_status -eq 0 ]; then
# Streams capture not configured on the db
$RMAN target / << zZ >> $backupLog
allocate channel for delete type disk;
delete noprompt force archivelog all backed up $retentionRedundancy times to device type disk;
delete noprompt force copy of archivelog all completed before 'sysdate-10';
delete noprompt force obsolete redundancy = $retentionRedundancy;
release channel;
exit;
zZ
  else
# Streams capture configured on the db
# We would like to avoid delegation of archives required by streams
# Delete obsolete is streams aware (note id 421176.1)
$RMAN target / << zZ >> $backupLog
allocate channel for delete type disk;
delete noprompt force obsolete redundancy = $retentionRedundancy;
release channel;
exit;
zZ
fi

echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- removing empty directories" >> $backupLog

for currDir in $dirList ; do
  echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- removing $currDir" >> $backupLog
  if [ $(ls -A $backupDestRoot/$currDir | wc -l) -eq 0 ]; then 
# direcory is empty 
    if [ $OS != "SunOS" ]; then
      \rmdir --ignore-fail-on-non-empty $backupDestRoot/$currDir
      else
      \rmdir $backupDestRoot/$currDir
    fi
  fi
done

# keep copy of backup log
cp $backupLog $backupDestRoot/for_backup/log/rman_$TIMESTAMP.log 

# Purge old log and err files older than 60 days
find $backupDestRoot/for_backup/log/ -mtime +60 \( -name '*.log' -o -name '*.err' \) -exec rm -f {} \;


echo "$FACILITY `date +"%d-%m-%Y %H:%M:%S"` INFO- rman backup finished for sid $sid" | tee -a $generalLog 

No comments:

Post a Comment