… ou YASHTBODB: Yep, Another Shell Script To Backup Oracle DataBase!
Já faz algum tempo que utilizo Shell Script para fazer backup no Oracle. Na verdade eu prefiro utilizar outras linguagens de programação, particularmente o PERL, para não precisar ficar chamando o SQL*Plus toda hora. Mas como existe uma barreira cultural por aqui, acabou ficando tudo em Shell Script mesmo. Bom, ocorre que chegou a hora de aposentá-los em favor do RMAN. Sim, com o uso do RAC junto com o ASM, backup manual ou “user managed backup” como a Oracle gosta de dizer, perdeu completamente o sentido. Além disso, no Oracle 10g, o Database Control implementou uma série de alertas sofisticados bem mais eficientes que o singelo script aqui em questão. Estou terminando de implantar o RMAN para todos os últimos servidores e então os últimos scripts cairão finalmente no ostracismo. Então estou publicando-os aqui, para que sirvam de referência futura.
Requisitos
Rotinas executadas a cada 30 minutos:
- Cópia dos archives para outro servidor;
- Criação de alerta se alguma partição possuir mais de 80% e 95% de ocupação.
Rotinas executadas a cada 24 horas:
- Rodar o analyze em todos objetos;
- Fazer backup lógico full;
- Copiar backup lógico para outro servidor;
- Verificar a integridade dos datafiles;
- Fazer cópia on-line dos datafiles permanentes para outro servidor;
- Verificar o volume de origem e o copiado dos datafiles;
- Fazer cópia do control_file em modo binário e lógico;
- Fazer cópia do spfile;
- Apagar archives com mais 8 dias;
- Verificar se algum tablespace está com mais de 80% de ocupação;
- Verificar todos os erros ocorridos no alert;
- Renomear o alert para um nome com o SID e data
Rotinas executadas a cada 7 dias:
- Cópia off-line dos datafiles permanentes para outro servidor;
- Cópia do spfile
Rotina mensal (realizadas no último dia de cada mês):
- Rodar scripts específicos de aplicações
- Arquivar todos os logs (adump, bdump, cdump, udump e backup logs) em uma pasta ‘old’
Outros requisitos:
- Criar um log contendo todos os erros ocorridos durante todas operações de backup;
- Registrar no log a duração de todas operações longas;
- Registrar no log o espaço disponível em cada partição de disco;
- Enviar um e-mail com o log ao término de cada operação de backup;
- Parametrizar o script de forma a utilizar o mesmo script para vários servidores distintos.
Preparação
Antes de mais nada, é preciso criar um usuário no SO e no Oracle. É preciso se assegurar que o usuário em questão tenha acesso às pastas que ele irá copiar. Existem pelo menos umas 4 formas de se fazer isso:
- Utilizar o próprio usuário Oracle. A vantagem de usar o usuário Oracle do SO, é não precisar colocar senha no script, por outro lado a pessoa que administra o script acaba tendo autorização para acessar o banco diretamente sem senha e com poderes de SYSDBA. Em termos de segurança, isto não é recomendado. No entanto, os backups off-lines e backups de spfile exigem o usuo de um usuário com permissões de SYSDBA ou SYSOPER, então acaba fazendo sentido utilizar o usuário Oracle do SO para estas operações;
- Alterar as permissões nas pastas do banco de dados para permitir a leitura para que qualquer usuário do SO (o terceiro dígito no sistema octal de permissões). Não gosto desta solução por problemas de segurança, uma vez que não apenas o usuário de backup como outros também terão acesso aos arquivos do Oracle. Se for para fazer isso, ainda é melhor usar o usuário Oracle do SO mesmo para tudo;
- Alterar os grupos donos dos arquivos e pastas a serem utilizados. Também não é uma boa idéia, uma vez que ao criar um novo datafile, ele é criado com o grupo oinstall por padrão. A cada vez que um novo datafile é criado, você teria de alterar o grupo do datafile;
- Adicionar o usuário de backup ao grupo oinstall. Pode não ser uma solução muito segura, mas veja que os datafiles são criados com a permissão 640 por padrão. O que significa que o usuário em questão só poderá ler os datafiles sem poder alterá-los, o que me parece bem razoável. Mesmo assim, você deverá acertar o acesso de algumas pastas e arquivos para que você possa gravar nelas, como a pasta onde o próprio script vai ficar e onde ele vai gerar os logs e os backups lógicos. Esta será a opção utilizada para a maioria das operações de backup. A excessão, como citado anteriormente fica para o backup do spfile e backup off line.
Para criar um usuário no SO que faça parate do grupo ‘oinstall’ (realmente estou supondo que você usou o nome dos usuários e grupos de usuáros padrões da instalação):
/usr/sbin/useradd -m -p senha -g oinstall -c 'Usuário que dispara os scripts de backup' backup
O mesmo usuário do SO deverá ter um correspondente dentro do banco de dados:
CREATE USER backup IDENTIFIED BY senha DEFAULT TABLESPACE users QUOTA UNLIMITED ON users ;
Se você quiser utilizar um usuário a parte mas não quer colocar a senha do usuário nos scripts (que é o que foi feito no nosso exemplo), pode criar o usuário com o comando abaixo:
CREATE USER backup IDENTIFIED EXTERNALLY DEFAULT TABLESPACE users QUOTA UNLIMITED ON users ;
Mas para utilizar usuários autenticados externamente (pelo SO) não esqueça de setar no ‘init.ora’ os seguintes parâmetros:
remote_os_authent=FALSE os_authent_prefix=''
O parâmetro ‘os_authent_prefix’ é opcional e permite que o nome no SO seja idêntico ao nome no banco de dados. Já o parâmetro ‘remote_os_authent’ é vital para garantir a segurnaça do banco de dados. O padrão do parâmetro é ‘FALSE’ e ninguém em sã consciência utiliza este parâmetro como ‘TRUE’.
Depois de criar o usuário precisamos conceder as permissões adequadas para ele:
GRANT CREATE SESSION TO backup; GRANT ALTER SESSION TO backup; GRANT ALTER DATABASE TO backup; GRANT ALTER SYSTEM TO backup; GRANT MANAGE TABLESPACE TO backup; GRANT ANALYZE ANY TO backup; GRANT ANALYZE ANY DICTIONARY TO backup; GRANT EXP_FULL_DATABASE TO backup;
Lembre-se de O usuário também deve ter um tablespace com alguma quota para criar as tabelas de logs do backup lógico (coisas do data pump a partir do 10g). O comando CREATE USER cria o usuário, com a senha: ‘senha’. Depois concedemos privilégio para o usuário se conectar no banco de dados em CREATE SESSION. O privilégio ALTER SESSION será utilizado para ajudar a identificar o backup lógico do control file enquanto o privilégio ALTER DATABASE é utilizado para realizar o backup físico e lógico do control file propriamente dito. O privilégio ALTER SYSTEM é necessário para realizar o checkpoint e o rotacionamento dos logs durante o backup físico on line enquanto o privilégio MANAGE TABLESPACE permite a operação de backup on line propriamente dita. Note que aqui a permissão de leitura dos datafiles pelo usuário do SO é necessária também. Depois temos os privilégios ANALYZE e ANALYZE ANY DICTIONARY necessários para as atualizações de estatísticas das tabelas e índices. Note que o privilégio ANALYZE ANY DICTIONARY surge apenas no Oracle 10g, não existindo nem sendo necessário em versões anteriores. Por último vem o privilégio EXP_FULL_DATABASE que é necessário para o backup lógico.
Se você for utilizar o Data Pump (muito recomendado e utilizado no nosso exemplo), a nova ferramente de backup lógico da Oracle a partir da versão 10g, você deverá utilizar também os seguintes comandos SQL:
CREATE DIRECTORY data_pump_dir_ORACLE_SID AS '/u03/app/oracle/admin/ORA_SID/exp'; GRANT READ, WRITE ON DIRECTORY data_pump_dir_ORA_SID
Onde ‘ORACLE_SID’ é o nome do seu banco de dados oracle. É claro que o ponto de montagem ‘/u03’ é específico do padrão que adoto nos meus servidores. Substitua o caminho do diretório para aquele que você reservou no seu servidor. Lembre-se que este diretório deve ser criado manualmente e o usuário ‘backup’ ou o grupo ‘oinstall’ do SO devem ter permissões de leitura e gravação neste diretório:
mkdir -p /u03/app/oracle/admin/ORA_SID/exp chown backup:oinstall /u03/app/oracle/admin/ORA_SID/exp chmod 755/u03/app/oracle/admin/ORA_SID/exp
Outras permissões deverão ser acertadas para o usuário de backup no SO como a permissão para apagar os archives (com uma permissão 770 na pasta por exemplo). Alguns acertos podem ser um pouco chatos e devem ser realizados no servidor de destino onde os arquivos são copiados também.
Um último detalhe é que é preciso configurar o SSH sem senha entre os servidores onde está o servidor Oracle e e o que vai receber todos os backups. Meus testes com NFS mostraram que ele é menos estável que o SSH e a diferença de performance é mínima. Existem vários tutoriais sobre como fazer isso, inclusive este da própria Oracle. No meu caso eu criei um usuário backup e um usuário oracle no servidor de destino e gerei o ssh sem senha entre os usuários com mesmo nome nos servidores de origem e destino dos backups.
Funcionamento do Script
Algumas premissas foram assumidas antes de criar o script:
- O mesmo script deveria ser utilizado independente do banco de dados que sofreria as operações. Para isso o script deve receber como parâmetro o nome do banco e todas as pastas devem receber o nome do banco também, seguindo as recomendações do OFA. Isto facilita e muito a utilização do mesmo script em vários servidores distintos ou quando temos mais de uma instância no mesmo servidor.
- O mesmo script deveria ser utilizado para diversas operações diferentes. Para isso o script deve receber como parâmetro o nome da operação.
- Excepto pelos parâmetros de nome da base e operação, todas as outras variáveis são identicas, sendo declaradas no início do script. Esta configuração é adequada para o caso onde se utiliza apenas um ORACLE_HOME para todas as bases do servidor, mas pode ser um problema em outros casos.
- Ao invés de colocar todo o código SQL em arquivos separados e chamarmos eles pelo SQL*Plus, optei por colocar todo o códio SQL dentro do script e envia-lo para o SQL*Plus utilizando o redirecionamento conhecido como “here document”, que é algo como um <<EOF … EOF onde “…” é o código SQL.
- Todas as chamadas do scripts seriam chamados a partir do crontab do usuário, mas isto não impede a chamada manual.
- Cada etapa do backup é colocada em uma função separada, de forma a podermos realocar as etapas para diferentes situações em necessidades específicas (como em servidores de teste e produção). A forma como o script está configurado aqui é apenas um exemplo. Em produção, tenho uma série de outras funções específicas de nossas regras de negócio que foram removidas também.
- O backup lógico aqui está sendo feito com o Data Pump, mas nada impede você de adaptar o script para utilizar a ferramenta tradicional de export da Oracle.
Variáveis de Ambiente
Antes de passar para os scripts de backup, segue abaixo algumas variáveis utilizadas não apenas pelos scripts em shell, como também os scripts em SQL. Vale a pena lembrar que quando os scripts são executados no modo não interativo (como quando chamados pelo cron) é comum que os arquivos .bashrc e .bash_profile ignorem suas configurações. Por via das dúvidas, vamos exportar todas as variáveis de ambiente do Oracle e outros que serão úteis em nossos scripts.
- ORACLE_HOME : o diretório onde o SGDB Oracle foi instalado;
- ORACLE_SID : o nome do banco de dados alvo das operações de backup;
- SQLPATH : o diretório padrão do SQL*Plus para armazenamento de scripts SQL;
- NLS_LANG : Diz respeito a localização e codificação de caracteres utilizados;
- PATH : deve incluir o caminho para o diretório com os aplicativos Oracle;
- dia : referência para saber a data em que a operação foi realizada. Gosto de utilizar o formato ano/mês/dia, pois é mais fácil de listar em órdem cronológica arquivos com este formato de data;
- log : arquivo contendo o log de toda a operação;
- arch_dest : local de destino local para os archives;
- dump_dest : local de destino local para os backups lógicos;
- remote_dest : nome ou ip do servidor remoto que receberá os backups
- dados: nome dos pontos de montagem onde se encontram os datafiles;
- oracle_mail : email para onde os logs e alertas serão enviados;
Chamadas no crontab
Segue aqui as chamadas utilizadas para acionar o script
00 06 1 * * /u01/app/oracle/admin/nome_base/adhoc/backup.sh nome_base rotina_mensal 00 22 * * * /u01/app/oracle/admin/nome_base/adhoc/backup.sh nome_base backup_noturno 00,30 * * * * /bin/bash /u01/app/oracle/admin/nome_base/adhoc/backup.sh nome_base copia_archives
Note que para realizar as rotinas de backup off line, é preciso do privilégio de SYSDBA para fechar e abrir a instância. Então se você utiliza um usuário separado para o backup, deverá colocar a linha abaixo no crontab do usuário oracle do SO e não usuário backup.
00 00 * * 0 /u01/app/oracle/admin/nome_base/adhoc/backup.sh nome_base backup_off_line
O Script
Bom, chega de enrolação, segue abaixo o script. Se você encontrar algum erro (eu tive que tirar algumas coisas muito específicas aqui do trabalho) ou alguma forma de melhorar ele, por favor deixe um comentário ou mande um e-mail.
#!/bin/bash ###################################################################################### # Arquivo: backup.sh # # Uso: Script para backup "user managed" de bancos de dados Oracle # # Criado por: Fábio Telles # # Última alteração: 14/08/2008 # # Motivo: Publicação # ###################################################################################### # TODO: Refazer todo script em PERL ;-) # ###################################################################################### # Verificação de parâmetros ORACLE_SID=$1 operation=$2 if [ -z $operation ]; then echo "***** Favor definir a operação a ser executada" echo "***** chamada $0 $* ilegal" echo "***** uso: $0 " exit 2 fi if [ -z $ORACLE_SID ]; then echo "***** Favor definir o nome do banco de dados" echo "***** chamada $0 $* ilegal" echo "***** uso: $0 " exit 2 fi # Definição de variáveis (variáveis referenciadas fora do script precisam ser exportadas) export ORACLE_SID export ORACLE_BASE=/opt/app/oracle export ORACLE_HOME=${ORACLE_BASE}/product/10.2.0/db_1 export LD_LIBRARY_PATH=${ORACLE_HOME}/lib export SQLPATH=/u01/app/oracle/admin/${ORACLE_SID}/adhoc export NLS_LANG=Portuguese_Brazil.WE8ISO8859P1 export PATH=$PATH:${ORACLE_HOME}/bin export dia=`date +%Y-%m-%d` export log=/u01/app/oracle/admin/${ORACLE_SID}/backup/${operation}_${dia}.log export arch_dest=/u02/app/oracle/admin/${ORACLE_SID}/arch export dump_dest=/u03/app/oracle/admin/${ORACLE_SID}/exp export remote_dest=seu_servidor_backup dados=(/u04 /u05) oracle_mail=email_do_dba@sua_empresa.com.br # Uma função para cada rotina copia_archives() { rsync -t ${arch_dest}/* ${remote_dest}:${arch_dest} 2>> $log if [ $? -ne 0 ]; then cat $log | mail -s "Erros na cópia de archives de `uname -n` p/ $remote_dest em ${dia}" $oracle_mail fi } verifica_discos() { # Verifica se alguma partição montada tem mais de 80% e 95% de ocupação for part in `df -hlP -t ext3 | cut -c0-9` ;do df $part > /dev/null 2> /dev/null if [ $? -eq 0 ]; then mount=`df $part | tail -1 | awk '{print $6}'` percent=`df $part | tail -1 | awk '{print $5}'` if [ ${percent%%} -gt 80 -a ${percent%%} -lt 95 ]; then echo "Atenção: `uname -n` c/ $part montada em $mount está c/ $percent ocupado." >> $log cat $log | mail -s "Alerta de disco em `uname -n`!" $oracle_mail elif [ ${percent%%} -ge 95 ]; then echo "ATENÇÃO URGENTE: `uname -n` c/ $part montada em $mount está c/ $percent ocupado." >> $log cat $log | mail -s "ALERTA CRÍTICO de disco em `uname -n`!" $oracle_mail fi fi done } analize() { echo "Analyze: analizando ${ORACLE_SID} em "`date +%R:%S` >> $log sqlplus -S / <> $log 2>> $log } backup_logico() { echo "Backup lógico: removendo exports de ${dump_dest} em "`date +%R:%S` >> $log rm -v ${dump_dest}/${ORACLE_SID}_full_* >> $log 2>> $log echo "Backup lógico: export iniciado em "`date +%R:%S` >> $log expdp / full=y directory=data_pump_dir_${ORACLE_SID} dumpfile=${ORACLE_SID}_full_${dia}.dmp logfile=${ORACLE_SID}_full_exp_${dia}.log tail -n 1 ${dump_dest}/${ORACLE_SID}_full_exp_${dia}.log >> $log 2>> $log echo "Backup lógico: copiando dump para ${remote_dest}/${dump_dest} em "`date +%R:%S` >> $log scp ${dump_dest}/${ORACLE_SID}_full_${dia}.dmp ${remote_dest}:${dump_dest}/${ORACLE_SID}_full_${dia}.dmp >> $log 2>> $log scp ${dump_dest}/${ORACLE_SID}_full_exp_${dia}.log ${remote_dest}:${dump_dest}/${ORACLE_SID}_full_exp_${dia}.log >> $log 2>> $log echo "" >> $log } verifica_data_file() { echo "Verificação física on-line iniciada em "`date +%R:%S` >> $log sqlplus -S / <> ${SQLPATH}/db_verify.log' FROM dba_data_files ORDER BY tablespace_name, file_name; SPOOL OFF @db_verify.txt EXIT EOF_VERIFICA_DATA_FILE egrep --color -n -B 7 -A 9 'Total Pages Failing.*(Data).*[^0]$' ${SQLPATH}/db_verify.log >> $log 2>> $log egrep --color -n -B 9 -A 7 'Total Pages Failing.*(Index).*[^0]$' ${SQLPATH}/db_verify.log >> $log 2>> $log egrep --color -n -B 14 -A 2 'Total Pages Marked Corrupt.*[^0]$' ${SQLPATH}/db_verify.log >> $log 2>> $log echo "" >> $log 2>> $log } backup_fisico_on_line() { echo "Backup físico on-line: copiando data files para ${remote_dest} em "`date +%R:%S` >> $log sqlplus -S / <> $log' command FROM dba_data_files a, dba_tablespaces b WHERE a.tablespace_name = b.tablespace_name AND b.contents != 'TEMPORARY' UNION SELECT '4' ordem, tablespace_name, 'ALTER TABLESPACE ' || tablespace_name || ' END BACKUP;' command FROM dba_tablespaces WHERE contents != 'TEMPORARY' ) ORDER BY tablespace_name, ordem; SELECT 'ALTER SYSTEM ARCHIVE LOG CURRENT;' FROM dual; SELECT 'EXIT;' FROM dual; SPOOL OFF SET PAGES 50 SPOOL ${SQLPATH}/backup_on_line.log @${SQLPATH}/backup_on_line.txt SPOOL OFF EOF_BACKUP_ON_LINE egrep --color -n -B 2 '(ORA-|SP2-)' ${SQLPATH}/backup_on_line.txt >> $log 2>> $log egrep --color -n -B 2 '(ORA-|SP2-)' ${SQLPATH}/backup_on_line.log >> $log 2>> $log echo "" >> $log } compara_backup_fisico() { echo "Backup físico on-line: comparando origem e destino em "`date +%R:%S` >> $log echo "Backup físico on-line: origem =" >> $log 2>> $log for p in ${dados[*]}; do du -hs ${p}/oradata/${ORACLE_SID} --exclude temp* >> $log 2>> $log done echo "Backup físico on-line: destino =" >> $log 2>> $log for p in ${dados[*]}; do ssh $remote_dest du -hs ${p}/oradata/${ORACLE_SID} >> $log 2>> $log done echo "" >> $log } backup_control_file() { echo "Backup físico on-line: copiando control files para ${ORACLE_HOME}/dbs em "`date +%R:%S` >> $log sqlplus -S / <> $log' FROM v$parameter par, v$instance ins, v$process pro, v$session ses WHERE par.name='user_dump_dest' AND ses.sid = SYS_CONTEXT ('USERENV', 'SID') AND ses.paddr = pro.addr ; SPOOL OFF SPOOL ${SQLPATH}/backup_control_file.log ALTER SESSION SET TRACEFILE_IDENTIFIER = 'control_file'; ALTER DATABASE BACKUP CONTROLFILE TO TRACE; ALTER SESSION SET TRACEFILE_IDENTIFIER = ''; @${SQLPATH}/backup_control_file.txt ALTER DATABASE BACKUP CONTROLFILE TO '${ORACLE_HOME}/dbs/control_file_back.bin' REUSE; SPOOL OFF EOF_BACKUP_ON_LINE egrep --color -n -B 2 '(ORA-|SP2-)' ${SQLPATH}/backup_control_file.txt >> $log 2>> $log egrep --color -n -B 2 '(ORA-|SP2-)' ${SQLPATH}/backup_control_file.log >> $log 2>> $log echo "" >> $log } backup_dbs() { echo "Backup físico on-line: copiando ${ORACLE_HOME}/dbs para ${remote_dest}:${ORACLE_HOME}/dbs_${ORACLE_SID}.tar.bz2 em "`date +%R:%S` >> $log cd $ORACLE_HOME tar -cjf ${SQLPATH}/dbs_${ORACLE_SID}.tar.bz2 dbs >> $log 2>> $log scp ${SQLPATH}/dbs_${ORACLE_SID}.tar.bz2 ${remote_dest}:${SQLPATH}/dbs_${ORACLE_SID}.tar.bz2 >> $log 2>> $log } limpa_archives() { echo "Archives: removendo archives com mais de 8 dias de $arch_dest em "`date +%R:%S` >> $log find $arch_dest -daystart -mtime +8 -exec rm -fv {} ; >> $log 2>> $log echo "" >> $log } verifica_alert() { echo "Alert: erros encontrados =>" >> $log egrep --color -n -B 2 '(ORA-|SP2-)' /u01/app/oracle/admin/${ORACLE_SID}/bdump/alert_${ORACLE_SID}.log >> $log 2>> $log echo "Alert: renomeando bdump/alert_${ORACLE_SID}.log para ${ORACLE_SID}_${dia}.log" >> $log if [ -f /u01/app/oracle/admin/${ORACLE_SID}/bdump/alert_${ORACLE_SID}.log ]; then mv /u01/app/oracle/admin/${ORACLE_SID}/bdump/alert_${ORACLE_SID}.log /u01/app/oracle/admin/${ORACLE_SID}/bdump/${ORACLE_SID}_${dia}.log >> $log fi } verifica_tablespaces() { echo "Tablespaces com mais de 80% de espaço ocupado =>" >> $log sqlplus -S / < 80 UNION SELECT tablespace_name || ' com ' || TO_CHAR( 100 * SUM (user_bytes) / SUM (DECODE (autoextensible, 'NO', bytes, maxbytes)) , '999.9') || '% ocupado' tablespace FROM dba_temp_files GROUP BY tablespace_name HAVING 100 * SUM(user_bytes) / SUM (DECODE (autoextensible, 'NO', bytes, maxbytes)) > 80 ; SPOOL OFF EXIT; EOF_VERIFICA_TABLESPACES cat ${SQLPATH}/verifica_tablespaces.log >> $log 2>> $log } mostra_espaco_disco() { echo "Espaço em disco =>" >> $log df -hl -t ext3 >> $log 2>> $log echo "" >> $log } backup_spfile() { echo "Copiando spfile para ${ORACLE_HOME}/dbs/init${ORACLE_SID}_backup.ora em "`date +%R:%S` >> $log #Só funciona se o spfile existir if [ -f ${ORACLE_HOME}/dbs/spfile${ORACLE_SID}.ora ]; then #Só pode ser executado pelo usuário Oracle do SO. Verificação abaixo if [ $USER != 'oracle' ]; then echo "***** A operação ${operation} não é válida com o usuário $USER" >> $log echo "***** tente novamente com o usuário oracle do SO." >> $log exit 2 fi echo " --Backup do spfile (precisa de privilégio sysdba ou sysoper)" sqlplus -S / as sysdba <> $log 2>> $log else echo "SPFILE ${ORACLE_HOME}/dbs/spfile${ORACLE_SID}.ora não encontrado!" >> $log fi } shut_down() { echo "Backup físico off line: desligando instância em "`date +%R:%S` >> $log #Só pode ser executado pelo usuário Oracle do SO. Verificação abaixo if [ $USER != 'oracle' ]; then echo "***** A operação ${operation} não é válida com o usuário $USER" >> $log echo "***** tente novamente com o usuário oracle do SO." >> $log exit 2 fi sqlplus -S / as sysdba <> $log 2>> $log proc=`ps -ef | egrep pmon_$ORACLE_SID | grep -v grep` if [ -n $proc ]; then echo "***** Problema ao desligar a instância $ORACLE_SID" >> $log echo "***** Tentando realizar um shutdown abort" >> $log sqlplus -S / as sysdba <> $log 2>> $log proc=`ps -ef | egrep pmon_$ORACLE_SID | grep -v grep` if [ -n $proc ]; then echo "***** Algum problema sério aconteceu no banco $ORACLE_SID" >> $log echo "***** O servidor pode estar num estado inconsistente" >> $log cat $log | mail -s "URGENTE!!! Erro no backup off line de `uname -n`/$dia" $oracle_mail exit 2 grep --color -n -B 2 ORA- ${SQLPATH}/shut_down_abort.log >> $log 2>> $log fi fi echo "" >> $log 2>> $log } copia_datafiles() { echo "Backup físico of line: copiando arquivos de dados em "`date +%R:%S` >> $log for p in ${dados[*]}; do scp ${p}/oradata/${ORACLE_SID}/* ${remote_dest}:${p}/oradata/${ORACLE_SID} 2>> $log done } start_up() { echo "Backup físico: ligando instância em "`date +%R:%S` >> $log #Só pode ser executado pelo usuário Oracle do SO. Verificação abaixo if [ $USER != 'oracle' ]; then echo "***** A operação ${operation} não é válida com o usuário $USER" >> $log echo "***** tente novamente com o usuário oracle do SO." >> $log exit 2 fi sqlplus -S / as sysdba <> $log 2>> $log if [ $? -eq 0 ]; then echo "***** Problema ao ligar a instância $ORACLE_SID" >> $log cat $log | mail -s "URGENTE!!! Erro no backup off line de `uname -n`/$dia" $oracle_mail exit 2 else proc=`ps -ef | egrep pmon_$ORACLE_SID | grep -v grep` if [ -z $proc ]; then echo "***** Problema ao ligar a instância $ORACLE_SID" >> $log cat $log | mail -s "URGENTE!!! Erro no backup off line de `uname -n`/$dia" $oracle_mail exit 2 fi fi echo "" >> $log } define_mes_anterior() { mes=`date +%m` mes=$(expr $mes - 1) if [ $mes = 0 ]; then ano=`date +%Y` ano=$(expr $ano - 1) mes=${ano}-12 else mes=`date +%Y`-$mes fi } move_logs() { echo "Logs: Movendo logs em adump para adump/old/${ORACLE_SID}_audit_${mes}.tar.bz2" >> $log cd /u01/app/oracle/admin/${ORACLE_SID}/adump touch ${ORACLE_SID}_audit_${mes}.tar $log 2>> $log find -name "ora_*.aud" -exec tar -rf ${ORACLE_SID}_audit_${mes}.tar {} ; 2>> $log if [ -s ${ORACLE_SID}_audit_${mes}.tar ]; then bzip2 ${ORACLE_SID}_audit_${mes}.tar >> $log 2>> $log mv ${ORACLE_SID}_audit_${mes}.tar.bz2 old >> $log 2>> $log rm ora_*.aud else rm ${ORACLE_SID}_audit_${mes}.tar >> $log 2>> $log fi echo "Logs: Movendo logs em bdump para bdump/old/${ORACLE_SID}_bdump_log_${mes}.tar.bz2" >> $log cd /u01/app/oracle/admin/${ORACLE_SID}/bdump touch ${ORACLE_SID}_bdump_log_${mes}.tar $log 2>> $log find -name "${ORACLE_SID}_${mes}-*.log" -exec tar -rf ${ORACLE_SID}_bdump_log_${mes}.tar {} ; 2>> $log if [ -s ${ORACLE_SID}_bdump_log_${mes}.tar ]; then bzip2 ${ORACLE_SID}_bdump_log_${mes}.tar >> $log 2>> $log mv ${ORACLE_SID}_bdump_log_${mes}.tar.bz2 old >> $log 2>> $log rm ${ORACLE_SID}_${mes}-*.log else rm ${ORACLE_SID}_bdump_log_${mes}.tar >> $log 2>> $log fi echo "Logs: Movendo trace em bdump para bdump/old/${ORACLE_SID}_bdump_trace_${mes}.tar.bz2"` >> $log cd /u01/app/oracle/admin/${ORACLE_SID}/bdump touch ${ORACLE_SID}_bdump_trace_${mes}.tar $log 2>> $log find -name "${ORACLE_SID}_*.trc" -exec tar -rf ${ORACLE_SID}_bdump_trace_${mes}.tar {} ; 2>> $log if [ -s ${ORACLE_SID}_bdump_trace_${mes}.tar ]; then bzip2 ${ORACLE_SID}_bdump_trace_${mes}.tar >> $log 2>> $log mv ${ORACLE_SID}_bdump_trace_${mes}.tar.bz2 old >> $log 2>> $log rm ${ORACLE_SID}_*.trc else rm ${ORACLE_SID}_bdump_trace_${mes}.tar >> $log 2>> $log fi echo "Logs: Movendo trace em cdump para cdump/old/${ORACLE_SID}_cdump_trace_${mes}.tar.bz2" >> $log cd /u01/app/oracle/admin/${ORACLE_SID}/cdump touch ${ORACLE_SID}_cdump_trace_${mes}.tar $log 2>> $log find -name "core_*" -exec tar -rf ${ORACLE_SID}_cdump_trace_${mes}.tar {} ; 2>> $log if [ -s ${ORACLE_SID}_cdump_trace_${mes}.tar ]; then bzip2 ${ORACLE_SID}_cdump_trace_${mes}.tar >> $log 2>> $log mv ${ORACLE_SID}_cdump_trace_${mes}.tar.bz2 old >> $log 2>> $log rm -R core_* else rm ${ORACLE_SID}_cdump_trace_${mes}.tar >> $log 2>> $log fi echo "Logs: Movendo trace em udump para udump/old/${ORACLE_SID}_udump_trace_${mes}.tar.bz2" >> $log cd /u01/app/oracle/admin/${ORACLE_SID}/udump touch ${ORACLE_SID}_udump_trace_${mes}.tar $log 2>> $log find -name "${ORACLE_SID}_*.trc" -exec tar -rf ${ORACLE_SID}_udump_trace_${mes}.tar {} ; 2>> $log if [ -s ${ORACLE_SID}_udump_trace_${mes}.tar ]; then bzip2 ${ORACLE_SID}_udump_trace_${mes}.tar >> $log 2>> $log mv ${ORACLE_SID}_udump_trace_${mes}.tar.bz2 old >> $log 2>> $log rm ${ORACLE_SID}_*.trc else rm ${ORACLE_SID}_udump_trace_${mes}.tar >> $log fi echo "Logs: Movendo logs de backup para backup/old/${ORACLE_SID}_backup_${mes}.tar.bz2" >> $log cd /u01/app/oracle/admin/${ORACLE_SID}/backup touch ${ORACLE_SID}_udump_trace_${mes}.tar $log 2>> $log find -name "*_${mes}.log" -exec tar -rf ${ORACLE_SID}_backup_log_${mes}.tar {} ; 2>> $log if [ -s ${ORACLE_SID}_backup_log_${mes}.tar ]; then bzip2 ${ORACLE_SID}_backup_log_${mes}.tar >> $log 2>> $log mv ${ORACLE_SID}_backup_log_${mes}.tar.bz2 old >> $log 2>> $log rm ${ORACLE_SID}_${mes}-*.log else rm ${ORACLE_SID}_backup_log_${mes}.tar >> $log 2>> $log fi } #Rotina principal case $operation in 'copia_archives') copia_archives verifica_discos ;; 'backup_noturno') echo "" >> $log 2>> $log echo "Inicio da rotina de backup noturno em $ORACLE_SID em "`uname -n`" para o dia ${dia}" >> $log echo "=================================================================" >> $log echo "" >> $log analize backup_logico verifica_data_file backup_fisico_on_line compara_backup_fisico backup_control_file backup_dbs limpa_archives verifica_alert verifica_tablespaces mostra_espaco_disco echo "Fim do backup noturno. Este log está disponível em $log" >> $log cat $log | mail -s "Log do backup noturno de `uname -n`/${dia}" $oracle_mail ;; 'backup_off_line') echo "" >> $log echo "Início do backup off line de $ORACLE_SID em "`uname -n`" para o dia ${dia}" >> $log echo "==============================================================================" >> $log echo "" >> $log shut_down copia_datafiles start_up echo "Fim do backup off line. Este log está disponível em $log" >> $log cat $log | mail -s "Log do backup off line de `uname -n`/${dia}" $oracle_mail ;; 'rotina_mensal') define_mes_anterior echo "" >> $log echo "Início da rotina mensal de $ORACLE_SID em "`uname -n`" para o mês ${mes} em ${dia}" >> $log echo "==============================================================================" >> $log echo "" >> $log move_logs verifica_espaco_disco echo "Fim da rotina mensal. Este log está disponível em $log" >> $log cat $log | mail -s "Log da rotina mensal de `uname -n`/${dia}" $oracle_mail ;; *) echo "***** A operação ${operation} não é válida" >> $log echo "***** chamada $0 $* ilegal" echo "***** uso: $0 " >> $log ;; esac
Referências
- An Introduction to Linux Shell Scripting for DBAs
- Página sobre Shell Script do Aurélio Verde
- Optimal Flexible Architecture
- Making User-Managed Backups
- SQL*Plus User’s Guide and Reference
- Oracle Data Pump
- DBVERIFY: Offline Database Verification Utility