5 import config |
5 import config |
6 import logging |
6 import logging |
7 import time |
7 import time |
8 import borgend |
8 import borgend |
9 import repository |
9 import repository |
10 import sleep |
10 import dreamtime |
11 from enum import IntEnum |
11 from enum import IntEnum |
12 from instance import BorgInstance |
12 from instance import BorgInstance |
13 from threading import Thread, Lock, Condition |
13 from threading import Thread, Lock, Condition |
14 from scheduler import TerminableThread |
14 from scheduler import TerminableThread |
15 |
15 |
141 scheduling=config.check_string(cfg, 'scheduling', |
141 scheduling=config.check_string(cfg, 'scheduling', |
142 'Scheduling mode', loc, |
142 'Scheduling mode', loc, |
143 default="dreamtime") |
143 default="dreamtime") |
144 |
144 |
145 if scheduling=="dreamtime": |
145 if scheduling=="dreamtime": |
146 self.timeclass=sleep.DreamTime |
146 self.timeclass=dreamtime.DreamTime |
147 elif scheduling=="realtime": |
147 elif scheduling=="realtime": |
148 self.timeclass=sleep.MonotonicTime |
148 self.timeclass=dreamtime.MonotonicTime |
149 elif scheduling=="manual": |
149 elif scheduling=="manual": |
150 self.backup_interval=0 |
150 self.backup_interval=0 |
151 else: |
151 else: |
152 logging.error("Invalid time class '%s' for %s" % (scheduling, loc)) |
152 logging.error("Invalid time class '%s' for %s" % (scheduling, loc)) |
153 |
153 |
170 self.scheduled_operation=None |
170 self.scheduled_operation=None |
171 self.lastrun_when=None |
171 self.lastrun_when=None |
172 self.lastrun_finished=None |
172 self.lastrun_finished=None |
173 self.state=State.INACTIVE |
173 self.state=State.INACTIVE |
174 self.errors=Errors.OK |
174 self.errors=Errors.OK |
175 self.timeclass=sleep.DreamTime |
175 self.timeclass=dreamtime.DreamTime |
176 |
176 |
177 self.__decode_config(cfg) |
177 self.__decode_config(cfg) |
178 |
178 |
179 super().__init__(target = self.__main_thread, name = self.backup_name) |
179 super().__init__(target = self.__main_thread, name = self.backup_name) |
180 self.daemon=True |
180 self.daemon=True |
298 self.thread_res=t_res |
298 self.thread_res=t_res |
299 self.borg_instance=inst |
299 self.borg_instance=inst |
300 self.current_operation=op |
300 self.current_operation=op |
301 # Update scheduled time to real starting time to schedule |
301 # Update scheduled time to real starting time to schedule |
302 # next run relative to this |
302 # next run relative to this |
303 self.current_operation.time=sleep.MonotonicTime.now() |
303 self.current_operation.time=dreamtime.MonotonicTime.now() |
304 self.state=State.ACTIVE |
304 self.state=State.ACTIVE |
305 # Reset error status when starting a new operation |
305 # Reset error status when starting a new operation |
306 self.errors=Errors.OK |
306 self.errors=Errors.OK |
307 self.__update_status() |
307 self.__update_status() |
308 |
308 |
470 return Operation(Operation.CREATE, tm, reason='initial') |
470 return Operation(Operation.CREATE, tm, reason='initial') |
471 elif not self.errors.ok(): |
471 elif not self.errors.ok(): |
472 if self.retry_interval==0: |
472 if self.retry_interval==0: |
473 return None |
473 return None |
474 else: |
474 else: |
475 tm=sleep.MonotonicTime(self.lastrun_finished+self.retry_interval) |
475 tm=dreamtime.MonotonicTime(self.lastrun_finished+self.retry_interval) |
476 return Operation(Operation.CREATE, tm, reason='retry') |
476 return Operation(Operation.CREATE, tm, reason='retry') |
477 else: |
477 else: |
478 if self.backup_interval==0: |
478 if self.backup_interval==0: |
479 return None |
479 return None |
480 else: |
480 else: |
516 with self._cond: |
516 with self._cond: |
517 res=self.__status_unlocked() |
517 res=self.__status_unlocked() |
518 return res[0] |
518 return res[0] |
519 |
519 |
520 def create(self): |
520 def create(self): |
521 op=Operation(Operation.CREATE, sleep.MonotonicTime.now(), reason='manual') |
521 op=Operation(Operation.CREATE, dreamtime.MonotonicTime.now(), reason='manual') |
522 with self._cond: |
522 with self._cond: |
523 self.scheduled_operation=op |
523 self.scheduled_operation=op |
524 self._cond.notify() |
524 self._cond.notify() |
525 |
525 |
526 def prune(self): |
526 def prune(self): |
527 op=Operation(Operation.PRUNE, sleep.MonotonicTime.now(), reason='manual') |
527 op=Operation(Operation.PRUNE, dreamtime.MonotonicTime.now(), reason='manual') |
528 with self._cond: |
528 with self._cond: |
529 self.scheduled_operation=op |
529 self.scheduled_operation=op |
530 self._cond.notify() |
530 self._cond.notify() |
531 |
531 |
532 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |
532 # TODO: Decide exact (manual) abort mechanism. Perhaps two stages |