예제 #1
0
 def blockcheck(self):
     info("ACTION: Validating database for corruptions")
     # The following command will introduce some corruption to test database validation
     # check_call(['dd','if=/dev/urandom','of=/nfs/autorestore/mnt/data_D-ORCL_I-1373437895_TS-SOE_FNO-5_0sqov4pv','bs=8192','count=10','seek=200','conv=notrunc' ])
     try:
         self._exec_rman(self._restoretemplate.get('validateblocks'))
         self._validatecorruption = True
     finally:
         self._exec_sqlplus(self._restoretemplate.get('showcorruptblocks'))
예제 #2
0
def delete_expired_datafilecopy():
    output = exec_sqlplus(rmantemplateconfig.get('deletedatafilecopy'),
                          silent=True)
    rmanscript = ""
    for line in output.splitlines():
        if line.startswith('DELETECOPY: '):
            rmanscript += "%s\n" % line.strip()[12:]
    if rmanscript:
        info("- Deleting expired datafile copies")
        exec_rman(rmanscript)
예제 #3
0
def backup_missing_archlog():
    output = exec_sqlplus(rmantemplateconfig.get('archivelogmissing'),
                          silent=True)
    archlogscript = ""
    for line in output.splitlines():
        if line.startswith('BACKUP force as copy'):
            archlogscript += "%s\n" % line.strip()
    if archlogscript:
        info("- Copying missing archivelogs")
        exec_rman(
            "run {\n%s\n%s\n}" %
            (rmantemplateconfig.get('allocatearchlogchannel'), archlogscript))
예제 #4
0
def generate_restore():
    print "\n============="
    info(rmantemplateconfig.get('headerrestore'))
    if registercatalog:
        info(rmantemplateconfig.get('headercatalog'))
    info(rmantemplateconfig.get('fullrestore'))
    info(rmantemplateconfig.get('restorefooter'))
예제 #5
0
 def run(self):
     self.starttime = datetime.now()
     info("Starting to restore")
     #
     success = False
     self.clone()
     try:
         self._mount()
     except:
         self.cleanup()
         raise Exception('restore', 'Mount failed')
     self._set_parameters()
     self._createinitora()
     self._exec = OracleExec(oraclehome=Configuration.get('oraclehome', 'generic'),
         tnspath=os.path.join(scriptpath(), Configuration.get('tnsadmin', 'generic')),
         sid=self._dbparams['dbname'])
     #
     self._run_restore()
예제 #6
0
def configure():
    rmanscript = ''
    # Create directory for archive logs
    if not os.path.exists(archdir):
        os.makedirs(archdir)
    # Register database in catalog if needed
    if registercatalog:
        alreadyregistered = False
        info("Checking from RMAN catalog if database is already registered")
        output = exec_sqlplus(
            rmantemplateconfig.get('isdbregisteredincatalog'),
            silent=True,
            header=False)
        for line in output.splitlines():
            if line.startswith('DATABASE IS REGISTERED IN RC'):
                alreadyregistered = True
        if not alreadyregistered:
            rmanscript += rmantemplateconfig.get('registerdatabase')
    # Configure archivelog deletion policy
    if hasdataguard:
        rmanscript += "\n%s" % rmantemplateconfig.get('configdelaldg')
    else:
        rmanscript += "\n%s" % rmantemplateconfig.get('configdelalnodg')
    # configures rman default settings
    rmanscript += "\n%s" % rmantemplateconfig.get('config')
    info("Running RMAN configuration")
    exec_rman(rmanscript)
    info("Running additional configuration from SQL*Plus")
    exec_sqlplus(rmantemplateconfig.get('configfromsqlplus'))
예제 #7
0
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
    #
    debug("Oracle home: %s" % Configuration.get("oraclehome", "generic"))
    debug("Clone mount path: %s" % restoreparams['mountpath'])
    debug("Target instance SID: %s" % restoreparams['sid'])
    debug("Restore target time UTC: %s" % restoreparams['timepoint'].astimezone(pytz.utc))
    debug("Restore target time local: %s" % restoreparams['timepoint'].astimezone(get_localzone()))
    debug("Restored from snapshot: %s" % restore.sourcesnapid)
    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)
예제 #8
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)
예제 #9
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
            f1 = mkstemp(suffix=".adi")
            ftmp = os.fdopen(f1[0], "w")
            ftmp.write("set base %s\n" % logdir)
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)
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)
예제 #12
0
def imagecopywithsnap():
    starttime = datetime.now()
    restoreparamfile = os.path.join(backupdest, 'autorestore.cfg')
    #
    info("Check if there are missing archivelogs")
    backup_missing_archlog()
    #
    info("Switch current log")
    output = exec_sqlplus(rmantemplateconfig.get('archivecurrentlogs'),
                          silent=True)
    if os.path.isfile(restoreparamfile):
        with open(restoreparamfile, 'a') as f:
            for line in output.splitlines():
                if line.startswith('CURRENT DATABASE SCN:'):
                    f.write("lastscn: %s\n" % line.strip()[22:])
                elif line.startswith('CURRENT DATABASE TIME:'):
                    f.write("lasttime: %s\n" % line.strip()[23:])
                elif line.startswith('BCT FILE:'):
                    f.write("bctfile: %s\n" % line.strip()[10:])
    #
    if dosnapshot:
        info("Snap the current backup area")
        snapid = snap.snap()
        debug("Created snapshot: %s" % snapid)
    #
    info("Checking for expired datafile copies")
    delete_expired_datafilecopy()
    #
    info("Refresh imagecopy")
    backup('imagecopy')
    exec_sqlplus(rmantemplateconfig.get('archivecurrentlogs'))
    #
    if dosnapshot:
        info("Clean expired snapshots")
        cleaningresult = snap.clean()
        for r in cleaningresult:
            debug(r['infostring'])
    #
    info("Dump additional information about the environment to the log file")
    if gimanaged:
        p = Popen([os.path.join(scriptpath, 'dbinfo.py'), configsection],
                  stdout=PIPE,
                  stderr=None,
                  stdin=None)
        output, outerr = p.communicate()
        debug(output)
    # Write ORACLE_HOME patch information to log file
    p = Popen([
        os.path.join(Configuration.get('oraclehome', 'generic'), 'OPatch',
                     'opatch'), 'lsinventory'
    ],
              stdout=PIPE,
              stderr=None,
              stdin=None)
    output, outerr = p.communicate()
    debug(output)
    #
    info("Write database parameters for autorestore")
    with open(restoreparamfile, 'w') as f:
        f.write("[dbparams]\n")
        output = exec_sqlplus(rmantemplateconfig.get('autorestoreparameters'),
                              silent=True)
        for line in output.splitlines():
            if line.startswith('dbconfig-'):
                f.write("%s\n" % line[9:])
    #
    endtime = datetime.now()
    info("------------ TOTAL ------------")
    info("Total execution time: %s" % (endtime - starttime))
    info("Execution started: %s" % starttime)
    info("Execution finished: %s" % endtime)
예제 #13
0
    for line in output.splitlines():
        if line.startswith('CDB-DETECT:') and line.strip() <> 'CDB-DETECT: NO':
            commonprefix = line.strip()[12:]
    Configuration.substitutions.update({'scheduleuserprefix': commonprefix})
    #
    script = "%s\n" % rmantemplateconfig.get('createuser')
    script += "%s\n" % rmantemplateconfig.get('dropschedule')
    script += "%s\n" % rmantemplateconfig.get('createschedule')
    exec_sqlplus(script)


################################################
### Main section
################################################

info("Configuration file: %s" % Configuration.configfilename)

lock = BackupLock(lockdir=backupdest,
                  maxlockwait=int(Configuration.get('maxlockwait', 'generic')))

try:
    # User interface action execution
    if scriptaction == 'config':
        configure()
    elif scriptaction == 'generaterestore':
        generate_restore()
    elif scriptaction == 'imagecopywithsnap':
        imagecopywithsnap()
    elif scriptaction == 'setschedule':
        setschedule()
    elif scriptaction == 'missingarchlog':