Source code for atmoswing_vigicrues.disseminations.transfer_sftp_out

import os
import socket
import ssl
import paramiko

import atmoswing_vigicrues as asv

from .dissemination import Dissemination


[docs] class TransferSftpOut(Dissemination): """ Transfer des résultats par SFTP. Parameters ---------- name: str Le nom de l'action options: dict Un dictionnaire contenant les options de l'action. Les champs possibles sont: * local_dir : str Répertoire local contenant les fichiers à exporter. * extension : str Extension des fichiers à exporter. * hostname : str Adresse du serveur pour la diffusion des résultats. * port : int Port du serveur distant. * username : str Utilisateur ayant un accès au serveur. * password : str Mot de passe de l'utilisateur sur le serveur. * proxy_host : str Adresse du proxy, si nécessaire. * proxy_port : int Port du proxy si nécessaire (par défaut: 1080). * remote_dir : str Chemin sur le serveur distant où enregistrer les fichiers. Attributes ---------- type_name : str Le nom du type de l'action. name : str Le nom de l'action. local_dir : str Répertoire local contenant les fichiers à exporter. extension : str Extension des fichiers à exporter. hostname : str Adresse du serveur pour la diffusion des résultats. port : int Port du serveur distant. username : str Utilisateur ayant un accès au serveur. password : str Mot de passe de l'utilisateur sur le serveur. proxy_host : str Adresse du proxy, si nécessaire. proxy_port : int Port du proxy si nécessaire (par défaut: 1080). remote_dir : str Chemin sur le serveur distant où enregistrer les fichiers. """ def __init__(self, name, options): """ Initialisation de l'instance TransferSftp """ self.type_name = "Transfert SFTP" self.name = name self.local_dir = options['local_dir'] self.extension = options['extension'] self.hostname = options['hostname'] self.port = int(options['port']) self.username = options['username'] self.password = options['password'] self.remote_dir = options['remote_dir'] if 'proxy_host' in options and len(options['proxy_host']) > 0: self.proxy_host = options['proxy_host'] if 'proxy_port' in options: if isinstance(options['proxy_port'], str) and len( options['proxy_port']) > 0: self.proxy_port = int(options['proxy_port']) elif isinstance(options['proxy_port'], int): self.proxy_port = options['proxy_port'] else: raise asv.Error("Le port du proxy doit être une chaîne de " "caractères ou un entier.") else: self.proxy_port = 8080 else: self.proxy_host = None super().__init__()
[docs] def run(self, date) -> bool: """ Exécution de la diffusion par SFTP. Parameters ---------- date : datetime.datetime Date de la prévision. Returns ------- bool Vrai (True) en cas de succès, faux (False) autrement. """ if not self._file_paths: print(" -> Aucun fichier à traiter") return False try: if self.proxy_host: proxy_socket = self._connect_via_http_proxy( self.proxy_host, self.proxy_port, self.hostname, self.port) transport = paramiko.Transport(proxy_socket) else: # Create a transport object for the SFTP connection transport = paramiko.Transport((self.hostname, self.port)) # Authenticate with the SFTP server transport.connect(username=self.username, password=self.password) # Create SFTP client sftp = paramiko.SFTPClient.from_transport(transport) self._chdir_or_mkdir(self.remote_dir, sftp) self._chdir_or_mkdir(date.strftime('%Y'), sftp) self._chdir_or_mkdir(date.strftime('%m'), sftp) self._chdir_or_mkdir(date.strftime('%d'), sftp) for file in self._file_paths: filename = os.path.basename(file) asv.check_file_exists(file) # If file exists remotely, do not upload try: sftp.stat(filename) print(f"Le fichier {filename} existe déjà sur le serveur distant.") continue except FileNotFoundError: pass sftp.put(file, filename) sftp.close() transport.close() return True except paramiko.ssh_exception.PasswordRequiredException as e: print(f"SFTP PasswordRequiredException {e}") except paramiko.ssh_exception.BadAuthenticationType as e: print(f"SFTP BadAuthenticationType {e}") except paramiko.ssh_exception.AuthenticationException as e: print(f"SFTP AuthenticationException {e}") except paramiko.ssh_exception.ChannelException as e: print(f"SFTP ChannelException {e}") except paramiko.ssh_exception.ProxyCommandFailure as e: print(f"SFTP ProxyCommandFailure {e}") except paramiko.ssh_exception.SSHException as e: print(f"SFTP SSHException {e}") except FileNotFoundError as e: print(f"SFTP FileNotFoundError {e}") except Exception as e: print(f"La diffusion SFTP a échoué ({e}).") if 'sftp' in locals(): sftp.close() if 'transport' in locals(): transport.close() return False
@staticmethod def _connect_via_http_proxy(proxy_host, proxy_port, target_host, target_port): sock = socket.create_connection((proxy_host, proxy_port)) connect_str = (f"CONNECT {target_host}:{target_port} HTTP/1.1\r\nHost: " f"{target_host}:{target_port}\r\n\r\n") sock.sendall(connect_str.encode()) # Wait for HTTP 200 connection established response = sock.recv(4096).decode() if "200 connection established" not in response.lower(): raise Exception(f"Failed to connect via proxy. Response:\n{response}") return sock @staticmethod def _chdir_or_mkdir(dir_path, sftp): try: sftp.chdir(dir_path) except OSError: sftp.mkdir(dir_path) sftp.chdir(dir_path)