backup.py

changeset 38
085a635f23f5
parent 34
9fce700d42de
child 45
aa2a95dc6093
equal deleted inserted replaced
37:9fab8200f7eb 38:085a635f23f5
109 109
110 self.__decode_config(cfg) 110 self.__decode_config(cfg)
111 111
112 self.config=config 112 self.config=config
113 self.lastrun_when=None 113 self.lastrun_when=None
114 self.lastrun_success=None 114 self.lastrun_errors=None
115 self.borg_instance=None 115 self.borg_instance=None
116 self.current_operation=None 116 self.current_operation=None
117 self.thread_log=None 117 self.thread_log=None
118 self.thread_res=None 118 self.thread_res=None
119 self.timer=None 119 self.timer=None
208 208
209 logger.debug('Result listener thread waiting for result') 209 logger.debug('Result listener thread waiting for result')
210 210
211 res=self.borg_instance.read_result() 211 res=self.borg_instance.read_result()
212 212
213 success=True 213 errors=False
214 214
215 logger.debug('Borg result: %s' % str(res)) 215 logger.debug('Borg result: %s' % str(res))
216 216
217 if res==None: 217 if res is None:
218 success=False 218 errors=True
219 219
220 logger.debug('Waiting for borg subprocess to terminate in result thread') 220 logger.debug('Waiting for borg subprocess to terminate in result thread')
221 221
222 success=success and self.borg_instance.wait() 222 errors=errors or not self.borg_instance.wait()
223 223
224 logger.debug('Borg subprocess terminated (success: %s); terminating result listener thread' % str(success)) 224 logger.debug('Borg subprocess terminated (errors: %s); terminating result listener thread' % str(errors))
225 225
226 self.thread_log.join() 226 self.thread_log.join()
227 227
228 with self.lock: 228 with self.lock:
229 if self.current_operation['operation']=='create': 229 if self.current_operation['operation']=='create':
230 self.lastrun_when=self.current_operation['when_monotonic'] 230 self.lastrun_when=self.current_operation['when_monotonic']
231 self.lastrun_success=success 231 self.lastrun_errors=errors
232 self.thread_res=None 232 self.thread_res=None
233 self.thread_log=None 233 self.thread_log=None
234 self.borg_instance=None 234 self.borg_instance=None
235 self.current_operation=None 235 self.current_operation=None
236 self.__schedule_unlocked() 236 self.__schedule_unlocked()
292 else: 292 else:
293 raise NotImplementedError("Invalid operation '%s'" % op['operation']) 293 raise NotImplementedError("Invalid operation '%s'" % op['operation'])
294 except Exception as err: 294 except Exception as err:
295 logger.debug('Rescheduling after failure') 295 logger.debug('Rescheduling after failure')
296 self.lastrun_when=time.monotonic() 296 self.lastrun_when=time.monotonic()
297 self.lastrun_success=False 297 self.lastrun_errors=True
298 self.__schedule_unlocked() 298 self.__schedule_unlocked()
299 raise err 299 raise err
300 300
301 return True 301 return True
302 302
367 return None 367 return None
368 else: 368 else:
369 return {'operation': 'create', 369 return {'operation': 'create',
370 'detail': 'initial', 370 'detail': 'initial',
371 'when_monotonic': now+initial_interval} 371 'when_monotonic': now+initial_interval}
372 elif not self.lastrun_success: 372 elif self.lastrun_errors:
373 if self.retry_interval==0: 373 if self.retry_interval==0:
374 return None 374 return None
375 else: 375 else:
376 return {'operation': 'create', 376 return {'operation': 'create',
377 'detail': 'retry', 377 'detail': 'retry',
379 else: 379 else:
380 if self.backup_interval==0: 380 if self.backup_interval==0:
381 return None 381 return None
382 else: 382 else:
383 return {'operation': 'create', 383 return {'operation': 'create',
384 'detail': None, 384 'detail': 'normal',
385 'when_monotonic': self.lastrun_when+self.backup_interval} 385 'when_monotonic': self.lastrun_when+self.backup_interval}
386 386
387 def __schedule_unlocked(self): 387 def __schedule_unlocked(self):
388 if self.current_operation: 388 if self.current_operation:
389 return self.current_operation 389 return self.current_operation
411 res=self.__status_unlocked() 411 res=self.__status_unlocked()
412 return res[0] 412 return res[0]
413 413
414 def __status_unlocked(self): 414 def __status_unlocked(self):
415 callback=self.__status_update_callback 415 callback=self.__status_update_callback
416
416 if self.current_operation: 417 if self.current_operation:
417 status=self.current_operation 418 status=self.current_operation
418 status['type']='current' 419 status['type']='current'
419 elif self.scheduled_operation: 420 # Errors should be set by listeners
420 status=self.scheduled_operation
421 status['type']='scheduled'
422 else: 421 else:
423 status={'type': 'nothing'} 422 if self.scheduled_operation:
424 423 status=self.scheduled_operation
425 status['name']=self.name 424 status['type']='scheduled'
425 else:
426 status={'type': 'nothing'}
427
428 if self.lastrun_errors is not None:
429 status['errors']=self.lastrun_errors
430
431 if 'detail' not in status:
432 status['detail']='NONE'
426 433
427 if 'errors' not in status: 434 if 'errors' not in status:
428 status['errors']=False 435 status['errors']=False
436
437 status['name']=self.name
429 438
430 if 'when_monotonic' in status: 439 if 'when_monotonic' in status:
431 status['when']=(status['when_monotonic'] 440 status['when']=(status['when_monotonic']
432 -time.monotonic()+time.time()) 441 -time.monotonic()+time.time())
433 442

mercurial