/*auto readmore*/ /*auto readmore*/ /* an hien script*/ // an hien password /*an hien ma chuong trinh cong tru */ /*Scrollbox thanh cuon*/ /***Nhung CODE***/ /* dòng xanh dòng trắng */ /* https://cdnjs.com/libraries/prism lay thu vien, can vao ten file ma goi 1. copy link vao vi du:prism-python.min.js 2. ten ngon nua la python */ /*=== New posts ===*/ /*header slider*/ /*=== bai viet lien quan===*/ /*===tabcode===*/

Network Automation #004 - Netmiko How To Build Network Maps/Discover Network Topology Diagram Based on CDP/LLDP

Nên xem các bài dưới đây trước khi xem bài này:


Sơ đồ lab:


Dùng thư viện netmiko và các câu lệnh show cdp để thực hiện, thông tin thiết bị như file device_listCDP.csv dưới:



Yêu cầu:
1. Ghi lại thông tin đấu nối các cổng của các thiết bị trong sơ đồ lab.
2. Cấu hình cdp run trên Sw_13 (dùng netmiko để cấu hình), thực hiện show cdp để lấy thông tin đấu nối và ghi tiếp vào kết quả của yêu cầu 1


Chuẩn bị:

Thực hiện:

1. Ghi lại thông tin đấu nối các cổng của các thiết bị trong sơ đồ lab.

  • Code
Hàm xử lý show cdp (1):
from netmiko import ConnectHandler 
import re
import os

file_cdp = "show_cdp_neighbors.txt"
file_cdp_not = "show_cdp_NOT_enable.csv"
path = os.getcwd()	# lấy đường dẫn hiện tại

cdp_device = {} 
def show_cdp(txt):
	cmd = "show cdp neighbors"
	cmd2 = "show cdp entry"
	filename = txt
	
	print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	
	net_connect = ConnectHandler(**cdp_device)

	output = net_connect.send_command(cmd)
	
	if "CDP is not enabled" in  output:							# nếu cdp không được enable
		with open (file_cdp_not,"a") as afile:					# mở file ghi log và sẽ xử lý sau
			afile.write(values[1] + "," + values[2] + "," + values[3] + "," + values[4] + "," + output + "\n") 		# nội dung là IP, dấu 2 chấm, lỗi trả về, xuống hàng
	else:		
		
		with open (file_cdp, "a") as afile:
			afile.write("\n\n" + "*" * 40 + values[1] + "*" * 40 +"\n")
			afile.write(output)
		
		'''
		output của lệnh: "show cdp neighbors" trả về có dạng:
		---------------------------------------------------------------------------
		Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge
                  S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone, 
                  D - Remote, C - CVTA, M - Two-port Mac Relay 

		Device ID        Local Intrfce     Holdtme    Capability  Platform  Port ID
		Sw_12.netmiko.lab
		                 Eth 0/2           137             R S I  Linux Uni Eth 0/0
		Sw_11.netmiko.lab
		                 Eth 0/1           135             R S I  Linux Uni Eth 0/0

		Total cdp entries displayed : 2
		---------------------------------------------------------------------------
		bỏ 5 dòng đầu tiên là header, 
		lấy từ dòng số 6 đến cuối kết quả và bỏ 2 dòng cuối cùng
		mỗi dòng chuyển thành list
		'''
		lines = output.splitlines()[5:-2]
		
		''' 
		xử lý và trích lọc trong lệnh show cdp neighbors, show cdp entry *
		- 
		-
		'''
		hostname = None
		for line in lines:
			fields = line.split()					# chuyển mỗi dòng sang list
			if len(fields) == 1:					# đối với những hostname dài kết quả của neighbors sẽ trả về 2 dòng cho mỗi neighbors
				hostname = fields[0]

			elif hostname == None:					# kết quả của neighbors sẽ trả về là 1 dòng thì thực hiện trong elif này
				hostname = fields[0]				# lấy ra hostname của láng giềng
				localint = "".join(fields[1:3])		# lấy ra local interface (lấy trường số 1 đến số 2)
				remoteint = "".join(fields[-2:])	# lấy ra remote interface


				outputentry = net_connect.send_command(cmd2 + " " + hostname) 
				regex = r'\d{1,3}(?:\.\d{1,3}){3}'  	# định nghĩa regular expression của IPv4 có dạng
				ips = re.findall(regex, outputentry)    # trích lọc lấy IPv4 ra, IP trả về là dạng list
				ips = "".join(list(set(ips)))			# remove duplicate IP và convert to string
				
				with open ("show_cdp_neighbors.txt", "a") as afile:
					
					afile.write("{}{}".format("\n\n","-" * 80))
					afile.write("\nThe information of the neighbors:\n")
					afile.write("\nNeighbors hostname is: " + hostname)
					afile.write("\nIP address: " + ips)
					afile.write("\n\nLocal interface: " + localint + " of " + values[1] + " connect to interface: " + remoteint + " of IP(s) " + ips)
				
			else:
				outputentry = net_connect.send_command(cmd2 + " " + hostname)
				regex = r'\d{1,3}(?:\.\d{1,3}){3}'			# định nghĩa regular expression của IPv4 có dạng
				ips = re.findall(regex, outputentry)		# trích lọc lấy IPv4 ra, IP trả về là dạng list
				ips = "".join(list(set(ips)))				# remove duplicate IP và convert to string	
				localint = "".join(fields[:2])				# lấy 2 trường đầu tiên
				remoteint = "".join(fields[-2:])			# lấy 2 trường cuối cùng

				with open ("show_cdp_neighbors.txt", "a") as afile:
					afile.write("{}{}".format("\n\n","-" * 80))
					afile.write("\nThe information of the neighbors:\n")
					afile.write("\nNeighbors hostname is: " + hostname)

					afile.write("\n\nLocal interface: " + localint + " of " + values[1] + " connect to interface: " + remoteint + " of IP(s) " + ips)	




Mở file và gọi hàm xử lý (2)
with open ("device_listCDP.csv","r") as rfile: # mở file

	keys = rfile.readline().split(",")
	values = rfile.read() 

#print(keys)
#print(values)

for values in values.splitlines(): 
	values = values.split(",") 
	for i in range(1,len(keys)-1,1): 
		cdp_device[keys[i]] = values[i]  
	
	#print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	
	show_cdp(values[1])
print("Thong tin neighbors da luu vao file: '{}' tai duong dan '{}'".format(file_cdp,path))

Nối 2 đoạn code trên thành code chạy (1) + (2) = (3):
from netmiko import ConnectHandler 
import re
import os

file_cdp = "show_cdp_neighbors.txt"
file_cdp_not = "show_cdp_NOT_enable.csv"
path = os.getcwd()	# lấy đường dẫn hiện tại

cdp_device = {} 
def show_cdp(txt):
	cmd = "show cdp neighbors"
	cmd2 = "show cdp entry"
	filename = txt
	
	print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	
	net_connect = ConnectHandler(**cdp_device)

	output = net_connect.send_command(cmd)
	
	if "CDP is not enabled" in  output:							# nếu cdp không được enable
		with open (file_cdp_not,"a") as afile:					# mở file ghi log và sẽ xử lý sau
			afile.write(values[1] + "," + values[2] + "," + values[3] + "," + values[4] + "," + output + "\n") 		# nội dung là IP, dấu 2 chấm, lỗi trả về, xuống hàng
	else:		
		
		with open (file_cdp, "a") as afile:
			afile.write("\n\n" + "*" * 40 + values[1] + "*" * 40 +"\n")
			afile.write(output)
		
		'''
		output của lệnh: "show cdp neighbors" trả về có dạng:
		---------------------------------------------------------------------------
		Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge
                  S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone, 
                  D - Remote, C - CVTA, M - Two-port Mac Relay 

		Device ID        Local Intrfce     Holdtme    Capability  Platform  Port ID
		Sw_12.netmiko.lab
		                 Eth 0/2           137             R S I  Linux Uni Eth 0/0
		Sw_11.netmiko.lab
		                 Eth 0/1           135             R S I  Linux Uni Eth 0/0

		Total cdp entries displayed : 2
		---------------------------------------------------------------------------
		bỏ 5 dòng đầu tiên là header, 
		lấy từ dòng số 6 đến cuối kết quả và bỏ 2 dòng cuối cùng
		mỗi dòng chuyển thành list
		'''
		lines = output.splitlines()[5:-2]
		
		''' 
		xử lý và trích lọc trong lệnh show cdp neighbors, show cdp entry *
		- 
		-
		'''
		hostname = None
		for line in lines:
			fields = line.split()					# chuyển mỗi dòng sang list
			if len(fields) == 1:					# đối với những hostname dài kết quả của neighbors sẽ trả về 2 dòng cho mỗi neighbors
				hostname = fields[0]

			elif hostname == None:					# kết quả của neighbors sẽ trả về là 1 dòng thì thực hiện trong elif này
				hostname = fields[0]				# lấy ra hostname của láng giềng
				localint = "".join(fields[1:3])		# lấy ra local interface (lấy trường số 1 đến số 2)
				remoteint = "".join(fields[-2:])	# lấy ra remote interface


				outputentry = net_connect.send_command(cmd2 + " " + hostname) 
				regex = r'\d{1,3}(?:\.\d{1,3}){3}'  	# định nghĩa regular expression của IPv4 có dạng
				ips = re.findall(regex, outputentry)    # trích lọc lấy IPv4 ra, IP trả về là dạng list
				ips = "".join(list(set(ips)))			# remove duplicate IP và convert to string
				
				with open ("show_cdp_neighbors.txt", "a") as afile:
					
					afile.write("{}{}".format("\n\n","-" * 80))
					afile.write("\nThe information of the neighbors:\n")
					afile.write("\nNeighbors hostname is: " + hostname)
					afile.write("\nIP address: " + ips)
					afile.write("\n\nLocal interface: " + localint + " of " + values[1] + " connect to interface: " + remoteint + " of IP(s) " + ips)
				
			else:
				outputentry = net_connect.send_command(cmd2 + " " + hostname)
				regex = r'\d{1,3}(?:\.\d{1,3}){3}'			# định nghĩa regular expression của IPv4 có dạng
				ips = re.findall(regex, outputentry)		# trích lọc lấy IPv4 ra, IP trả về là dạng list
				ips = "".join(list(set(ips)))				# remove duplicate IP và convert to string	
				localint = "".join(fields[:2])				# lấy 2 trường đầu tiên
				remoteint = "".join(fields[-2:])			# lấy 2 trường cuối cùng

				with open ("show_cdp_neighbors.txt", "a") as afile:
					afile.write("{}{}".format("\n\n","-" * 80))
					afile.write("\nThe information of the neighbors:\n")
					afile.write("\nNeighbors hostname is: " + hostname)

					afile.write("\n\nLocal interface: " + localint + " of " + values[1] + " connect to interface: " + remoteint + " of IP(s) " + ips)					


with open ("device_listCDP.csv","r") as rfile: # mở file

	keys = rfile.readline().split(",")
	values = rfile.read() 

#print(keys)
#print(values)

for values in values.splitlines(): 
	values = values.split(",") 
	for i in range(1,len(keys)-1,1): 
		cdp_device[keys[i]] = values[i]  
	
	#print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	
	show_cdp(values[1])
print("Thong tin neighbors da luu vao file: '{}' tai duong dan '{}'".format(file_cdp,path))



  • Kết quả:
C:\python>python Demo.py
Dang ket noi vao IP:'192.168.0.1' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.11' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.12' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.13' voi Username: 'admin'
Thong tin neighbors da luu vao file: 'show_cdp_neighbors.txt' tai duong dan 'C:\python'

C:\python>
Nội dung file 


Chúng ta thấy rằng thông tin neighbor của Sw_13 chưa được thể hiện trong file, vì thiết bị này cdp không được cài đặt. Thông tin các thiết bị đã cấu hình tắt cdp được lưu ở file show_cdp_NOT_enable.csv (file này sinh ra trong khi thực thi chương trình)

2. Cấu hình cdp run trên Sw_13 (dùng netmiko để cấu hình), thực hiện show cdp để lấy thông tin đấu nối và ghi tiếp vào kết quả của yêu cầu 1

  • Code
Định nghĩa hàm show_cdp_not_running (4):
from netmiko import ConnectHandler
import time
file_cdp_not = "show_cdp_NOT_enable.csv"
conf_t = "conf t"
cdp_run = "cdp run"
keys = "no., host, username, password, device_type, remark" # header cho file show_cdp_NOT_enable.csv
txt = file_cdp_not

cdp_device = {} 
def show_cdp_not_running(txt):

	cmd_run = "cdp run"
	net_connect = ConnectHandler(**cdp_device)
	#output = net_connect.send_command(cmd)
	output = net_connect.send_command_timing(conf_t) 			# vào mode config t
	output += net_connect.send_command_timing(cdp_run)			# cấu hình cdp run
	
	'''
	đợi 65s sau đó gọi hàm show_cdp(txt). 
	Mặc định cứ 60s/lần cdp sẽ gửi thông tin cdp cho láng giềng, để chắc ăn chúng ta thêm vài giây
	'''
	time.sleep(65)												
	show_cdp(txt)                                               # gọi hàm show_cdp như bình thường, vì đã cấu hình cdp run
	
	output += net_connect.send_command_timing("no " + cdp_run)  # trả lại cấu hình ban đầu

Mở file và gọi hàm xử lý (5)
try: 
	with open (file_cdp_not,"r") as rfile: 
		keys = key_csv.split(", ") #
		values = rfile.read()
		for values in values.splitlines(): 
			values = values.split(",") 
			for i in range(1,len(keys)-1,1): 
				cdp_device[keys[i]] = values[i]  
			
			show_cdp_not_running(file_cdp_not) # truyền chuỗi vào nhằm mục đích ghi chú
except NameError: 
	
	print("File'{}' khong ton tai!".format(file_cdp_not))
	pass

Vì file "show_cdp_NOT_enable.csv" có thể tồn tại hoặc không, chúng ta thực bắt lỗi để khi nếu có lỗi về việc này chương trình vẫn tiếp tục.

  • Code chính gộp các đoạn (3) + (4) + (5) = (6)
from netmiko import ConnectHandler 
import re
import os
import time

file_cdp = "show_cdp_neighbors.txt"
file_cdp_not = "show_cdp_NOT_enable.csv"
path = os.getcwd()	# lấy đường dẫn hiện tại

conf_t = "conf t"
cdp_run = "cdp run"
key_csv = "no., host, username, password, device_type, remark" # header cho file show_cdp_NOT_enable.csv
txt = file_cdp_not

cdp_device = {} 
def show_cdp(txt):
	cmd = "show cdp neighbors"
	cmd2 = "show cdp entry"
	
	if txt == file_cdp_not:
		print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}' '{txt}'")	# sau khi enable cdp sẽ thông báo dòng này
	else:	
		print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	
	
	net_connect = ConnectHandler(**cdp_device)

	output = net_connect.send_command(cmd)
	i = 0 # định nghĩa biến đếm chỉ dùng trong trường hợp CDP not enable
	
	if "CDP is not enabled" in  output:							# nếu cdp không được enable
		i += 1
		with open (file_cdp_not,"a") as afile:					# mở file ghi log và sẽ xử lý sau
			afile.write(str(i) + "," + values[1] + "," + values[2] + "," + values[3] + "," + values[4] + "," + output + "\n") 		# ghi thông tin ip, username, password.... vào file
	else:		
		with open (file_cdp, "a") as afile:
			if txt == file_cdp_not:
				afile.write("\n\n" + "=" * 40 + txt + "=" * 40) # chèn thêm dòng này file log nếu nếu cdp không được enable
			afile.write("\n\n" + "*" * 40 + values[1] + "*" * 40 +"\n")
			afile.write(output)
		
		'''
		output của lệnh: "show cdp neighbors" trả về có dạng:
		---------------------------------------------------------------------------
		Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge
                  S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone, 
                  D - Remote, C - CVTA, M - Two-port Mac Relay 

		Device ID        Local Intrfce     Holdtme    Capability  Platform  Port ID
		Sw_12.netmiko.lab
		                 Eth 0/2           137             R S I  Linux Uni Eth 0/0
		Sw_11.netmiko.lab
		                 Eth 0/1           135             R S I  Linux Uni Eth 0/0

		Total cdp entries displayed : 2
		---------------------------------------------------------------------------
		bỏ 5 dòng đầu tiên là header, 
		lấy từ dòng số 6 đến cuối kết quả và bỏ 2 dòng cuối cùng
		mỗi dòng chuyển thành list
		'''
		lines = output.splitlines()[5:-2]
		
		''' 
		xử lý và trích lọc trong lệnh show cdp neighbors, show cdp entry *
		- 
		-
		'''
		hostname = None
		for line in lines:
			fields = line.split()					# chuyển mỗi dòng sang list
			if len(fields) == 1:					# đối với những hostname dài kết quả của neighbors sẽ trả về 2 dòng cho mỗi neighbors
				hostname = fields[0]

			elif hostname == None:					# kết quả của neighbors sẽ trả về là 1 dòng thì thực hiện trong elif này
				hostname = fields[0]				# lấy ra hostname của láng giềng
				localint = "".join(fields[1:3])		# lấy ra local interface (lấy trường số 1 đến số 2)
				remoteint = "".join(fields[-2:])	# lấy ra remote interface


				outputentry = net_connect.send_command(cmd2 + " " + hostname) 
				regex = r'\d{1,3}(?:\.\d{1,3}){3}'  	# định nghĩa regular expression của IPv4 có dạng
				ips = re.findall(regex, outputentry)    # trích lọc lấy IPv4 ra, IP trả về là dạng list
				ips = "".join(list(set(ips)))			# remove duplicate IP và convert to string
				
				with open ("show_cdp_neighbors.txt", "a") as afile:
					
					afile.write("{}{}".format("\n\n","-" * 80))
					afile.write("\nThe information of the neighbors:\n")
					afile.write("\nNeighbors hostname is: " + hostname)
					afile.write("\nIP address: " + ips)
					afile.write("\n\nLocal interface: " + localint + " of " + values[1] + " connect to interface: " + remoteint + " of IP(s) " + ips)
				
			else:
				outputentry = net_connect.send_command(cmd2 + " " + hostname)
				regex = r'\d{1,3}(?:\.\d{1,3}){3}'			# định nghĩa regular expression của IPv4 có dạng
				ips = re.findall(regex, outputentry)		# trích lọc lấy IPv4 ra, IP trả về là dạng list
				ips = "".join(list(set(ips)))				# remove duplicate IP và convert to string	
				localint = "".join(fields[:2])				# lấy 2 trường đầu tiên
				remoteint = "".join(fields[-2:])			# lấy 2 trường cuối cùng

				with open ("show_cdp_neighbors.txt", "a") as afile:
					afile.write("{}{}".format("\n\n","-" * 80))
					afile.write("\nThe information of the neighbors:\n")
					afile.write("\nNeighbors hostname is: " + hostname)

					afile.write("\n\nLocal interface: " + localint + " of " + values[1] + " connect to interface: " + remoteint + " of IP(s) " + ips)					

def show_cdp_not_running(txt):

	cmd_run = "cdp run"
	net_connect = ConnectHandler(**cdp_device)
	#output = net_connect.send_command(cmd)
	output = net_connect.send_command_timing(conf_t) 			# vào mode config t
	output += net_connect.send_command_timing(cdp_run)			# cấu hình cdp run
	
	'''
	đợi 65s sau đó gọi hàm show_cdp(txt). 
	Mặc định cứ 60s/lần cdp sẽ gửi thông tin cdp cho láng giềng, để chắc ăn chúng ta thêm vài giây
	'''
	time.sleep(65)												
	show_cdp(txt)                                               # gọi hàm show_cdp như bình thường, vì đã cấu hình cdp run
	
	output += net_connect.send_command_timing("no " + cdp_run)  # trả lại cấu hình ban đầu




with open ("device_listCDP.csv","r") as rfile: # mở file

	keys = rfile.readline().split(",")
	values = rfile.read() 

#print(keys)
#print(values)

for values in values.splitlines(): 
	values = values.split(",") 
	for i in range(1,len(keys)-1,1): 
		cdp_device[keys[i]] = values[i]  
	
	#print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	
	show_cdp(values[1]) # trong trường hợp này biến values[1] truyền vào nhưng không dùng đến

'''
dùng trong trường hợp cdp run đã được tắt
danh sách này có được khi ta thực hiện lệnh show cdp không thành lưu nó lại
bây giờ mở ra để xử lý
'''
try: 
	with open (file_cdp_not,"r") as rfile: 
		keys = key_csv.split(", ") #
		values = rfile.read()
		for values in values.splitlines(): 
			values = values.split(",") 
			for i in range(1,len(keys)-1,1): 
				cdp_device[keys[i]] = values[i]  
			
			show_cdp_not_running(file_cdp_not) # truyền chuỗi vào nhằm mục đích ghi chú
except NameError: 
	
	print("File'{}' khong ton tai!".format(file_cdp_not))
	pass

print("Thong tin neighbors da luu vao file: '{}' tai duong dan '{}'".format(file_cdp,path))


P/s: trong phần code của hàm show_cdp có chèn thêm các dòng 20 -> 22 và 36,37 như hình dưới:


  • Chạy code
C:\python>python Demo.py
Dang ket noi vao IP:'192.168.0.1' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.11' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.12' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.13' voi Username: 'admin'
Dang ket noi vao IP:'192.168.0.13' voi Username: 'admin' 'show_cdp_NOT_enable.csv'
Thong tin neighbors da luu vao file: 'show_cdp_neighbors.txt' tai duong dan 'C:\python'

    Chúng ta thấy ip 192.168.0.13 được kết nối vào 2 lần:
    - Lần 1: kiểm tra show cdp không thành công => đưa ip này vào danh sách thiết bị cdp không được cấu hình/hay tắt
    - Lần 2: kết nối vào cấu hinh cdp run rồi thực hiện show cdp như bình thường, xong trả lại cấu hình ban đầu cho thiết bị

    • Kết quả

    Đối với các thiết bị không cấu hình cdp run nó sẽ thêm vào log dòng show_cdp_NOT_enable như hình.


    Xong!


    No comments:

    Post a Comment

    /*header slide*/