SSH與Python模塊paramiko


paramiko是用python語言寫的一個模塊,遵循SSH2協議,支持以加密和認證的方式,進行遠程服務器的連接。paramiko支持Linux, Solaris, BSD, MacOS X, Windows等平台通過SSH從一個平台連接到另外一個平台。利用該模塊,可以方便的進行ssh連接和sftp協議進行sftp文件傳輸。

一、paramiko模塊的安裝

paramiko模塊依賴PyCrypto模塊,而PyCrypto需要GCC庫編譯,不過一般發行版的源里帶有該模塊。這里以ubuntu為例,直接借助以下命令可以直接完成安裝:

sudo pip3 install paramiko 

二、paramiko的連接

使用paramiko模塊有兩種連接方式,一種是通過paramiko.SSHClient()函數,另外一種是通過paramiko.Transport()函數。

方法一:

import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("某IP地址",22,"用戶名", "口令")

上面的第二行代碼的作用是允許連接不在know_hosts文件中的主機。

方法二:

import paramiko
t = paramiko.Transport(("主機","端口"))
t.connect(username = "用戶名", password = "口令")

如果連接遠程主機需要提供密鑰,上面第二行代碼可改成:

t.connect(username = "用戶名", password = "口令", hostkey="密鑰")

三、paramiko ssh連接

以下是一個簡單的通過paramiko模塊定義的ssh連接並執行命令的函數,如下:

#!/usr/bin/python3
#-*- coding: utf-8 -*-
import paramiko
#paramiko.util.log_to_file('/tmp/sshout')
def ssh2(ip,username,passwd,cmd):
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(ip,22,username,passwd,timeout=5)
        stdin,stdout,stderr = ssh.exec_command(cmd)
        # stdin.write("Y") #interact with server, typing Y 
        print(stdout.read())
        # for x in stdout.readlines():
        # print x.strip("n")
        print('%s OK\n'%(ip))
        ssh.close()
    except :
        print('%s Error\n' %(ip))

ssh2("45.76.22.112","root","password","ls")

其中第四行的日志部分,是記錄ssh連接交互時的一些信息,可以看做是類似於debug的輸出,一般情況下不需要開啟。

stdin.write部分是用於交互情況下,通過該命令可以執行交互。注意這里可能會引起歧義,這里的交互並不是ssh連接過程中出現的讓輸入yes的交互,因為paramiko模塊在連接過程中會自動處理好yes確認。這里的交互是指后面的cmd需要的執行的程序可能出現交互的情況下,可以通過該參數進行交互。

stdout標准輸出,在輸出內容比較少時,可以通過直接使用read讀取出所有的輸出;但在輸出內容比較多時,建議通過按行讀取進行處理。不過按行讀取時,每行結尾會有換行符n,這樣輸出的結果很不美觀。可以通過strip進行字符串的處理。
在函數調用過程中需要注意的是,**IP、username、passwd都是屬於字符串型的,所以需要加引號。后面執行的cmd,如果有多個命令需要操作時,需要通過分號進行分割。

四、paramiko sftp示例

單個文件小傳下載的示例:

import paramiko
#建立一個加密的管道
scp=paramiko.Transport(('192.168.0.102',22))
#建立連接
scp.connect(username='root',password='361way')
#建立一個sftp客戶端對象,通過ssh transport操作遠程文件
sftp=paramiko.SFTPClient.from_transport(scp)
#Copy a remote file (remotepath) from the SFTP server to the local host
sftp.get('/root/testfile','/tmp/361way')
#Copy a local file (localpath) to the SFTP server as remotepath
sftp.put('/root/crash-6.1.6.tar.gz','/tmp/crash-6.1.6.tar.gz')
scp.close()

一個目錄下多個文件上傳下載的示例:

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import paramiko,datetime,os
hostname='192.168.0.102'
username='root'
password='361way'
port=22
local_dir='/tmp/getfile'
remote_dir='/tmp/abc'
try:
    t=paramiko.Transport((hostname,port))
    t.connect(username=username,password=password)
    sftp=paramiko.SFTPClient.from_transport(t)
    #files=sftp.listdir(dir_path)
    files=sftp.listdir(remote_dir)
    for f in files:
    print ''
    print '#########################################'
    print 'Beginning to download file from %s %s ' % (hostname,datetime.datetime.now())
    print 'Downloading file:',os.path.join(remote_dir,f)
    sftp.get(os.path.join(remote_dir,f),os.path.join(local_dir,f))#下載
    #sftp.put(os.path.join(local_dir,f),os.path.join(remote_dir,f))#上傳
    print 'Download file success %s ' % datetime.datetime.now()
    print ''
    print '##########################################'
    t.close()
except Exception:
    print "connect error!" 

注:本處的目錄下所有文件進行下載或上傳的示例中,在遇到目錄下還有嵌套的目錄存在時,會將目錄也當做文件進行處理,所以如果想要更加的完美的話,可以通過引入stat模塊下的S_ISDIR方法進行處理
paramiko.transport對象也支持以socket的方式進行連接,如下示例:

import paramiko
transport = paramiko.Transport(('localhost',22))
transport.connect(username='root', password = 'password')
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.get(remotefile,localfile)
#如果是上傳則用:
#sftp.put(localfile, remotefile)
transport.close()
#用socket連接
tcpsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcpsock.settimeout(5)
tcpsock.connect((ip,22),)
ssh = paramiko.Transport(tcpsock)
ssh.connect(username=user,password=password)
sftpConnect=paramiko.SFTPClient.from_transport(ssh) 

五、利用paramiko實現ssh的交互式連接

以下是通過paramiko模塊直接用ssh協議登陸到遠程服務器的操作代碼,這里先定義一個interactive模塊,代碼如下:

import socket
import sys
# windows does not have termios...
try:
 import termios
 import tty
 has_termios = True
except ImportError:
 has_termios = False
def interactive_shell(chan):
 if has_termios:
 posix_shell(chan)
 else:
 windows_shell(chan)
def posix_shell(chan):
 import select
 oldtty = termios.tcgetattr(sys.stdin)
 try:
 tty.setraw(sys.stdin.fileno())
 tty.setcbreak(sys.stdin.fileno())
 chan.settimeout(0.0)
 while True:
 r, w, e = select.select([chan, sys.stdin], [], [])
 if chan in r:
 try:
 x = chan.recv(1024)
 if len(x) == 0:
 print 'rn*** EOFrn',
 break
 sys.stdout.write(x)
 sys.stdout.flush()
 except socket.timeout:
 pass
 if sys.stdin in r:
 x = sys.stdin.read(1)
 if len(x) == 0:
 break
 chan.send(x)
 finally:
 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
# thanks to Mike Looijmans for this code
def windows_shell(chan):
 import threading
 sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.rnrn")
 def writeall(sock):
 while True:
 data = sock.recv(256)
 if not data:
 sys.stdout.write('rn*** EOF ***rnrn')
 sys.stdout.flush()
 break
 sys.stdout.write(data)
 sys.stdout.flush()
 writer = threading.Thread(target=writeall, args=(chan,))
 writer.start()
 try:
 while True:
 d = sys.stdin.read(1)
 if not d:
 break
 chan.send(d)
 except EOFError:
 # user hit ^Z or F6
 pass

代碼內容可以從paramiko 在github項目上的demo里獲取。再另外寫一個ssh_inter.py的交互主程序,內容如下:

import paramiko
import interactive
#記錄日志
paramiko.util.log_to_file('/tmp/test')
#建立ssh連接
ssh=paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.168.0.102',port=22,username='root',password='xxxxxx',compress=True)
#建立交互式shell連接
channel=ssh.invoke_shell()
#建立交互式管道
interactive.interactive_shell(channel)
#關閉連接
channel.close()
ssh.close()

執行效果就像我們平時直接使用ssh登錄一樣。

六、總結

paramiko模塊是一個比較強大的ssh連接模塊,以上的示例只是列出了該模塊的一些簡單的使用方法,還可以使用threading模塊加塊程序並發的速度;也可以使用configparser模塊處理配置文件,而我們將所有IP、用戶信息操作都放入配置文件;使用setproctitle模塊為執行的程序加一個容易區分的title等。
同樣,雖然連fabric這樣大名鼎鼎的軟件使用的ssh都是用paramiko模塊進行的封裝,不過你依然可以選擇不使用它,你也可以選擇pexpect模塊實現封裝一個簡易的ssh連接工具、或者使用同樣比較火的salt-ssh模塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM