mirror of
https://github.com/borgbackup/borg.git
synced 2025-01-30 11:11:28 +00:00
Merge pull request #1232 from PlasmaPower/serve-append-only
Add --append-only to borg serve (1.0-maint)
This commit is contained in:
commit
02c72b9925
5 changed files with 24 additions and 7 deletions
|
@ -115,7 +115,7 @@ def print_file_status(self, status, path):
|
|||
def do_serve(self, args):
|
||||
"""Start in server mode. This command is usually not used manually.
|
||||
"""
|
||||
return RepositoryServer(restrict_to_paths=args.restrict_to_paths).serve()
|
||||
return RepositoryServer(restrict_to_paths=args.restrict_to_paths, append_only=args.append_only).serve()
|
||||
|
||||
@with_repository(create=True, exclusive=True, manifest=False)
|
||||
def do_init(self, args, repository):
|
||||
|
@ -916,6 +916,8 @@ def build_parser(self, args=None, prog=None):
|
|||
subparser.set_defaults(func=self.do_serve)
|
||||
subparser.add_argument('--restrict-to-path', dest='restrict_to_paths', action='append',
|
||||
metavar='PATH', help='restrict repository access to PATH')
|
||||
subparser.add_argument('--append-only', dest='append_only', action='store_true',
|
||||
help='only allow appending to repository segment files')
|
||||
init_epilog = textwrap.dedent("""
|
||||
This command initializes an empty repository. A repository is a filesystem
|
||||
directory containing the deduplicated data from zero or more archives.
|
||||
|
@ -1491,8 +1493,9 @@ def get_args(self, argv, cmd):
|
|||
if result.func != forced_result.func:
|
||||
# someone is trying to execute a different borg subcommand, don't do that!
|
||||
return forced_result
|
||||
# the only thing we take from the forced "borg serve" ssh command is --restrict-to-path
|
||||
# we only take specific options from the forced "borg serve" command:
|
||||
result.restrict_to_paths = forced_result.restrict_to_paths
|
||||
result.append_only = forced_result.append_only
|
||||
return result
|
||||
|
||||
def parse_args(self, args=None):
|
||||
|
|
|
@ -54,9 +54,10 @@ class RepositoryServer: # pragma: no cover
|
|||
'break_lock',
|
||||
)
|
||||
|
||||
def __init__(self, restrict_to_paths):
|
||||
def __init__(self, restrict_to_paths, append_only):
|
||||
self.repository = None
|
||||
self.restrict_to_paths = restrict_to_paths
|
||||
self.append_only = append_only
|
||||
|
||||
def serve(self):
|
||||
stdin_fd = sys.stdin.fileno()
|
||||
|
@ -123,7 +124,7 @@ def open(self, path, create=False, lock_wait=None, lock=True):
|
|||
break
|
||||
else:
|
||||
raise PathNotAllowed(path)
|
||||
self.repository = Repository(path, create, lock_wait=lock_wait, lock=lock)
|
||||
self.repository = Repository(path, create, lock_wait=lock_wait, lock=lock, append_only=self.append_only)
|
||||
self.repository.__enter__() # clean exit handled by serve() method
|
||||
return self.repository.id
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ class CheckNeeded(ErrorWithTraceback):
|
|||
class ObjectNotFound(ErrorWithTraceback):
|
||||
"""Object with key {} not found in repository {}."""
|
||||
|
||||
def __init__(self, path, create=False, exclusive=False, lock_wait=None, lock=True):
|
||||
def __init__(self, path, create=False, exclusive=False, lock_wait=None, lock=True, append_only=False):
|
||||
self.path = os.path.abspath(path)
|
||||
self._location = Location('file://%s' % self.path)
|
||||
self.io = None
|
||||
|
@ -64,6 +64,7 @@ def __init__(self, path, create=False, exclusive=False, lock_wait=None, lock=Tru
|
|||
self.do_lock = lock
|
||||
self.do_create = create
|
||||
self.exclusive = exclusive
|
||||
self.append_only = append_only
|
||||
|
||||
def __del__(self):
|
||||
if self.lock:
|
||||
|
@ -169,7 +170,9 @@ def open(self, path, exclusive, lock_wait=None, lock=True):
|
|||
raise self.InvalidRepository(path)
|
||||
self.max_segment_size = self.config.getint('repository', 'max_segment_size')
|
||||
self.segments_per_dir = self.config.getint('repository', 'segments_per_dir')
|
||||
self.append_only = self.config.getboolean('repository', 'append_only', fallback=False)
|
||||
# append_only can be set in the constructor
|
||||
# it shouldn't be overridden (True -> False) here
|
||||
self.append_only = self.append_only or self.config.getboolean('repository', 'append_only', fallback=False)
|
||||
self.id = unhexlify(self.config.get('repository', 'id').strip())
|
||||
self.io = LoggedIO(self.path, self.max_segment_size, self.segments_per_dir)
|
||||
|
||||
|
|
|
@ -201,11 +201,14 @@ def test_ignores_commit_tag_in_data(self):
|
|||
|
||||
|
||||
class RepositoryAppendOnlyTestCase(RepositoryTestCaseBase):
|
||||
def open(self, create=False):
|
||||
return Repository(os.path.join(self.tmppath, 'repository'), create=create, append_only=True)
|
||||
|
||||
def test_destroy_append_only(self):
|
||||
# Can't destroy append only repo (via the API)
|
||||
self.repository.append_only = True
|
||||
with self.assert_raises(ValueError):
|
||||
self.repository.destroy()
|
||||
assert self.repository.append_only
|
||||
|
||||
def test_append_only(self):
|
||||
def segments_in_repository():
|
||||
|
|
|
@ -727,6 +727,13 @@ To activate append-only mode, edit the repository ``config`` file and add a line
|
|||
In append-only mode Borg will create a transaction log in the ``transactions`` file,
|
||||
where each line is a transaction and a UTC timestamp.
|
||||
|
||||
In addition, ``borg serve`` can act as if a repository is in append-only mode with
|
||||
its option ``--append-only``. This can be very useful for fine-tuning access control
|
||||
in ``.ssh/authorized_keys`` ::
|
||||
|
||||
command="borg serve --append-only ..." ssh-rsa <key used for not-always-trustable backup clients>
|
||||
command="borg serve ..." ssh-rsa <key used for backup management>
|
||||
|
||||
Example
|
||||
+++++++
|
||||
|
||||
|
|
Loading…
Reference in a new issue