예제 #1
0
 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)
예제 #3
0
 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()
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
                                           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
예제 #7
0
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:
예제 #10
0
# 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,