def rman(self, finalscript): self._setenv() debug("RMAN execution starts") BackupLogger.close() starttime = datetime.now() with TemporaryFile() as f: p = Popen([os.path.join(self.oraclehome, 'bin', 'rman'), "log", BackupLogger.logfile, "append"], stdout=f, stderr=f, stdin=PIPE) # Send the script to RMAN p.communicate(input=finalscript) endtime = datetime.now() BackupLogger.init() debug("RMAN execution time %s" % (endtime-starttime)) # If RMAN exists with any code except 0, then there was some error if p.returncode != 0: error("RMAN execution failed with code %d" % p.returncode) raise Exception('rman', "RMAN exited with code %d" % p.returncode) else: debug("RMAN execution successful")
def exec_restore(): global exitvalue restore.clone(False) print "Please execute the following command as root to mount the backup volume:" print "" print "mount -t nfs -o rw,bg,hard,nointr,rsize=32768,wsize=32768,tcp,vers=3,timeo=600 %s %s" % (restore.mountstring, restoreparams['mountpath']) print "" while ask_yn("Did you execute it") == "N": print "Please execute it then." # Verify that clone is mounted autorestorefile = os.path.join(restoreparams['mountpath'], 'autorestore.cfg') if not os.path.isfile(autorestorefile): print "The mounted path does not look correct, file %s not found" % autorestorefile exitvalue = 1 return # BackupLogger.init('/tmp/restore_%s_%s.log' % (datetime.now().strftime('%Y%m%dT%H%M%S'), configname)) BackupLogger.clean() Configuration.substitutions.update({ 'logdir': '/tmp', 'logfile': BackupLogger.logfile }) print "Session log file: %s" % BackupLogger.logfile info("Starting database restore") # try: restore.pit_restore(restoreparams['mountpath'], restoreparams['sid']) restore.verify(False) info("Database restore complete") info("SID: %s" % restoreparams['sid']) info("Requested target time: %s" % restoreparams['timepoint'].astimezone(get_localzone())) info("Verified restored database time: %s" % restore.verifytime) info("Difference from target: %s" % restore.verifydiff) except: exception("Database restore failed") exitvalue = 1 print "" print "Commands to clean up:" print "1. Shut down database instance %s" % restoreparams['sid'] print "2. Execute as root: umount %s" % restoreparams['mountpath'] print "3. Drop clone: BACKUPCONFIG=%s %s %s dropclone %s" % (os.path.basename(Configuration.configfilename), os.path.join(scriptpath(), 'zsnapper.py'), configname, restore.clonename)
def sqlplus(self, finalscript, silent=False): self._setenv() with TemporaryFile() as f: args = [os.path.join(self.oraclehome, 'bin', 'sqlplus')] if silent: args.append('-S') args.append('/nolog') debug("SQL*Plus execution starts") BackupLogger.close() p = Popen(args, stdout=f, stderr=f, stdin=PIPE) p.communicate(input=finalscript) BackupLogger.init() if p.returncode != 0: error("SQL*Plus exited with code %d" % p.returncode) raise Exception('sqlplus', "sqlplus exited with code %d" % p.returncode) else: debug("SQL*Plus execution successful") if silent: f.seek(0,0) return f.read()
exitvalue = 0 restoreparams = {} printheader() if len(sys.argv) not in [3]: printhelp() if os.geteuid() == 0: print "No, I will not run as root." sys.exit(0) configname = sys.argv[2] Configuration.init(defaultsection=configname, configfilename=sys.argv[1], additionaldefaults={'customverifydate': 'select max(time_dp) from sys.smon_scn_time', 'autorestoreenabled': '1', 'autorestoreinstancenumber': '1', 'autorestorethread': '1'}) BackupLogger.init('/tmp/restore_%s_%s.log' % (datetime.now().strftime('%Y%m%dT%H%M%S'), configname), configname) BackupLogger.clean() Configuration.substitutions.update({ 'logdir': '/tmp', 'logfile': BackupLogger.logfile }) print "Session log file: %s" % BackupLogger.logfile restore = RestoreDB(configname) ask_user_input() if exitvalue == 0: exec_restore() sys.exit(exitvalue)
def runrestore(database): global exitstatus # Configuration.defaultsection = database # Reinitialize logging BackupLogger.init( os.path.join( logdir, "%s-%s.log" % (datetime.now().strftime('%Y%m%dT%H%M%S'), database)), database) BackupLogger.clean() # restore = RestoreDB(database) restore.set_mount_path(mountdest) restore.set_restore_path(restoredest) # info("Logfile: %s" % BackupLogger.logfile) Configuration.substitutions.update({'logfile': BackupLogger.logfile}) cleantarget() # success = False # if validatemodulus > 0: # Validation based on modulus validationinfo = validationdate(database) validatecorruption = validationinfo[0] if not validatecorruption: debug("Next database validation in %d days: %s" % (validationinfo[1], validationinfo[2])) else: # Validation based on random validatecorruption = (validatechance > 0) and (randint( 1, validatechance) == validatechance) if validatecorruption: debug("Database will be validated during this restore session") # Start restore try: restore.run() restore.verify() if validatecorruption: restore.blockcheck() success = True except: exitstatus = 1 exception( "Error happened, but we can continue with the next database.") finally: restore.cleanup() # Log result to catalog Configuration.substitutions.update({ 'log_dbname': database, 'log_start': restore.starttime.strftime('%Y-%m-%d %H-%M-%S'), 'log_stop': restore.endtime.strftime('%Y-%m-%d %H-%M-%S'), 'log_success': '1' if success else '0', 'log_diff': restore.verifyseconds, 'log_snapid': restore.sourcesnapid, 'log_validated': '1' if validatecorruption else '0' }) debug('Logging the result to catalog.') try: oexec.sqlldr(Configuration.get('autorestorecatalog', 'autorestore'), restoretemplate.get('sqlldrlog')) except: debug("Sending the logfile to catalog failed.") try: oexec.sqlplus(restoretemplate.get('insertlog'), silent=False) except: debug("Logging the result to catalog failed.") # Finish up info("Restore %s, elapsed time: %s" % ('successful' if success else 'failed', restore.endtime - restore.starttime)) BackupLogger.close(True)
validationinfo[1]) else: if validatechance > 0: print "Validation is based on chance, probability 1/%d" % validatechance else: print "Database validation is not turned on" else: # Actions that need a lock lock = BackupLock(Configuration.get('autorestorelogdir', 'autorestore')) try: if action is not None: if action.startswith('--'): if action == '--createcatalog': BackupLogger.init( os.path.join( logdir, "%s-config.log" % (datetime.now().strftime('%Y%m%dT%H%M%S'))), 'config') info("Logfile: %s" % BackupLogger.logfile) Configuration.substitutions.update( {'logfile': BackupLogger.logfile}) oexec.sqlplus(restoretemplate.get('createcatalog'), silent=False) else: runrestore(action) else: # Loop through all sections for configname in loopdatabases(): runrestore(configname) # Run ADRCI to clean up diag adrage = int(Configuration.get('logretention', 'generic')) * 1440
def printhelp(): print "Usage: report.py [comma separated list of databases]" sys.exit(2) if len(sys.argv) not in [1, 2]: printhelp() # Directory where the executable script is located scriptpath = scriptpath() # Read configuration logf = mkstemp(prefix='backupreport-', suffix='.log') os.close(logf[0]) Configuration.init('generic') BackupLogger.init(logf[1], 'reporting') Configuration.substitutions.update({ 'logfile': BackupLogger.logfile, 'autorestorecatalog': Configuration.get('autorestorecatalog', 'autorestore') }) reporttemplate = BackupTemplate('reporttemplate.cfg') def exec_sqlplus(oraexec, script, header='sqlplusheader'): finalscript = "%s\n%s\n%s" % (reporttemplate.get(header), script, reporttemplate.get('sqlplusfooter')) output = oraexec.sqlplus(finalscript, silent=True) for line in output.splitlines(): if line.startswith('OUTLOG: '):
def runrestore(database): global exitstatus # Configuration.defaultsection = database # restoredest = Configuration.get('autorestoredestination', 'autorestore') mountdest = Configuration.get('autorestoremountpoint', 'autorestore') logdir = Configuration.get('autorestorelogdir', 'autorestore') Configuration.substitutions.update({ 'logdir': logdir, 'autorestorecatalog': Configuration.get('autorestorecatalog', 'autorestore') }) if restoredest is None or not os.path.exists( restoredest) or not os.path.isdir(restoredest): print "Restore directory %s not found or is not a proper directory" % restoredest sys.exit(2) if mountdest is None or not os.path.exists(mountdest) or not os.path.isdir( mountdest): print "Clone mount directory %s not found or is not a proper directory" % mountdest sys.exit(2) # validatechance = int( Configuration.get('autorestorevalidatechance', 'autorestore')) validatemodulus = int( Configuration.get('autorestoremodulus', 'autorestore')) # Reinitialize logging BackupLogger.init( os.path.join( logdir, "%s-%s.log" % (datetime.now().strftime('%Y%m%dT%H%M%S'), database)), database) BackupLogger.clean() # restore = RestoreDB(database) restore.set_mount_path(mountdest) restore.set_restore_path(restoredest) # info("Logfile: %s" % BackupLogger.logfile) Configuration.substitutions.update({'logfile': BackupLogger.logfile}) cleantarget(restoredest) # success = False # if validatemodulus > 0: # Validation based on modulus validationinfo = validationdate(database) validatecorruption = validationinfo[0] if not validatecorruption: debug("Next database validation in %d days: %s" % (validationinfo[1], validationinfo[2])) else: # Validation based on random validatecorruption = (validatechance > 0) and (randint( 1, validatechance) == validatechance) if validatecorruption: debug("Database will be validated during this restore session") # Start restore try: restore.run() restore.verify() if validatecorruption: restore.blockcheck() success = True except: exitstatus = 1 exception( "Error happened, but we can continue with the next database.") finally: restore.cleanup() # Log result to catalog Configuration.substitutions.update({ 'log_dbname': database, 'log_start': restore.starttime.strftime('%Y-%m-%d %H-%M-%S'), 'log_stop': restore.endtime.strftime('%Y-%m-%d %H-%M-%S'), 'log_success': '1' if success else '0', 'log_diff': restore.verifyseconds, 'log_snapid': restore.sourcesnapid, 'log_validated': '1' if validatecorruption else '0' }) debug('Logging the result to catalog.') try: oexec.sqlldr(Configuration.get('autorestorecatalog', 'autorestore'), restoretemplate.get('sqlldrlog')) except: debug("Sending the logfile to catalog failed.") try: oexec.sqlplus(restoretemplate.get('insertlog'), silent=False) except: debug("Logging the result to catalog failed.") # Finish up info("Restore %s, elapsed time: %s" % ('successful' if success else 'failed', restore.endtime - restore.starttime)) # Run ADRCI to clean up diag adrage = int(Configuration.get('logretention', 'generic')) * 1440 f1 = mkstemp(suffix=".adi") ftmp = os.fdopen(f1[0], "w") ftmp.write("set base %s\n" % logdir) ftmp.write("show homes\n") ftmp.close() f2 = mkstemp(suffix=".adi") ftmp2 = os.fdopen(f2[0], "w") ftmp2.write("set base %s\n" % logdir) with TemporaryFile() as f: try: oexec.adrci(f1[1], f) f.seek(0, 0) output = f.read() startreading = False for line in output.splitlines(): if line.startswith('ADR Homes:'): startreading = True elif startreading: ftmp2.write("set home %s\n" % line.strip()) ftmp2.write("purge -age %d\n" % adrage) ftmp2.close() oexec.adrci(f2[1], f) except: print "Executing ADRCI failed." finally: os.unlink(f1[1]) os.unlink(f2[1]) # BackupLogger.close(True)
validationinfo = validationdate(configname) print "%s: %s (in %d days)" % (configname, validationinfo[2], validationinfo[1]) else: validatechance = int( Configuration.get('autorestorevalidatechance', 'autorestore')) if validatechance > 0: print "Validation is based on chance, probability 1/%d" % validatechance else: print "Database validation is not turned on" else: if action is not None and action.startswith('--'): if action == '--createcatalog': BackupLogger.init( os.path.join( Configuration.get('autorestorelogdir', 'autorestore'), "%s-config.log" % (datetime.now().strftime('%Y%m%dT%H%M%S'))), 'config') info("Logfile: %s" % BackupLogger.logfile) Configuration.substitutions.update( {'logfile': BackupLogger.logfile}) oexec.sqlplus(restoretemplate.get('createcatalog'), silent=False) else: # Loop through all sections for configname in loopdatabases(): Configuration.defaultsection = configname lock = BackupLock( Configuration.get('autorestorelogdir', 'autorestore')) try: runrestore(configname) finally:
# Database specific configuration backupdest = os.path.join(Configuration.get('backupdest', 'generic'), configsection) archdir = os.path.join(backupdest, 'archivelog') hasdataguard = Configuration.get('hasdataguard').upper() == 'TRUE' dosnapshot = Configuration.get('dosnapshot').upper() == 'TRUE' gimanaged = Configuration.get('gimanaged').upper() == 'TRUE' registercatalog = Configuration.get('registercatalog').upper() == 'TRUE' # Log file for this session logdir = os.path.join(backupdest, 'backup_logs') logfile = os.path.join( logdir, "%s_%s_%s.log" % (configsection, datetime.now().strftime('%Y%m%dT%H%M%S'), scriptaction)) print "Log file for this session: %s" % logfile BackupLogger.init(logfile, configsection) BackupLogger.clean() # Oracle environment variables oraexec = OracleExec( Configuration.get('oraclehome', 'generic'), os.path.join(scriptpath, Configuration.get('tnsadmin', 'generic'))) # Prepare a dictionary of all possible template substitutions Configuration.substitutions.update({ 'recoverywindow': Configuration.get('recoverywindow'), 'parallel': Configuration.get('parallel'), 'backupdest': backupdest,