backup.py

changeset 5
4c5514b2fa76
parent 4
d72c4844e791
child 6
46c89e5a219f
equal deleted inserted replaced
4:d72c4844e791 5:4c5514b2fa76
2 # Borgend Backup instance 2 # Borgend Backup instance
3 # 3 #
4 4
5 import config 5 import config
6 import logging 6 import logging
7 import time
7 from instance import BorgInstance 8 from instance import BorgInstance
8 from queue import Queue 9 from queue import Queue
9 from threading import Thread, Lock 10 from threading import Thread, Lock
10 11
11 class Backup: 12 class Backup:
50 51
51 self.__decode_config(cfg) 52 self.__decode_config(cfg)
52 53
53 self.config=config 54 self.config=config
54 self.lastrun=None 55 self.lastrun=None
56 self.lastrun_success=None
55 self.borg_instance=None 57 self.borg_instance=None
58 self.current_operation=None
56 self.thread=None 59 self.thread=None
57 self.lock=Lock() 60 self.lock=Lock()
58 61
59 def __block_when_running(self): 62 def __block_when_running(self):
60 self.lock.acquire() 63 with self.lock:
61 not_running=self.borg_instance is None and self.thread is None 64 not_running=self.borg_instance is None and self.thread is None
62 self.lock.release()
63 assert(not_running) 65 assert(not_running)
64 66
65 def __listener(self): 67 def __listener(self):
68 success=True
66 for status in iter(self.borg_instance.read, None): 69 for status in iter(self.borg_instance.read, None):
67 t=status['type'] 70 t=status['type']
68 if t=='progress_percent': 71 if t=='progress_percent':
69 pass 72 pass
70 elif t=='archive_progress': 73 elif t=='archive_progress':
71 pass 74 pass
72 elif t=='progress_message': 75 elif t=='progress_message':
76 # handle errors
73 pass 77 pass
74 elif t=='progress_percent': 78 elif t=='progress_percent':
75 pass 79 pass
76 elif t=='file_status': 80 elif t=='file_status':
77 pass 81 pass
78 elif t=='log_message': 82 elif t=='log_message':
79 pass 83 pass
80 elif t=='exception': 84 elif t=='exception':
85 success=False
81 pass 86 pass
82 elif t=='unparsed_error': 87 elif t=='unparsed_error':
88 success=False
83 pass 89 pass
84 # What to do? 90 # What to do?
85 print(status) 91 print(status)
86 92
87 logging.info('Borg subprocess finished; terminating listener thread') 93 logging.info('Borg subprocess finished; terminating listener thread')
88 94
89 self.lock.acquire() 95 with self.lock:
90 self.borg_instance=None 96 if self.current_operation=='create':
91 self.thread=None 97 self.lastrun=self.time_started
92 self.lock.release() 98 self.lastrun_success=success
99 self.borg_instance=None
100 self.thread=None
101 self.current_operation=None
102 self.time_started=None
93 103
94 def __launch(self, queue, operation, archive_or_repository, *args): 104 def __launch(self, queue, operation, archive_or_repository, *args):
95 105
96 inst=BorgInstance(operation, archive_or_repository, *args) 106 inst=BorgInstance(operation, archive_or_repository, *args)
97 inst.launch() 107 inst.launch()
100 t.daemon=True 110 t.daemon=True
101 111
102 self.thread=t 112 self.thread=t
103 self.borg_instance=inst 113 self.borg_instance=inst
104 self.queue=queue 114 self.queue=queue
115 self.current_operation=operation
116 self.time_started=time.monotonic()
105 117
106 t.start() 118 t.start()
107 119
108 def create(self, queue): 120 def create(self, queue):
109 self.__block_when_running() 121 self.__block_when_running()
120 self.__launch(queue, 'prune', self.repository, 132 self.__launch(queue, 'prune', self.repository,
121 [{'prefix': self.archive_prefix}] + self.prune_parameters) 133 [{'prefix': self.archive_prefix}] + self.prune_parameters)
122 134
123 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages 135 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages
124 def abort(self): 136 def abort(self):
125 self.lock.acquire() 137 with self.lock:
126 if self.borg_instance: 138 if self.borg_instance:
127 self.borg_instance.terminate() 139 self.borg_instance.terminate()
128 if self.thread: 140 if self.thread:
129 self.thread.terminate() 141 self.thread.terminate()
130 self.lock.release()
131 142
132 def join(self): 143 def join(self):
133 if self.thread: 144 if self.thread:
134 self.thread.join() 145 self.thread.join()
135 146
147 def next_action():
148 # TODO pruning as well
149 now=time.monotonic()
150 if not self.lastrun:
151 return 'create', now+self.retry_interval
152 elif not self.lastrun_success:
153 return 'create', self.lastrun+self.retry_interval
154 else:
155 if self.backup_interval==0:
156 return 'none', 0
157 else:
158 return 'create', self.lastrun+self.backup_interval
136 159
137 160

mercurial