Project

General

Profile

Backport #1594 » backup.rb

bdezonia (Barry DeZonia), 06/10/2009 12:55 AM

 
require "ftools"

# UNRESOLVED PROBLEMS
# Backup logs: move complains of readlink unimplemented in ftools. Used to work yesterday.
# Apparently this was from multiple file writers locking file.
# Make trimbackup and backup into one file with small front end. Front end simply takes
# robocopy flags, base log name, and batch file name.
# For some reason this script (and trimbackup.rb) unexpectedly quit after
# backing up a machine after a few days. No idea why. It is in the
# backupmachine loop in main. I'm trying to see if .bat crashes system()
# or if its something else weird that crashes ruby. I'm not having much
# luck debugging this.

# CONSTANTS

NumLogs = 8

BackupList = "directoryList.txt"

BaseLogName = "backup"

Log = "#{BaseLogName}01.log"

OneDayInSeconds = 24*60*60

# constants used for array of start and end times for runhours string and window Start/End

WorkStart = [8,00] # 8 am
WorkEnd = [17,30] # 5:30 pm

# time window constants

Before = 0
In = 1
AfterSameDay = 2
AfterLaterDay = 3

def formatToTwoInts(value)
str = ""
if value < 10
str += "0#{value}"
else
str += "#{value}"
end
end

tmp = ""
tmp += formatToTwoInts(WorkEnd[0])
tmp += formatToTwoInts(WorkEnd[1])
tmp += "-"
tmp += formatToTwoInts(WorkStart[0])
tmp += formatToTwoInts(WorkStart[1])

RunHours = tmp

# RoboCopy flags
#
# /xjd - exclude junction points: avoid infinite path name for vista
# /a-:rash - turn off specified attributes in copied files
# /np - turn off % progress indicator
# /r:0 - retry failed copies 0 times
# /fft - Fat File Times: useful for third party NTFS support
# /rh:1800-0730 - only copy files between 6:00 pm and 7:30 am
# /pf - check time per file
# /s - include all subdirs too (but not empty ones)
# /tee - output to screen while outputting to log file
# /log+:fname - append output to logfile named fname
# /xd "Temporary Internet Files" - exclude all temp internet files directories

RoboCopyFlags = "/xjd /a-:rash /np /r:0 /fft /rh:#{RunHours} /pf /s /tee /log+:#{Log} /xd \"Temporary Internet Files\" \"System Volume Information\" \"Program Files\" Cache Recycler"

# GLOBALS

# used to hold machines etc. to backup
@usrs = []
@psswrds = []
@machines = []
@srcShares = []
@srcDirs = []
@destMachines = []
@destShares = []

# FUNCTIONS

def appendLog(str)
File.open(Log,"a") do | file |
file.print(str,"\n")
end
end

def saveLogs()
NumLogs.downto(1) do | logNum |
case logNum
when 1,2,3,4,5,6,7,8
logFile = "#{BaseLogName}0#{logNum}.log"
savedFile = "#{BaseLogName}0#{logNum+1}.log"
when 9
logFile = "#{BaseLogName}0#{logNum}.log"
savedFile = "#{BaseLogName}#{logNum+1}.log"
else
logFile = "#{BaseLogName}#{logNum}.log"
savedFile = "#{BaseLogName}#{logNum+1}.log"
end
if FileTest.exist?(logFile)
File.rm_f(savedFile) if FileTest.exist?(savedFile)
# file move from curr log to next log
File.move(logFile,savedFile)
end
end
logFile = "#{BaseLogName}01.log"
File.rm_f(logFile) if FileTest.exist?(logFile)
end

def readBackupList()
@usrs = []
@psswrds = []
@srcMachines = []
@srcShares = []
@srcDirs = []
@destMachines = []
@destShares = []
file = File.new(BackupList).each do | fileSpec |
next if (fileSpec.length > 0) and (fileSpec[0].chr == "#")
if fileSpec =~ /(.*),(.*),(.*),(.*),(.*),(.*),(.*)/
#print "Found one: #{$1} #{$2} #{$3} #{$4} #{$5} #{$6} #{$7}\n"
@usrs << $1
@psswrds << $2
@srcMachines << $3
@srcShares << $4
@srcDirs << $5
@destMachines << $6
@destShares << $7
end
end
end

def decrypt(pss)
outStr = ""
pss.each_byte do | ch |
if (ch > 79) # 80 <= ch <= 126
newCh = (ch - 47).chr
#print "[#{ch.chr}] went to [#{newCh}]\n"
outStr << newCh
else # 33 <= ch <= 79
newCh = (ch + 47).chr
#print "[#{ch.chr}] went to [#{newCh}]\n"
outStr << newCh
end
end
outStr
end

def backupMachine(usr,psswrd,machine,share,directory,destMachine,destShare)
# build batch file
# File.open("copyIt.bat","w") do | file |
# file.print("net use q: /delete\n")
# file.print("net use q: \"\\\\#{machine}\\#{share}\" #{decrypt(psswrd)} /user:#{usr}\n")
# file.print("robocopy \"q:\\#{directory}\" \"\\\\#{destMachine}\\#{destShare}\\#{machine}\\#{share}\\#{directory}\" #{RoboCopyFlags}\n")
# file.print("net use q: /delete\n")
# end
appendLog("\nStart backup of \\\\#{machine}\\#{share}\\#{directory} ********")
srcShare = "\"\\\\#{machine}\\#{share}\""
srcDir = "\"q:\\#{directory}\""
dstDir = "\"\\\\#{destMachine}\\#{destShare}\\#{machine}\\#{share}\\#{directory}\""
# run batch file
system("doBackupRobo.bat #{usr} #{decrypt(psswrd)} #{srcShare} #{srcDir} #{dstDir} #{RoboCopyFlags}")

appendLog("End backup of \\\\#{machine}\\#{share}\\#{directory} **********\n")
end

def forbiddenTime(currTime, startForbiddenWindow, endForbiddenWindow)
forbidden = nil
if ((startForbiddenWindow <= currTime) and (currTime <= endForbiddenWindow))
forbidden = true
else
forbidden = false
end
forbidden
end

def sleepUntilOpenWindow(currTime,endForbiddenWindow)
secondsToSleep = endForbiddenWindow - currTime
if secondsToSleep > 0.0
print "Sleeping #{secondsToSleep} seconds until next backup window at #{endForbiddenWindow}\n"
sleep(secondsToSleep)
else # looks impossible to get here as this method is used
print "Weird timing error in sleepUntilOpenWindow\n"
print " Called with currTime beyond #{endForbiddenWindow}: #{currTime}!\n"
end
end

def classifyPeriod(time,startWin,endWin)
value = Before - 1
if time < startWin
value = Before
elsif (startWin <= time) and (time <= endWin)
value = In
else
if ((time.year == endWin.year) and
(time.month == endWin.month) and
(time.day == endWin.day))
value = AfterSameDay
else
value = AfterLaterDay
end
end
value
end

def nextDayWindowEnd(fromTime)
endWindow =
Time.local(fromTime.year, fromTime.month, fromTime.day,
WorkEnd[0], WorkEnd[1], 0, 0) + OneDayInSeconds
endWindow
end

# MAIN PROGRAM

until (true == false) do

print "Starting a pass through the backup loop\n"
iterStart = Time.now

startForbiddenWindow =
Time.local(iterStart.year, iterStart.month, iterStart.day,
WorkStart[0], WorkStart[1], 0, 0)
endForbiddenWindow =
Time.local(iterStart.year, iterStart.month, iterStart.day,
WorkEnd[0], WorkEnd[1], 0, 0)

started = classifyPeriod(iterStart,startForbiddenWindow,endForbiddenWindow)
# run the file copying
saveLogs
readBackupList
0.upto((@srcMachines.length)-1) do | i |
backupMachine(@usrs[i],@psswrds[i],
@srcMachines[i],@srcShares[i],@srcDirs[i],
@destMachines[i],@destShares[i])
end
iterEnd = Time.now

ended = classifyPeriod(iterEnd,startForbiddenWindow,endForbiddenWindow)
# determine how long to sleep based on when started and ended
if (started == Before) and (ended == Before)
sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
elsif (started == Before) and (ended == In)
sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
elsif (started == Before) and (ended == AfterSameDay)
endForbiddenWindow = nextDayWindowEnd(iterEnd)
sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
elsif (started == Before) and (ended == AfterLaterDay)
# do nothing: next iteration and backup immediately
elsif (started == In) and (ended == AfterSameDay)
endForbiddenWindow = nextDayWindowEnd(iterEnd)
sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
elsif (started == In) and (ended == AfterLaterDay)
# do nothing: next iteration and backup immediately
elsif (started == AfterSameDay) and (ended == AfterSameDay)
endForbiddenWindow = nextDayWindowEnd(iterEnd)
sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
elsif (started == AfterSameDay) and (ended == AfterLaterDay)
endForbiddenWindow = nextDayWindowEnd(iterStart)
if (iterEnd < endForbiddenWindow)
sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
else
# do nothing: next iteration and backup immediately
end
else
print "Unhandled combo of start #{started} and end #{ended}\n"
end
end
(1-1/2)