Esempio n. 1
0
def init_db(qapp):
    vorta.models.db.drop_tables(models)
    vorta.models.init_db()

    new_repo = RepoModel(url='[email protected]:repo')
    new_repo.save()

    profile = BackupProfileModel.get(id=1)
    profile.repo = new_repo.id
    profile.save()

    test_archive = ArchiveModel(snapshot_id='99999',
                                name='test-archive',
                                time=dt(2000, 1, 1, 0, 0),
                                repo=1)
    test_archive.save()

    test_archive1 = ArchiveModel(snapshot_id='99998',
                                 name='test-archive1',
                                 time=dt(2000, 1, 1, 0, 0),
                                 repo=1)
    test_archive1.save()

    source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo)
    source_dir.save()

    qapp.open_main_window_action()
Esempio n. 2
0
def app(tmpdir, qtbot, mocker):
    tmp_db = tmpdir.join('settings.sqlite')
    mock_db = peewee.SqliteDatabase(str(tmp_db))
    vorta.models.init_db(mock_db)
    mocker.patch.object(vorta.application.VortaApp,
                        'set_borg_details_action',
                        return_value=None)

    new_repo = RepoModel(url='[email protected]:repo')
    new_repo.save()

    profile = BackupProfileModel.get(id=1)
    profile.repo = new_repo.id
    profile.save()

    test_archive = ArchiveModel(snapshot_id='99999',
                                name='test-archive',
                                time=dt(2000, 1, 1, 0, 0),
                                repo=1)
    test_archive.save()

    source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo)
    source_dir.save()

    app = VortaApp([])
    app.open_main_window_action()
    qtbot.addWidget(app.main_window)
    app.main_window.tests_running = True
    return app
Esempio n. 3
0
def app(tmpdir, qtbot):
    tmp_db = tmpdir.join('settings.sqlite')
    mock_db = peewee.SqliteDatabase(str(tmp_db))
    vorta.models.init_db(mock_db)

    new_repo = RepoModel(url='[email protected]:repo')
    new_repo.save()

    profile = BackupProfileModel.get(id=1)
    profile.repo = new_repo.id
    profile.save()

    test_archive = ArchiveModel(snapshot_id='99999',
                                name='test-archive',
                                time=dt(2000, 1, 1, 0, 0),
                                repo=1)
    test_archive.save()

    source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo)
    source_dir.save()

    app = VortaApp([])
    app.main_window.show()
    qtbot.addWidget(app.main_window)
    return app
Esempio n. 4
0
def init_db(qapp):
    vorta.models.db.drop_tables(models)
    vorta.models.init_db()

    new_repo = RepoModel(url='[email protected]:repo')
    new_repo.encryption = 'none'
    new_repo.save()

    profile = BackupProfileModel.get(id=1)
    profile.repo = new_repo.id
    profile.dont_run_on_metered_networks = False
    profile.save()

    test_archive = ArchiveModel(snapshot_id='99999',
                                name='test-archive',
                                time=dt(2000, 1, 1, 0, 0),
                                repo=1)
    test_archive.save()

    test_archive1 = ArchiveModel(snapshot_id='99998',
                                 name='test-archive1',
                                 time=dt(2000, 1, 1, 0, 0),
                                 repo=1)
    test_archive1.save()

    source_dir = SourceFileModel(dir='/tmp/another',
                                 repo=new_repo,
                                 dir_size=100,
                                 dir_files_count=18,
                                 path_isdir=True)
    source_dir.save()

    qapp.main_window = MainWindow(
        qapp)  # Re-open main window to apply mock data in UI
Esempio n. 5
0
    def from_db(cls, profile, store_password=True, include_settings=True):
        profile_dict = model_to_dict(profile, exclude=[RepoModel.id])  # Have to retain profile ID

        keyring = VortaKeyring.get_keyring()
        if store_password:
            profile_dict['password'] = keyring.get_password('vorta-repo', profile.repo.url)

        # For all below, exclude ids to prevent collisions. DB will automatically reassign ids
        # Add SourceFileModel
        profile_dict['SourceFileModel'] = [
            model_to_dict(
                source,
                recurse=False, exclude=[SourceFileModel.id]) for source in SourceFileModel.select().where(
                SourceFileModel.profile == profile)]
        # Add SchemaVersion
        profile_dict['SchemaVersion'] = model_to_dict(SchemaVersion.get(id=1))

        if include_settings:
            # Add WifiSettingModel
            profile_dict['WifiSettingModel'] = [
                model_to_dict(
                    wifi, recurse=False) for wifi in WifiSettingModel.select().where(
                    WifiSettingModel.profile == profile.id)]
            # Add SettingsModel
            profile_dict['SettingsModel'] = [
                model_to_dict(s, exclude=[SettingsModel.id]) for s in SettingsModel]
        return ProfileExport(profile_dict)
Esempio n. 6
0
def init_db(qapp, qtbot, tmpdir_factory):
    tmp_db = tmpdir_factory.mktemp('Vorta').join('settings.sqlite')
    mock_db = peewee.SqliteDatabase(str(tmp_db),
                                    pragmas={
                                        'journal_mode': 'wal',
                                    })
    vorta.models.init_db(mock_db)

    default_profile = BackupProfileModel(name='Default')
    default_profile.save()

    new_repo = RepoModel(url='[email protected]:repo')
    new_repo.encryption = 'none'
    new_repo.save()

    default_profile.repo = new_repo.id
    default_profile.dont_run_on_metered_networks = False
    default_profile.save()

    test_archive = ArchiveModel(snapshot_id='99999',
                                name='test-archive',
                                time=dt(2000, 1, 1, 0, 0),
                                repo=1)
    test_archive.save()

    test_archive1 = ArchiveModel(snapshot_id='99998',
                                 name='test-archive1',
                                 time=dt(2000, 1, 1, 0, 0),
                                 repo=1)
    test_archive1.save()

    source_dir = SourceFileModel(dir='/tmp/another',
                                 repo=new_repo,
                                 dir_size=100,
                                 dir_files_count=18,
                                 path_isdir=True)
    source_dir.save()

    qapp.main_window.deleteLater()
    del qapp.main_window
    qapp.main_window = MainWindow(
        qapp)  # Re-open main window to apply mock data in UI

    yield
    qapp.backup_cancelled_event.emit()
    qtbot.waitUntil(lambda: not vorta.borg.borg_thread.BorgThread.is_running())
    mock_db.close()
Esempio n. 7
0
def test_import_bootstrap_success(qapp, mocker):
    mocked_unlink = mocker.MagicMock()
    mocker.patch.object(Path, 'unlink', mocked_unlink)
    qapp.bootstrap_profile(Path(VALID_IMPORT_FILE))

    assert mocked_unlink.called

    restored_profile = BackupProfileModel.get_or_none(
        name="Test Profile Restoration")
    assert restored_profile is not None

    restored_repo = restored_profile.repo
    assert restored_repo is not None

    assert len(SourceFileModel.select().where(
        SourceFileModel.profile == restored_profile)) == 3
    assert BackupProfileModel.select().count() == 2
Esempio n. 8
0
def test_import_success(qapp, qtbot, rootdir, monkeypatch):
    monkeypatch.setattr(QFileDialog, "getOpenFileName",
                        lambda *args: [VALID_IMPORT_FILE])
    monkeypatch.setattr(QMessageBox, 'information', lambda *args: None)

    main = qapp.main_window
    main.profile_import_action()
    import_dialog: ImportWindow = main.window
    import_dialog.overwriteExistingSettings.setChecked(True)

    qtbot.mouseClick(import_dialog.buttonBox.button(QDialogButtonBox.Ok),
                     QtCore.Qt.LeftButton)
    qtbot.waitSignal(import_dialog.profile_imported, **pytest._wait_defaults)

    restored_profile = BackupProfileModel.get_or_none(
        name="Test Profile Restoration")
    assert restored_profile is not None

    restored_repo = restored_profile.repo
    assert restored_repo is not None
    assert len(SourceFileModel.select().where(
        SourceFileModel.profile == restored_profile)) == 3
Esempio n. 9
0
    def to_db(self, overwrite_profile=False, overwrite_settings=True):
        profile_schema = self._profile_dict['SchemaVersion']['version']
        keyring = VortaKeyring.get_keyring()
        if SCHEMA_VERSION < profile_schema:
            raise VersionException()
        elif SCHEMA_VERSION > profile_schema:
            # Add model upgrading code here, only needed if not adding columns
            if profile_schema < 16:
                for sourcedir in self._profile_dict['SourceFileModel']:
                    sourcedir['dir_files_count'] = -1
                    sourcedir['dir_size'] = -1
                    sourcedir['path_isdir'] = False

        existing_profile = None
        if overwrite_profile:
            existing_profile = BackupProfileModel.get_or_none(BackupProfileModel.name == self.name)
            if existing_profile:
                self._profile_dict['id'] = existing_profile.id
        if not overwrite_profile or not existing_profile:
            # Guarantee uniqueness of ids
            while BackupProfileModel.get_or_none(BackupProfileModel.id == self.id) is not None:
                self._profile_dict['id'] += 1

            # Add suffix incase names are the same
            if BackupProfileModel.get_or_none(BackupProfileModel.name == self.name) is not None:
                suffix = 1
                while BackupProfileModel.get_or_none(BackupProfileModel.name == f"{self.name}-{suffix}") is not None:
                    suffix += 1
                self._profile_dict['name'] = f"{self.name}-{suffix}"

        # Load existing repo or restore it
        if self._profile_dict['repo']:
            repo = RepoModel.get_or_none(RepoModel.url == self.repo_url)
            if repo is None:
                # Load repo from export
                repo = dict_to_model(RepoModel, self._profile_dict['repo'])
                repo.save(force_insert=True)
            self._profile_dict['repo'] = model_to_dict(repo)

        if self.repo_password:
            keyring.set_password('vorta-repo', self.repo_url, self.repo_password)
            del self._profile_dict['password']

        # Delete and recreate the tables to clear them
        if overwrite_settings:
            db.drop_tables([SettingsModel, WifiSettingModel])
            db.create_tables([SettingsModel, WifiSettingModel])
            SettingsModel.insert_many(self._profile_dict['SettingsModel']).execute()
            WifiSettingModel.insert_many(self._profile_dict['WifiSettingModel']).execute()

        # Set the profile ids to be match new profile
        for source in self._profile_dict['SourceFileModel']:
            source['profile'] = self.id
        SourceFileModel.insert_many(self._profile_dict['SourceFileModel']).execute()

        # Delete added dictionaries to make it match BackupProfileModel
        del self._profile_dict['SettingsModel']
        del self._profile_dict['SourceFileModel']
        del self._profile_dict['WifiSettingModel']
        del self._profile_dict['SchemaVersion']

        # dict to profile
        new_profile = dict_to_model(BackupProfileModel, self._profile_dict)
        if overwrite_profile and existing_profile:
            force_insert = False
        else:
            force_insert = True
        new_profile.save(force_insert=force_insert)
        init_db()  # rerun db init code to perform the same operations on the new as as on application boot
        return new_profile
Esempio n. 10
0
    def prepare(cls, profile):
        """
        `borg create` is called from different places and needs some preparation.
        Centralize it here and return the required arguments to the caller.
        """
        ret = super().prepare(profile)
        if not ret['ok']:
            return ret
        else:
            ret['ok'] = False  # Set back to False, so we can do our own checks here.

        n_backup_folders = SourceFileModel.select().count()
        if n_backup_folders == 0:
            ret['message'] = trans_late('messages',
                                        'Add some folders to back up first.')
            return ret

        network_status_monitor = get_network_status_monitor()
        current_wifi = network_status_monitor.get_current_wifi()
        if current_wifi is not None:
            wifi_is_disallowed = WifiSettingModel.select().where(
                (WifiSettingModel.ssid == current_wifi) & (
                    WifiSettingModel.allowed == False  # noqa
                ) & (WifiSettingModel.profile == profile))
            if wifi_is_disallowed.count() > 0 and profile.repo.is_remote_repo(
            ):
                ret['message'] = trans_late('messages',
                                            'Current Wifi is not allowed.')
                return ret

        if profile.repo.is_remote_repo() and profile.dont_run_on_metered_networks \
                and network_status_monitor.is_network_metered():
            ret['message'] = trans_late(
                'messages', 'Not running backup over metered connection.')
            return ret

        ret['profile'] = profile
        ret['repo'] = profile.repo

        # Run user-supplied pre-backup command
        if cls.pre_post_backup_cmd(ret) != 0:
            ret['message'] = trans_late(
                'messages', 'Pre-backup command returned non-zero exit code.')
            return ret

        if not profile.repo.is_remote_repo() and not os.path.exists(
                profile.repo.url):
            ret['message'] = trans_late('messages',
                                        'Repo folder not mounted or moved.')
            return ret

        if 'zstd' in profile.compression and not borg_compat.check('ZSTD'):
            ret['message'] = trans_late(
                'messages',
                'Your current Borg version does not support ZStd compression.')
            return ret

        cmd = [
            'borg',
            'create',
            '--list',
            '--progress',
            '--info',
            '--log-json',
            '--json',
            '--filter=AM',
            '-C',
            profile.compression,
        ]

        # Add excludes
        # Partly inspired by borgmatic/borgmatic/borg/create.py
        if profile.exclude_patterns is not None:
            exclude_dirs = []
            for p in profile.exclude_patterns.split('\n'):
                if p.strip():
                    expanded_directory = os.path.expanduser(p.strip())
                    exclude_dirs.append(expanded_directory)

            if exclude_dirs:
                pattern_file = tempfile.NamedTemporaryFile('w', delete=False)
                pattern_file.write('\n'.join(exclude_dirs))
                pattern_file.flush()
                cmd.extend(['--exclude-from', pattern_file.name])

        if profile.exclude_if_present is not None:
            for f in profile.exclude_if_present.split('\n'):
                if f.strip():
                    cmd.extend(['--exclude-if-present', f.strip()])

        # Add repo url and source dirs.
        new_archive_name = format_archive_name(profile,
                                               profile.new_archive_name)
        cmd.append(f"{profile.repo.url}::{new_archive_name}")

        for f in SourceFileModel.select().where(
                SourceFileModel.profile == profile.id):
            cmd.append(f.dir)

        ret['message'] = trans_late('messages', 'Starting backup...')
        ret['ok'] = True
        ret['cmd'] = cmd

        return ret