The file transfer connection API
Uploading, downloading, reading, writing and managing remote entries - the same API for SFTP and SMB.
SFTP and SMB connections share one API. The methods to upload, download, read, write, list and manage remote entries are the same for both, so everything in this chapter applies to either protocol unless a difference is called out.
Getting a connection
Obtain a connection object by name, then call its methods. The only difference between the protocols is the attribute the lookup goes through - self.sftp for one, self.smb for the other.
from zato.server.service import Service
class MyService(Service):
def handle(self):
# Get a connection by name - use self.smb['My SMB Connection'] for SMB
conn = self.sftp['My SFTP Connection']
# Confirm the remote server responds
conn.ping()
Uploading and downloading
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.sftp['My SFTP Connection']
# Upload a local file to a remote path
conn.upload('/local/path/file.txt', '/remote/path/file.txt')
# Download a remote file to a local path
conn.download_file('/remote/path/file.txt', '/local/path/file.txt')
# Download an entry - with SFTP, this can be a whole directory downloaded
# recursively, whereas with SMB it is an alias to .download_file.
conn.download('/remote/path', '/local/path')
Reading and writing data directly
You do not need local files to exchange data with a remote server - remote files can be read into and written out of your service directly.
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.sftp['My SFTP Connection']
# Write data out to a remote file
data = 'My data'
conn.write(data, '/remote/path/file.txt')
# Read the contents of a remote file
out = conn.read('/remote/path/file.txt')
self.logger.info(out)
Guaranteed delivery
Where .write sends data once and raises if the remote server is down, .publish queues it for delivery with automatic retries and backoff - the data is spooled locally first, so it survives until the remote side is reachable again. This is the method to use when a file must arrive even if the SFTP server happens to be offline at the moment of sending.
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.sftp['My SFTP Connection']
# Queue the data for delivery - returns immediately,
# the transfer itself is retried until it succeeds
conn.publish('My data', '/remote/path/file.txt')
Managing directories and entries
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.sftp['My SFTP Connection']
# Create a new directory - with SMB, any missing parent directories
# are created too.
conn.create_directory('/path/to/new/directory')
# Delete a directory
conn.delete_directory('/path/to/delete')
# Delete a file
conn.delete_file('/path/to/delete')
# Move or rename remote files and directories
conn.move('/from/path', '/to/path')
# An alias to .move
conn.rename('/from/path', '/to/path')
Getting information about entries
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.sftp['My SFTP Connection']
# Check if a path exists at all
result = conn.exists('/remote/path')
# Get information about an entry, e.g. its size and modification time
info = conn.get_info('/remote/path')
self.logger.info(info.name)
self.logger.info(info.size)
self.logger.info(info.size_human)
self.logger.info(info.last_modified)
# Whether the path is a directory
result = conn.is_directory('/remote/path')
# Whether the path is a file
result = conn.is_file('/remote/path')
# List the contents of a directory - items are in the same format .get_info uses
items = conn.list('/remote/path')
for item in items:
self.logger.info(f'{item.name} {item.size_human}')
Differences between SFTP and SMB
Everything above is shared. What follows is the complete list of the differences between the two protocols.
With SMB, remote paths are always rooted in a share, e.g. MyShare/documents/invoice.pdf, whereas SFTP paths are ordinary remote file system paths, e.g. /home/user/documents/invoice.pdf.
With SMB, .get_info returns the entry's name, size and modification time. With SFTP, it additionally returns the owner and the permissions, e.g. info.owner and info.permissions_oct.
Everything below is available with SFTP only.
from zato.server.service import Service
class MyService(Service):
def handle(self):
conn = self.sftp['My SFTP Connection']
# Execute a script of one or more SFTP commands, newline-separated -
# the same functionality that the SFTP command shell in Dashboard offers.
out = conn.execute('ls -la /remote/path')
# Standard output of the commands executed
self.logger.info(out.stdout)
# The result also includes is_ok, stderr and response_time. By default,
# a failed command raises - pass raise_on_error=False to inspect
# the outcome yourself instead.
out = conn.execute('rm /may/not/exist', raise_on_error=False)
if not out.is_ok:
self.logger.info(f'Command failed: {out.stderr}')
# Create a new symlink
conn.create_symlink('/path/to/point/to', '/path/to/new/symlink')
# Create a new hard link
conn.create_hardlink('/path/to/point/to', '/path/to/new/hardlink')
# Delete an entry, possibly recursively, no matter what kind it is
conn.delete('/path/to/delete')
# Delete a symlink
conn.delete_symlink('/path/to/delete')
# Whether the path is a symlink
result = conn.is_symlink('/remote/path')
# Change the mode of the entry at path
conn.chmod('600', '/path/to/entry')
# Change the owner of the entry at path
conn.chown('myuser', '/path/to/entry')
# Change the group of the entry at path
conn.chgrp('mygroup', '/path/to/entry')
Related
- Outgoing SFTP connections and outgoing SMB connections - creating the connections these methods run against
- File transfer schedules - having Zato watch a directory rather than calling
.listyourself