目前公司使用多個服務器對外提供服務。其中只有一臺服務器有外網帶寬,有幾臺內網業務服務器。這帶有兩個問題:python
針對這兩個問題,咱們使用SSH/SCP和PEXPECT來解決。linux
咱們使用SSH經過有外網的服務器創建起本地和沒有外網的服務器的隧道,以後全部的操做均可以經過這個隧道來進行操做。正則表達式
首先進行隧道的建立。windows
ssh -L [bind_address:]tunnelport:host:hostport <SSH hostname>
而後就是經過隧道使用SSH登錄無外網帶寬的服務器服務器
ssh -p tunnelport x@127.0.0.1
這裏使用-p參數,把ssh使用的端口爲以前綁定的隧道端口tunnelport。ssh
使用SCP進行文件的傳輸操做。函數
scp -P tunnelport src_file x@127.0.0.1:dst_file
這裏使用-P參數,把SCP使用的端口設置爲以前綁定的隧道端口tunnelport。測試
Pexpect 是一個用來啓動子程序並對其進行自動控制的 Python 模塊。 Pexpect 能夠用來和像 ssh、ftp、passwd、telnet 等命令行程序進行自動交互,方便在工做中實現與命令行交互的自動化。spa
在作實驗的過程主要使用了spawn、sendline和expect三個函數來實現咱們的要求。命令行
spawn
class spawn: def __init__(self,command,args=[],timeout=30,maxread=2000,searchwindowsize=None, logfile=None, cwd=None, env=None) spawn是Pexpect模塊主要的類,用以實現啓動子程序,它有豐富的方法與子程序交互從而實現用戶對子程序的控制。它主要使用 pty.fork() 生成子進程,並調用 exec() 系列函數執行 command 參數的內容。
expect
expect(self, pattern, timeout=-1, searchwindowsize=None)在參數中: pattern 能夠是正則表達式, pexpect.EOF , pexpect.TIMEOUT ,或者由這些元素組成的列表。須要注意的是,當 pattern 的類型是一個列表時,且子程序輸出結果中不止一個被匹配成功,則匹配返回的結果是緩衝區中最早出現的那個元素,或者是列表中最左邊的元素。使用 timeout 能夠指定等待結果的超時時間 ,該時間以秒爲單位。當超過預訂時間時, expect 匹配到pexpect.TIMEOUT。
sendline
這些方法用來向子程序發送命令,會額外在後面多加個回車來模擬操做。與之相關的還有send和sendcontrol兩個函數
#!/usr/bin/env python # -*- coding: utf-8 -*- import pexpect import os import time #cmd須要向命令行輸入的命令 #passeword host的密碼 def ssh_login (cmd, password): ssh_newkey = 'Are you sure you want to continue connecting' new_ssh = pexpect.spawn(cmd) i = new_ssh.expect([pexpect.TIMEOUT, ssh_newkey, 'password: ']) #登錄的時候會有兩種狀態 if i == 0: #若是是超時 print 'ERROR!' print 'SSH could not login. Here is what SSH said:' print new_ssh.before, new_ssh.after return None if i == 1: #若是須要輸入信息登錄 new_ssh.sendline ('yes') i = new_ssh.expect([pexpect.TIMEOUT, 'password: ']) if i == 0: print 'ERROR!' print 'SSH could not login. Here is what SSH said:' print new_ssh.before, new_ssh.after return None new_ssh.sendline(password) return new_ssh #登出 def ssh_logout(newpexpect): newpexpect.close() #等待終端出輸入符號 def ssh_wait_prompts(ssh): ssh.expect([pexpect.EOF, '[$#>]']) #因爲scp須要在沒有創建連接的時候須要驗證,因此封裝一下 def scp_run(cmd, password): new_scp = ssh_login(cmd, password) ssh_wait_prompts(new_scp) ssh_logout(new_scp) def main (): #建立隧道,這個須要一直保持,直到不用這個隧道時才能釋放 server1_tunnel = ssh_login ("ssh -L 8082:192.168.132.144:22 x@192.168.132.141","x") slb = ssh_login('ssh x@192.168.132.144', 'x') #正常登錄服務器 server1 = ssh_login('ssh -p 8082 x@127.0.0.1', 'x') #經過隧道登錄服務器 scp_run('scp -P 8082 /home/x/test.py x@127.0.0.1:/home/x/tesdt.py', 'x') #經過隧道傳送文件 ssh_wait_prompts(server1) #經過ssh運行一個腳本,刪除文件 server1.sendline('/home/x/del.sh') #測試連通性 ssh_wait_prompts(server1) server1.sendline('ls') ssh_wait_prompts(server1) print server1.before ssh_logout(server1) ssh_logout(slb) ssh_logout(server1_tunnel) if __name__ == '__main__': try: main() except Exception, e: print 'fail', str(e) traceback.print_exc() os._exit(1)