Project

General

Profile

Backport #1594 ยป backup.rb

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

 
1
require "ftools"
2

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

    
14
# CONSTANTS
15

    
16
NumLogs = 8
17

    
18
BackupList = "directoryList.txt"
19

    
20
BaseLogName = "backup"
21

    
22
Log = "#{BaseLogName}01.log"
23

    
24
OneDayInSeconds = 24*60*60
25

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

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

    
31
# time window constants
32

    
33
Before        = 0
34
In            = 1
35
AfterSameDay  = 2
36
AfterLaterDay = 3
37

    
38
def formatToTwoInts(value)
39
  str = ""
40
  if value < 10
41
    str += "0#{value}"
42
  else
43
    str += "#{value}"
44
  end
45
end
46

    
47
tmp = ""
48
tmp += formatToTwoInts(WorkEnd[0])
49
tmp += formatToTwoInts(WorkEnd[1])
50
tmp += "-"
51
tmp += formatToTwoInts(WorkStart[0])
52
tmp += formatToTwoInts(WorkStart[1])
53

    
54
RunHours = tmp
55

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

    
70
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"
71

    
72
# GLOBALS
73

    
74
# used to hold machines etc. to backup
75
@usrs = []
76
@psswrds = []
77
@machines = []
78
@srcShares = []
79
@srcDirs = []
80
@destMachines = []
81
@destShares = []
82

    
83
# FUNCTIONS
84

    
85
def appendLog(str)
86
  File.open(Log,"a") do | file |
87
    file.print(str,"\n")
88
  end
89
end
90

    
91
def saveLogs()
92
  NumLogs.downto(1) do | logNum |
93
    case logNum
94
      when 1,2,3,4,5,6,7,8
95
        logFile = "#{BaseLogName}0#{logNum}.log"
96
        savedFile = "#{BaseLogName}0#{logNum+1}.log"
97
      when 9
98
        logFile = "#{BaseLogName}0#{logNum}.log"
99
        savedFile = "#{BaseLogName}#{logNum+1}.log"
100
      else
101
        logFile = "#{BaseLogName}#{logNum}.log"
102
        savedFile = "#{BaseLogName}#{logNum+1}.log"
103
    end
104
    if FileTest.exist?(logFile)
105
      File.rm_f(savedFile) if FileTest.exist?(savedFile)
106
      # file move from curr log to next log
107
      File.move(logFile,savedFile)
108
    end
109
  end
110
  logFile = "#{BaseLogName}01.log"
111
  File.rm_f(logFile) if FileTest.exist?(logFile)
112
end
113

    
114
def readBackupList()
115
  @usrs = []
116
  @psswrds = []
117
  @srcMachines = []
118
  @srcShares = []
119
  @srcDirs = []
120
  @destMachines = []
121
  @destShares = []
122
  file = File.new(BackupList).each do | fileSpec |
123
    next if (fileSpec.length > 0) and (fileSpec[0].chr == "#")
124
    if fileSpec =~ /(.*),(.*),(.*),(.*),(.*),(.*),(.*)/
125
      #print "Found one: #{$1} #{$2} #{$3} #{$4} #{$5} #{$6} #{$7}\n"
126
      @usrs             << $1
127
      @psswrds      << $2
128
      @srcMachines    << $3
129
      @srcShares       << $4
130
      @srcDirs           << $5
131
      @destMachines  << $6
132
      @destShares     << $7
133
    end
134
  end
135
end
136

    
137
def decrypt(pss)
138
  outStr = ""
139
  pss.each_byte do | ch |
140
    if (ch > 79)  # 80 <= ch <= 126
141
      newCh = (ch - 47).chr
142
      #print "[#{ch.chr}] went to [#{newCh}]\n"
143
      outStr << newCh
144
    else # 33 <= ch <= 79
145
      newCh = (ch + 47).chr
146
      #print "[#{ch.chr}] went to [#{newCh}]\n"
147
      outStr << newCh
148
    end
149
  end
150
  outStr
151
end
152

    
153
def backupMachine(usr,psswrd,machine,share,directory,destMachine,destShare)
154
  
155
  # build batch file
156
  
157
#  File.open("copyIt.bat","w") do | file |
158
#    file.print("net use q: /delete\n")
159
#    file.print("net use q: \"\\\\#{machine}\\#{share}\" #{decrypt(psswrd)} /user:#{usr}\n")
160
#    file.print("robocopy \"q:\\#{directory}\" \"\\\\#{destMachine}\\#{destShare}\\#{machine}\\#{share}\\#{directory}\" #{RoboCopyFlags}\n")
161
#    file.print("net use q: /delete\n")
162
#  end
163
  
164
  appendLog("\nStart backup of \\\\#{machine}\\#{share}\\#{directory} ********")
165
  
166
  srcShare = "\"\\\\#{machine}\\#{share}\""
167
  srcDir = "\"q:\\#{directory}\""
168
  dstDir = "\"\\\\#{destMachine}\\#{destShare}\\#{machine}\\#{share}\\#{directory}\""
169
  
170
  # run batch file
171
  
172
  system("doBackupRobo.bat #{usr} #{decrypt(psswrd)} #{srcShare} #{srcDir} #{dstDir} #{RoboCopyFlags}")
173

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

    
177
def forbiddenTime(currTime, startForbiddenWindow, endForbiddenWindow)
178
  forbidden = nil
179
  if ((startForbiddenWindow <= currTime) and (currTime <= endForbiddenWindow))
180
    forbidden = true
181
  else
182
    forbidden = false
183
  end
184
  forbidden
185
end
186

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

    
198
def classifyPeriod(time,startWin,endWin)
199
  value = Before - 1
200
  if time < startWin
201
    value = Before
202
  elsif (startWin <= time) and (time <= endWin)
203
    value = In
204
  else
205
    if ((time.year == endWin.year) and
206
        (time.month == endWin.month) and
207
        (time.day == endWin.day))
208
      value = AfterSameDay
209
    else
210
      value = AfterLaterDay
211
    end
212
  end
213
  value
214
end
215

    
216
def nextDayWindowEnd(fromTime)
217
  endWindow =
218
    Time.local(fromTime.year, fromTime.month, fromTime.day,
219
               WorkEnd[0], WorkEnd[1], 0, 0) + OneDayInSeconds
220
  endWindow
221
end
222

    
223
# MAIN PROGRAM
224

    
225
until (true == false) do
226

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

    
231
  startForbiddenWindow =
232
    Time.local(iterStart.year, iterStart.month, iterStart.day,
233
               WorkStart[0], WorkStart[1], 0, 0)
234
  endForbiddenWindow =
235
    Time.local(iterStart.year, iterStart.month, iterStart.day,
236
               WorkEnd[0], WorkEnd[1], 0, 0)
237

    
238
  started = classifyPeriod(iterStart,startForbiddenWindow,endForbiddenWindow)
239
  
240
  # run the file copying  
241
  saveLogs
242
  readBackupList
243
  0.upto((@srcMachines.length)-1) do | i |
244
    backupMachine(@usrs[i],@psswrds[i],
245
                          @srcMachines[i],@srcShares[i],@srcDirs[i],
246
                          @destMachines[i],@destShares[i])
247
  end
248
  
249
  iterEnd = Time.now
250

    
251
  ended = classifyPeriod(iterEnd,startForbiddenWindow,endForbiddenWindow)
252
  
253
  # determine how long to sleep based on when started and ended
254
  
255
  if (started == Before) and (ended == Before)
256
    sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
257
  elsif (started == Before) and (ended == In)
258
    sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
259
  elsif (started == Before) and (ended == AfterSameDay)
260
    endForbiddenWindow = nextDayWindowEnd(iterEnd)
261
    sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
262
  elsif (started == Before) and (ended == AfterLaterDay)
263
    # do nothing: next iteration and backup immediately
264
  elsif (started == In) and (ended == AfterSameDay)
265
    endForbiddenWindow = nextDayWindowEnd(iterEnd)
266
    sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
267
  elsif (started == In) and (ended == AfterLaterDay)
268
    # do nothing: next iteration and backup immediately
269
  elsif (started == AfterSameDay) and (ended == AfterSameDay)
270
    endForbiddenWindow = nextDayWindowEnd(iterEnd)
271
    sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
272
  elsif (started == AfterSameDay) and (ended == AfterLaterDay)
273
    endForbiddenWindow = nextDayWindowEnd(iterStart)
274
    if (iterEnd < endForbiddenWindow)
275
      sleepUntilOpenWindow(iterEnd,endForbiddenWindow)
276
    else
277
      # do nothing: next iteration and backup immediately
278
    end
279
  else
280
    print "Unhandled combo of start #{started} and end #{ended}\n"
281
  end
282
  
283
end