| 76 def ok(self): |
86 def ok(self): |
| 77 return self.errors.ok() |
87 return self.errors.ok() |
| 78 |
88 |
| 79 def add_error(self, error): |
89 def add_error(self, error): |
| 80 self.errors=self.errors.combine(error) |
90 self.errors=self.errors.combine(error) |
| |
91 |
| |
92 def name(self): |
| |
93 if 'reason' in self.detail: |
| |
94 return str(self.type) + '.' + self.detail['reason'] |
| |
95 else: |
| |
96 return str(self.type) |
| 81 |
97 |
| 82 |
98 |
| 83 class Status(Operation): |
99 class Status(Operation): |
| 84 def __init__(self, backup, op=None): |
100 def __init__(self, backup, op=None): |
| 85 op=None |
101 op=None |
| 445 self.borg_instance=inst |
461 self.borg_instance=inst |
| 446 self.current_operation=op |
462 self.current_operation=op |
| 447 # Update scheduled time to real starting time to schedule |
463 # Update scheduled time to real starting time to schedule |
| 448 # next run relative to this |
464 # next run relative to this |
| 449 self.current_operation.start_time=MonotonicTime.now() |
465 self.current_operation.start_time=MonotonicTime.now() |
| 450 self.state=State.ACTIVE |
|
| 451 # Reset error status when starting a new operation |
466 # Reset error status when starting a new operation |
| 452 self.__update_status() |
467 self.__update_status(State.ACTIVE) |
| 453 |
468 |
| 454 t_log.start() |
469 t_log.start() |
| 455 t_res.start() |
470 t_res.start() |
| 456 |
471 |
| 457 |
472 |
| 575 def __main_thread_wait_schedule(self): |
590 def __main_thread_wait_schedule(self): |
| 576 op=None |
591 op=None |
| 577 if self._pause: |
592 if self._pause: |
| 578 self.logger.info("Waiting for resume to be signalled") |
593 self.logger.info("Waiting for resume to be signalled") |
| 579 |
594 |
| 580 self.state=State.PAUSED |
595 self.__update_status(State.PAUSED) |
| 581 self.__update_status() |
|
| 582 |
596 |
| 583 self._cond.wait() |
597 self._cond.wait() |
| 584 else: |
598 else: |
| 585 if not self.scheduled_operation: |
599 if not self.scheduled_operation: |
| 586 op=self.__next_operation_unlocked() |
600 op=self.__next_operation_unlocked() |
| 587 if op: |
601 if op: |
| 588 self.logger.info("Scheduling '%s' (detail: %s) on %s [%s]" % |
|
| 589 (str(op.type), op.detail or 'none', |
|
| 590 op.start_time.isoformat(), |
|
| 591 op.start_time.__class__.__name__)) |
|
| 592 |
|
| 593 self.scheduled_operation=op |
602 self.scheduled_operation=op |
| 594 self.state=State.SCHEDULED |
603 |
| 595 self.__update_status() |
604 self.__update_status(State.SCHEDULED) |
| 596 |
605 |
| 597 # Wait under scheduled wait |
606 # Wait under scheduled wait |
| 598 self.scheduler.wait_until(op.start_time, self._cond, self.backup_name) |
607 eventname=op.name() + '@' + self.backup_name |
| |
608 self.scheduler.wait_until(op.start_time, self._cond, eventname) |
| 599 else: |
609 else: |
| 600 # Nothing scheduled - just wait |
610 # Nothing scheduled - just wait |
| 601 self.logger.info("Waiting for manual scheduling") |
611 self.logger.info("Waiting for manual scheduling") |
| 602 |
612 |
| 603 self.state=State.INACTIVE |
613 self.__update_status(State.INACTIVE) |
| 604 self.__update_status() |
|
| 605 |
614 |
| 606 self._cond.wait() |
615 self._cond.wait() |
| 607 |
616 |
| 608 # Main thread/3. If there is a scheduled operation (it might have been |
617 # Main thread/3. If there is a scheduled operation (it might have been |
| 609 # changed manually from 'op' created in __main_thread_wait_schedule above), |
618 # changed manually from 'op' created in __main_thread_wait_schedule above), |
| 610 # queue it on the repository, and launch the operation once repository |
619 # queue it on the repository, and launch the operation once repository |
| 611 # available |
620 # available |
| 612 def __main_thread_queue_and_launch(self): |
621 def __main_thread_queue_and_launch(self): |
| 613 if self.scheduled_operation: |
622 if self.scheduled_operation: |
| 614 self.logger.debug("Queuing") |
623 |
| 615 self.state=State.QUEUED |
624 self.__update_status(State.QUEUED) |
| 616 self.__update_status() |
625 |
| 617 res=self.repository.queue_action(self._cond, |
626 res=self.repository.queue_action(self._cond, |
| 618 action=self.__launch_and_wait, |
627 action=self.__launch_and_wait, |
| 619 name=self.backup_name) |
628 name=self.backup_name) |
| 620 if not res: |
629 if not res: |
| 621 self.logger.debug("Queueing aborted") |
630 self.logger.debug("Queueing aborted") |
| 709 callback=self.__status_update_callback |
718 callback=self.__status_update_callback |
| 710 status=Status(self) |
719 status=Status(self) |
| 711 |
720 |
| 712 return status, callback |
721 return status, callback |
| 713 |
722 |
| 714 def __update_status(self): |
723 def __update_status(self, state): |
| |
724 self.logger.debug("Entering %s state", str(state)) |
| |
725 self.state=state |
| 715 status, callback = self.__status_unlocked() |
726 status, callback = self.__status_unlocked() |
| 716 if callback: |
727 if callback: |
| 717 #self._cond.release() |
728 #self._cond.release() |
| 718 try: |
729 try: |
| 719 callback(status) |
730 callback(status) |