現(xiàn)在,我們已經(jīng)知道如何在不同的操作系統(tǒng)中使用和安裝Python以及如何使用EVE-NG搭建網(wǎng)絡(luò)拓?fù)?。在本章中,我們將學(xué)習(xí)如何使用目前常用的網(wǎng)絡(luò)自動(dòng)化庫自動(dòng)完成各種網(wǎng)絡(luò)任務(wù)。Python可以在不同的網(wǎng)絡(luò)層上與網(wǎng)絡(luò)設(shè)備進(jìn)行交互。 首先,Python可以通過套接字編程和socket模塊操縱底層網(wǎng)絡(luò),從而為Python所在的操作系統(tǒng)和網(wǎng)絡(luò)設(shè)備之間搭建一個(gè)低層次的網(wǎng)絡(luò)接口。此外,Python模塊還可以通過Telnet、SSH和API與網(wǎng)絡(luò)設(shè)備進(jìn)行更高級(jí)別的交互。本章將深入探討如何在Python中使用Telnet與SSH模塊在遠(yuǎn)程設(shè)備上建立連接和執(zhí)行命令。 本章主要介紹以下內(nèi)容:
應(yīng)檢查是否正確安裝了下列工具并保證它們能夠正常使用:
本章中出現(xiàn)的所有腳本請參見GitHub網(wǎng)站。 4.1.1 Python和SSHSSH和Telnet的不同之處在于客戶端與服務(wù)器之間交換數(shù)據(jù)的通道不一樣。SSH使用的是安全鏈路,在客戶端和設(shè)備之間創(chuàng)建了一個(gè)使用不同的安全機(jī)制進(jìn)行加密的隧道,通信內(nèi)容很難被解密。因此在需要保證網(wǎng)絡(luò)安全的時(shí)候,網(wǎng)絡(luò)工程師會(huì)首先選擇使用SSH協(xié)議。 Paramiko庫遵循SSH2協(xié)議,支持身份驗(yàn)證,密鑰處理(DSA、RSA、ECDSA和ED25519),以及其他SSH功能(如proxy命令和SFTP)。在Python中當(dāng)需要使用SSH連接到網(wǎng)絡(luò)設(shè)備時(shí)通常使用這個(gè)庫。 4.1.2 Paramiko模塊Paramiko是Python中應(yīng)用最廣的SSH模塊。模塊本身使用Python語言編寫和開發(fā),只有像crypto這樣的核心函數(shù)才會(huì)用到C語言。從其GitHub官方鏈接上能夠看到代碼的貢獻(xiàn)者和模塊歷史等諸多信息。 1.安裝模塊打開Windows cmd或Linux shell,運(yùn)行下面的命令,從PyPI下載最新的Paramiko模塊。如下圖所示,同時(shí),該命令會(huì)自動(dòng)下載其他依賴包(如cyrptography、ipaddress和six),并將它們安裝到計(jì)算機(jī)上。 pip install paramiko 在命令行中輸入Python,然后導(dǎo)入Paramiko模塊,驗(yàn)證是否安裝成功。如下圖所示,正確安裝之后,能夠成功導(dǎo)入模塊。也就是說,命令行上不會(huì)出現(xiàn)任何錯(cuò)誤提示。 如前所述,要使用Paramiko模塊,首先需要在Python腳本中導(dǎo)入它,然后通過繼承SSHClient()來創(chuàng)建SSH客戶端。然后,設(shè)置Paramiko的參數(shù),使其能夠自動(dòng)添加任意未知的主機(jī)密鑰并信任與服務(wù)器之間的連接。接下來,將遠(yuǎn)程主機(jī)的信息(IP地址、用戶名和密碼等)傳遞給connect函數(shù)。
最后,invoke_shell()將啟動(dòng)一個(gè)連接到SSH服務(wù)器的交互式shell會(huì)話。在調(diào)用該函數(shù)時(shí)可以傳入一些其他參數(shù)(如終端類型、寬度、高度等)。 Paramiko的連接參數(shù)如下。
最后一步,把各種命令(如show ip int b和show arp)發(fā)送到設(shè)備終端,并將返回結(jié)果輸出到Python窗口中。 shell.send('enable\n')shell.send('access123\n')shell.send('terminal length 0\n')shell.send('show ip int b\n')shell.send('show arp \n')time.sleep(2)print shell.recv(5000)Channel.close() 腳本運(yùn)行結(jié)果如下圖所示。 4.1.3 netmiko模塊 netmiko是Paramiko的增強(qiáng)版本,專門面向網(wǎng)絡(luò)設(shè)備。雖然Paramiko能夠處理與設(shè)備的SSH連接并判斷設(shè)備類型是服務(wù)器、打印機(jī)還是網(wǎng)絡(luò)設(shè)備,但netmiko在設(shè)計(jì)時(shí)針對網(wǎng)絡(luò)設(shè)備做了優(yōu)化,能夠更有效地處理SSH連接。netmiko還支持各種不同的設(shè)備廠商和平臺(tái)。 netmiko也是對Paramiko的封裝,它使用許多其他增強(qiáng)功能擴(kuò)展了Paramiko,比如使用啟用的密碼直接訪問所支持的設(shè)備,從文件讀取配置并將推送到設(shè)備,在登錄期間禁用分頁顯示,以及默認(rèn)在每條命令后面加上回車符'\n'。 1.支持的設(shè)備商netmiko支持許多供應(yīng)商的設(shè)備,并定期在支持列表中添加新的供應(yīng)商。netmiko支持的供應(yīng)商列表分為定期測試類、有限測試類和實(shí)驗(yàn)類。在該模塊的GitHub頁面上可以找到這個(gè)列表。 定期測試類中支持的供應(yīng)商如下圖所示。 有限測試類中支持的供應(yīng)商如下圖所示。 實(shí)驗(yàn)類中支持的供應(yīng)商如下圖所示。 安裝netmiko非常簡單。打開Windows命令行窗口或Linux shell,執(zhí)行下面的命令就可以從PyPI獲取最新版本的netmiko包(見下圖)。
然后,在Python shell中導(dǎo)入netmiko,驗(yàn)證模塊是否正確地安裝到Python site-packages中。 $python>>>import netmiko 現(xiàn)在該開始使用netmiko了,讓我們來看看它強(qiáng)大的SSH功能。首先連接到網(wǎng)絡(luò)設(shè)備并在上面執(zhí)行命令。默認(rèn)情況下,netmiko在建立會(huì)話(session)的過程中會(huì)在后臺(tái)處理許多操作(如添加未知的SSH密鑰主機(jī),設(shè)置終端類型、寬度和高度),在需要的時(shí)候還可以進(jìn)入特權(quán)(enable)模式,然后通過運(yùn)行供應(yīng)商提供的命令來禁用分頁。 首先,以字典格式定義設(shè)備并提供下列5個(gè)必需的關(guān)鍵信息。
第一個(gè)參數(shù)是device_type,為了執(zhí)行正確的命令,需要使用這個(gè)參數(shù)來定義平臺(tái)供應(yīng)商。然后,需要SSH的IP地址。如果已經(jīng)使用DNS解析了IP地址,該參數(shù)可能是主機(jī)名;否則,該參數(shù)是IP地址。接下來,提供username、password以及以secret參數(shù)傳遞的特權(quán)模式的密碼。注意,可以使用getpass()模塊隱藏密碼,并且只在腳本執(zhí)行期間提示它們。
接下來,從netmiko模塊導(dǎo)入ConnectHandler函數(shù),并提供定義的字典來開始建立連接。因?yàn)樗械脑O(shè)備是通過特權(quán)模式的密碼配置的,所以需要為創(chuàng)建的連接提供.enable(),以在特權(quán)模式下訪問。使用.send_command()在路由器終端上執(zhí)行命令,.send_command()將會(huì)執(zhí)行命令并通過變量的值顯示設(shè)備的輸出。 from netmiko import ConnectHandlerconnection = ConnectHandler(**R1)connection.enable()output = connection.send_command('show ip int b')print output 腳本輸出結(jié)果如下。 注意,這里看到的輸出結(jié)果去掉了命令行中的命令回顯和設(shè)備提示符。默認(rèn)情況下,netmiko會(huì)替換設(shè)備的返回結(jié)果,使輸出更加整潔,替換過程通過正則表達(dá)式完成,這部分會(huì)在下一章中介紹。 如果不想使用這種方式,而是希望看到命令提示符,并在返回結(jié)果的后面執(zhí)行命令,可以在.send_command()函數(shù)中加上以下參數(shù)。
strip_command=False和strip_prompt=False告訴netmiko保留而不是替換命令行回顯和提示符。默認(rèn)情況下它為True,可以根據(jù)需要進(jìn)行設(shè)置。 netmiko可以通過SSH配置遠(yuǎn)程設(shè)備,通過.config方法進(jìn)入設(shè)備的配置模式,然后按照list格式中的信息(配置列表)配置設(shè)備。配置列表可以直接寫在Python腳本中,也可以從文件中讀取,然后用readlines()方法轉(zhuǎn)換為列表。 from netmiko import ConnectHandlerSW2 = { 'device_type': 'cisco_ios', 'ip': '10.10.88.112', 'username': 'admin', 'password': 'access123', 'secret': 'access123',}core_sw_config = ['int range gig0/1 - 2','switchport trunk encapsulationdot1q', 'switchport mode trunk','switchport trunk allowed vlan1,2']print '########## Connecting to Device {0} ############'.format(SW2['ip'])net_connect = ConnectHandler(**SW2)net_connect.enable()print '***** Sending Configuration to Device *****'net_connect.send_config_set(core_sw_config) 上面的腳本以另外一種形式連接到SW2并進(jìn)入特權(quán)模式。但這次使用的是另一個(gè)netmiko方法——send_config_set(),該方法需要使用列表形式的配置文件,同時(shí)進(jìn)入設(shè)備的配置模式并根據(jù)列表對設(shè)備進(jìn)行配置。這里測試了一個(gè)簡單的配置,即修改gig0/1和gig0/2,并將這兩個(gè)端口配成trunk模式。在設(shè)備上執(zhí)行show run命令時(shí),如果命令執(zhí)行成功,會(huì)出現(xiàn)類似下面的輸出。 在設(shè)計(jì)Python腳本時(shí),我們可能會(huì)假設(shè)設(shè)備已啟動(dòng)并運(yùn)行,并且用戶已提供了正確的登錄信息,但實(shí)際情況并非總是如此。有時(shí)Python和遠(yuǎn)程設(shè)備之間的網(wǎng)絡(luò)連接可能存在問題,或者用戶輸入了錯(cuò)誤的登錄信息。如果發(fā)生這種情況,Python通常會(huì)拋出異常并退出,但這種解決方案顯然不夠完美。 netmiko中的異常處理模塊netmiko.ssh_exception提供的一些異常處理類可以處理上面所說的那些情況。第一個(gè)類AuthenticationException能夠捕獲遠(yuǎn)程設(shè)備中的身份驗(yàn)證錯(cuò)誤。第二個(gè)類NetMikoTimeoutException能夠捕獲netmiko和設(shè)備之間的超時(shí)或任何連接問題。下面的例子中使用try-except子句包含了ConnectHandler()方法,用來捕獲超時(shí)和身份驗(yàn)證異常。 6.設(shè)備自動(dòng)發(fā)現(xiàn)netmiko提供了一種可以“猜測”設(shè)備類型和發(fā)現(xiàn)設(shè)備的機(jī)制。通過組合使用SNMP發(fā)現(xiàn)OIDS和在遠(yuǎn)程控制臺(tái)上執(zhí)行多個(gè)show命令這兩種方式,根據(jù)輸出字符串檢測路由器的操作系統(tǒng)和類型。然后,netmiko將相應(yīng)的驅(qū)動(dòng)程序加載到ConnectHandler()類中。 #!/usr/local/bin/python__author__ = 'Bassim Aly'__EMAIL__ = 'basim.alyy@gmail.com'from netmiko import SSHDetect, Netmikodevice = {'device_type': 'autodetect','host': '10.10.88.110','username': 'admin','password': 'access123',}detect_device = SSHDetect(**device)device_type = detect_device.autodetect()print(device_type)print(detect_device.potential_matches)device['device_type'] = device_typeconnection = Netmiko(**device) 在上面的腳本中,應(yīng)注意以下幾點(diǎn)。 首先,設(shè)備字典中的device_type等于autodetect,也就是告訴netmiko在檢測到設(shè)備類型之前不要加載驅(qū)動(dòng)程序。 然后,使用netmiko的SSHDetect()類發(fā)現(xiàn)設(shè)備。它使用SSH連接到設(shè)備,并執(zhí)行一些命令以找出操作系統(tǒng)的類型,結(jié)果以字典形式返回。 接著,使用autodetect()函數(shù)將匹配度最高的結(jié)果賦給device_type變量。 接下來,輸出potential_matches,查看字典內(nèi)的全部返回結(jié)果。 最后,可以更新設(shè)備字典并為其分配新的device_type。 4.2 在Python中使用Telnet協(xié)議Telnet是TCP/IP協(xié)議棧中最早可用的協(xié)議之一,主要用來在服務(wù)器和客戶端之間建立連接、交換數(shù)據(jù)。服務(wù)器端監(jiān)聽TCP端口23,等待客戶端的連接請求。 在下面的例子中,我們將創(chuàng)建一個(gè)Python腳本作為Telnet客戶端,拓?fù)渲械钠渌酚善骱徒粨Q機(jī)則作為Telnet服務(wù)器。Python原生的telnetlib庫已經(jīng)支持Telnet,所以不需要另外安裝。 客戶端對象可以通過telnetlib模塊中的Telnet()類實(shí)例化創(chuàng)建。通過這個(gè)對象,我們能夠使用telnetlib中的兩個(gè)重要函數(shù)——read_until()(用于讀取輸出結(jié)果)和write()(用于向遠(yuǎn)程設(shè)備寫入內(nèi)容)。這兩個(gè)函數(shù)用來和Telnet連接交互,從Telnet連接讀取或向Telnet連接寫入數(shù)據(jù)。 還有一點(diǎn)非常關(guān)鍵,使用read_until()讀取Telnet連接的內(nèi)容之后緩沖區(qū)會(huì)被清空,無法再次讀取。因此,如果在后面的處理中還會(huì)用到之前讀取的重要數(shù)據(jù),需要在腳本里將其另存為變量。
讓我們一步步分析這個(gè)腳本。 (1)在Python腳本中導(dǎo)入telnetlib模塊,在變量中定義用戶名和密碼。代碼如下。
(2)定義一個(gè)變量,用來和遠(yuǎn)程主機(jī)建立連接。注意,只需要提供遠(yuǎn)程主機(jī)的IP地址,不用在連接建立過程中提供用戶名或密碼。 cnx = telnetlib.Telnet(host='10.10.88.110') #here we're telnet toGateway (3)通過讀取Telnet連接返回的輸出并搜索“Username:”關(guān)鍵字來提供Telnet連接的用戶名。然后寫入管理員用戶名。如果需要,用同樣的方法輸入Telnet密碼。
(4)向Telnet連接寫入show ip interface brief命令并開始讀取返回內(nèi)容,直到出現(xiàn)路由器提示符(#)為止。通過以下命令可以得到路由器的接口配置。 cnx.read_until('#')cnx.write('show ip int b' + '\n')output = cnx.read_until('#')print output 完整的腳本如下所示。 腳本運(yùn)行結(jié)果如下所示。 注意,在輸出中包含了執(zhí)行的命令show ip int b,并且在stdout中輸出和返回了路由器提示符'R1#'。可以使用內(nèi)置的字符串函數(shù)(如replace())從輸出中清除它們。
你可能已經(jīng)注意到腳本中使用了密碼并將密碼以明文形式寫下來,這樣做顯然是不安全的。同時(shí),在Python腳本中使用硬編碼也不是好習(xí)慣。在下一節(jié)中,我們將學(xué)習(xí)如何隱藏密碼并設(shè)計(jì)一種機(jī)制,從而在腳本運(yùn)行時(shí)要求用戶輸入密碼。 此外,如果要執(zhí)行那些輸出結(jié)果可能跨越多個(gè)頁面的命令(如show running config),則需要在連接到設(shè)備之后和發(fā)送命令之前,先通過發(fā)送termindl length 0來禁用分頁。 使用telnetlib推送配置在上一節(jié)中,我們通過執(zhí)行show ip int brief簡單介紹了telnetlib的操作過程?,F(xiàn)在我們要用telnetlib將VLAN配置推送到實(shí)驗(yàn)室網(wǎng)絡(luò)拓?fù)渲械?臺(tái)交換機(jī)。使用Python的range()函數(shù)創(chuàng)建一個(gè)VLAN列表,遍歷列表將VLAN ID推送到當(dāng)前交換機(jī)。注意,我們將交換機(jī)的IP地址放到了另一個(gè)列表中,使用外部for循環(huán)來遍歷這個(gè)列表。同時(shí)使用內(nèi)置模塊getpass隱藏控制臺(tái)中的密碼,在腳本運(yùn)行時(shí)提示用戶輸入密碼。 #!/usr/bin/pythonimport telnetlibimport getpassimport timeswitch_ips = ['10.10.88.111', '10.10.88.112', '10.10.88.113','10.10.88.114']username = raw_input('Please Enter your username:')password = getpass.getpass('Please Enter your Password:')enable_password = getpass.getpass('Please Enter your Enable Password:')for sw_ip in switch_ips: print '\n#################### Working on Device ' + sw_ip + '####################' connection = telnetlib.Telnet(host=sw_ip.strip()) connection.read_until('Username:') connection.write(username + '\n') connection.read_until('Password:') connection.write(password + '\n') connection.read_until('>') connection.write('enable' + '\n') connection.read_until('Password:') connection.write(enable_password + '\n') connection.read_until('#') connection.write('config terminal' + '\n') # now i'm in config mode vlans = range(300,400) for vlan_id in vlans: print '\n********* Adding VLAN ' + str(vlan_id) + '**********' connection.read_until('#') connection.write('vlan ' + str(vlan_id) + '\n') time.sleep(1) connection.write('exit' + '\n') connection.read_until('#') connection.close() 最外層的for循環(huán)用來遍歷設(shè)備列表,然后在每次循環(huán)(每個(gè)設(shè)備)中生成范圍為300~400的VLAN ID并將它們推送到當(dāng)前設(shè)備。 腳本運(yùn)行結(jié)果如下。 當(dāng)然,也可以通過交換機(jī)控制臺(tái)檢查運(yùn)行結(jié)果(僅顯示部分結(jié)果)。 管理和操作IP地址是網(wǎng)絡(luò)工程師最重要的任務(wù)之一。Python開發(fā)人員提供了一個(gè)令人驚嘆的庫—— netaddr,它可以識(shí)別IP地址并對其進(jìn)行處理。假設(shè)你開發(fā)了一個(gè)應(yīng)用程序,其中需要獲取129.183.1.55/21的網(wǎng)絡(luò)地址和廣播地址,通過模塊內(nèi)的內(nèi)置方法network和broadcast可以輕松地獲取到相應(yīng)的地址。
netaddr支持很多功能。 在第3層的地址中,netaddr支持下列功能。
在第2層的地址中,netaddr支持下列功能。
使用pip安裝netaddr模塊,命令如下。 pip install netaddr 安裝完成之后打開PyCharm或Python控制臺(tái)并導(dǎo)入模塊,驗(yàn)證模塊是否安裝成功。如果沒有出現(xiàn)錯(cuò)誤信息,說明模塊安裝成功。 4.3.2 使用netaddr的方法netaddr模塊提供了兩種重要的方法來定義IP地址并對其進(jìn)行處理。第一種方法是IPAddress(),它用來定義具有默認(rèn)子網(wǎng)掩碼的單個(gè)有類IP地址。第二種方法是IPNetwork(),它使用CIDR定義無類IP地址。 兩種方法都將IP地址作為字符串來處理,根據(jù)字符串返回IP地址或IP網(wǎng)絡(luò)對象。返回的對象還可以繼續(xù)執(zhí)行許多方法,比如判斷IP地址是單播地址、多播地址、環(huán)回地址、私有地址還是公有地址,以及地址有效還是無效地址。這些操作的結(jié)果是True或False。在Python的if條件中可以直接使用這些方法。 另外,該模塊支持使用==、<和>等比較運(yùn)算符比較兩個(gè) IP 地址,從而生成子網(wǎng)。它還可以檢索一個(gè)給定IP地址或者子網(wǎng)術(shù)語的超網(wǎng)列表。最終,netaddr模塊可以生成有效主機(jī)的一個(gè)完整列表(不包括網(wǎng)絡(luò)IP地址和網(wǎng)絡(luò)廣播地址)。 #!/usr/bin/python__author__ = 'Bassim Aly'__EMAIL__ = 'basim.alyy@gmail.com'from netaddr import IPNetwork,IPAddressdef check_ip_address(ipaddr): ip_attributes = [] ipaddress = IPAddress(ipaddr) if ipaddress.is_private(): ip_attributes.append('IP Address is Private') else: ip_attributes.append('IP Address is public') if ipaddress.is_unicast(): ip_attributes.append('IP Address is unicast') elif ipaddress.is_multicast(): ip_attributes.append('IP Address is multicast') if ipaddress.is_loopback(): ip_attributes.append('IP Address is loopback') return '\n'.join(ip_attributes)def operate_on_ip_network(ipnet): net_attributes = [] net = IPNetwork(ipnet) net_attributes.append('Network IP Address is ' + str(net.network) + ' and Netowrk Mask is ' + str(net.netmask)) net_attributes.append('The Broadcast is ' + str(net.broadcast) ) net_attributes.append('IP Version is ' + str(net.version) ) net_attributes.append('Information known about this network is ' + str(net.info) ) net_attributes.append('The IPv6 representation is ' + str(net.ipv6())) net_attributes.append('The Network size is ' + str(net.size)) net_attributes.append('Generating a list of ip addresses inside the subnet') for ip in net: net_attributes.append('\t' + str(ip)) return '\n'.join(net_attributes)ipaddr = raw_input('Please Enter the IP Address: ')print check_ip_address(ipaddr)ipnet = raw_input('Please Enter the IP Network: ')print operate_on_ip_network(ipnet) 在上面的腳本中,首先使用raw_input()函數(shù)請求用戶輸入IP地址和IP網(wǎng)絡(luò),然后將輸入的值作為參數(shù)傳遞給兩個(gè)用戶方法check_ip_address()和operate_on_ip_network()并調(diào)用它們。第一個(gè)函數(shù)check_ip_address()會(huì)檢查輸入的IP地址,同時(shí)嘗試生成有關(guān)IP地址屬性的報(bào)告(例如,IP地址是單播、多播、私有還是環(huán)回地址),并將輸出返回給用戶。 第二個(gè)函數(shù)operate_on_ip_network()用來完成和網(wǎng)絡(luò)相關(guān)的操作,即生成網(wǎng)絡(luò)ID、掩碼、廣播、版本、網(wǎng)絡(luò)上的已知信息、IPv6地址的顯示方式,最后生成該子網(wǎng)內(nèi)的所有IP地址。 注意,net.info只能對公共IP地址生成可用信息,對私有IP地址不起作用。 同樣,在使用之前需要先從netaddr模塊導(dǎo)入IP Network和IP Address。 腳本運(yùn)行結(jié)果如下所示。 隨著網(wǎng)絡(luò)變得越來越大,其中包含更多來自各種不同供應(yīng)商的設(shè)備,這就需要?jiǎng)?chuàng)建模塊化的Python腳本來自動(dòng)執(zhí)行各種任務(wù)。接下來的幾節(jié)將分析3個(gè)用例,這些用例可以從網(wǎng)絡(luò)中收集不同信息,縮短解決問題所需的時(shí)間,或者至少將網(wǎng)絡(luò)配置恢復(fù)到其上次已知的良好狀態(tài)。使用自動(dòng)化工作流來處理網(wǎng)絡(luò)故障、修復(fù)網(wǎng)絡(luò)環(huán)境,網(wǎng)絡(luò)工程師能夠更關(guān)心工作完成情況,提高業(yè)務(wù)水平。 4.4.1 備份設(shè)備配置備份設(shè)備配置對于任何一名網(wǎng)絡(luò)工程師來說都是最重要的任務(wù)之一。在這個(gè)用例中,我們將使用netmiko庫設(shè)計(jì)一個(gè)示例Python腳本。該腳本用來備份設(shè)備配置,它適用于不同的供應(yīng)商和平臺(tái)。 為方便日后訪問或引用,我們將根據(jù)設(shè)備IP地址格式化輸出文件名,例如,SW1備份操作的輸出文件保存在dev_10.10.88.111_.cfg中。 創(chuàng)建Python腳本從定義交換機(jī)開始,我們希望將其配置備份為文本文件(設(shè)備文件),用逗號(hào)分隔訪問設(shè)備的用戶名、密碼等詳細(xì)信息。這樣就可以在Python腳本中使用split()函數(shù)來獲取這些數(shù)據(jù),方便在ConnectHandler函數(shù)中使用這些數(shù)據(jù)。此外,還可以從Microsoft Excel工作表或任何數(shù)據(jù)庫中輕松導(dǎo)出該文件以及把該文件導(dǎo)入其中。 文件結(jié)構(gòu)如下。
創(chuàng)建Python腳本,使用with open子句在腳本中導(dǎo)入該文件。在導(dǎo)入的文件對象上使用readlines()方法將文件中的每一行組成列表,然后用for循環(huán)逐行遍歷文件,用split()函數(shù)獲取每一行中用逗號(hào)隔開的設(shè)備信息,并將它們賦予相應(yīng)的變量。 from netmiko import ConnectHandlerfrom datetime import datetimewithopen('/media/bassim/DATA/GoogleDrive/Packt/EnterpriseAutomationProject/Chapter5_Using_Python_to_manage_network_devices/UC1_devices.txt') asdevices_file: devices = devices_file.readlines()for line in devices: line = line.strip('\n') ipaddr = line.split(',')[0] username = line.split(',')[1] password = line.split(',')[2] enable_password = line.split(',')[3] vendor = line.split(',')[4] if vendor.lower() == 'cisco': device_type = 'cisco_ios' backup_command = 'show running-config' elif vendor.lower() == 'juniper': device_type = 'juniper' backup_command = 'show configuration | display set' 由于我們的目標(biāo)是創(chuàng)建模塊化的、支持多種設(shè)備供應(yīng)商的腳本,因此在if子句中需要檢查設(shè)備供應(yīng)商,并為該設(shè)備分配正確的device_type和backup_command。 接下來,建立與設(shè)備的SSH連接,使用netmiko模塊中的.send_command()方法執(zhí)行備份命令。
在最后的幾行中,以寫入方式打開一個(gè)文件(文件不存在時(shí)將自動(dòng)創(chuàng)建),文件名中包含了前面從設(shè)備文件中讀取的ipaddr變量。 腳本運(yùn)行結(jié)果如下。 需要注意的是,備份的配置文件存儲(chǔ)在項(xiàng)目的主目錄中,文件名稱包含每個(gè)設(shè)備的IP地址(見下圖)。 4.4.2 創(chuàng)建訪問終端 在Python或其他編程活動(dòng)中,你就是自己的設(shè)備供應(yīng)商。為了滿足自己的需求,你可以創(chuàng)建任何喜歡的代碼組合和程序。在第二個(gè)例子中我們創(chuàng)建自己的終端(terminal),通過telnetlib訪問路由器。只需要在終端寫幾個(gè)單詞,就會(huì)在網(wǎng)絡(luò)設(shè)備中執(zhí)行很多命令并返回輸出結(jié)果。輸出結(jié)果將會(huì)顯示在標(biāo)準(zhǔn)輸出或保存在文件中。 #!/usr/bin/python__author__ = 'Bassim Aly'__EMAIL__ = 'basim.alyy@gmail.com'import telnetlibconnection = telnetlib.Telnet(host='10.10.88.110')connection.read_until('Username:')connection.write('admin' + '\n')connection.read_until('Password:')connection.write('access123' + '\n')connection.read_until('>')connection.write('en' + '\n')connection.read_until('Password:')connection.write('access123' + '\n')connection.read_until('#')connection.write('terminal length 0' + '\n')connection.read_until('#')while True: command = raw_input('#:') if 'health' in command.lower(): commands = ['show ip int b', 'show ip route', 'show clock', 'show banner motd' ] elif 'discover' in command.lower(): commands = ['show arp', 'show version | i uptime', 'show inventory', ]else: commands = [command]for cmd in commands: connection.write(cmd + '\n') output = connection.read_until('#') print output print '===================' 首先,建立到路由器的Telnet連接并輸入相應(yīng)的用戶信息,一直到打開特權(quán)(enable)模式。然后,創(chuàng)建一個(gè)始終為true的無限while循環(huán),使用內(nèi)置的raw_input()函數(shù)捕捉用戶輸入的命令。腳本捕獲到用戶輸入之后,在網(wǎng)絡(luò)設(shè)備上執(zhí)行這些命令。 如果用戶輸入關(guān)鍵字health或discover,終端將自動(dòng)執(zhí)行一系列命令以反映期望的操作。這些關(guān)鍵字在排除網(wǎng)絡(luò)故障時(shí)非常有用,可以根據(jù)常用的操作自由擴(kuò)展它們。想象一下,在需要解決兩個(gè)路由器之間的開放式最短路徑優(yōu)先(Open Shortest Path First,OSPF)鄰居問題時(shí),只要打開自己的Python終端腳本(這個(gè)腳本中已經(jīng)寫好了幾個(gè)排除故障常用的命令),并將這些命令打包到諸如tshoot_ospf之類的if條件之后。一旦腳本看到這個(gè)關(guān)鍵字,它就會(huì)執(zhí)行這些命令,輸出OSPF鄰居狀態(tài)、MTU的接口、OSPF的廣播網(wǎng)絡(luò)等,簡化定位問題的過程。 通過在提示符中輸入health嘗試腳本中的第一條命令。腳本輸出結(jié)果如下。 可以看到,腳本將返回在設(shè)備上執(zhí)行多條命令后的結(jié)果。 接著試一下第二個(gè)命令discover。腳本輸出結(jié)果如下。 這次腳本返回discover命令的輸出。在后面的章節(jié)中,我們將會(huì)解析返回的輸出結(jié)果并從中提取有用的信息。 4.4.3 從Excel工作表中讀取數(shù)據(jù)網(wǎng)絡(luò)和IT工程師始終使用Excel工作表來存儲(chǔ)基礎(chǔ)設(shè)施的相關(guān)信息,如IP地址、設(shè)備供應(yīng)商和登錄憑證。Python支持從Excel工作表中讀取數(shù)據(jù)并對其進(jìn)行處理,以便我們在腳本中使用數(shù)據(jù)。 在這個(gè)用例中,我們將使用Excel Read(xlrd)模塊讀取UC3_devices.xlsx文件。該文件保存了基礎(chǔ)設(shè)施的主機(jī)名、IP地址、用戶名、普通密碼、特權(quán)模式下的密碼和供應(yīng)商名稱。然后將讀到的數(shù)據(jù)用作netmiko模塊的輸入。 Excel工作表中的內(nèi)容如下圖所示。 首先,用pip安裝xlrd模塊,因?yàn)樾枰盟鼇碜x取Microsoft Excel工作表。
xlrd模塊能夠讀取Excel工作表并將行和列轉(zhuǎn)換為矩陣。比如,row[0][0]代表第一行第一列的單元格,右邊緊接著它的單元格是row[0][1](見下圖),以此類推。 xlrd在讀取工作表時(shí),每次讀取一行,同時(shí)特殊計(jì)數(shù)器nrows(行數(shù))自動(dòng)加1。同樣,每次讀取一列,ncols(列數(shù))自動(dòng)加1,這樣我們就能夠通過這兩個(gè)參數(shù)知道矩陣的大小。 然后,在xlrd的open_workbook()函數(shù)中輸入文件路徑,并用sheet_by_index()或sheet_by_name()函數(shù)訪問工作表。在本例中,數(shù)據(jù)存儲(chǔ)在第一個(gè)工作表(index = 0)中,工作表文件存儲(chǔ)在以章為名的文件夾下。接著,遍歷工作表的每一行,或者使用row()函數(shù)來訪問指定行。返回的輸出結(jié)果是一個(gè)列表,使用索引可以訪問列表中的元素。 Python腳本如下。 __author__ = 'Bassim Aly'__EMAIL__ = 'basim.alyy@gmail.com'from netmiko import ConnectHandlerfrom netmiko.ssh_exception import AuthenticationException,NetMikoTimeoutExceptionimport xlrdfrom pprint import pprintworkbook =xlrd.open_workbook(r'/media/bassim/DATA/GoogleDrive/Packt/EnterpriseAutomationProject/Chapter4_Using_Python_to_manage_network_devices/UC3_devices.xlsx')sheet = workbook.sheet_by_index(0)for index in range(1, sheet.nrows): hostname = sheet.row(index)[0].value ipaddr = sheet.row(index)[1].value username = sheet.row(index)[2].value password = sheet.row(index)[3].value enable_password = sheet.row(index)[4].value vendor = sheet.row(index)[5].value device = { 'device_type': vendor, 'ip': ipaddr, 'username': username, 'password': password, 'secret': enable_password, } # pprint(device) print '########## Connecting to Device {0}############'.format(device['ip']) try: net_connect = ConnectHandler(**device) net_connect.enable() print '***** show ip configuration of Device *****' output = net_connect.send_command('show ip int b') print output net_connect.disconnect() except NetMikoTimeoutException: print '=======SOMETHING WRONG HAPPEN WITH{0}======='.format(device['ip']) except AuthenticationException: print '=======Authentication Failed with{0}======='.format(device['ip'])except Exception as unknown_error: print '=======SOMETHING UNKNOWN HAPPEN WITH {0}=======' 使用netmiko可以實(shí)現(xiàn)很多網(wǎng)絡(luò)自動(dòng)化用例。例如,在升級(jí)期間從遠(yuǎn)程設(shè)備上傳/下載文件,利用Jinja2模板加載配置,訪問終端服務(wù)器,訪問終端設(shè)備等。要了解更多用例,請參見GitHub官網(wǎng)(見下圖)。 在本章中,我們開始使用Python進(jìn)入網(wǎng)絡(luò)自動(dòng)化世界。本章討論了Python中的一些工具,通過Telnet和SSH建立到遠(yuǎn)程節(jié)點(diǎn)的連接,并在遠(yuǎn)程設(shè)備上執(zhí)行命令。此外,本章還講述了如何在netaddr模塊的幫助下處理IP地址和網(wǎng)絡(luò)子網(wǎng)。最后通過兩個(gè)實(shí)際用例鞏固了這些知識(shí)。 本文摘自:《Python自動(dòng)化運(yùn)維實(shí)戰(zhàn)》
《Python自動(dòng)化運(yùn)維實(shí)戰(zhàn)》介紹了如何通過Python來自動(dòng)完成服務(wù)器的配置與管理,自動(dòng)完成系統(tǒng)的管理任務(wù)(如用戶管理、數(shù)據(jù)庫管理和進(jìn)程管理),以及完成這些工作所需的模塊、庫和工具。此外,本書還講述了如何使用Python腳本自動(dòng)執(zhí)行測試,如何通過Python在云基礎(chǔ)設(shè)施和虛擬機(jī)上自動(dòng)執(zhí)行任務(wù),如何使用基于Python的安全工具自動(dòng)完成與安全相關(guān)的任務(wù)。 本書適合運(yùn)維人員和開發(fā)人員閱讀,也可作為相關(guān)專業(yè)人士的參考書。 |
|