Merge pull request #248 from anarcat/ssh-env

add support for arbitrary SSH commands
This commit is contained in:
TW 2015-10-06 01:20:23 +02:00
commit 974dd58c23
4 changed files with 38 additions and 18 deletions

View File

@ -571,10 +571,10 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
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:

View File

@ -3,6 +3,7 @@ import fcntl
import msgpack
import os
import select
import shlex
from subprocess import Popen, PIPE
import sys
import tempfile
@ -108,8 +109,9 @@ class RepositoryServer: # pragma: no cover
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 @@ class RemoteRepository:
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))
else:
args.append('%s' % location.host)
args += [self.remote_path, 'serve'] + umask
args = [sys.executable, '-m', 'borg.archiver', 'serve' ] + self.extra_test_args
else:
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 @@ class RemoteRepository:
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

View File

@ -325,6 +325,12 @@ class RemoteRepositoryTestCase(RepositoryTestCase):
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):

View File

@ -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)