mirror of
https://github.com/borgbackup/borg.git
synced 2024-12-27 02:08:54 +00:00
Merge pull request #248 from anarcat/ssh-env
add support for arbitrary SSH commands
This commit is contained in:
commit
974dd58c23
4 changed files with 38 additions and 18 deletions
|
@ -571,10 +571,10 @@ def run(self, args=None):
|
|||
help='verbose output')
|
||||
common_parser.add_argument('--no-files-cache', dest='cache_files', action='store_false',
|
||||
help='do not load/update the file metadata cache used to detect unchanged files')
|
||||
common_parser.add_argument('--umask', dest='umask', type=lambda s: int(s, 8), default=0o077, metavar='M',
|
||||
help='set umask to M (local and remote, default: 0o077)')
|
||||
common_parser.add_argument('--remote-path', dest='remote_path', default='borg', metavar='PATH',
|
||||
help='set remote path to executable (default: "borg")')
|
||||
common_parser.add_argument('--umask', dest='umask', type=lambda s: int(s, 8), default=RemoteRepository.umask, metavar='M',
|
||||
help='set umask to M (local and remote, default: %(default)s)')
|
||||
common_parser.add_argument('--remote-path', dest='remote_path', default=RemoteRepository.remote_path, metavar='PATH',
|
||||
help='set remote path to executable (default: "%(default)s")')
|
||||
|
||||
# We can't use argparse for "serve" since we don't want it to show up in "Available commands"
|
||||
if args:
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import msgpack
|
||||
import os
|
||||
import select
|
||||
import shlex
|
||||
from subprocess import Popen, PIPE
|
||||
import sys
|
||||
import tempfile
|
||||
|
@ -108,8 +109,9 @@ def open(self, path, create=False):
|
|||
|
||||
class RemoteRepository:
|
||||
extra_test_args = []
|
||||
remote_path = None
|
||||
umask = None
|
||||
remote_path = 'borg'
|
||||
# default umask, overriden by --umask, defaults to read/write only for owner
|
||||
umask = 0o077
|
||||
|
||||
class RPCError(Exception):
|
||||
def __init__(self, name):
|
||||
|
@ -125,19 +127,14 @@ def __init__(self, location, create=False):
|
|||
self.responses = {}
|
||||
self.unpacker = msgpack.Unpacker(use_list=False)
|
||||
self.p = None
|
||||
# use local umask also for the remote process
|
||||
umask = ['--umask', '%03o' % self.umask]
|
||||
# XXX: ideally, the testsuite would subclass Repository and
|
||||
# override ssh_cmd() instead of this crude hack, although
|
||||
# __testsuite__ is not a valid domain name so this is pretty
|
||||
# safe.
|
||||
if location.host == '__testsuite__':
|
||||
args = [sys.executable, '-m', 'borg.archiver', 'serve'] + umask + self.extra_test_args
|
||||
else: # pragma: no cover
|
||||
args = ['ssh']
|
||||
if location.port:
|
||||
args += ['-p', str(location.port)]
|
||||
if location.user:
|
||||
args.append('%s@%s' % (location.user, location.host))
|
||||
args = [sys.executable, '-m', 'borg.archiver', 'serve' ] + self.extra_test_args
|
||||
else:
|
||||
args.append('%s' % location.host)
|
||||
args += [self.remote_path, 'serve'] + umask
|
||||
args = self.ssh_cmd()
|
||||
self.p = Popen(args, bufsize=0, stdin=PIPE, stdout=PIPE)
|
||||
self.stdin_fd = self.p.stdin.fileno()
|
||||
self.stdout_fd = self.p.stdout.fileno()
|
||||
|
@ -160,6 +157,21 @@ def __del__(self):
|
|||
def __repr__(self):
|
||||
return '<%s %s>' % (self.__class__.__name__, self.location.canonical_path())
|
||||
|
||||
def umask_flag(self):
|
||||
return ['--umask', '%03o' % self.umask]
|
||||
|
||||
def ssh_cmd(self, location):
|
||||
args = shlex.split(os.environ.get('BORG_RSH', 'ssh'))
|
||||
if location.port:
|
||||
args += ['-p', str(location.port)]
|
||||
if location.user:
|
||||
args.append('%s@%s' % (location.user, location.host))
|
||||
else:
|
||||
args.append('%s' % location.host)
|
||||
# use local umask also for the remote process
|
||||
args += [self.remote_path, 'serve'] + self.umask_flag()
|
||||
return args
|
||||
|
||||
def call(self, cmd, *args, **kw):
|
||||
for resp in self.call_many(cmd, [args], **kw):
|
||||
return resp
|
||||
|
|
|
@ -325,6 +325,12 @@ def open(self, create=False):
|
|||
def test_invalid_rpc(self):
|
||||
self.assert_raises(InvalidRPCMethod, lambda: self.repository.call('__init__', None))
|
||||
|
||||
def test_ssh_cmd(self):
|
||||
assert self.repository.umask is not None
|
||||
assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', 'example.com', 'borg', 'serve'] + self.repository.umask_flag()
|
||||
os.environ['BORG_RSH'] = 'ssh --foo'
|
||||
assert self.repository.ssh_cmd(Location('example.com:foo')) == ['ssh', '--foo', 'example.com', 'borg', 'serve'] + self.repository.umask_flag()
|
||||
|
||||
|
||||
class RemoteRepositoryCheckTestCase(RepositoryCheckTestCase):
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ General:
|
|||
can either leave it away or abbreviate as `::`, if a positional parameter is required.
|
||||
BORG_PASSPHRASE
|
||||
When set, use the value to answer the passphrase question for encrypted repositories.
|
||||
BORG_RSH
|
||||
When set, use this command instead of ``ssh``.
|
||||
TMPDIR
|
||||
where temporary files are stored (might need a lot of temporary space for some operations)
|
||||
|
||||
|
|
Loading…
Reference in a new issue