概述ssh是一个协议,OpenSSH是开源实现之一,paramiko是Python的一个库,实现了SSHv2协议(密码学在底部)。借助Paramiko,我们可以直接使用SSH协议在Python代码中对远程服务器进行操作,而不是通过ssh命令来操作远程服务器。今天主要介绍Paramiko的一些相关概念。Paramiko简介Paramiko包含两个核心组件:SSHClient和SFTPClient。SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装。该类封装了SFTPClient建立的传输(Transport)、通道(Channel)和方法(open_sftp),通常用于执行远程命令。SFTPClient的功能类似于Linux的sftp命令。是对SFTP客户端的封装,实现远程文件操作,如文件上传、下载、文件权限修改等。Paramiko中的几个基本术语:Channel:是Socket的一种,一种安全的SSH传输通道;Transport:是一个加密的session,使用的时候会同步创建一个加密的Tunnels(通道)。这个Tunnels叫做Channel;Session:是client与server保持连接的对象,使用connect()/start_client()/start_server()来启动session。Paramiko的基本使用一、SSHClient常用方法介绍(1)connect():实现远程服务器的连接和认证。对于此方法,只有主机名是必需的参数。常用参数hostname连接目标主机port=SSH_PORT指定端口username=None认证用户名password=None认证用户密码pkey=None认证的私钥方式key_filename=None文件名或文件列表,指定私钥文件timeout=Noneoptionaltcpconnectiontimeoutallow_agent=True,是否允许连接sshagent,默认为True,allowlook_for_keys=True,是否在~/.ssh中搜索私钥文件,默认为True,allowcompress=False,是否开启压缩(2)set_missing_host_key_policy():设置known_hosts文件中没有记录远程服务器时的响应策略。目前支持三种策略:当连接的远程主机没有本地主机密钥或HostKeys对象时设置策略,目前支持三种:AutoAddPolicy自动将主机名和主机密钥添加到本地HostKeys对象,与load_system_host_key的配置无关.即在建立新的ssh连接时不需要输入yes或no进行确认。WarningPolicy用于记录未知主机密钥的python警告。而accept,功能类似AutoAddPolicy,但是会提示新连接RejectPolicy自动拒绝未知主机名和密钥,具体取决于load_system_host_key的配置。这是默认选项(3)exec_command():一种在远程服务器上执行Linux命令的方法。(4)open_sftp():在当前ssh会话的基础上创建一个sftp会话。此方法将返回一个SFTPClient对象。使用SSHClient对象的open_sftp()方法,可以直接返回一个基于当前连接的sftp对象,可以进行文件上传等操作。sftp=client.open_sftp()sftp.put('test.txt','text.txt')七大案例1.Paramiko远程密码连接importparamiko##1。创建一个ssh对象client=paramiko.SSHClient()#2。解决问题:如果之前没有ipconnected,会有选择yesorno的操作,##Automaticallyselectyesclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())#3.连接服务器client.connect(hostname='172.25.254.31',端口=22,用户名='root',密码='westos')#4。执行操作stdin、stdout、stderr=client.exec_command('hostname')#5。获取命令执行结果result=stdout.read().decode('utf-8')print(result)#6。关闭连接客户端.close()2。使用sftp上传文件importparamiko#GetTransportinstancetran=paramiko.Transport("172.25.254.31",22)#ConnecttoSSHservertran.connect(username="root",password="westos")#GetSFTPinstancesftp=paramiko.SFTPClient.from_transport(tran)#设置上传的本地/远程文件路径localpath="passwd.html"##本地文件路径remotepath="/home/kiosk/Desktop/fish"##上传对象所在的文件路径保存#执行上传动作sftp.put(localpath,remotepath)tran.close()3.使用sftp下载文件importparamiko#获取SSHClient实例cclient=paramiko.SSHClient()client.set_missing_host_key_policy(paramiko.AutoAddPolicy())#连接SSH服务器client.connect("172.25.254.31",username="root",password="westos")#GetTransportinstancetran=client.get_transport()#获取SFTP实例sftp=paramiko.SFTPClient.from_transport(tran)remotepath='/home/kiosk/Desktop/fish'localpath='/home/kiosk/Desktop/fish'sftp.get(remotepath,localpath)client.close()4.批量远程密码连接fromparamiko.ssh_exceptionimportNoValidConnectionsErrorfromparamiko.ssh_exceptionimportAuthenticationExceptiondefconnect(cmd,hostname,port=22,username='root',passwd='westos'):importparamiko##1。创建一个ssh对象client=paramiko.SSHClient()#2。解决问题:如果之前没有连接ip,会有选择yes或no的操作,##Automaticallyselectyesclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())#3。连接服务器试试:client.connect(hostnamehostname=hostname,portport=port,usernameusername=username,password=passwd)print('Connectingtohost%s...'%(hostname))exceptNoValidConnectionsErrorase:###Whenthe用户不存在错误打印(“连接失败”)exceptAuthenticationExceptionast:##Wrongpassworderrorprint('passworderror')else:#4.执行操作stdin,stdout,stderr=client.exec_command(cmd)#5。获取命令执行结果result=stdout.read()。解码('utf-8')打印(结果)#6。最后关闭连接:client.close()withopen('ip.txt')asf:#ip.txt是本地局域网中的一些用户信息forlineinf:lineline=line.strip()##去掉换行hostname,port,username,passwd=line.split(':')print(hostname.center(50,'*'))connect('uname',hostname,port,username,passwd)5.Paramiko基于公钥importparamikofromparamiko进行连接。ssh_exceptionimportNoValidConnectionsError,AuthenticationExceptiondefconnect(cmd,hostname,port=22,user='root'):client=paramiko.SSHClient()private_key=paramiko.RSAKey.from_private_key_file('id_rsa')###id_rsa是本地局域网密钥文件客户端。set_missing_host_key_policy(paramiko.AutoAddPolicy())try:client.connect(hostnamehostname=hostname,portport=port,userusername=user,pkey=private_key)stdin,stdout,stderr=client.exec_command(cmd)exceptNoValidConnectionsErrorase:print("连接失败")exceptAuthenticationExceptionase:打印(&“密码错误”)else:result=stdout.read().decode('utf-8')print(result)finally:client.close()forcountinrange(254):host='172.25.254.%s'%(count+1)print(host.center(50,'*'))connect('uname',host)6.基于key的上传下载importparamikoprivate_key=paramiko.RSAKey.from_private_key_file('id_rsa')tran=paramiko.Transport('172.25.254.31',22)tran.connect(username='root',password='westos')#getSFTP实例sftp=paramiko.SFTPClient.from_transport(tran)remotepath='/home/kiosk/Desktop/fish8'localpath='/home/kiosk/Desktop/fish1'sftp.put(localpath,remotepath)sftp.get(remotepath,本地路径)7。paramikoimportosimportparamikofromparamiko.ssh_exceptionimportNoValidConnectionsError,AuthenticationException,SSHExceptionclass__f__injectHit(self,hostname,port,user,passwd,cmd):self.hostname=hostnameself.port=portself.user=userself.passwd=passwdself.cmd=cmddefrun(self)重新打包:”""默认调用内容"""#cmdhostname#put#getcmd_str=self.cmd.split()[0]#cmd#reflection,判断类是否可以支持这个操作ifhasattr(self,'do_'+cmd_str):#do_cmdgetattr(self,'do_'+cmd_str)()else:print("目前不支持这个功能")defdo_cmd(self):client=paramiko.SSHClient()client.set_missing_host_key_policy(paramiko.AutoAddPolicy())try:client.connect(hostname=self.hostname,port=self.port,username=self.user,password=self.passwd)print("连接到%s......."%(self.hostname))exceptNoValidConnectionsErrorase:print("Connectionfailed")exceptAuthenticationExceptionase:print("Passworderror")else:#4.执行操作cmd=''.join(self.cmd.split()[1:])##取出input后面的为stdin,stdout,stderr=client.exec_command(cmd)#5。获取命令执行结果result=stdout.read().decode('utf-8')print(result)finally:#6.关闭连接client.close()defdo_put(self):###put/tmp/passwd###上传本地的/tmp/passwd到远程的/tmp/passwdprint('Uploading...')try:#GetTransportinstancetran=paramiko.Transport(self.hostname,int(self.port))##因为端口是塑料的,我们用split方法得到的是str#连接到SSH服务器tran.connect(username=self.user,password=self.passwd)exceptSSHExceptionase:print('connectionfailed')else:#获取SFTP实例sftp=paramiko.SFTPClient.from_transport(tran)newCmd=self.cmd.split()[1:]iflen(newCmd)==2:#设置上传的本地/远程文件路径localpath=newCmd[0]remotepath=newCmd[1]#执行上传动作sftp.put(localpath,remotepath)print('%s文件上传到%s主机的%s文件成功'%(localpath,self.hostname,remotepath))else:print('上传文件信息错误')tran.close()defdo_get(self):print('Downloading...')try:#GetTransportinstancetran=paramiko.Transport(self.hostname,int(self.port))##因为端口是塑料的,我们用split方法得到的是str#ConnecttotheSSHservertran.connect(username=self.user,password=self.passwd)exceptSSHExceptionase:print('Connectionfailed')else:#GettheSFTPinstancesftp=帕拉米科SFTPClient.from_transport(tran)newCmd=self.cmd.split()[1:]iflen(newCmd)==2:#设置下载的本地/远程文件路径localpath=newCmd[1]remotepath=newCmd[0]#执行上传动作sftp.get(remotepath,localpath)print('%s文件从%s主机下载到%s文件成功'%(self.hostname,remotepath,localpath))else:print('上传文件信息错误')tran.close()importparamikoimportos#1。选择运行的主机组:eg:mysql,web,ftpgroups=[file.rstrip('.conf')forfileinos.listdir('conf')]print("主机组显示:".center(50,'*'))forgroupgroups:print('\t',group)choiceGroup=input("选择批量操作的主机组(eg:mysql):")##2.根据选择的主机组,显示包含的主机IP/主机名#1)。打开文件conf/choiceGroup.conf#2)。依次读取文件的每一行#3)。只取出print("Hostsincludedinthehostgroup:".center(50,'*'))withopen('conf/%s.conf'%(choiceGroup))asf:forlineinf:print(line.split(':')[0])f.seek(0,0)##将指针移到文件开头hostinfos=[line.strip()forlineinf.readlines()]###3.让用户确认信息,选择要批量执行的命令;##-cmdshell命令##-放本地文件远程文件##-获取远程文件本地文件print("批量执行脚本".center(50,"*"))whileTrue:cmd=input('>>:').strip()ifcmd:ifcmd=='exit'orcmd=="quit":print("Completed,exiting")breakforinfoinhostinfos:host,port,user,passwd=info.split(':')clientObj=SshRemoteHost(主机,port,user,passwd,cmd)clientObj.run()
