pythonpython-3.xsubprocessremote-backup

Problem with args when trying to run rsync in Python 3 subprocess


I am developing a backup python program, one of the modules makes a rsync backup of a remote folder into my local device.

This is the part of the code where I have the problem:

            try:
                process = subprocess.Popen(
                    ['sshpass',
                    '-p',
                    password,
                    'rsync',
                    '-avz',
                    '-e',
                    'ssh -o StrictHostKeyChecking=no',
                    '-p',
                    port,
                    '{}@{}:{}'.format(user, host, folder),
                    dest_folder],
                    stdout=subprocess.PIPE
                )
                output = process.communicate()[0]
                if int(process.returncode) != 0:
                    print('Command failed. Return code : {}'.format(process.returncode))
                    exit(1)
                return output
            except Exception as e:
                print(e)
                exit(1)

The shown error is:

Unexpected remote arg: debian@12.345.67.89:/folder1/folder2/
rsync error: syntax or usage error (code 1) at main.c(1372) [sender=3.1.3]
Command failed. Return code : 1

I believe that the problem is with the array in Popen. If I run the single command in bash I rsync successfully.

What should I change from subprocess.Popen array?


Solution

  • This is caused by -p flag being consumed by rsync rather than ssh, and as such the destination effectively is set to port.

    The -e argument of rsync takes exactly one parameter. That means that only 'ssh -o StrictHostKeyChecking=no' will be passed as an argument. Unluckily for you, -p is an actual flag of rsync, and as such it's processed without error. It means 'preserve permissions'. This means that rather than setting port to use with ssh, you're passing a flag to rsync, and the next parameter gets interpreted as a destination.

    You can fix it by changing

     'ssh -o StrictHostKeyChecking=no',
     '-p',
     port,
    

    to simply

     'ssh -o StrictHostKeyChecking=no -p {}'.format(port),