巧用Python登陆远程服务器( 二 )


self.scp = None与self.client相同,但专门处理传输文件的连接 。
Self._upload_ssh_key()不是一个变量,而是一个在客户机实例化时自动运行的函数 。调用_upload_ssh_key()是告诉我们的RemoteClient对象在创建时立即检查本地ssh密钥,以便我们可以尝试将它们传递到远程主机 。否则,我们根本无法建立联系 。

巧用Python登陆远程服务器

文章插图
 
上传SSH密钥到远程主机
RemoteClient将从两个私有方法开始:_get_ssh_key()和_upload_ssh_key() 。前者将获取本地存储的公钥,如果成功,后者将把这个公钥传递给我们的远程主机,作为访问的橄榄枝 。一旦本地创建的公钥存在于远程机器上,该机器将永远信任我们的连接请求:不需要密码 。我们将在此过程中包括适当的日志记录,以防我们遇到任何麻烦:
"""Client to handle connections and actions executed against a remote host."""from os import systemfrom paramiko import SSHClient, AutoAddPolicy, RSAKeyfrom paramiko.auth_handler import AuthenticationException, SSHExceptionfrom scp import SCPClient, SCPExceptionfrom .log import loggerclass RemoteClient:"""Client to interact with a remote host via SSH & SCP."""...def _get_ssh_key(self):"""Fetch locally stored SSH key."""try:self.ssh_key = RSAKey.from_private_key_file(self.ssh_key_filepath)logger.info(f'Found SSH key at self {self.ssh_key_filepath}')except SSHException as error:logger.error(error)return self.ssh_keydef _upload_ssh_key(self):try:system(f'ssh-copy-id -i {self.ssh_key_filepath} {self.user}@{self.host}>/dev/null 2>&1')system(f'ssh-copy-id -i {self.ssh_key_filepath}.pub {self.user}@{self.host}>/dev/null 2>&1')logger.info(f'{self.ssh_key_filepath} uploaded to {self.host}')except FileNotFoundError as error:logger.error(error) 
_get_ssh_key()非常简单:它验证SSH密钥是否存在于我们在配置中指定的用于连接到主机的路径上 。如果该文件确实存在,我们很乐意设置self.ssh_key变量,这样我们的客户端就可以上传和使用这个密钥了 。Paramiko为我们提供了一个名为RSAKey的子模块,可以轻松处理所有与RSA密钥相关的事情,比如将一个私钥文件解析为一个可用的连接身份验证 。这就是我们得到的:
RSAKey.from_private_key_file(self.ssh_key_filepath)如果我们的RSA密钥是不可理解的废话,而不是真正的密钥,Paramiko的SSHException会捕捉到这一点,并在解释这一点之前就引发一个异常 。正确地利用库的错误处理需要对“哪里出了问题”进行大量猜测,特别是在某些情况下,比如在一个我们都不会经常搞混的小空间中,可能存在许多未知的情况 。
巧用Python登陆远程服务器

文章插图
 
连接到客户端
我们将在客户机中添加一个名为connect()的方法来处理到主机的连接:
...class RemoteClient:"""Client to interact with a remote host via SSH & SCP."""...def _connect(self):"""Open connection to remote host."""if self.conn is None:try:self.client = SSHClient()self.client.load_system_host_keys()self.client.set_missing_host_key_policy(AutoAddPolicy())self.client.connect(self.host,username=self.user,key_filename=self.ssh_key_filepath,look_for_keys=True,timeout=5000)self.scp = SCPClient(self.client.get_transport())except AuthenticationException as error:logger.error(f'Authentication failed:did you remember to create an SSH key? {error}')raise errorreturn self.client让我们来分析一下: