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)
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."
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()
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)
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()
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
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
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,
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')
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
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)