def scp_file(dest_path, contents=None, kwargs=None, local_file=None):
    '''
    Use scp or sftp to copy a file to a server
    '''
    file_to_upload = None
    try:
        if contents is not None:
            try:
                tmpfd, file_to_upload = tempfile.mkstemp()
                os.write(tmpfd, contents)
            finally:
                try:
                    os.close(tmpfd)
                except OSError as exc:
                    if exc.errno != errno.EBADF:
                        raise exc

        log.debug('Uploading %s to %s', dest_path, kwargs['hostname'])

        ssh_args = [
            # Don't add new hosts to the host key database
            '-oStrictHostKeyChecking=no',
            # Set hosts key database path to /dev/null, i.e., non-existing
            '-oUserKnownHostsFile=/dev/null',
            # Don't re-use the SSH connection. Less failures.
            '-oControlPath=none'
        ]

        if local_file is not None:
            file_to_upload = local_file
            if os.path.isdir(local_file):
                ssh_args.append('-r')

        if 'key_filename' in kwargs:
            # There should never be both a password and an ssh key passed in, so
            ssh_args.extend([
                # tell SSH to skip password authentication
                '-oPasswordAuthentication=no',
                '-oChallengeResponseAuthentication=no',
                # Make sure public key authentication is enabled
                '-oPubkeyAuthentication=yes',
                # do only use the provided identity file
                '-oIdentitiesOnly=yes',
                # No Keyboard interaction!
                '-oKbdInteractiveAuthentication=no',
                # Also, specify the location of the key file
                '-i {0}'.format(kwargs['key_filename'])
            ])

        if 'port' in kwargs:
            ssh_args.append('-oPort={0}'.format(kwargs['port']))

        ssh_args.append(__ssh_gateway_arguments(kwargs))

        try:
            if socket.inet_pton(socket.AF_INET6, kwargs['hostname']):
                ipaddr = '[{0}]'.format(kwargs['hostname'])
            else:
                ipaddr = kwargs['hostname']
        except socket.error:
            ipaddr = kwargs['hostname']

        if file_to_upload is None:
            log.warning(
                'No source file to upload. Please make sure that either file '
                'contents or the path to a local file are provided.'
            )
        cmd = (
            'scp {0} {1} {2[username]}@{4}:{3} || '
            'echo "put {1} {3}" | sftp {0} {2[username]}@{4} || '
            'rsync -avz -e "ssh {0}" {1} {2[username]}@{2[hostname]}:{3}'.format(
                ' '.join(ssh_args), file_to_upload, kwargs, dest_path, ipaddr
            )
        )

        log.debug('SCP command: \'%s\'', cmd)
        retcode = _exec_ssh_cmd(cmd,
                                error_msg='Failed to upload file \'{0}\': {1}\n{2}',
                                password_retries=3,
                                **kwargs)
    finally:
        if contents is not None:
            try:
                os.remove(file_to_upload)
            except OSError as exc:
                if exc.errno != errno.ENOENT:
                    raise exc
    return retcode
Use scp or sftp to copy a file to a server