Skip to content

Test Mount API #2039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 25 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
269fc67
Extract Bounce from encfstools to avoid circular import
daviewales Feb 8, 2025
a799c7f
Factor out config file creation for reuse in other tests
daviewales Feb 17, 2025
fe85054
test_mount: create test configs for all mount modes
daviewales Feb 17, 2025
1b18394
Test high level Mount API with 'local' backend
daviewales Feb 17, 2025
d17808e
WIP: debug EncFS mount args
daviewales Feb 8, 2025
0d5c36f
encfstools: Include encfs return code on error
daviewales Feb 18, 2025
fab1785
mount: Add debug messages
daviewales Feb 18, 2025
0e3ca97
WIP: test_mount: start testing encfs mount
daviewales Feb 18, 2025
81f6d9c
del encode.py
buhtz Apr 25, 2025
54adbdc
split encode preserve history
buhtz Apr 25, 2025
c5ae7f4
re-create encode.py
buhtz Apr 25, 2025
9d2d690
full linter battery on encode.py
buhtz Apr 25, 2025
9760c39
minor adjustments
buhtz Apr 25, 2025
4825797
Mount: Remove redundant test
daviewales May 13, 2025
f42e9f6
Test uninitialised mount
daviewales May 13, 2025
0153492
Add encfs to Travis
daviewales Jul 10, 2025
2b067ad
Improve linting
daviewales Jul 10, 2025
e3f1281
Test remount of same profile
daviewales Jul 14, 2025
2723302
Simplify local EncFS tests
daviewales Jul 14, 2025
dbd204a
Move mocks to test class, improve linting
daviewales Jul 14, 2025
fdcb591
Remove redundant 'pass' statement
daviewales Jul 15, 2025
57d46d1
Fix typo in comment
daviewales Jul 15, 2025
8308ac0
Test remount to new local profile
daviewales Jul 15, 2025
86dfb4a
Test remount to new local EncFS profile
daviewales Jul 15, 2025
2984404
Remove unused attribute
daviewales Jul 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ before_install:
- sudo apt-get -qq update
# install screen, and util-linux (provides flock) for test_sshtools
- sudo apt-get install -y sshfs screen util-linux libdbus-1-dev
- sudo apt-get install -y ruby rubygems asciidoctor
- sudo apt-get install -y ruby rubygems asciidoctor encfs
- sudo gem install asciidoctor

jobs:
Expand Down
3 changes: 2 additions & 1 deletion common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import bitbase
import tools
import configfile
import encode
import logger
import sshtools
import encfstools
Expand Down Expand Up @@ -121,7 +122,7 @@ class Config(configfile.ConfigFileWithProfiles):
DEFAULT_REDIRECT_STDERR_IN_CRON = False
DEFAULT_OFFSET = 0

ENCODE = encfstools.Bounce()
ENCODE = encode.Bounce()
PLUGIN_MANAGER = pluginmanager.PluginManager()

def __init__(self, config_path=None, data_path=None):
Expand Down
49 changes: 23 additions & 26 deletions common/encfstools.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from datetime import datetime
from packaging.version import Version
import config
import encode
import password
import password_ipc
import tools
Expand All @@ -27,6 +28,15 @@ class EncFS_mount(MountControl):
"""Mount encrypted paths with encfs."""

def __init__(self, *args, **kwargs):
# TODO: Remove these debug calls as they are just to help me
# setup testing!
logger.debug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
logger.debug("REMOVE THESE TEMPORARY DEBUG LINES!")
logger.debug("EncFS_mount args:")
logger.debug(str(args))
logger.debug("EncFS_mount kwargs:")
logger.debug(str(kwargs))
logger.debug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
# init MountControl
super(EncFS_mount, self).__init__(*args, **kwargs)

Expand All @@ -36,6 +46,7 @@ def __init__(self, *args, **kwargs):
self.config_path = None

self.setattrKwargs('path', self.config.localEncfsPath(self.profile_id), **kwargs)
print(f"{self.path=}")
self.setattrKwargs('reverse', False, **kwargs)
self.setattrKwargs('config_path', None, **kwargs)
self.setattrKwargs('password', None, store = False, **kwargs)
Expand Down Expand Up @@ -77,10 +88,12 @@ def _mount(self):
self.backupConfig()
if proc.returncode:
raise MountException(
'{}:\n\n{}'.format(
'{}:\n\n{}\n\n{}'.format(
_("Unable to mount '{command}'")
.format(command=' '.join(encfs)),
output))
output,
f"Return code: {proc.returncode}",
))

def preMountCheck(self, first_run=False):
"""Check what ever conditions must be given for the mount.
Expand Down Expand Up @@ -208,6 +221,7 @@ def backupConfig(self):
%(cfg, new_backup), self)
shutil.copy2(cfg, new_backup)


class EncFS_SSH(EncFS_mount):
"""
Mount encrypted remote path with sshfs and encfs.
Expand Down Expand Up @@ -273,7 +287,7 @@ def umount(self, *args, **kwargs):
call umount for encfs, encfs --reverse and sshfs
"""
self.config.ENCODE.close()
self.config.ENCODE = Bounce()
self.config.ENCODE = encode.Bounce()
logger.debug('Unmount encfs', self)
super(EncFS_SSH, self).umount(*args, **kwargs)
logger.debug('Unmount local filesystem root mount encfs --reverse', self)
Expand Down Expand Up @@ -340,11 +354,13 @@ def splitKwargs(self, mode):
d['hash_id'] = d['hash_id_1']
return d


class Encode:
"""
encode path with encfsctl.
ENCFS_SSH will replace config.ENCODE with this
"""

def __init__(self, encfs):
self.encfs = encfs
self.password = self.encfs.password
Expand Down Expand Up @@ -410,8 +426,10 @@ def exclude(self, path):

enc = ''
m = self.re_asterisk.search(path)

if not m is None:
path_ = path[:]

while True:
#search for foo/*, foo/*/bar, */bar or **/bar
#but not foo* or foo/*bar
Expand Down Expand Up @@ -462,34 +480,13 @@ def close(self):
logger.debug('stop \'encfsctl encode\' process', self)
self.p.communicate()

class Bounce:
"""
Dummy class that will simply return all input.
This is the standard for config.ENCODE
"""
def __init__(self):
self.chroot = os.sep

def path(self, path):
return path

def exclude(self, path):
return path

def include(self, path):
return path

def remote(self, path):
return path

def close(self):
pass

class Decode:
"""
decode path with encfsctl.
"""
def __init__(self, cfg, string = True):

def __init__(self, cfg, string=True):
self.config = cfg
self.mode = cfg.snapshotsMode()

Expand Down
43 changes: 43 additions & 0 deletions common/encode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# SPDX-FileCopyrightText: © 2012-2022 Germar Reitze
# SPDX-FileCopyrightText: © 2012-2022 Taylor Raack
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This file is part of the program "Back In Time" which is released under GNU
# General Public License v2 (GPLv2). See LICENSES directory or go to
# <https://spdx.org/licenses/GPL-2.0-or-later.html>.
#
# Split from common/encfstools.py.

"""Module related to encrypted backup profiles.
"""
import os


class Bounce:
"""Dummy class that will simply return all input.
This is the standard for config.ENCODE.
"""

def __init__(self):
self.chroot = os.sep

def path(self, path: str) -> str:
"""The path."""
return path

def exclude(self, path: str) -> str:
"""Exclude entry."""
return path

def include(self, path: str) -> str:
"""Include entry."""
return path

def remote(self, path: str) -> str:
"""Remote path."""
return path

def close(self) -> None:
"""Nothing."""
6 changes: 3 additions & 3 deletions common/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,6 @@ def __init__(self,
f'Failed to {action} pw-cache: {proc.returncode}',
self)

pass

def mount(self, mode=None, check=True, **kwargs):
"""High-level `mount`. Check if the selected ``mode`` need to be mounted,
select the low-level backend and mount it.
Expand Down Expand Up @@ -310,7 +308,7 @@ def preMountCheck(self, mode=None, first_run=False, **kwargs):

return backend.preMountCheck(first_run)

def remount(self, new_profile_id, mode = None, hash_id = None, **kwargs):
def remount(self, new_profile_id, mode=None, hash_id=None, **kwargs):
"""
High-level `remount`. Unmount the old profile presented by ``hash_id``
and mount new profile ``new_profile_id`` with mode ``mode``. If old and
Expand Down Expand Up @@ -463,6 +461,7 @@ def setDefaultArgs(self):
# mount.
args = list(self.all_kwargs.keys())
self.destination = '%s:' % self.all_kwargs['mode']
logger.debug(f"{self.destination=}")

args.remove('mode')
args.sort()
Expand All @@ -475,6 +474,7 @@ def setDefaultArgs(self):
# the same mountpoint.
if self.hash_id is None:
self.hash_id = self.hash(self.destination)
logger.debug(f"{self.hash_id=}")

# e.g. ~/.local/share/backintime/mnt
self.mount_root = self.config._LOCAL_MOUNT_ROOT
Expand Down
3 changes: 2 additions & 1 deletion common/snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import logger
import tools
import encfstools
import encode
import mount
import progress
import snapshotlog
Expand Down Expand Up @@ -1260,7 +1261,7 @@ def backupPermissions(self, sid):
if self.config.snapshotsMode() == 'ssh_encfs':
decode = encfstools.Decode(self.config, False)
else:
decode = encfstools.Bounce()
decode = encode.Bounce()

# backup permissions of /
# bugfix for https://github.com/bit-team/backintime/issues/708
Expand Down
81 changes: 80 additions & 1 deletion common/test/config
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
config.version=6
profiles.version=1
profiles=1:2:3:4:5

profile1.snapshots.mode=local
profile1.snapshots.include.1.type=0
profile1.snapshots.include.1.value=/tmp/test
profile1.snapshots.include.size=1
Expand All @@ -15,4 +19,79 @@ profile1.snapshots.remove_old_snapshots.unit=80
profile1.snapshots.remove_old_snapshots.value=10
profile1.snapshots.rsync_options.enabled=false
profile1.snapshots.rsync_options.value=
profiles.version=1

profile2.name=test-ssh-mount
profile2.snapshots.mode=ssh
profile2.snapshots.include.1.type=0
profile2.snapshots.include.1.value=/tmp/test
profile2.snapshots.include.size=1
profile2.snapshots.no_on_battery=false
profile2.snapshots.notify.enabled=true
profile2.snapshots.path=/tmp/snapshots
profile2.snapshots.path.host=test-host
profile2.snapshots.path.profile=1
profile2.snapshots.path.user=test-user
profile2.snapshots.preserve_acl=false
profile2.snapshots.preserve_xattr=false
profile2.snapshots.remove_old_snapshots.enabled=true
profile2.snapshots.remove_old_snapshots.unit=80
profile2.snapshots.remove_old_snapshots.value=10
profile2.snapshots.rsync_options.enabled=false
profile2.snapshots.rsync_options.value=

profile3.name=test-local_encfs-mount
profile3.snapshots.mode=local_encfs
profile3.snapshots.include.1.type=0
profile3.snapshots.include.1.value=/tmp/test
profile3.snapshots.include.size=1
profile3.snapshots.no_on_battery=false
profile3.snapshots.notify.enabled=true
profile3.snapshots.path=/tmp/snapshots
profile3.snapshots.path.host=test-host
profile3.snapshots.path.profile=1
profile3.snapshots.path.user=test-user
profile3.snapshots.preserve_acl=false
profile3.snapshots.preserve_xattr=false
profile3.snapshots.remove_old_snapshots.enabled=true
profile3.snapshots.remove_old_snapshots.unit=80
profile3.snapshots.remove_old_snapshots.value=10
profile3.snapshots.rsync_options.enabled=false
profile3.snapshots.rsync_options.value=

profile4.name=test-local_encfs-mount-2
profile4.snapshots.mode=local_encfs
profile4.snapshots.include.1.type=0
profile4.snapshots.include.1.value=/tmp/test
profile4.snapshots.include.size=1
profile4.snapshots.no_on_battery=false
profile4.snapshots.notify.enabled=true
profile4.snapshots.path=/tmp/snapshots
profile4.snapshots.path.host=test-host
profile4.snapshots.path.profile=1
profile4.snapshots.path.user=test-user
profile4.snapshots.preserve_acl=false
profile4.snapshots.preserve_xattr=false
profile4.snapshots.remove_old_snapshots.enabled=true
profile4.snapshots.remove_old_snapshots.unit=80
profile4.snapshots.remove_old_snapshots.value=10
profile4.snapshots.rsync_options.enabled=false
profile4.snapshots.rsync_options.value=

profile5.name=test-ssh_encfs-mount
profile5.snapshots.mode=ssh_encfs
profile5.snapshots.include.1.type=0
profile5.snapshots.include.1.value=/tmp/test
profile5.snapshots.include.size=1
profile5.snapshots.no_on_battery=false
profile5.snapshots.notify.enabled=true
profile5.snapshots.path=/tmp/snapshots
profile5.snapshots.path.host=test-host
profile5.snapshots.path.profile=1
profile5.snapshots.path.user=test-user
profile5.snapshots.preserve_acl=false
profile5.snapshots.preserve_xattr=false
profile5.snapshots.remove_old_snapshots.enabled=true
profile5.snapshots.remove_old_snapshots.unit=80
profile5.snapshots.remove_old_snapshots.value=10
profile5.snapshots.rsync_options.enabled=false
profile5.snapshots.rsync_options.value=
1 change: 1 addition & 0 deletions common/test/test_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
# 'clicommands.py',
'daemon.py',
'event.py',
'encode.py',
'languages.py',
'inhibitsuspend.py',
'schedule.py',
Expand Down
Loading