def test_cli_args():
    """Test CLI arguments."""
    # Suppress STDERR
    with capture_sys_output():
        assert_raises(SystemExit, _sync_argv, [])
        assert_raises(SystemExit, _sync_argv, [LOCAL_FOLDER])

    with override_env_variables():
        _sync_argv(
            [LOCAL_FOLDER,
             '127.0.0.1:' + '/' + REMOTE_FOLDER,
             '-f',
             '-k', t_path("id_rsa"),
             '-p', "2222",
             '-d',
             '-c', '/dev/null'
             ],
        )

    _sync_argv(
        [LOCAL_FOLDER,
         '[email protected]:' + '/' + REMOTE_FOLDER,
         '-f',
         '-k', t_path("id_rsa"),
         '-p', "2222",
         '-d',
         '-c', '/dev/null'
         ],
    )

    _sync_argv(
        [LOCAL_FOLDER,
         'test:[email protected]:' + '/' + REMOTE_FOLDER,
         '-p', "2222",
         '-d'
         ],
    )

    _sync_argv(
        [LOCAL_FOLDER,
         'test:[email protected]:' + '/' + REMOTE_FOLDER,
         '-p', "2222",
         '-n', t_path("known_hosts")
         ],
    )

    _sync_argv(
        [LOCAL_FOLDER,
         'backup:' + '/' + REMOTE_FOLDER,
         '-c', t_path("config"),
         # hard to insert relative path in cfg, so we have to cheat
         '-k', t_path("id_rsa"),
         '-d'
         ],
    )
Exemple #2
0
def _start_sftp_server():
    """Start the SFTP local server."""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setblocking(0)
    sock.bind(('localhost', 2222))
    sock.listen(10)

    reads = {sock}
    others = set()

    while not event.is_set():
        ready_to_read, _, _ = \
            select.select(
                reads,
                others,
                others,
                1)

        if sock in ready_to_read:
            client_socket, address = sock.accept()
            ts = paramiko.Transport(client_socket)

            host_key = paramiko.RSAKey.from_private_key_file(
                t_path('server_id_rsa'))
            ts.add_server_key(host_key)
            server = StubServer()
            ts.set_subsystem_handler('sftp', paramiko.SFTPServer,
                                     StubSFTPServer)
            ts.start_server(server=server)

    sock.close()
Exemple #3
0
def _sync(password=False,
          fix=False,
          exclude=None,
          ssh_agent=False,
          delete=True):
    """Launch sync and do basic comparison of dir trees."""
    if not password:
        remote = '[email protected]:' + '/' + REMOTE_FOLDER
    else:
        remote = 'test:[email protected]:' + '/' + REMOTE_FOLDER

    sync = SFTPClone(LOCAL_FOLDER,
                     remote,
                     port=2222,
                     fix_symlinks=fix,
                     identity_files=[t_path("id_rsa")],
                     exclude_file=exclude,
                     ssh_agent=ssh_agent,
                     delete=delete)
    sync.run()

    if not exclude and delete:
        # check the directory trees
        assert \
            file_tree(
                LOCAL_FOLDER
            )[LOCAL_FOLDER_NAME] == file_tree(
                REMOTE_PATH
            )[REMOTE_FOLDER]
def _start_sftp_server():
    """Start the SFTP local server."""
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setblocking(0)
    sock.bind(('localhost', 2222))
    sock.listen(10)

    reads = {sock}
    others = set()

    while not event.is_set():
        ready_to_read, _, _ = \
            select.select(
                reads,
                others,
                others,
                1)

        if sock in ready_to_read:
            client_socket, address = sock.accept()
            ts = paramiko.Transport(client_socket)

            host_key = paramiko.RSAKey.from_private_key_file(
                t_path('server_id_rsa')
            )
            ts.add_server_key(host_key)
            server = StubServer()
            ts.set_subsystem_handler(
                'sftp', paramiko.SFTPServer, StubSFTPServer)
            ts.start_server(server=server)

    sock.close()
def _sync(
        password=False, fix=False,
        exclude=None, ssh_agent=False,
        delete=True

):
    """Launch sync and do basic comparison of dir trees."""
    if not password:
        remote = '[email protected]:' + '/' + REMOTE_FOLDER
    else:
        remote = 'test:[email protected]:' + '/' + REMOTE_FOLDER

    sync = SFTPClone(
        LOCAL_FOLDER,
        remote,
        port=2222,
        fix_symlinks=fix,
        identity_files=[t_path("id_rsa")],
        exclude_file=exclude,
        ssh_agent=ssh_agent,
        delete=delete
    )
    sync.run()

    if not exclude and delete:
        # check the directory trees
        assert \
            file_tree(
                LOCAL_FOLDER
            )[LOCAL_FOLDER_NAME] == file_tree(
                REMOTE_PATH
            )[REMOTE_FOLDER]
Exemple #6
0
def test_inner_exclude():
    """Test pattern exclusion (with recursion) handling."""
    os.mkdir(join(LOCAL_FOLDER, "bar"))
    os.mkdir(join(LOCAL_FOLDER, "bar", "inner"))

    os.open(join(LOCAL_FOLDER, "bar", "file_one"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "bar", "inner", "foo"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "bar", "inner", "bar"), os.O_CREAT)

    _sync(exclude=t_path("exclude"))

    assert set(os.listdir(join(REMOTE_PATH, "bar"))) == {"file_one", "inner"}
    eq_(set(os.listdir(join(REMOTE_PATH, "bar", "inner"))), {"bar"})
def test_inner_exclude():
    """Test pattern exclusion (with recursion) handling."""
    os.mkdir(join(LOCAL_FOLDER, "bar"))
    os.mkdir(join(LOCAL_FOLDER, "bar", "inner"))

    os.open(join(LOCAL_FOLDER, "bar", "file_one"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "bar", "inner", "foo"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "bar", "inner", "bar"), os.O_CREAT)

    _sync(exclude=t_path("exclude"))

    assert set(os.listdir(join(REMOTE_PATH, "bar"))) == {"file_one", "inner"}
    eq_(set(os.listdir(join(REMOTE_PATH, "bar", "inner"))), {"bar"})
def test_create_remote_directory():
    """Test create a remote folder."""

    os.mkdir(LOCAL_FOLDER)
    os.mkdir(join(LOCAL_FOLDER, "foofolder"))

    _sync_argv([
        LOCAL_FOLDER, 'test:[email protected]:' + '/' + REMOTE_FOLDER, '-p',
        "2222", '-n',
        t_path("known_hosts"), '-r'
    ])

    assert (os.listdir(REMOTE_PATH) == os.listdir(LOCAL_FOLDER))
Exemple #9
0
def test_exclude():
    """Test pattern exclusion handling."""
    excluded = {"foofolder"}
    os.mkdir(join(LOCAL_FOLDER, "foofolder"))

    excluded |= {"foo", "foofile"}
    os.open(join(LOCAL_FOLDER, "file_one"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "file_two"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "foo"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "foofile"), os.O_CREAT)

    _sync(exclude=t_path("exclude"))

    assert not set(os.listdir(REMOTE_PATH)) & excluded
def test_exclude():
    """Test pattern exclusion handling."""
    excluded = {"foofolder"}
    os.mkdir(join(LOCAL_FOLDER, "foofolder"))

    excluded |= {"foo", "foofile"}
    os.open(join(LOCAL_FOLDER, "file_one"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "file_two"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "foo"), os.O_CREAT)
    os.open(join(LOCAL_FOLDER, "foofile"), os.O_CREAT)

    _sync(exclude=t_path("exclude"))

    assert not set(os.listdir(REMOTE_PATH)) & excluded
def test_remote_tilde_home():
    """Test tilde expansion on remote end."""
    normal_files = ("bar", "bis")  # just to add noise
    for f in normal_files:
        os.open(join(LOCAL_FOLDER, f), os.O_CREAT)
        os.open(join(REMOTE_PATH, f), os.O_CREAT)

    sync = SFTPClone(
        LOCAL_FOLDER,
        remote_url='[email protected]:' + '~' + REMOTE_FOLDER,
        port=2222,
        identity_files=[t_path("id_rsa"), ]
    )
    sync.run()

    assert file_tree(LOCAL_FOLDER)[LOCAL_FOLDER_NAME] == file_tree(REMOTE_PATH)[REMOTE_FOLDER]
Exemple #12
0
import paramiko
import socket
import select

from nose import with_setup
from nose.tools import assert_raises, raises, eq_
from contextlib import contextmanager

import sys
# unicode / string differentiation
if sys.version_info > (3, 0):
    from io import StringIO
else:
    from StringIO import StringIO

REMOTE_ROOT = t_path("server_root")
REMOTE_FOLDER = "server_folder"
REMOTE_PATH = join(REMOTE_ROOT, REMOTE_FOLDER)

LOCAL_FOLDER_NAME = "local_folder"
LOCAL_FOLDER = t_path(LOCAL_FOLDER_NAME)

_u = functools.partial(unicodedata.normalize, "NFKD")

event = threading.Event()

# attach existing loggers (use --nologcapture option to see output)
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(levelname)s - %(message)s')

import paramiko
import socket
import select

from nose import with_setup
from nose.tools import assert_raises, raises, eq_
from contextlib import contextmanager

import sys
# unicode / string differentiation
if sys.version_info > (3, 0):
    from io import StringIO
else:
    from StringIO import StringIO

REMOTE_ROOT = t_path("server_root")
REMOTE_FOLDER = "server_folder"
REMOTE_PATH = join(REMOTE_ROOT, REMOTE_FOLDER)

LOCAL_FOLDER_NAME = "local_folder"
LOCAL_FOLDER = t_path(LOCAL_FOLDER_NAME)

_u = functools.partial(unicodedata.normalize, "NFKD")

event = threading.Event()

# attach existing loggers (use --nologcapture option to see output)
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
Exemple #14
0
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.

"""
A stub SFTP server for loopback SFTP testing.
"""

import os
from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \
    SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, AUTH_FAILED, OPEN_SUCCEEDED, RSAKey
from paramiko.common import o666

from sftpclone.t.utils import t_path

USERNAME = "******"
PASSWORD = "******"
RSA_KEY = t_path("id_rsa")

SERVER_ROOT = "server_root"


class StubServer (ServerInterface):

    good_pub_key = RSAKey(filename=RSA_KEY)

    def check_auth_password(self, username, password):
        if username == USERNAME and password == PASSWORD:
            return AUTH_SUCCESSFUL
        return AUTH_FAILED

    def check_auth_publickey(self, username, key):
        if username == USERNAME and key == self.good_pub_key:
Exemple #15
0
class StubSFTPServer (SFTPServerInterface):
    ROOT = t_path(SERVER_ROOT)

    def _realpath(self, path):
        return self.ROOT + self.canonicalize(path)

    def list_folder(self, path):
        path = self._realpath(path)
        try:
            out = []
            flist = os.listdir(path)
            for fname in flist:
                attr = SFTPAttributes.from_stat(
                    os.lstat(os.path.join(path, fname))
                )
                attr.filename = fname.encode("utf-8")
                out.append(attr)
            return out
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)

    def stat(self, path):
        path = self._realpath(path)
        try:
            return SFTPAttributes.from_stat(os.stat(path))
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)

    def lstat(self, path):
        path = self._realpath(path)
        try:
            return SFTPAttributes.from_stat(os.lstat(path))
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)

    def open(self, path, flags, attr):
        path = self._realpath(path)
        try:
            binary_flag = getattr(os, 'O_BINARY', 0)
            flags |= binary_flag
            mode = getattr(attr, 'st_mode', None)
            if mode is not None:
                fd = os.open(path, flags, mode)
            else:
                # os.open() defaults to 0777 which is
                # an odd default mode for files
                fd = os.open(path, flags, o666)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        if (flags & os.O_CREAT) and (attr is not None):
            attr._flags &= ~attr.FLAG_PERMISSIONS
            SFTPServer.set_file_attr(path, attr)
        if flags & os.O_WRONLY:
            if flags & os.O_APPEND:
                fstr = 'ab'
            else:
                fstr = 'wb'
        elif flags & os.O_RDWR:
            if flags & os.O_APPEND:
                fstr = 'a+b'
            else:
                fstr = 'r+b'
        else:
            # O_RDONLY (== 0)
            fstr = 'rb'
        try:
            f = os.fdopen(fd, fstr)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        fobj = StubSFTPHandle(flags)
        fobj.filename = path
        fobj.readfile = f
        fobj.writefile = f
        return fobj

    def remove(self, path):
        path = self._realpath(path)
        try:
            os.remove(path)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        return SFTP_OK

    def rename(self, oldpath, newpath):
        oldpath = self._realpath(oldpath)
        newpath = self._realpath(newpath)
        try:
            os.rename(oldpath, newpath)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        return SFTP_OK

    def mkdir(self, path, attr):
        path = self._realpath(path)
        try:
            os.mkdir(path)
            if attr is not None:
                SFTPServer.set_file_attr(path, attr)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        return SFTP_OK

    def rmdir(self, path):
        path = self._realpath(path)
        try:
            os.rmdir(path)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        return SFTP_OK

    def chattr(self, path, attr):
        path = self._realpath(path)
        try:
            SFTPServer.set_file_attr(path, attr)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        return SFTP_OK

    def symlink(self, target_path, path):
        path = self._realpath(path)
        if (len(target_path) > 0) and (target_path[0] == '/'):
            # absolute symlink
            target_path = os.path.join(self.ROOT, target_path[1:])

        try:
            os.symlink(target_path, path)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        return SFTP_OK

    def readlink(self, path):
        path = self._realpath(path)
        try:
            symlink = os.readlink(path)
        except OSError as e:
            return SFTPServer.convert_errno(e.errno)
        # if it's absolute, remove the root
        if os.path.isabs(symlink):
            if symlink[:len(self.ROOT)] == self.ROOT:
                symlink = symlink[len(self.ROOT):]
                if (len(symlink) == 0) or (symlink[0] != '/'):
                    symlink = '/' + symlink
            else:
                symlink = '<error>'
        return symlink
Exemple #16
0
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.

"""
A stub SFTP server for loopback SFTP testing.
"""

import os
from paramiko import ServerInterface, SFTPServerInterface, SFTPServer, SFTPAttributes, \
    SFTPHandle, SFTP_OK, AUTH_SUCCESSFUL, AUTH_FAILED, OPEN_SUCCEEDED, RSAKey
from paramiko.common import o666

from sftpclone.t.utils import t_path

USERNAME = "******"
PASSWORD = "******"
RSA_KEY = t_path("id_rsa")

SERVER_ROOT = "server_root"


class StubServer (ServerInterface):

    good_pub_key = RSAKey(filename=RSA_KEY)

    def check_auth_password(self, username, password):
        if username == USERNAME and password == PASSWORD:
            return AUTH_SUCCESSFUL
        return AUTH_FAILED

    def check_auth_publickey(self, username, key):
        if username == USERNAME and key == self.good_pub_key: