def __copySegmentDirectories(self, gpEnv, gpArray, directives): """ directives should be composed of GpCopySegmentDirectoryDirective values """ if len(directives) == 0: return srcSegments = [d.getSrcSegment() for d in directives] destSegments = [d.getDestSegment() for d in directives] isTargetReusedLocation = [ d.isTargetReusedLocation() for d in directives ] destSegmentByHost = GpArray.getSegmentsByHostName(destSegments) newSegmentInfo = gp.ConfigureNewSegment.buildSegmentInfoForNewSegment( destSegments, isTargetReusedLocation) logger.info('Building template directory') (tempDir, blankTarFile, tarFileName) = self.__buildTarFileForTransfer(gpEnv, gpArray.master, srcSegments[0], destSegments) def createConfigureNewSegmentCommand(hostName, cmdLabel, validationOnly): segmentInfo = newSegmentInfo[hostName] checkNotNone("segmentInfo for %s" % hostName, segmentInfo) return gp.ConfigureNewSegment(cmdLabel, segmentInfo, tarFile=tarFileName, newSegments=True, verbose=gplog.logging_is_verbose(), batchSize=self.__parallelDegree, ctxt=gp.REMOTE, remoteHost=hostName, validationOnly=validationOnly) # # validate directories for target segments # logger.info('Validating remote directories') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append( createConfigureNewSegmentCommand(hostName, 'validate blank segments', True)) for cmd in cmds: self.__pool.addCommand(cmd) self.__pool.wait_and_printdots(len(cmds), self.__quiet) validationErrors = [] for item in self.__pool.getCompletedItems(): results = item.get_results() if not results.wasSuccessful(): if results.rc == 1: # stdoutFromFailure = results.stdout.replace("\n", " ").strip() lines = results.stderr.split("\n") for line in lines: if len(line.strip()) > 0: validationErrors.append( "Validation failure on host %s %s" % (item.remoteHost, line)) else: validationErrors.append(str(item)) self.__pool.empty_completed_items() if validationErrors: raise ExceptionNoStackTraceNeeded("\n" + ("\n".join(validationErrors))) # # copy tar from master to target hosts # logger.info('Copying template directory file') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append( gp.RemoteCopy("copy segment tar", blankTarFile, hostName, tarFileName)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear( cmds, "building and transferring basic segment directory") # # unpack and configure new segments # logger.info('Configuring new segments') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append( createConfigureNewSegmentCommand(hostName, 'configure blank segments', False)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear( cmds, "unpacking basic segment directory") # # copy dump files from old segment to new segment # for srcSeg in srcSegments: for destSeg in destSegments: if srcSeg.content == destSeg.content: cmd = Scp('copy db_dumps from old segment to new segment', os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps*', '*'), os.path.join(destSeg.getSegmentDataDirectory(), 'db_dumps'), srcSeg.getSegmentAddress(), destSeg.getSegmentAddress(), recursive=True) cmd.run(validateAfter=True) break # # Clean up copied tar from each remote host # logger.info('Cleaning files') cmds = [] for hostName, segments in destSegmentByHost.iteritems(): cmds.append( unix.RemoveFiles('remove tar file', tarFileName, ctxt=gp.REMOTE, remoteHost=hostName)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear( cmds, "cleaning up tar file on segment hosts") # # clean up the local temp directory # unix.RemoveFiles.local('remove temp directory', tempDir)
def __copySegmentDirectories(self, gpEnv, gpArray, directives): """ directives should be composed of GpCopySegmentDirectoryDirective values """ if len(directives) == 0: return srcSegments = [] destSegments = [] isTargetReusedLocation = [] timeStamp = datetime.datetime.today().strftime('%Y%m%d_%H%M%S') for directive in directives: srcSegment = directive.getSrcSegment() destSegment = directive.getDestSegment() destSegment.primaryHostname = srcSegment.getSegmentHostName() destSegment.primarySegmentPort = srcSegment.getSegmentPort() destSegment.progressFile = '%s/pg_basebackup.%s.dbid%s.out' % ( gplog.get_logger_dir(), timeStamp, destSegment.getSegmentDbId()) srcSegments.append(srcSegment) destSegments.append(destSegment) isTargetReusedLocation.append(directive.isTargetReusedLocation()) destSegmentByHost = GpArray.getSegmentsByHostName(destSegments) newSegmentInfo = gp.ConfigureNewSegment.buildSegmentInfoForNewSegment( destSegments, isTargetReusedLocation) def createConfigureNewSegmentCommand(hostName, cmdLabel, validationOnly): segmentInfo = newSegmentInfo[hostName] checkNotNone("segmentInfo for %s" % hostName, segmentInfo) return gp.ConfigureNewSegment(cmdLabel, segmentInfo, gplog.get_logger_dir(), newSegments=True, verbose=gplog.logging_is_verbose(), batchSize=self.__parallelDegree, ctxt=gp.REMOTE, remoteHost=hostName, validationOnly=validationOnly, forceoverwrite=self.__forceoverwrite) # # validate directories for target segments # self.__logger.info('Validating remote directories') cmds = [] for hostName in list(destSegmentByHost.keys()): cmds.append( createConfigureNewSegmentCommand(hostName, 'validate blank segments', True)) for cmd in cmds: self.__pool.addCommand(cmd) if self.__quiet: self.__pool.join() else: base.join_and_indicate_progress(self.__pool) validationErrors = [] for item in self.__pool.getCompletedItems(): results = item.get_results() if not results.wasSuccessful(): if results.rc == 1: # stdoutFromFailure = results.stdout.replace("\n", " ").strip() lines = results.stderr.split("\n") for line in lines: if len(line.strip()) > 0: validationErrors.append( "Validation failure on host %s %s" % (item.remoteHost, line)) else: validationErrors.append(str(item)) self.__pool.empty_completed_items() if validationErrors: raise ExceptionNoStackTraceNeeded("\n" + ("\n".join(validationErrors))) # Configure a new segment # # Recover segments using gpconfigurenewsegment, which # uses pg_basebackup. gprecoverseg generates a log filename which is # passed to gpconfigurenewsegment as a confinfo parameter. gprecoverseg # tails this file to show recovery progress to the user, and removes the # file when one done. A new file is generated for each run of # gprecoverseg based on a timestamp. self.__logger.info('Configuring new segments') cmds = [] progressCmds = [] removeCmds = [] for hostName in list(destSegmentByHost.keys()): for segment in destSegmentByHost[hostName]: progressCmd, removeCmd = self.__getProgressAndRemoveCmds( segment.progressFile, segment.getSegmentDbId(), hostName) removeCmds.append(removeCmd) if progressCmd: progressCmds.append(progressCmd) cmds.append( createConfigureNewSegmentCommand(hostName, 'configure blank segments', False)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear( cmds, "unpacking basic segment directory", suppressErrorCheck=False, progressCmds=progressCmds) self.__runWaitAndCheckWorkerPoolForErrorsAndClear( removeCmds, "removing pg_basebackup progress logfiles", suppressErrorCheck=False) # # copy dump files from old segment to new segment # for srcSeg in srcSegments: for destSeg in destSegments: if srcSeg.content == destSeg.content: src_dump_dir = os.path.join( srcSeg.getSegmentDataDirectory(), 'db_dumps') cmd = base.Command('check existence of db_dumps directory', 'ls %s' % (src_dump_dir), ctxt=base.REMOTE, remoteHost=destSeg.getSegmentAddress()) cmd.run() if cmd.results.rc == 0: # Only try to copy directory if it exists cmd = Scp( 'copy db_dumps from old segment to new segment', os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps*', '*'), os.path.join(destSeg.getSegmentDataDirectory(), 'db_dumps'), srcSeg.getSegmentAddress(), destSeg.getSegmentAddress(), recursive=True) cmd.run(validateAfter=True) break
def __copySegmentDirectories(self, gpEnv, gpArray, directives): """ directives should be composed of GpCopySegmentDirectoryDirective values """ if len(directives) == 0: return srcSegments = [] destSegments = [] isTargetReusedLocation = [] for directive in directives: srcSegment = directive.getSrcSegment() destSegment = directive.getDestSegment() destSegment.primaryHostname = srcSegment.getSegmentHostName() destSegment.primarySegmentPort = srcSegment.getSegmentPort() srcSegments.append(srcSegment) destSegments.append(destSegment) isTargetReusedLocation.append(directive.isTargetReusedLocation()) destSegmentByHost = GpArray.getSegmentsByHostName(destSegments) newSegmentInfo = gp.ConfigureNewSegment.buildSegmentInfoForNewSegment( destSegments, isTargetReusedLocation) def createConfigureNewSegmentCommand(hostName, cmdLabel, validationOnly): segmentInfo = newSegmentInfo[hostName] checkNotNone("segmentInfo for %s" % hostName, segmentInfo) return gp.ConfigureNewSegment(cmdLabel, segmentInfo, newSegments=True, verbose=gplog.logging_is_verbose(), batchSize=self.__parallelDegree, ctxt=gp.REMOTE, remoteHost=hostName, validationOnly=validationOnly, forceoverwrite=self.__forceoverwrite) # # validate directories for target segments # self.__logger.info('Validating remote directories') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append( createConfigureNewSegmentCommand(hostName, 'validate blank segments', True)) for cmd in cmds: self.__pool.addCommand(cmd) self.__pool.wait_and_printdots(len(cmds), self.__quiet) validationErrors = [] for item in self.__pool.getCompletedItems(): results = item.get_results() if not results.wasSuccessful(): if results.rc == 1: # stdoutFromFailure = results.stdout.replace("\n", " ").strip() lines = results.stderr.split("\n") for line in lines: if len(line.strip()) > 0: validationErrors.append( "Validation failure on host %s %s" % (item.remoteHost, line)) else: validationErrors.append(str(item)) self.__pool.empty_completed_items() if validationErrors: raise ExceptionNoStackTraceNeeded("\n" + ("\n".join(validationErrors))) # # unpack and configure new segments # self.__logger.info('Configuring new segments') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append( createConfigureNewSegmentCommand(hostName, 'configure blank segments', False)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear( cmds, "unpacking basic segment directory") # # copy dump files from old segment to new segment # for srcSeg in srcSegments: for destSeg in destSegments: if srcSeg.content == destSeg.content: src_dump_dir = os.path.join( srcSeg.getSegmentDataDirectory(), 'db_dumps') cmd = base.Command('check existence of db_dumps directory', 'ls %s' % (src_dump_dir), ctxt=base.REMOTE, remoteHost=destSeg.getSegmentAddress()) cmd.run() if cmd.results.rc == 0: # Only try to copy directory if it exists cmd = Scp( 'copy db_dumps from old segment to new segment', os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps*', '*'), os.path.join(destSeg.getSegmentDataDirectory(), 'db_dumps'), srcSeg.getSegmentAddress(), destSeg.getSegmentAddress(), recursive=True) cmd.run(validateAfter=True) break
def __copySegmentDirectories(self, gpEnv, gpArray, directives): """ directives should be composed of GpCopySegmentDirectoryDirective values """ if len(directives) == 0: return srcSegments = [] destSegments = [] isTargetReusedLocation = [] for directive in directives: srcSegment = directive.getSrcSegment() destSegment = directive.getDestSegment() destSegment.primaryHostname = srcSegment.getSegmentHostName() destSegment.primarySegmentPort = srcSegment.getSegmentPort() srcSegments.append(srcSegment) destSegments.append(destSegment) isTargetReusedLocation.append(directive.isTargetReusedLocation()) destSegmentByHost = GpArray.getSegmentsByHostName(destSegments) newSegmentInfo = gp.ConfigureNewSegment.buildSegmentInfoForNewSegment(destSegments, isTargetReusedLocation) def createConfigureNewSegmentCommand(hostName, cmdLabel, validationOnly): segmentInfo = newSegmentInfo[hostName] checkNotNone("segmentInfo for %s" % hostName, segmentInfo) return gp.ConfigureNewSegment(cmdLabel, segmentInfo, gplog.get_logger_dir(), newSegments=True, verbose=gplog.logging_is_verbose(), batchSize=self.__parallelDegree, ctxt=gp.REMOTE, remoteHost=hostName, validationOnly=validationOnly, forceoverwrite=self.__forceoverwrite) # # validate directories for target segments # self.__logger.info('Validating remote directories') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append(createConfigureNewSegmentCommand(hostName, 'validate blank segments', True)) for cmd in cmds: self.__pool.addCommand(cmd) if self.__quiet: self.__pool.join() else: base.join_and_indicate_progress(self.__pool) validationErrors = [] for item in self.__pool.getCompletedItems(): results = item.get_results() if not results.wasSuccessful(): if results.rc == 1: # stdoutFromFailure = results.stdout.replace("\n", " ").strip() lines = results.stderr.split("\n") for line in lines: if len(line.strip()) > 0: validationErrors.append("Validation failure on host %s %s" % (item.remoteHost, line)) else: validationErrors.append(str(item)) self.__pool.empty_completed_items() if validationErrors: raise ExceptionNoStackTraceNeeded("\n" + ("\n".join(validationErrors))) # # unpack and configure new segments # self.__logger.info('Configuring new segments') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append(createConfigureNewSegmentCommand(hostName, 'configure blank segments', False)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear(cmds, "unpacking basic segment directory") # # copy dump files from old segment to new segment # for srcSeg in srcSegments: for destSeg in destSegments: if srcSeg.content == destSeg.content: src_dump_dir = os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps') cmd = base.Command('check existence of db_dumps directory', 'ls %s' % (src_dump_dir), ctxt=base.REMOTE, remoteHost=destSeg.getSegmentAddress()) cmd.run() if cmd.results.rc == 0: # Only try to copy directory if it exists cmd = Scp('copy db_dumps from old segment to new segment', os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps*', '*'), os.path.join(destSeg.getSegmentDataDirectory(), 'db_dumps'), srcSeg.getSegmentAddress(), destSeg.getSegmentAddress(), recursive=True) cmd.run(validateAfter=True) break
def __copySegmentDirectories(self, gpEnv, gpArray, directives): """ directives should be composed of GpCopySegmentDirectoryDirective values """ if len(directives) == 0: return srcSegments = [] destSegments = [] isTargetReusedLocation = [] timeStamp = datetime.datetime.today().strftime('%Y%m%d_%H%M%S') for directive in directives: srcSegment = directive.getSrcSegment() destSegment = directive.getDestSegment() destSegment.primaryHostname = srcSegment.getSegmentHostName() destSegment.primarySegmentPort = srcSegment.getSegmentPort() destSegment.progressFile = '%s/pg_basebackup.%s.dbid%s.out' % (gplog.get_logger_dir(), timeStamp, destSegment.getSegmentDbId()) srcSegments.append(srcSegment) destSegments.append(destSegment) isTargetReusedLocation.append(directive.isTargetReusedLocation()) destSegmentByHost = GpArray.getSegmentsByHostName(destSegments) newSegmentInfo = gp.ConfigureNewSegment.buildSegmentInfoForNewSegment(destSegments, isTargetReusedLocation) def createConfigureNewSegmentCommand(hostName, cmdLabel, validationOnly): segmentInfo = newSegmentInfo[hostName] checkNotNone("segmentInfo for %s" % hostName, segmentInfo) return gp.ConfigureNewSegment(cmdLabel, segmentInfo, gplog.get_logger_dir(), newSegments=True, verbose=gplog.logging_is_verbose(), batchSize=self.__parallelDegree, ctxt=gp.REMOTE, remoteHost=hostName, validationOnly=validationOnly, forceoverwrite=self.__forceoverwrite) # # validate directories for target segments # self.__logger.info('Validating remote directories') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append(createConfigureNewSegmentCommand(hostName, 'validate blank segments', True)) for cmd in cmds: self.__pool.addCommand(cmd) if self.__quiet: self.__pool.join() else: base.join_and_indicate_progress(self.__pool) validationErrors = [] for item in self.__pool.getCompletedItems(): results = item.get_results() if not results.wasSuccessful(): if results.rc == 1: # stdoutFromFailure = results.stdout.replace("\n", " ").strip() lines = results.stderr.split("\n") for line in lines: if len(line.strip()) > 0: validationErrors.append("Validation failure on host %s %s" % (item.remoteHost, line)) else: validationErrors.append(str(item)) self.__pool.empty_completed_items() if validationErrors: raise ExceptionNoStackTraceNeeded("\n" + ("\n".join(validationErrors))) # Configure a new segment # # Recover segments using gpconfigurenewsegment, which # uses pg_basebackup. gprecoverseg generates a log filename which is # passed to gpconfigurenewsegment as a confinfo parameter. gprecoverseg # tails this file to show recovery progress to the user, and removes the # file when one done. A new file is generated for each run of # gprecoverseg based on a timestamp. # # There is race between when the pg_basebackup log file is created and # when the progress command is run. Thus, the progress command touches # the file to ensure its present before tailing. self.__logger.info('Configuring new segments') cmds = [] progressCmds = [] removeCmds= [] for hostName in destSegmentByHost.keys(): for segment in destSegmentByHost[hostName]: if self.__progressMode != GpMirrorListToBuild.Progress.NONE: progressCmds.append( GpMirrorListToBuild.ProgressCommand("tail the last line of the file", "set -o pipefail; touch -a {0}; tail -1 {0} | tr '\\r' '\\n' | tail -1".format( pipes.quote(segment.progressFile)), segment.getSegmentDbId(), segment.progressFile, ctxt=base.REMOTE, remoteHost=hostName)) removeCmds.append( base.Command("remove file", "rm -f %s" % pipes.quote(segment.progressFile), ctxt=base.REMOTE, remoteHost=hostName)) cmds.append( createConfigureNewSegmentCommand(hostName, 'configure blank segments', False)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear(cmds, "unpacking basic segment directory", suppressErrorCheck=False, progressCmds=progressCmds) self.__runWaitAndCheckWorkerPoolForErrorsAndClear(removeCmds, "removing pg_basebackup progress logfiles", suppressErrorCheck=False) # # copy dump files from old segment to new segment # for srcSeg in srcSegments: for destSeg in destSegments: if srcSeg.content == destSeg.content: src_dump_dir = os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps') cmd = base.Command('check existence of db_dumps directory', 'ls %s' % (src_dump_dir), ctxt=base.REMOTE, remoteHost=destSeg.getSegmentAddress()) cmd.run() if cmd.results.rc == 0: # Only try to copy directory if it exists cmd = Scp('copy db_dumps from old segment to new segment', os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps*', '*'), os.path.join(destSeg.getSegmentDataDirectory(), 'db_dumps'), srcSeg.getSegmentAddress(), destSeg.getSegmentAddress(), recursive=True) cmd.run(validateAfter=True) break
def __copySegmentDirectories(self, gpEnv, gpArray, directives): """ directives should be composed of GpCopySegmentDirectoryDirective values """ if len(directives) == 0: return srcSegments = [d.getSrcSegment() for d in directives] destSegments = [d.getDestSegment() for d in directives] isTargetReusedLocation = [d.isTargetReusedLocation() for d in directives] destSegmentByHost = GpArray.getSegmentsByHostName(destSegments) newSegmentInfo = gp.ConfigureNewSegment.buildSegmentInfoForNewSegment(destSegments, isTargetReusedLocation) logger.info('Building template directory') (tempDir, blankTarFile, tarFileName) = self.__buildTarFileForTransfer(gpEnv, gpArray.master, srcSegments[0], destSegments) def createConfigureNewSegmentCommand(hostName, cmdLabel, validationOnly): segmentInfo = newSegmentInfo[hostName] checkNotNone("segmentInfo for %s" % hostName, segmentInfo) return gp.ConfigureNewSegment(cmdLabel, segmentInfo, tarFile=tarFileName, newSegments=True, verbose=gplog.logging_is_verbose(), batchSize=self.__parallelDegree, ctxt=gp.REMOTE, remoteHost=hostName, validationOnly=validationOnly) # # validate directories for target segments # logger.info('Validating remote directories') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append(createConfigureNewSegmentCommand(hostName, 'validate blank segments', True)) for cmd in cmds: self.__pool.addCommand(cmd) self.__pool.wait_and_printdots(len(cmds), self.__quiet) validationErrors = [] for item in self.__pool.getCompletedItems(): results = item.get_results() if not results.wasSuccessful(): if results.rc == 1: # stdoutFromFailure = results.stdout.replace("\n", " ").strip() lines = results.stderr.split("\n") for line in lines: if len(line.strip()) > 0: validationErrors.append("Validation failure on host %s %s" % (item.remoteHost, line)) else: validationErrors.append(str(item)) self.__pool.empty_completed_items() if validationErrors: raise ExceptionNoStackTraceNeeded("\n" + ("\n".join(validationErrors))) # # copy tar from master to target hosts # logger.info('Copying template directory file') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append( gp.RemoteCopy("copy segment tar", blankTarFile, hostName, tarFileName )) self.__runWaitAndCheckWorkerPoolForErrorsAndClear(cmds, "building and transferring basic segment directory") # # unpack and configure new segments # logger.info('Configuring new segments') cmds = [] for hostName in destSegmentByHost.keys(): cmds.append(createConfigureNewSegmentCommand(hostName, 'configure blank segments', False)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear(cmds, "unpacking basic segment directory") # # copy dump files from old segment to new segment # for srcSeg in srcSegments: for destSeg in destSegments: if srcSeg.content == destSeg.content: src_dump_dir = os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps') cmd = base.Command('check existence of db_dumps directory', 'ls %s' % (src_dump_dir), ctxt=base.REMOTE, remoteHost=destSeg.getSegmentAddress()) cmd.run() if cmd.results.rc == 0: # Only try to copy directory if it exists cmd = Scp('copy db_dumps from old segment to new segment', os.path.join(srcSeg.getSegmentDataDirectory(), 'db_dumps*', '*'), os.path.join(destSeg.getSegmentDataDirectory(), 'db_dumps'), srcSeg.getSegmentAddress(), destSeg.getSegmentAddress(), recursive=True) cmd.run(validateAfter=True) break # # Clean up copied tar from each remote host # logger.info('Cleaning files') cmds = [] for hostName, segments in destSegmentByHost.iteritems(): cmds.append(unix.RemoveFiles('remove tar file', tarFileName, ctxt=gp.REMOTE, remoteHost=hostName)) self.__runWaitAndCheckWorkerPoolForErrorsAndClear(cmds, "cleaning up tar file on segment hosts") # # clean up the local temp directory # unix.RemoveFiles.local('remove temp directory', tempDir)