#!/usr/bin/env python # #******************************************************************************* # #Copyright (c) 2009, Perforce Software, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #******************************************************************************* # #Author: Stephen Moon #Date: 7/9/2010 #Summary: Backs up Perforce metadata # #******************************************************************************* from subprocess import Popen,PIPE,STDOUT from datetime import date import sys,os,re,time,logging,smtplib #Enable logging of the backup script logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M', filename='p4backup.log', filemode='w') # define a Handler which writes INFO messages or higher to the sys.stderr console = logging.StreamHandler() console.setLevel(logging.INFO) # set a format which is simpler for console use formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') # tell the handler to use this format console.setFormatter(formatter) # add the handler to the root logger logging.getLogger('').addHandler(console) checkForJnlRotation = re.compile(r'^(Checkpointing).+\n(Rotating).*$',re.MULTILINE) checkForP4D = re.compile(r'^(Checkpointing).+\n(Rotating).*$',re.MULTILINE) #define all the environmental variables p4debug = logging.getLogger('p4debug') p4error = logging.getLogger('p4error') path = '/Users/smoon/local/20092/' path2p4d = path + 'p4d' path2p4 = path + 'p4' path2ck = path + 'chkpt/chkpnt' mailhost = 'smtp.perforce.com' server = 'localhost:' port = '20092' jnlDir = '/Users/smoon/local/20092/jnl/' jnlFile = 'p4jnl' logDir = '/Users/smoon/local/20092/log/' logFile = 'p4log' P4USER = 'smoon' P4ROOT = '/Users/smoon/local/20092' P4CHARSET = 'utf8' #set it to empty string if your server is not Unicode P4PORT = server + port P4JOURNAL = jnlDir + jnlFile P4LOG = logDir + logFile os.environ['P4ROOT'] = P4ROOT os.environ['P4JOURNAL']= P4JOURNAL os.environ['P4PORT'] = P4PORT os.environ['P4LOG'] = P4LOG os.environ['P4USER'] = P4USER os.environ['P4CHARSET'] = P4CHARSET def emailAdmin(status): #failure is 1 and success is 0 f = open('p4backup.log') line = f.readline() fromaddr = P4USER + '@' + mailhost toaddr = [P4USER + '@' + mailhost] msg = "From: %s\nTo: %s\n\n" % (fromaddr, ",".join(toaddr)) if status: msg = "Subject: Perforce Checkpoint FAILED on %s\n\n" % (date.today()) else: msg = "Subject: Perforce Checkpoint SUCCEEDED on %s\n\n" % (date.today()) while line: line = f.readline() msg += line f.close() try: server = smtplib.SMTP(mailhost) except: p4error.exception('Unable to create mailport') exit(1) try: server.sendmail(fromaddr,toaddr,msg) except: p4error.exception('Unable to send an email') exit(1) try: server.quit() except: p4error.exception('Unable to quit mail') exit(1) def main(): if os.path.isfile(P4JOURNAL): pass else: p4error.exception("The running journal: " + P4JOURNAL + " does not exist") emailAdmin(1) exit(1) #stop the server. May need to be customized stopServer = [path2p4,'admin','stop'] p = Popen(stopServer,stdout=PIPE,stderr=PIPE) stopOut,stopErr = p.communicate() p.stdout.close() p.stderr.close() if stopErr == "": print('Server stopped successfully!\n') p4debug.debug('Server stopped successfully...') else: sys.stderr.write(stopErr) p4error.exception('Error stopping the server: \n%s' % stopErr) emailAdmin(1) exit(1) #After the server is stopped, a checkpoint is taken #This creates a compressed checkpoint takeCkpnt = [path2p4d,'-z','-jc',path2ck] p1 = Popen(takeCkpnt,stdout=PIPE,stderr=PIPE) chkOut,chkErr = p1.communicate() p1.stdout.close() p1.stderr.close() if chkOut != "": jnlRotate = checkForJnlRotation.match(chkOut) if jnlRotate.group(1) and jnlRotate.group(2): print(chkOut) p4debug.debug('Taking a checkpoint: \n%s' % chkOut) p4debug.debug("Checkpoint taken successfully") else: sys.stderr.write(chkErr) p4error.exception('Error while taking a checkpoint: \n%s' % chkErr) p4error.exception("Checkpoint failed") emailAdmin(1) exit(1) else: sys.stderr.write(chkErr) p4error.exception('Error while taking a checkpoint: \n%s' % chkErr) p4error.exception("Checkpoint failed") emailAdmin(1) exit(1) #This runs in a no-wait mode, so that it doesn't hang the script. #p4pid contains the PID of the server process. It is an indication #that the Perforce server has started successfully. p4pid = Popen(path2p4d,shell=True,stdout=PIPE,stderr=PIPE).pid if p4pid: print 'Server started successfully!\n' p4debug.debug('Starting the server... PID: %d' % p4pid) p4debug.debug('Server started successfully!\n') emailAdmin(0) else: p4error.exception('Failed to start the server.') emailAdmin(1) exit(1) if __name__ == '__main__': main()