- Fixed issue with destination not handling sub-folders - Refactored transfer_file to use validate_equals_with_retry Change-Id: I357620bde7b792c50bb7e52ade52e9ef7191f70d
111 lines
5.7 KiB
Python
111 lines
5.7 KiB
Python
import os
|
|
|
|
from framework.logging.automation_logger import get_logger
|
|
from framework.ssh.secure_transfer_file.secure_transfer_file_enum import TransferDirection
|
|
from framework.ssh.secure_transfer_file.secure_transfer_file_input_object import SecureTransferFileInputObject
|
|
from framework.validation.validation import validate_equals_with_retry
|
|
from keywords.python.string import String
|
|
|
|
|
|
class SecureTransferFile:
|
|
"""
|
|
Class that provides an easier way to transfer a file over SFTP.
|
|
"""
|
|
|
|
def __init__(self, secure_transfer_file_input_object: SecureTransferFileInputObject):
|
|
"""
|
|
Constructor
|
|
Args:
|
|
secure_transfer_file_input_object (SecureTransferFileInputObject): an instance of SecureTransferFileInputObject
|
|
with the setup to transfer a single file via SFTP.
|
|
"""
|
|
# Check the required fields.
|
|
if secure_transfer_file_input_object.get_sftp_client() is None:
|
|
raise ValueError("The field 'sftp_client' in the 'SecureTransferFileInputObject' instance must be defined.")
|
|
|
|
if String.is_empty(secure_transfer_file_input_object.get_origin_path()):
|
|
raise ValueError("The field 'origin_path' in the 'SecureTransferFileInputObject' instance cannot be empty.")
|
|
|
|
if String.is_empty(secure_transfer_file_input_object.get_destination_path()):
|
|
raise ValueError("The field 'destination_path' in the 'SecureTransferFileInputObject' instance cannot be empty.")
|
|
|
|
if secure_transfer_file_input_object.get_transfer_direction() not in TransferDirection:
|
|
raise ValueError("The field 'transfer_direction' in the 'SecureTransferFileInputObject' must be specified as one of the values in 'TransferDirection'.")
|
|
|
|
self.secure_transfer_file_input_object = secure_transfer_file_input_object
|
|
|
|
def transfer_file(self) -> bool:
|
|
"""
|
|
Transfer the file specified in the constructor via SFTP.
|
|
Returns:
|
|
bool: True, if the file specified in the constructor of this class was successfully transferred; False
|
|
otherwise.
|
|
|
|
"""
|
|
# Origin path.
|
|
origin_path = self.secure_transfer_file_input_object.get_origin_path()
|
|
|
|
# Destination path.
|
|
destination_path = self.secure_transfer_file_input_object.get_destination_path()
|
|
destination_file_name = os.path.basename(destination_path)
|
|
destination_folder_name = os.path.dirname(destination_path)
|
|
|
|
# Gets the SFTP client
|
|
sftp_client = self.secure_transfer_file_input_object.get_sftp_client()
|
|
|
|
# Determines the transfer direction to perform either a 'get' or 'put' operation.
|
|
transfer_direction = self.secure_transfer_file_input_object.transfer_direction
|
|
|
|
# Transfers the file from remote to local destination.
|
|
if transfer_direction == TransferDirection.FROM_REMOTE_TO_LOCAL:
|
|
|
|
def is_file_at_destination():
|
|
return os.path.isfile(destination_path)
|
|
|
|
# Manages forced file transfer.
|
|
force_transfer = self.secure_transfer_file_input_object.get_force()
|
|
if is_file_at_destination():
|
|
if not force_transfer:
|
|
get_logger().log_info(f"The file {destination_path} already exists. Try setting the 'force' property of the SecureTransferFileInputObject instance to 'True' if you want to overwrite it.")
|
|
return False
|
|
|
|
# Transfers the file from remote to local destination.
|
|
try:
|
|
sftp_client.get(origin_path, destination_path)
|
|
except Exception as ex:
|
|
get_logger().log_exception(f"Error when trying to transfer the file {origin_path} to destination {destination_path}. Exception: {ex}")
|
|
raise ex
|
|
|
|
# Validate that the file was transferred successfully
|
|
validate_equals_with_retry(is_file_at_destination, True, f"File {origin_path} is transferred to {destination_path}.", timeout=self.secure_transfer_file_input_object.get_timeout_in_seconds())
|
|
|
|
# Transfers to remote destination.
|
|
elif transfer_direction == TransferDirection.FROM_LOCAL_TO_REMOTE:
|
|
|
|
def is_file_at_destination():
|
|
file_list = sftp_client.listdir(destination_folder_name)
|
|
return any(destination_file_name == file for file in file_list)
|
|
|
|
# Manages forced file transfer.
|
|
force_transfer = self.secure_transfer_file_input_object.get_force()
|
|
if is_file_at_destination():
|
|
if not force_transfer:
|
|
get_logger().log_info(f"The file {destination_path} already exists. Try setting the 'force' property of the SecureTransferFileInputObject instance to 'True' if you want to overwrite it.")
|
|
return False
|
|
|
|
# Transfers the file to remote destination.
|
|
try:
|
|
sftp_client.put(origin_path, destination_path)
|
|
except Exception as ex:
|
|
get_logger().log_exception(f"Error when trying to transfer the file {origin_path} to destination {destination_path}. Exception: {ex}")
|
|
raise ex
|
|
|
|
# Validate that the file was transferred successfully
|
|
validate_equals_with_retry(is_file_at_destination, True, f"File {origin_path} is transferred to {destination_path}.", timeout=self.secure_transfer_file_input_object.get_timeout_in_seconds())
|
|
|
|
# The property 'transfer_direction' was not properly specified.
|
|
else:
|
|
message = f"Error when trying to transfer the file {origin_path} to destination {destination_path}. Property 'transfer_direction' must be specified as either TransferDirection.FROM_LOCAL_TO_REMOTE or TransferDirection.FROM_REMOTE_TO_LOCAL"
|
|
get_logger().log_exception(message)
|
|
raise ValueError(message)
|