Esempio n. 1
0
    def delete_backup(self):
        current_item = self.backups_tree_widget.currentItem()
        if current_item is None:
            return
        backup_name = current_item.whatsThis(0)
        backup = Backups.load(backup_name)

        password, ret = QInputDialog.getText(self, "Password",
                                             "Enter your password:"******"Incorrect password",
                                "Incorrect password")
            return

        reply = QMessageBox.question(
            self, "Confirm delete?",
            f"Are you sure you want to delete {backup_name}?",
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply is QMessageBox.Yes:
            Backups.delete(backup_name)
            self.populate()
            self.app.scheduler.reload()
Esempio n. 2
0
    def command_done(self, res):
        self.setEnabled(True)

        ret, message = res
        if not ret:
            QMessageBox.warning(self.window, "Invalid details", message)
            return

        if self.just_save:
            Backups.save(self.backup)

        super().accept()
Esempio n. 3
0
    def command_done(self, ret):
        self.setEnabled(True)
        if not ret:
            QMessageBox.warning(
                self.window, "Invalid details",
                f"Backup {self.backup.name} has not been initialized")
            return
        Backups.save(self.backup)

        self.window.app.scheduler.reload()

        super().accept()
Esempio n. 4
0
    def update_logs(self, force=False):
        current_item = self.backups_tree_widget.currentItem()
        if current_item is None:
            return
        backup_name = current_item.whatsThis(0)
        backup = Backups.load(backup_name)

        if not force and (self.log_file_thread.backup is not None
                          and backup_name == self.log_file_thread.backup.name):
            return

        self.log_text_edit.clear()
        self.old_logs_thread = OldLogsThread(backup_name)
        self.old_logs_thread.started.connect(
            lambda: self.log_text_edit.setPlainText("Loading logs..."))
        self.old_logs_thread.result.connect(
            lambda x: self.got_old_logs(x, backup))
        self.old_logs_thread.start()

        self.log_file_thread.set_backup(backup)

        self.set_sensitive_actions_status(False)
        self.backups_tree_widget.setEnabled(False)
        self.log_text_edit.hide()
        self.go_action.setEnabled(False)
        self.stop_action.setEnabled(False)
        self.only_errors_radio_button.setEnabled(False)
        self.show_everything_radio_button.setEnabled(False)
Esempio n. 5
0
 def run_all(self, location=None):
     if location is None:
         backups = Backups.load_all()
     else:
         backups = [
             name for name, val in Backups.load_all().items()
             if val.location == location
         ]
     if len(backups) is 0:
         QMessageBox.information(self, "No backups", "No backups to run")
         return
     backups_str = ',\n'.join(backups)
     reply = QMessageBox.question(
         self, "Run all?",
         f"You are about to run {len(backups)} backups: \n\n{backups_str}\n\nContinue?",
         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
     if reply is QMessageBox.No:
         return
     for backup_name in backups:
         self.go_backup(backup_name=backup_name)
Esempio n. 6
0
 def populate(self, backup_name=None):
     self.backups_tree_widget.clear()
     self.original_item_texts = {}
     plans = Backups.load_all()
     if len(plans) is 0:
         self.hide_regular_widgets()
         self.welcome_widget.show()
         return
     self.show_regular_widgets()
     self.welcome_widget.hide()
     selected_item = None
     for plan in plans.values():
         schedule = "Manual"
         daily = plan.backup_daily_time
         if daily is not None and plan.backup_days is not None:
             days_order = {
                 "mon": 0,
                 "tue": 1,
                 "wed": 2,
                 "thu": 3,
                 "fri": 4,
                 "sat": 5,
                 "sun": 6
             }
             days_map = {
                 "mon": "M",
                 "tue": "T",
                 "wed": "W",
                 "thu": "Th",
                 "fri": "F",
                 "sat": "S",
                 "sun": "Su"
             }
             time_str = datetime.datetime.strptime(
                 f"{daily.hour()}:{daily.minute()}",
                 "%H:%M").strftime("%I:%M %p")
             schedule = f"{time_str} | {','.join(days_map[d] for d in sorted(plan.backup_days.split(','), key=lambda x: days_order[x]))}"
         if plan.every_hour is not None and plan.every_min is not None:
             schedule = f"Every {plan.every_hour} hour(s) ({plan.every_min} mins)"
         item = QTreeWidgetItem(
             [plan.name, plan.location, "Idle", schedule])
         item.setWhatsThis(0, plan.name)
         if backup_name is None:
             if selected_item is None:
                 selected_item = item
         else:
             if plan.name == backup_name:
                 selected_item = item
         self.backups_tree_widget.addTopLevelItem(item)
     self.log_file_thread.reset = True
     self.backups_tree_widget.setCurrentItem(selected_item)
     self.update_logs(force=True)
Esempio n. 7
0
    def go_backup(self, status=False, backup_name=None):
        if self.thread is not None:
            self.app.notify(
                f"Scheduled backup {backup_name} skipped because a restore is running."
            )
            return
        if backup_name is None:
            current_item = self.backups_tree_widget.currentItem()
            if current_item is None:
                return
            backup_name = current_item.whatsThis(0)
        else:
            current_item = self.get_item_with_name(backup_name)
        backup = Backups.load(backup_name)

        if backup_name in self.threads:
            self.app.notify(
                f"Scheduled backup {backup_name} skipped because it's already running."
            )
            return

        self.app.notify(f"{backup_name} backup started")

        if backup.paths is None or len(backup.paths) is 0:
            QMessageBox.warning(self, "Error",
                                "This backup has no folders selected")
            return

        current_item.setText(2, "Running")
        self.status_bar.clearMessage()

        thread = BackupThread(backup, current_item,
                              self.debug_mode_action.isChecked())

        self.threads[backup_name] = thread
        thread.updated.connect(lambda item, message: item.setText(2, message))
        thread.backup_finished.connect(self.backup_finished)
        thread.stop_initiated.connect(
            lambda item: item.setText(2, "Stopping backup"))
        thread.stop_finished.connect(self.backup_stopped)
        thread.error.connect(self.thread_error)
        thread.files_skipped.connect(self.files_skipped)
        thread.start()

        self.update_logs(force=True)

        self.set_sensitive_actions_status(False)
        self.go_action.setEnabled(False)
Esempio n. 8
0
def delete_older_filename(filename, interval, profile="default", config=CONFIG_FILE, destination=None, **kwargs):
    """Delete backups matching the given filename older than the given interval string.

    :type filename: str
    :param filename: File/directory name.

    :type interval: str
    :param interval: Interval string like 1M, 1W, 1M3W4h2s...
        (s => seconds, m => minutes, h => hours, D => days, W => weeks, M => months, Y => Years).

    :type destination: str
    :param destination: glacier|s3|swift

    :type conf: dict
    :keyword conf: Override/set AWS configuration.

    :rtype: list
    :return: A list containing the deleted keys (S3) or archives (Glacier).

    """
    storage_backend, destination, conf = _get_store_backend(config, destination, profile)

    session_id = str(uuid.uuid4())
    events.before_delete_older_than(session_id)

    interval_seconds = _interval_string_to_seconds(interval)
    backup_date_filter = int(datetime.utcnow().strftime("%s")) - interval_seconds

    deleted = []

    for backup in Backups.search_older_than(filename, backup_date_filter, destination=destination,
                                            profile=profile, config=config):
        real_key = backup.stored_filename
        log.info("Deleting {0}".format(real_key))

        storage_backend.delete(real_key)

        backup.set_deleted()
        deleted.append(backup)

    events.on_delete_older_than(session_id, deleted)

    return deleted
Esempio n. 9
0
    def edit_backup(self):
        current_item = self.backups_tree_widget.currentItem()
        if current_item is None:
            return
        backup_name = current_item.whatsThis(0)

        if backup_name in self.threads:
            return

        backup = Backups.load(backup_name)

        password, ret = QInputDialog.getText(self, "Password",
                                             "Enter your password:"******"Incorrect password",
                                "Incorrect password")
            return

        self.backup_settings(BackupSettings(backup, self, True))
Esempio n. 10
0
 def reload(self):
     self.remove_all_jobs()
     backups = Backups.load_all()
     for backup in backups.values():
         trigger = None
         if backup.backup_daily_time is not None:
             trigger = CronTrigger(hour=backup.backup_daily_time.hour(),
                                   minute=backup.backup_daily_time.minute(),
                                   day_of_week=backup.backup_days)
         if backup.every_hour is not None and backup.every_min is not None:
             trigger = CronTrigger(hour=f'*/{backup.every_hour}',
                                   minute=backup.every_min)
         if self.get_job(backup.name) is not None and trigger is not None:
             self.reschedule_job(backup.name, trigger=trigger)
         elif trigger is not None:
             self.add_job(func=self.app.start_backup.emit,
                          args=(False, backup.name),
                          trigger=trigger,
                          id=backup.name,
                          misfire_grace_time=180)
         elif self.get_job(backup.name) is not None and trigger is None:
             self.remove_job(backup.name)
Esempio n. 11
0
    def view_backup(self):
        current_item = self.backups_tree_widget.currentItem()
        if current_item is None:
            return
        backup_name = current_item.whatsThis(0)
        backup = Backups.load(backup_name)

        password, ret = QInputDialog.getText(self, "Password",
                                             "Enter your password:"******"Incorrect password",
                                "Incorrect password")
            return

        dialog = RestoreDialog(self, backup)
        dialog.setParent(self, Qt.Dialog)
        if dialog.exec_():
            self.thread = RestoreThread(backup, dialog.snapshot_id,
                                        dialog.restore_dir, dialog.paths,
                                        self.debug_mode_action.isChecked())
            self.thread.updated.connect(
                lambda x: self.status_bar.showMessage(x))
            self.thread.restore_finished.connect(self.restore_finished)
            self.thread.error.connect(self.restore_thread_error)
            self.set_sensitive_actions_status(False)
            self.set_control_actions_status(False)
            if backup.name in self.threads and self.threads[
                    backup.name] is not None:
                self.app.notify(
                    f"Restore skipped because this backup is running.")
                return
            self.thread.start()
            self.app.notify("Restore started")

            self.update_logs(force=True)
Esempio n. 12
0
 def validate_plan_name(name):
     if len(name) is 0:
         return False, "Backup name must not be empty"
     if name in Backups.load_all():
         return False, "Backup name is already in use"
     return True, None