Paramiko模組簡單使用

昀溪發表於2018-08-22

介紹

Paramiko 一個第三方包,需要單獨安裝我們知道遠端批次主機管理,比如ansible、Fabric,不需要安裝客戶端的遠端執行命令等,這些都是基於Python原生的SSH,相當於模擬了一個SSH客戶端。其實用的就是paramiko。其實想Fabric這種東西你自己也可以寫,其實特別簡單。paramiko 就是模擬了SSH的客戶端,然後透過和SSH伺服器互動就可以登入,執行命令等操作。

程式碼例項

簡單的SSH登入實現

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # Author: rex.cheny
 4 # E-mail: rex.cheny@outlook.com
 5 
 6 
 7 import paramiko
 8 
 9 
10 def main():
11     # 例項化SSH客戶端
12     ssh = paramiko.SSHClient()
13     # 允許連線不在 known_hosts 檔案的IP
14     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
15     # 連線伺服器
16     ssh.connect(hostname="172.16.42.136", port=22, username="root", password="12qwaszx!")
17 
18     # 執行命令,它返回三個結果,stdin 是你輸入的,stdout是它返回給你的,stderr是錯誤資訊
19     stdin, stdout, stderr = ssh.exec_command("ls /")
20     result = stdout.read()
21     print(result.decode(encoding="utf-8"))
22     ssh.close()
23 
24 
25 if __name__ == '__main__':
26     main()

簡單的SFTP實現

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # Author: rex.cheny
 4 # E-mail: rex.cheny@outlook.com
 5 
 6 import paramiko
 7 
 8 
 9 def main():
10     try:
11         # 例項化SSH客戶端
12         ssh = paramiko.SSHClient()
13         # 允許連線不在 known_hosts 檔案的IP
14         ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
15         # 連線伺服器
16         ssh.connect(hostname="172.16.42.136", port=22, username="root", password="12qwaszx!")
17         transport = ssh.get_transport()
18 
19         """
20         上面程式碼也可以這樣寫
21         transport = paramiko.Transport((host, port))
22         transport.connect(username=username, password=password)
23         """
24 
25         sftp = paramiko.SFTPClient.from_transport(transport)
26         sftp.put("./readme", "/tmp")
27         transport.close()
28     except Exception as err:
29         print(err)
30 
31 
32 if __name__ == '__main__':
33     main()

包含SFTP和SSH功能的程式碼例項

  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 
  4 import sys
  5 import os
  6 import paramiko
  7 import configparser
  8 
  9 
 10 class paramikoTools(object):
 11 
 12     def __init__(self, hostname, port, username, password, privateKeyFile=None, privateKeyFilePwd=None):
 13         """
 14 
 15         :param hostname: SSH伺服器地址
 16         :param port: 埠
 17         :param username: 使用者名稱
 18         :param password: 密碼
 19         :param privateKeyFile: 私鑰路徑,如果沒有則不用填寫
 20         :param privateKeyFilePwd: 私鑰解壓密碼如果私鑰加密了請務必輸入否則登陸將會失敗
 21         :return:
 22         """
 23         self._hostname = hostname
 24         self._port = port
 25         self._username = username
 26         self._password = password
 27         self._privateKeyFile = privateKeyFile
 28         self._privateKeyFilePwd = privateKeyFilePwd
 29 
 30         # 例項化一個SSH客戶端物件
 31         self._sshClient = paramiko.SSHClient()
 32         # 第一次SSH登入伺服器需要輸入一個Yes,這個就是幫你自動輸入yes
 33         self._sshClient.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 34         #
 35         self._transport = None
 36         #
 37         self._sftpClient = None
 38 
 39         # 用於記錄是否建立了SFTP客戶端例項
 40         self._isSftpSessionOpened = False
 41         # 用於記錄當前是否已經登入
 42         self._isLogined = False
 43 
 44     def login(self):
 45         if self._privateKeyFile:
 46             if os.path.exists(self._privateKeyFile):
 47                 self._isLogined = self._loginWithPrivateKey()
 48             else:
 49                 print("私鑰路徑不存在。")
 50         else:
 51             self._isLogined = self._loginWithPassword()
 52 
 53     # 使用者名稱和密碼登陸方法
 54     def _loginWithPassword(self):
 55         try:
 56             # 連線遠端伺服器
 57             self._sshClient.connect(hostname=self._hostname, port=self._port, username=self._username,
 58                                     password=self._password)
 59             print("密碼登陸成功。")
 60         except Exception as err:
 61             # print err
 62             print("連線失敗,請檢查主機名、埠、使用者名稱或者密碼是否正確。")
 63             return False
 64         else:
 65             return True
 66 
 67     # 私鑰登陸方法
 68     def _loginWithPrivateKey(self):
 69         try:
 70             if self._privateKeyFilePwd:
 71                 # 取出私鑰,有時私鑰加密了這裡就需要設定私鑰的密碼,用於對私鑰解密。
 72                 key = paramiko.RSAKey.from_private_key_file(self._privateKeyFile, password=self._privateKeyFilePwd)
 73             else:
 74                 key = paramiko.RSAKey.from_private_key_file(self._privateKeyFile)
 75 
 76             self._sshClient.connect(hostname=self._hostname, port=self._port, username=self._username,
 77                                     password=self._password, pkey=key)
 78             print("秘鑰登陸成功。")
 79         except Exception as err:
 80             # print err
 81             print("連線失敗,請檢查主機名、埠、使用者名稱、密碼、私鑰是否正確。")
 82             return False
 83         else:
 84             return True
 85 
 86     @property
 87     def isLogined(self):
 88         return self._isLogined
 89 
 90     # 建立SFTP客戶端
 91     def _createSftpSession(self):
 92         """
 93         我這裡建立SFTP連線的方式和網上略有不同,我這裡是基於現有SSH連線來建立的SFTP會話。網上很多都是單純的建立SFTP會話
 94         但是即便單純建立SFTP會話其背後也要建立套接字和身份驗證,可能網上的其他形式如下:
 95         t = paramiko.Transport((host, port))
 96         t.connect(username=username, password=password)
 97         sftp = paramiko.SFTPClient.from_transport(t)
 98         """
 99         if self._isLogined:
100             try:
101                 # 使用現有SSH連線獲取一個 transport
102                 self._transport = self._sshClient.get_transport()
103                 # 把 transport 傳遞進去建立SFTP客戶端連線
104                 self._sftpClient = paramiko.SFTPClient.from_transport(self._transport)
105             except Exception as err:
106                 print(err)
107             else:
108                 self._isSftpSessionOpened = True
109         else:
110             print("ssh會話已經關閉或者沒有建立,無法建立SFTP客戶端連線。")
111             self._isSftpSessionOpened = False
112 
113     # 路徑檢查
114     def _pathChect(self, localPath, remotePath):
115         # F 表示檔案; D 表示目錄
116         CHECK_CODE = {"CODE": "0", "LOCALPATHTYPE": "F", "REMOTEPATHTYPE": "F"}
117         if os.path.exists(localPath):
118             return CHECK_CODE
119         else:
120             # 本地路徑檢查失敗,不存在。
121             CHECK_CODE = {"CODE": "101", "LOCALPATHTYPE": "", "REMOTEPATHTYPE": ""}
122             return CHECK_CODE
123 
124     # 獲取錯誤碼對資訊
125     def _getCheckCodeDesc(self, temp_code):
126         CHECK_CODE_DICT= {"0": "檢查透過", "101": "本地路徑檢查失敗可能不存在"}
127         DESC = ""
128         if CHECK_CODE_DICT.has_key(temp_code):
129             pass
130         else:
131             DESC = "錯誤碼不存在"
132             return DESC
133 
134     # 關閉ssh連線
135     def sshConnectLogOut(self):
136         self._sshClient.close()
137         self._transport.close()
138         self._isLogined = False
139         self._isSftpSessionOpened = False
140 
141     # 執行命令
142     def execCommand(self, cmd):
143         result = ''
144         if self._isLogined:
145             try:
146                 # 遠端執行命令,會返回元祖,裡面包含輸入、輸出、錯誤
147                 stdin, stdout, stderr = self._sshClient.exec_command(cmd)
148             except Exception as err:
149                 print(err)
150             else:
151                 # 輸出的就是字串內容
152                 print(stdout.read())
153                 # return result
154         else:
155             print("當前沒有建立SSH的有效連線。")
156 
157     # 上傳檔案
158     def upLoadFile(self, localPath, remotePath):
159         count = 0
160         # 如果SFTP客戶端會話沒有建立則自動建立,嘗試三次
161         for times in range(3):
162             if not self._isSftpSessionOpened:
163                 count = times + 1
164                 print("第 %d 次嘗試建立SFTP客戶端會話,如果失敗將再嘗試 %d 次" % (count, 3 - count))
165                 self._createSftpSession()
166                 if count == 3 and not self._isSftpSessionOpened:
167                     return None
168                 else:
169                     continue
170             else:
171                 print("SFTP客戶端會話建立成功。")
172                 break
173 
174         # 目前這裡是直接上傳,沒有區分檔案還是目錄,所以預設只能支援檔案,本地是檔案路徑、遠端也是檔案路徑
175         try:
176             CODE = self._pathChect(localPath, remotePath)["CODE"]
177             if CODE == "0":
178                 # 路徑檢查都成功後如何處理
179                 print("開始上傳檔案。")
180                 self._sftpClient.put(localPath, remotePath)
181                 print("上傳檔案完畢。")
182             else:
183                 print(self._getCheckCodeDesc(CODE))
184         except Exception as err:
185             print(err)
186         else:
187             pass
188 
189     # 下載檔案
190     def downLoad(self, remotePath, localPath):
191         pass
192 
193 
194 def main():
195     # 建立ini檔案讀取例項
196     config = configparser.ConfigParser()
197     # 設定配置檔案路徑
198     config_file_path = '/Users/rex.chen/PycharmProjects/Study/paramikoTest/config'
199     # 讀取檔案
200     config.read(config_file_path)
201     # 獲取內容,第一個引數是區,第二個引數是 鍵
202     hostname = config.get("ssh", "hostname")
203     port = config.getint("ssh", "port")
204     username = config.get("ssh", "username")
205     password = config.get("ssh", "password")
206     private_key_path = config.get("ssh", "private_key_path")
207 
208     a = paramikoTools(hostname, port, username, password, private_key_path, password)
209     a.login()
210     # a.execCommand("df")
211     # a.upLoadFile('/Users/rex.chen/Downloads/mapi-webapp.war', '/home/chenyun/update/mapi-webapp.war')
212     print(a.isLogined)
213 
214 
215 if __name__ == "__main__":
216     main()

同目錄的配置檔案如下:

# paramiko連線使用的配置檔案,不是必須的,只是這樣可以避免過多的硬編碼

[ssh]
hostname=
port=
username=
password=
private_key_path=

 

相關文章