Exemple #1
0
 def __init__(self, configname):
     zfscredfilename = os.path.join(scriptpath(), 'netappcredentials.cfg')
     if not os.path.isfile(zfscredfilename):
         raise Exception(
             self._exceptionbase,
             "Configuration file %s not found" % zfscredfilename)
     # Authentication information
     zfscredconfig = SafeConfigParser()
     zfscredconfig.read(zfscredfilename)
     zfsauth = (zfscredconfig.get('netappcredentials', 'user'),
                zfscredconfig.get('netappcredentials', 'password'))
     #
     self._filer = Configuration.get('filer', 'netapp')
     self._srv = NaServer(self._filer, 1, 1)
     # Check if CA certificate validation is needed
     try:
         self._cacert = os.path.join(scriptpath(), 'certs',
                                     Configuration.get('cacert', 'netapp'))
     except NoOptionError:
         self._cacert = None
     if self._cacert:
         self._srv.set_ca_certs(self._cacert)
         self._srv.set_server_cert_verification(True)
         self._srv.set_hostname_verification(False)
     #
     self._srv.set_admin_user(
         zfscredconfig.get('netappcredentials', 'user'),
         zfscredconfig.get('netappcredentials', 'password'))
     self._volprefix = Configuration.get('volumeprefix', 'netapp')
     self._volname = "%s%s" % (self._volprefix, configname)
     super(Netapp, self).__init__(configname)
Exemple #2
0
    def _set_parameters(self):
        dbconfig = SafeConfigParser()
        dbconfig.read(os.path.join(self._mountdest, 'autorestore.cfg'))
        self._dbparams['dbname'] = dbconfig.get('dbparams','db_name')
        if self.targettime is None:
            self._dbparams['restoretarget'] = datetime.strptime(dbconfig.get('dbparams','lasttime'), '%Y-%m-%d %H:%M:%S')
        else:
            self._dbparams['restoretarget'] = self.targettime.astimezone(get_localzone())
        self._dbparams['bctfile'] = dbconfig.get('dbparams','bctfile')
        Configuration.substitutions.update({
            'db_name': self._dbparams['dbname'],
            'db_compatible': dbconfig.get('dbparams','compatible'),
            'db_files': dbconfig.get('dbparams','db_files'),
            'db_undotbs': dbconfig.get('dbparams','undo_tablespace'),
            'db_block_size': dbconfig.get('dbparams','db_block_size'),
#            'lastscn': dbconfig.get('dbparams','lastscn'),
            'lasttime': self._dbparams['restoretarget'].strftime('%Y-%m-%d %H:%M:%S'),
            'dbid': Configuration.get('dbid', self._configname),
            'instancenumber': Configuration.get('autorestoreinstancenumber', self._configname),
            'thread': Configuration.get('autorestorethread', self._configname),
            'backupfinishedtime': dbconfig.get('dbparams','backup-finished'),
            'bctfile': self._dbparams['bctfile'],
            'autorestoredestination': self._restoredest,
            'mountdestination': self._mountdest,
        })
        try:
            Configuration.substitutions.update({'cdb': dbconfig.get('dbparams','enable_pluggable_database')})
        except:
            Configuration.substitutions.update({'cdb': 'FALSE'})
        self._initfile = os.path.join(self._restoredest, 'init.ora')
        Configuration.substitutions.update({
            'initora': self._initfile,
        })
def checkage():
    # Returns the latest snapshot age for nagios check
    exitcode = 0
    warning = timedelta(
        hours=int(Configuration.get('warningsnapage', 'generic')))
    critical = timedelta(
        hours=int(Configuration.get('criticalsnapage', 'generic')))
    try:
        snaps = zfs.listsnapshots()
        minage = None
        for s in snaps:
            d = zfs.str2date(s["creation"])
            age = datetime.utcnow() - d
            if (minage is None) or (age < minage):
                minage = age
        s = "OK"
        if (minage is None) or (minage >= critical):
            exitcode = 2
            s = "CRITICAL"
        elif minage >= warning:
            exitcode = 1
            s = "WARNING"
        print "%s: The latest snapshot age %s" % (s, minage)
    except Exception as detail:
        print "Exception occured: %s" % detail
        exitcode = 3
    sys.exit(exitcode)
 def verify(self, tolerancechecking=True):
     debug('ACTION: opening database to verify the result')
     if tolerancechecking:
         maxtolerance = timedelta(minutes=int(
             Configuration.get('autorestoremaxtoleranceminutes',
                               'autorestore')))
     Configuration.substitutions.update({
         'customverifydate':
         Configuration.get('customverifydate', self._configname),
     })
     output = self._exec_sqlplus(self._restoretemplate.get('openandverify'),
                                 returnoutput=True)
     for line in output.splitlines():
         if line.startswith('CUSTOM VERIFICATION TIME:'):
             self.verifytime = datetime.strptime(
                 line.split(':', 1)[1].strip(), '%Y-%m-%d %H:%M:%S')
     if self.verifytime is None:
         raise Exception('restore', 'Reading verification time failed.')
     self.verifydiff = self._dbparams['restoretarget'].replace(
         tzinfo=None) - self.verifytime
     self.verifyseconds = int(self.verifydiff.seconds +
                              self.verifydiff.days * 24 * 3600)
     debug("Expected time: %s" % self._dbparams['restoretarget'])
     debug("Verified time: %s" % self.verifytime)
     debug("VERIFY: Time difference %s" % self.verifydiff)
     if tolerancechecking and self.verifydiff > maxtolerance:
         raise Exception(
             'restore',
             "Verification time difference %s is larger than allowed tolerance %s"
             % (verifydiff, maxtolerance))
def process_database(dbname):
    Configuration.defaultsection = dbname
    Configuration.substitutions.update({'dbname': dbname})
    oraexec = OracleExec(oraclehome=Configuration.get('oraclehome', 'generic'),
                         tnspath=os.path.join(
                             scriptpath,
                             Configuration.get('tnsadmin', 'generic')))
    # Read job status information from the database
    jobinfo = {}
    for line in exec_sqlplus(oraexec, reporttemplate.get('jobstatus')):
        j = json.loads(line)
        if j["type"] == "job":
            if j["job_name"] == "ARCHLOGBACKUP_JOB":
                jobinfo["archlog"] = j
            elif j["job_name"] == "IMAGECOPY_JOB":
                jobinfo["imagecopy"] = j
        elif j["type"] == "exec":
            if j["job_name"] == "ARCHLOGBACKUP_JOB":
                jobinfo["archlogexec"] = j
            elif j["job_name"] == "IMAGECOPY_JOB":
                jobinfo["imagecopyexec"] = j
    # Read snapshot information
    zfs = create_snapshot_class(dbname)
    snaps = zfs.listsnapshots(True, True)
    # Autorestore information
    autorestoreinfo = None
    try:
        for line in exec_sqlplus(oraexec,
                                 reporttemplate.get('autorestorestatus'),
                                 'sqlplusautorestoreheader'):
            autorestoreinfo = json.loads(line)
    except:
        pass
    # Print output
    print "%s:" % dbname
    try:
        print "  Backup job: %s, last: %s, duration: %s, last failure: %s" % (
            jobinfo['imagecopy']['state'],
            jobinfo['imagecopy']['last_start_date'],
            jobinfo['imagecopy']['last_run_duration'],
            jobinfo['imagecopyexec']['last_failed'])
        print "  Archivelog job: %s, last: %s, duration: %s, last failure: %s" % (
            jobinfo['archlog']['state'], jobinfo['archlog']['last_start_date'],
            jobinfo['archlog']['last_run_duration'],
            jobinfo['archlogexec']['last_failed'])
        if len(snaps) > 0:
            firstsnap = zfs.getsnapinfo(snaps[0])
            lastsnap = zfs.getsnapinfo(snaps[-1])
            print "  Snapshots: %d, latest: %s, oldest: %s" % (
                len(snaps), firstsnap["creation"], lastsnap["creation"])
        else:
            print "  Snapshots: none"
        if autorestoreinfo is not None:
            print "  Last successful restore: %s, last restore failure: %s, last successful validation: %s, avg difference from target (s): %d, avg restore time (min): %d" % (
                autorestoreinfo["last_success"], autorestoreinfo["last_fail"],
                autorestoreinfo["last_validated"], autorestoreinfo["avgdiff"],
                autorestoreinfo["avgrestoremin"])
    except:
        print "  Error getting information."
Exemple #6
0
 def pit_restore(self, mountpath, sid):
     self._restoredest = mkdtemp(prefix="restore", dir=mountpath)
     self._mountdest = mountpath
     self._restoresid = sid
     self._set_parameters()
     self._createinitora()
     self._exec = OracleExec(oraclehome=Configuration.get('oraclehome', 'generic'),
         tnspath=os.path.join(scriptpath(), Configuration.get('tnsadmin', 'generic')),
         sid=sid)
     self._run_restore()
Exemple #7
0
 def __init__(self, configname):
     credfilename = os.path.join(scriptpath(), 'softnascredentials.cfg')
     if not os.path.isfile(credfilename):
       raise Exception(self._exceptionbase, "Configuration file %s not found" % credfilename)
     # Authentication information
     credconfig = SafeConfigParser()
     credconfig.read(credfilename)
     self._username = credconfig.get('credentials','user')
     self._password = credconfig.get('credentials','password')
     #
     self._serveraddress = Configuration.get('serveraddress', 'softnas')
     url = "https://%s/softnas" % self._serveraddress
     self._pool = Configuration.get('pool', 'softnas')
     self._filesystem = configname
     #
     self._http = SoftNASHttp(url)
     super(SoftNAS, self).__init__(configname)
Exemple #8
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()
Exemple #9
0
 def __init__(self, configname):
     zfscredfilename = os.path.join(scriptpath(), 'zfscredentials.cfg')
     if not os.path.isfile(zfscredfilename):
         raise Exception(
             self._exceptionbase,
             "Configuration file %s not found" % zfscredfilename)
     # Authentication information
     zfscredconfig = SafeConfigParser()
     zfscredconfig.read(zfscredfilename)
     zfsauth = (zfscredconfig.get('zfscredentials', 'zfsuser'),
                zfscredconfig.get('zfscredentials', 'zfspassword'))
     #
     zfssaurl = "%s/api/storage/v1" % Configuration.get('url', 'zfssa')
     self._pool = Configuration.get('pool', 'zfssa')
     self._project = Configuration.get('project', 'zfssa')
     self._filesystem = configname
     #
     self._http = ZFSHttp(zfssaurl, zfsauth)
     super(ZFSSA, self).__init__(configname)
 def _read_netapp_config(self, attribute, zfscredconfig):
     # Try reading Netapp configuration first from the credentials file, then fail over to main configuration file
     value = None
     try:
         return zfscredconfig.get('netapp', attribute)
     except (NoOptionError, NoSectionError) as e:
         pass
     try:
         return Configuration.get(attribute, 'netapp')
     except (NoOptionError, NoSectionError) as e:
         raise NoOptionError("Attribute %s not found" % attribute)
 def __init__(self, configname):
     zfscredfilename = os.path.join(scriptpath(), 'netappcredentials.cfg')
     if not os.path.isfile(zfscredfilename):
         raise Exception(
             self._exceptionbase,
             "Configuration file %s not found" % zfscredfilename)
     # Authentication information
     zfscredconfig = SafeConfigParser()
     zfscredconfig.read(zfscredfilename)
     zfsauth = (zfscredconfig.get('netappcredentials', 'user'),
                zfscredconfig.get('netappcredentials', 'password'))
     #
     self._filer = Configuration.get('filer', 'netapp')
     self._srv = NaServer(self._filer, 1, 1)
     self._srv.set_admin_user(
         zfscredconfig.get('netappcredentials', 'user'),
         zfscredconfig.get('netappcredentials', 'password'))
     self._volprefix = Configuration.get('volumeprefix', 'netapp')
     self._volname = "%s%s" % (self._volprefix, configname)
     super(Netapp, self).__init__(configname)
def validationdate(database):
    tmpsection = Configuration.defaultsection
    Configuration.defaultsection = database
    validatemodulus = int(
        Configuration.get('autorestoremodulus', 'autorestore'))
    Configuration.defaultsection = tmpsection
    #
    days_since_epoch = (datetime.utcnow() - datetime(1970, 1, 1)).days
    try:
        hashstring = Configuration.get('stringforvalidationmod', database)
    except:
        hashstring = database
    #
    mod1 = days_since_epoch % validatemodulus
    mod2 = hash(hashstring) % validatemodulus
    validatecorruption = mod1 == mod2
    days_to_next_validation = (mod2 -
                               mod1) if mod2 > mod1 else (validatemodulus -
                                                          (mod1 - mod2))
    next_validation = date.today() + timedelta(days=days_to_next_validation)
    return (validatecorruption, days_to_next_validation, next_validation)
def loopdatabases():
    excludelist = ['generic', 'rman', 'zfssa', 'autorestore', 'netapp']
    sections = Configuration.sections()
    if action is not None:
        if action[0] == "!":
            excludelist.append(action[1:])
        else:
            sections = [action]
    for configname in sections:
        if configname not in excludelist:
            if Configuration.get('autorestoreenabled', configname) == '1':
                yield configname
Exemple #14
0
def ask_user_input():
    global restoreparams, exitvalue

    is_safe = ui.ask_yn(
        "Is this system isolated with no access to production database storage"
    )
    if is_safe != "Y":
        print "Exiting. Please execute this script in an isolated environment."
        exitvalue = 1
        return
    restoreparams['mountpath'] = ui.ask_directory(
        "Directory where to mount clone:", False)
    restoreparams['timepoint'] = ui.ask_timestamp(
        "Restore database to time point")
    is_utc = ui.ask_yn("Was the timestamp in UTC (answer N for local time)")
    if is_utc == "Y":
        tz = pytz.utc
    else:
        tz = get_localzone()
    restoreparams['timepoint'] = tz.localize(restoreparams['timepoint'])
    restore.set_restore_target_time(restoreparams['timepoint'])
    restoreparams['sid'] = ui.ask_string("Target instance name:", 8, True)
    #
    splitter = "######################################"
    print splitter
    print ""
    print "Database unique name: %s" % configname
    print "Oracle home: %s" % Configuration.get("oraclehome", "generic")
    print "Clone mount path: %s" % restoreparams['mountpath']
    print "Target instance SID: %s" % restoreparams['sid']
    print "Restore target time UTC: %s" % restoreparams[
        'timepoint'].astimezone(pytz.utc)
    print "Restore target time local: %s" % restoreparams[
        'timepoint'].astimezone(get_localzone())
    print "Restored from snapshot: %s" % restore.sourcesnapid
    #
    print ""
    is_ok = ui.ask_yn("Are these parameters correct")
    if is_ok != "Y":
        print "Exiting. Please execute this script again."
        exitvalue = 1
        return
    print ""
    print splitter
Exemple #15
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)
    printhelp()

# Check environment
if (scriptaction == 'setschedule') and (os.getenv('OSPASSWORD') is None):
    print "Environment variable OSPASSWORD must be set."
    sys.exit(2)

# Directory where the executable script is located
scriptpath = scriptpath()

# Read configuration
configsection = sys.argv[1]
Configuration.init(configsection)

# 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()
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)
    print "THE RESTORE PROCESS CAN OVERWRITE OR DELETE FILES ON THEIR ORIGINAL CONTROL FILE LOCATIONS!"
    print "RUN IT ONLY ON A HOST THAT IS COMPLETELY SANDBOXED FROM PRODUCTION DATABASE ENVIRONMENT."
    print "TO CONTINUE, SET ENVIRONMENT VARIABLE AUTORESTORE_SAFE_SANDBOX TO VALUE TRUE (CASE SENSITIVE)."
    print ""
    sys.exit(3)

Configuration.init('autorestore',
                   configfilename=sys.argv[1],
                   additionaldefaults={
                       'customverifydate':
                       'select max(time_dp) from sys.smon_scn_time',
                       'autorestoreenabled': '1',
                       'autorestoreinstancenumber': '1',
                       'autorestorethread': '1'
                   })
oexec = OracleExec(oraclehome=Configuration.get('oraclehome', 'generic'),
                   tnspath=os.path.join(
                       scriptpath(), Configuration.get('tnsadmin', 'generic')))
restoretemplate = BackupTemplate('restoretemplate.cfg')

exitstatus = 0

# System actions


# Clean destination directory
def cleantarget(restoredest):
    debug("ACTION: Cleaning destination directory %s" % restoredest)
    for root, dirs, files in os.walk(restoredest, topdown=False):
        for name in files:
            os.remove(os.path.join(root, name))
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: '):
            yield (line.strip()[8:])


def process_database(dbname):
    Configuration.defaultsection = dbname
 def _set_parameters(self):
     # Detect if mountpath is actually a namespace containing multiple volumes
     orig_mount_dest = self._mountdest
     if not os.path.isfile(os.path.join(orig_mount_dest,
                                        'autorestore.cfg')):
         location_correct = False
         for item in os.listdir(orig_mount_dest):
             item_full_path = os.path.join(orig_mount_dest, item)
             if os.path.isdir(item_full_path):
                 self._mountpaths.append(item_full_path)
                 if os.path.isfile(
                         os.path.join(item_full_path, 'autorestore.cfg')):
                     location_correct = True
                     self._mountdest = item_full_path
         if not location_correct:
             raise Exception(
                 'restore',
                 'Mount path is not correct, autorestore.cfg was not found')
     else:
         self._mountpaths.append(self._mountdest)
     debug("All datafile mountpaths: %s" % self._mountpaths)
     debug("Main datafile mountpath: %s" % self._mountdest)
     debug("Location for temporary init.ora and other files: %s" %
           self._restoredest)
     #
     dbconfig = SafeConfigParser()
     dbconfig.read(os.path.join(self._mountdest, 'autorestore.cfg'))
     self._dbparams['dbname'] = dbconfig.get('dbparams', 'db_name')
     if self.targettime is None:
         self._dbparams['restoretarget'] = datetime.strptime(
             dbconfig.get('dbparams', 'lasttime'), '%Y-%m-%d %H:%M:%S')
     else:
         self._dbparams['restoretarget'] = self.targettime.astimezone(
             get_localzone())
     self._dbparams['bctfile'] = dbconfig.get('dbparams', 'bctfile')
     catalogstatements = []
     for item in self._mountpaths:
         catalogstatements.append(
             "catalog start with '%s/archivelog/' noprompt;" % item)
         catalogstatements.append(
             "catalog start with '%s/data_' noprompt;" % item)
     Configuration.substitutions.update({
         'db_name':
         self._dbparams['dbname'],
         'db_compatible':
         dbconfig.get('dbparams', 'compatible'),
         'db_files':
         dbconfig.get('dbparams', 'db_files'),
         'db_undotbs':
         dbconfig.get('dbparams', 'undo_tablespace'),
         'db_block_size':
         dbconfig.get('dbparams', 'db_block_size'),
         #            'lastscn': dbconfig.get('dbparams','lastscn'),
         'lasttime':
         self._dbparams['restoretarget'].strftime('%Y-%m-%d %H:%M:%S'),
         'dbid':
         Configuration.get('dbid', self._configname),
         'instancenumber':
         Configuration.get('autorestoreinstancenumber', self._configname),
         'thread':
         Configuration.get('autorestorethread', self._configname),
         'backupfinishedtime':
         dbconfig.get('dbparams', 'backup-finished'),
         'bctfile':
         self._dbparams['bctfile'],
         'autorestoredestination':
         self._restoredest,
         'mountdestination':
         self._mountdest,
         'catalogstatements':
         "\n".join(catalogstatements)
     })
     try:
         Configuration.substitutions.update(
             {'cdb': dbconfig.get('dbparams', 'enable_pluggable_database')})
     except:
         Configuration.substitutions.update({'cdb': 'FALSE'})
     self._initfile = os.path.join(self._restoredest, 'init.ora')
     Configuration.substitutions.update({
         'initora': self._initfile,
     })
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)
from subprocess import Popen, PIPE
from backupcommon import Configuration, scriptpath


def printhelp():
    print "Usage: dbinfo.py <config>"
    sys.exit(2)


if len(sys.argv) != 2:
    printhelp()

# Read configuration
configsection = sys.argv[1]
Configuration.init(configsection)
gimanaged = Configuration.get('gimanaged').upper() == 'TRUE'

if not gimanaged:
    print "gimanaged option is not set to TRUE for this database"
    sys.exit(2)

# Set oracle home, if it is not configured separately, take it from environment
oraclehome = Configuration.get('oraclehome', 'generic')
if os.environ.get('ORACLE_SID'):
    del os.environ['ORACLE_SID']
os.environ['ORACLE_HOME'] = oraclehome
os.environ['NLS_DATE_FORMAT'] = 'yyyy-mm-dd hh24:mi:ss'

# Get software version
p = Popen([os.path.join(scriptpath(), "get_oracle_version.sh"), oraclehome],
          stdout=PIPE,
Exemple #23
0
    print "RUN IT ONLY ON A HOST THAT IS COMPLETELY SANDBOXED FROM PRODUCTION DATABASE ENVIRONMENT."
    print "TO CONTINUE, SET ENVIRONMENT VARIABLE AUTORESTORE_SAFE_SANDBOX TO VALUE TRUE (CASE SENSITIVE)."
    print ""
    sys.exit(3)

Configuration.init('autorestore',
                   configfilename=sys.argv[1],
                   additionaldefaults={
                       'customverifydate':
                       'select max(time_dp) from sys.smon_scn_time',
                       'autorestoreenabled': '1',
                       'autorestoreinstancenumber': '1',
                       'autorestorethread': '1'
                   })
validatechance = int(
    Configuration.get('autorestorevalidatechance', 'autorestore'))
validatemodulus = int(Configuration.get('autorestoremodulus', 'autorestore'))
oexec = OracleExec(oraclehome=Configuration.get('oraclehome', 'generic'),
                   tnspath=os.path.join(
                       scriptpath(), Configuration.get('tnsadmin', 'generic')))
restoretemplate = BackupTemplate('restoretemplate.cfg')

# Does the backup destination exist?
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')
Exemple #24
0
def loopdatabases():
    excludelist = ['generic', 'rman', 'zfssa', 'autorestore', 'netapp']
    for configname in Configuration.sections():
        if configname not in excludelist:
            if Configuration.get('autorestoreenabled', configname) == '1':
                yield configname
Exemple #25
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)