/*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===*/
Showing posts with label networkautomation. Show all posts
Showing posts with label networkautomation. Show all posts

Network Automation #013 - Create/Unzip/Extract A ZIP Archive File In Python - Tạo/Bung/Giải File ZIP Trong Python

 YÊU CẦU

1. Viết hàm nén/tạo file ZIP:

a. Một loại định dạng file ở thư mục hiện tại.
b. Tất cả các file, đường dẫn tự truyền vào
c. Một loại định dạng file nhất định, đường dẫn và loại file được truyền vào
d. Thêm file vào file ZIP đã tồn tại

         

2. Viết hàm giải nén/extract file ZIP


THỰC HIỆN:

1. Viết hàm nén/tạo file ZIP:

a. Một loại định dạng file ở thư mục hiện tại.
'''
Tạo file nén ở thư mục hiện tại, file tự truyền vào.
Ví dụ chỉ nén các file *.py:
to_zip("abc",".py")
hoặc to_zip("abc1","csv")
'''
import os
from zipfile import ZipFile
from datetime import datetime
import zipfile

def to_zip(zip_file, type_file): # Hàm tạo file zip
	path = os.getcwd()  # lấy đường dẫn hiện tại	
	zip_file = zip_file + ".zip"
	if not os.path.isfile(zip_file):
   		zf = ZipFile(zip_file, "w")
	else: # Nếu file đã tồn tại thì không ghi header
   		zf = ZipFile(zip_file, "a")
	for file in os.listdir(os.curdir): # tương đương lệnh dir trong cmd của windows, liệt kê file, folder trong thư mục hiện tại
	    if file.endswith(type_file) and os.path.isfile(os.curdir + '/' + file): # đảm bảo đúng là file, và file có định dạng được đưa vào từ type_file
	       	#print(file) # Liệt kê các file cần nén
	       	zf.write(file)

	zf.close()
	print (f"***Please check files '{zip_file}' at '{path}' ***\n")		

# Gọi hàm zip
to_zip("abc",".py")
to_zip("abc1","csv")

 

b. Tất cả các file, đường dẫn tự truyền vào
'''
Nén tất cả các file ở thư mục
ví dụ nén tất cả các file tại đường dẫn "C:\Intel" thành file có tên abc123.zip:
to_zip_dir("abc123.zip", r"C:\Intel")
'''
from zipfile import ZipFile
import os
from os.path import basename
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn

def to_zip_dir(zip_file, dir_name): # Hàm nén tất cả các file trong thư mục
    path = os.getcwd()  # lấy đường dẫn hiện tại    path = os.getcwd()  # lấy đường dẫn hiện tại    
    with ZipFile(zip_file, 'w') as zipObj:
       for folder_Name, sub_folders, file_names in os.walk(dir_name): # lấy thông tin của file, folder tại đường dẫn dir_name
           #pprint(list(os.walk(dir_name)) )
           for file_name in file_names:
               filePath = os.path.join(folder_Name, file_name) # đường dẫn đầy đủ đến file cần backup
               zipObj.write(filePath, basename(filePath)) # thực hiện nén file
    print (f"***Please check files '{zip_file}' at '{path}' ***\n")            

#gọi hàm nén file
to_zip_dir("abc123.zip", r"C:\Intel")

 

c. Một loại định dạng file nhất định, đường dẫn và loại file được truyền vào 
'''
Ví dụ:
Thực hiện nén các file *.py tại đường dẫn "C:\Intel" thành file có tên abcde.zip:
to_zip_filter("abcde.zip",r"C:\Intel","py")

Thực hiện nén các file *.* tại đường dẫn "C:\Intel" thành file có tên abcdef.zip:
to_zip_filter("abcdef.zip",r"C:\Intel","")
'''
from zipfile import ZipFile
import os
from os.path import basename
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn

def to_zip_filter(zip_file, dir_name, type_file): # Hàm nén (filter) file trong thư mục
    path = os.getcwd()  # lấy đường dẫn hiện tại    path = os.getcwd()  # lấy đường dẫn hiện tại    
    with ZipFile(zip_file, 'w') as zipObj:
       for folder_Name, sub_folders, file_names in os.walk(dir_name): # lấy thông tin của file, folder tại đường dẫn dir_name
           #pprint(list(os.walk(dir_name)) )
           for file_name in file_names:
               if file_name.endswith(type_file): # tên file tận cùng là ...
                 filePath = os.path.join(folder_Name, file_name) # đường dẫn đầy đủ đến file cần backup
                 zipObj.write(filePath, basename(filePath)) # thực hiện nén file
    print (f"***Please check files '{zip_file}' at '{path}' ***\n")            
         
to_zip_filter("abcde.zip",r"C:\Intel","py") # tất cả các file *.py
to_zip_filter("abcdef.zip",r"C:\Intel","") # tất cả các file


d. Thêm file vào file ZIP đã tồn tại


def add_tozip (path, file_name):
	with zipfile.ZipFile(rf"{path}\File_ZIP_DangTonTai.zip", 'a') as zipf: # Mở file zip tại đường dẫn, nếu file chưa có tạo mới file
    # Thêm file source_path vào destination
    # Nếu file đã có sẽ ghi đè
    

	    source_path = rf"{path}\{file_name}" 
	    destination = rf"{file_name}"
	    zipf.write(source_path, destination) # thực hiện việc ghi file, nếu có ghi đè (nhưng chương trình sẽ thông báo)

2. Viết hàm giải nén/extract file ZIP

'''
Giải nén file zip
Ví dụ:
- zip_extract(r"C:\Intel\now.zip", "abc.csv", r"C:\Intel") # tìm file abc.csv trong file "C:\Intel\now.zip" và extract đến đường dẫn "C:\Intel"
- zip_extract(r"C:\Intel\now.zip", "", r"C:\Intel") # Giải nén tất cả các file trong file "C:\Intel\now.zip" và extract đến đường dẫn "C:\Intel"

'''
import os
from zipfile import ZipFile
from datetime import datetime
import zipfile

def zip_extract(zip_file, type_file, to_dir): #Hàm giải nén file zip
	#zip_file = zip_file + ".zip"
	with ZipFile(zip_file, 'r') as zip:
		if type_file == "all" or type_file == "*" or type_file == "":
		    print('Extracting all the files ...')
		    zip.printdir()# in thông tin các file có trong file zip
		    zip.extractall(to_dir) # extract tất cả các file
		else: 
			zip.extract(type_file, to_dir) # extract 1 file với tên file mới truyền vào
	
	print (f"***Please check files '{type_file}' at '{to_dir}' ***\n")		

# cách gọi hàm    	
zip_extract(r"C:\Intel\now.zip", "abc.csv", r"C:\Intel") # tìm file abc.csv trong file "C:\Intel\now.zip" và extract đến đường dẫn "C:\Intel"
zip_extract(r"C:\Intel\now.zip", "", r"C:\Intel") # Giải nén tất cả các file trong file "C:\Intel\now.zip" và extract đến đường dẫn "C:\Intel"


Xong!

Network Automation #012 - SMTP Sending Emails With Attachment in Python - Gửi Mail Đính Kèm File Bằng Python

YÊU CẦU:

1. Sử dụng thư viện email smtplib của python để kết nối đến gmail để gửi mail đính kèm attach file

2. Gửi mail hàng loạt, đính kèm attach file với thông tin được lưu trữ trong file email_list.csv

3. Sử dụng profile hiện của MS Outlook để gửi mail.


THỰC HIỆN

1. Sử dụng thư viện email smtplib của python để kết nối đến gmail để gửi mail đính kèm attach file

Code:

'''
Kết nối đến Gmail để gửi mail và đính kèm attach file

Điều kiện:
1. Tắt bảo mật 2 lớp
https://myaccount.google.com/security?utm_source=OGB&utm_medium=act#signin

2. Allow less secure apps: ON
https://myaccount.google.com/u/1/lesssecureapps?pli=1&pageId=none

nếu không chúng ta sẽ gặp lỗi
#smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8  https://support.google.com/mail/?p=BadCredentials qe12sm2115875pjb.29 - gsmtp')

Link tham khảo
https://realpython.com/python-send-email/
'''
import email, smtplib, ssl
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def send_mail_att(mail_from, mail_password, mail_to, mail_subject, mail_body, att_file): # Hàm gửi mail
	port = 465  # For SSL
	smtp_server = "smtp.gmail.com"
	# Create a multipart message and set headers
	message = MIMEMultipart()
	message["From"] = mail_from
	message["To"] = mail_to
	message["Subject"] = mail_subject
	#message["Bcc"] = "khanhvc2003@yahoo.com"

	# Add body to email
	message.attach(MIMEText(mail_body, "plain"))

	# Open file in binary mode
	with open(att_file, "rb") as attachment:
	    # Add file as application/octet-stream
	    # Email client can usually download this automatically as attachment
	    part = MIMEBase("application", "octet-stream")
	    part.set_payload(attachment.read())

	# Encode file in ASCII characters to send by email    
	encoders.encode_base64(part)

	# Add header as key/value pair to attachment part
	part.add_header("Content-Disposition", f"attachment; filename = {att_file}")

	# Add attachment to message and convert message to string
	message.attach(part)
	text = message.as_string()

	# Log in to server using secure context and send email
	context = ssl.create_default_context()
	try:
		with smtplib.SMTP_SSL(smtp_server, port, context = context) as server:
		    server.login(mail_from, mail_password)
		    server.sendmail(mail_from, mail_to, text)
		    print (f"Successfuly sent to '{mail_to}'")
	except:
		print (f"Communication failure in '{smtp_server}'")

email_info = {
	"mail_from": "khanhvc.wrk@gmail.com",
	"mail_password": "matkhaucuaban" ,
	"mail_to": "khanhvc@hansollvina.com",
	"mail_subject" : "This is for testing 8.19 r duong dan BO PHAY" ,
	"mail_body": "This is for testing email",
	"att_file": r"C:\python\Blog\TextFSM Custom.JPG"
	#pass_mail = input("Type your password and press enter:")
}
send_mail_att(**email_info)


2. Gửi mail hàng loạt, đính kèm attach file với thông tin được lưu trữ trong file email_list.csv

Tạo file email_list.csv có dạng:



Code:
'''
Kết nối đến Gmail để gửi mail và đính kèm attach file, danh sách các địa chỉ email được lưu trong file

Điều kiện:
1. Tắt bảo mật 2 lớp
https://myaccount.google.com/security?utm_source=OGB&utm_medium=act#signin

2. Allow less secure apps: ON
https://myaccount.google.com/u/1/lesssecureapps?pli=1&pageId=none

nếu không chúng ta sẽ gặp lỗi
#smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8  https://support.google.com/mail/?p=BadCredentials qe12sm2115875pjb.29 - gsmtp')

Link tham khảo
https://realpython.com/python-send-email/
'''
import email, smtplib, ssl
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

import pandas as pd
from datetime import datetime
import os

path = os.getcwd()  # lấy đường dẫn hiện tại
now = datetime.now().strftime("%Y-%b-%d_%H%M%S")

ERR_log = f"Send_Mail_{now}_ERR_logs.log" # định nghĩa tên file lưu trữ thông tin lỗi

def send_mail_att(mail_from, mail_password, mail_to, mail_subject, mail_body, att_file): # Hàm gửi mail
	port = 465  # For SSL
	smtp_server = "smtp.gmail.com"
	# Create a multipart message and set headers
	message = MIMEMultipart()
	message["From"] = mail_from
	message["To"] = mail_to
	message["Subject"] = mail_subject
	#message["Bcc"] = "khanhvc2003@yahoo.com"

	# Add body to email
	message.attach(MIMEText(mail_body, "plain"))

	# Open file in binary mode
	with open(att_file, "rb") as attachment:
	    # Add file as application/octet-stream
	    # Email client can usually download this automatically as attachment
	    part = MIMEBase("application", "octet-stream")
	    part.set_payload(attachment.read())

	# Encode file in ASCII characters to send by email    
	encoders.encode_base64(part)

	# Add header as key/value pair to attachment part
	part.add_header("Content-Disposition", f"attachment; filename = {att_file}")

	# Add attachment to message and convert message to string
	message.attach(part)
	text = message.as_string()

	# Log in to server using secure context and send email
	context = ssl.create_default_context()
	try:
		with smtplib.SMTP_SSL(smtp_server, port, context = context) as server:
		    server.login(mail_from, mail_password)
		    server.sendmail(mail_from, mail_to, text)
		    print (f"Successfuly sent to '{mail_to}'")
	except:
		f = open(ERR_log,"a")
		f.write(f'Undelivered email to: {mail_to}')
		f.write("\n")
		f.close()
		print (f"Communication failure in '{smtp_server}'")
		pass

att_file = r"C:\python\Blog\TextFSM Custom.JPG" # tên file cần đính kèm

email_list = 'email_list.csv' # tên file lưu trữ thông tin thiết bị
column_name = ['mail_from', 'mail_subject', 'mail_to', 'mail_body', 'mail_password'] # chỉ định các cột cần lấy
try:
	email_list = pd.read_csv(email_list, usecols = column_name, encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8
	email_list = email_list.to_dict(orient='records') # chuyển đổi về dict tương ứng (ví dụ: nếu file có 10 dòng thì sẽ tạo ra 9 (10 dòng bỏ đi dòng đầu tiên đã làm key) dictionary tương ứng)
	#pprint(email_list)

	for email_info in email_list:
		email_info["att_file"] = att_file # thêm thông tin att_file vào dict
		send_mail_att(**email_info)
	ERR_info = f"*** ERROR: Please check file : '{ERR_log}' at '{path}' ***\n"
	print (ERR_info)
except:
	ERR_info = f"*** ERROR: Please check file : '{email_list}' at '{path}' ***\n"
	print (ERR_info)
	pass


3. Sử dụng profile hiện của MS Outlook để gửi mail.
import win32com.client
def outlook_send_mail(mail_to, mail_subject, mail_body, att_file):
	"""
 	gọi outlook hiện tại để send mail
	"""
	outlook = win32com.client.Dispatch('outlook.application')
	mail = outlook.CreateItem(0)
	mail.To = rf"{mail_to}"
	mail.Subject = rf"{mail_subject}"
	mail.HTMLBody = '

This is HTML Body

' mail.Body = rf"{mail_body}" mail.Attachments.Add(rf"{att_file}") # mail.Attachments.Add('them file nua.abc') # mail.CC = 'somebody@company.com' mail.Send()


Tham khảo bài gửi mail KHÔNG attach file tại đây.


Xong!

Network Automation #011 - SMTP Sending Emails With Python - Gửi Mail Bằng Python

 YÊU CẦU:

1. Sử dụng thư viện smtplib của python để kết nối đến gmail và gửi mail

2. Gửi mail hàng loạt với thông tin được lưu trữ trong file email_list.csv


THỰC HIỆN

1. Sử dụng thư viện smtplib của python để kết nối đến gmail và gửi mail

Code:
'''
Kết nối đến Gmail để gửi mail

Điều kiện:
1. Tắt bảo mật 2 lớp
https://myaccount.google.com/security?utm_source=OGB&utm_medium=act#signin

2. Allow less secure apps: ON
https://myaccount.google.com/u/1/lesssecureapps?pli=1&pageId=none

nếu không chúng ta sẽ gặp lỗi
#smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8  https://support.google.com/mail/?p=BadCredentials qe12sm2115875pjb.29 - gsmtp')

nếu trong nội dung email có gõ tiếng việt sẽ bị lỗi, các địa chỉ không gửi đến được sẽ được lưu vào file
'''
import smtplib, ssl

def send_mail(mail_from, mail_password, mail_to, mail_subject, mail_body): # Hàm gửi mail
	port = 465  # For SSL
	smtp_server = "smtp.gmail.com"
	#mail_password = input("Type your password and press enter: ")
	mail_message = f"Subject: {mail_subject}\n\n{mail_body}"
	context = ssl.create_default_context()
	try:
		with smtplib.SMTP_SSL(smtp_server, port, context = context) as server:
		    server.login(mail_from, mail_password)
		    server.sendmail(mail_from, mail_to, mail_message)
		    print (f"Successfuly sent to '{mail_to}'")
	except:
		print (f"Communication failure in '{smtp_server}'")
            
# Định nghĩa các thông tin 
email_info = {
	"mail_from": "khanhvc.wrk@gmail.com",
	"mail_password": "admin" ,
	"mail_to": "khanhvc@tencongty.com",
	"mail_subject" : "This is send python 3.10" ,
	"mail_body": "This is for testing email",
	#mail_password = input("Type your password and press enter:")
}

send_mail(**email_info)

2. Gửi mail hàng loạt với thông tin được lưu trữ trong file email_list.csv

Tạo file email_list.csv có dạng:


Code:
'''
Kết nối đến Gmail để gửi mail, danh sách các email được lưu trữ trong file email_list.csv

Điều kiện:
1. Tắt bảo mật 2 lớp
https://myaccount.google.com/security?utm_source=OGB&utm_medium=act#signin

2. Allow less secure apps: ON
https://myaccount.google.com/u/1/lesssecureapps?pli=1&pageId=none

nếu không chúng ta sẽ gặp lỗi
#smtplib.SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8  https://support.google.com/mail/?p=BadCredentials qe12sm2115875pjb.29 - gsmtp')
'''
import smtplib, ssl
import pandas as pd
from pprint import pprint
from datetime import datetime
import os

path = os.getcwd()  # lấy đường dẫn hiện tại
now = datetime.now().strftime("%Y-%b-%d_%H%M%S")

ERR_log = f"Send_Mail_{now}_ERR_logs.log" # định nghĩa tên file lưu trữ thông tin lỗi

def send_mail(mail_from, mail_password, mail_to, mail_subject, mail_body):
	port = 465  # For SSL
	smtp_server = "smtp.gmail.com"
	#mail_password = input("Type your password and press enter: ")
	mail_message = f"Subject: {mail_subject}\n\n{mail_body}"
	context = ssl.create_default_context()
	try:
		with smtplib.SMTP_SSL(smtp_server, port, context = context) as server:
		    server.login(mail_from, mail_password)
		    server.sendmail(mail_from, mail_to, mail_message)
		    print (f"Successfuly sent to '{mail_to}'")
	except:
		f = open(ERR_log,"a")
		f.write(f'Undelivered email to: {mail_to}')
		f.write("\n")
		f.close()
		print (f"Communication failure in '{smtp_server}'")
		pass
            
email_list = 'email_list.csv' # tên file lưu trữ thông tin thiết bị
column_name = ['mail_from', 'mail_subject', 'mail_to', 'mail_body', 'mail_password'] # chỉ định các cột cần lấy
try:
	email_list = pd.read_csv(email_list, usecols = column_name, encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8
	email_list = email_list.to_dict(orient='records') # chuyển đổi về dict tương ứng (ví dụ: nếu file có 10 dòng thì sẽ tạo ra 9 (10 dòng bỏ đi dòng đầu tiên đã làm key) dictionary tương ứng)
	#pprint(email_list)

	for email_info in email_list:
		send_mail(**email_info)
	ERR_info = f"*** ERROR: Please check file : '{ERR_log}' at '{path}' ***\n"
	print (ERR_info)
except:
	ERR_info = f"*** ERROR: Please check file : '{email_list}' at '{path}' ***\n"
	print (ERR_info)
	pass

Kết quả:


Tham khảo bài gửi mail có đính kèm attach file tại đây


Xong!


Network Automation #010 - Kiểm Tra MAC Address Lạ Gắng Vào Switch

 YÊU CẦU:

Kiểm tra các địa chỉ mac hiện trên switch nếu địa chỉ nào không có trong danh sách các địa chỉ mac đang đăng ký thì lưu thông tin của chúng vào file

THỰC HIỆN:

Chuẩn bị template lưu nội dung file show_mac_address.template:

Value VLAN (\d+)
Value MAC_ADDRESS ([0-9a-fA-F]{4}(?:\.[0-9a-fA-F]{4}){2})
Value INTERFACE ([^,\s]+)

Start
  ^Vlan\s+Mac Address\s+Type\s+Ports -> TYPE1

TYPE1
  ^\s*${VLAN}\s+${MAC_ADDRESS}\s+\w+\s+${INTERFACE}(?:\s|$$) -> Record


Code:

'''
- Kết nối switch kiểm tra các địa chỉ mac hiện trên switch nếu địa chỉ nào không có trong danh sách các địa chỉ mac đã đăng ký thì lưu thông tin của chúng vào file

- Câu lệnh sử dụng trong bài:
  show mac address-table

- Thư viện cần cài:
+ pip install textfsm
+ pip install pandas

'''

import pandas as pd # dùng khi ghi file csv 
from pprint import pprint # dùng để in ra đẹp, dễ nhìn hơn
import textfsm
from netmiko import ConnectHandler
import os

path = os.getcwd()	# lấy đường dẫn hiện tại

show_mac_01 = pd.read_csv('mac_store.csv', encoding = "utf-8") # đọc và xử lý chuyển dữ liệu về dạng DataFrame, và sử dụng code utf-8, lấy tất cả các cột hiện có
column_name = 'MAC_ADDRESS' # tên của cột phải tồn tại trong file mac_store.csv
mac_store = show_mac_01.values.tolist() # Trích lọc cột MAC_ADDRESS
mac_store = show_mac_01[column_name].values.tolist() 
#pprint(mac_store)

Sw_1 = { 
	"host":"192.168.100.23",
	"username":"admin",
	"password":"l2Hsv-Tw!!)",
	"device_type":"cisco_ios"
	}


print("Connecting to a host: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = ConnectHandler(**Sw_1) 
print("Connected successfully")

sh_mac_addr = "show mac address-table"
sh_mac_addr = net_connect.send_command(sh_mac_addr) # thực hiện lênh show arp với chính IP cần tìm

with open('show_mac_address.template') as template: # Mở file show_mac_address.template vừa định nghĩa
    fsm = textfsm.TextFSM(template)
    sh_mac_addr = fsm.ParseText(sh_mac_addr)
'''
for item in sh_mac_addr :
    if item[1] not in mac_store:
        print(item)
    else: print ("x")
'''
# lấy cụm thứ 2 (là địa chỉ MAC) và kiểm tra nếu chúng không có trong có trong file mac_store.csv thì đưa vào biến mac_diff
mac_diff = [item for item in sh_mac_addr if item[1] not in mac_store] 

file_name = f"MAC_diff_{Sw_1['host']}.csv"
df = pd.DataFrame(mac_diff) # convert dữ liệu sang kiểu DataFrame
df.to_csv(file_name, header = fsm.header, index = False) # thực hiện lưu các địa chỉ mac khác nhau vào file
print (f"Cac dia chi MAC chua dang ky duoc luu vao '{file_name}' tai '{path}'")

Tham khảo bài export MAC Address trong switch tại đây

Xong!

Network Automation #009 - Exporting MAC Address From Switches Cisco IOS & TextFSM Template

 YÊU CẦU:

1. Sử dụng thư viện netmiko kết nối vào switch kết hợp với TextFSM template để export toàn bộ MAC Address và lưu vào file MAC_TextFSM_template.CSV

2. Định nghĩa TextFSM template chỉ lấy các trường: Vlan (chỉ lấy các vlan là số), Mac Address, Port là lưu thành vào file MAC_TextFSM_Custom.CSV


THỰC HIỆN:

1. Sử dụng thư viện netmiko kết nối vào switch kết hợp với TextFSM template để export toàn bộ MAC Address và lưu vào file MAC_TextFSM_template.CSV

  • Chuẩn bị:
Cài đặt thư viện:
- pip install textfsm
- pip install pandas

Tham khảo cách cài đặt thư viện tại đây

  • Code:

'''
- Kết nối switch export tất cả các MAC Address và lưu thành file MAC_TextFSM_template.CSV

- Câu lệnh sử dụng trong bài:
+ show mac address-table

- Thư viện cần cài:
+ pip install textfsm
+ pip install pandas

'''
from netmiko import ConnectHandler
import textfsm
import pandas as pd
import os

path = os.getcwd()	# lấy đường dẫn hiện tại
file_name = "MAC_TextFSM_template.CSV" # tên file cần lưu

# Thông tin thiết bị cần SSH vào (định nghĩa dictionnary)
Sw_1 = { 
	"host":"192.168.100.23",
	"username":"admin",
	"password":"admin1234",
	"device_type":"cisco_ios"
	}
	
print("Dang ket noi den thiet bi co IP: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = ConnectHandler(**Sw_1) 
print("Ket noi thanh cong!")

sh_mac_addr = "show mac address-table"
sh_mac_addr = net_connect.send_command(sh_mac_addr, use_textfsm = True) # thực hiện lệnh và sử dụng thư viện TextFSM
df = pd.DataFrame(sh_mac_addr) # chuyển dữ liệu thành dạng DataFrame
df.to_csv(file_name, index = False) # thực hiện lưu file nhưng không lưu cột index
print (f"\n=====Tat ca MAC Address duoc luu vao file '{file_name}' tai '{path}'=====")


  • Kết Quả:

Dang ket noi den thiet bi co IP: 192.168.100.23...
Ket noi thanh cong!
=====Tat ca MAC Address duoc luu o file 'MAC_TextFSM_template.CSV' tai 'C:\python'=====
[Finished in 3.3s]



Nhận xét:
Khi sử dụng TextFSM để xử lý cột Mac Address đổi thành destination_address, và Ports đổi thành destination_port chúng ta khó có thể để chỉnh được theo ý.

2. Định nghĩa TextFSM template chỉ lấy các trường: Vlan (chỉ lấy các vlan là số), Mac Address, Port là lưu thành vào file MAC_TextFSM_Custom.CSV

  • Định nghĩa TextFSM Template lưu nội dung vào file show_mac_address.template
Value VLAN (\d+)
Value MAC_ADDRESS ([0-9a-fA-F]{4}(?:\.[0-9a-fA-F]{4}){2})
Value INTERFACE ([^,\s]+)

Start
  ^Vlan\s+Mac Address\s+Type\s+Ports -> TYPE1

TYPE1
  ^\s*${VLAN}\s+${MAC_ADDRESS}\s+\w+\s+${INTERFACE}(?:\s|$$) -> Record


Tham khảo TextFSM template tại đây

  • Code:

'''
- Kết nối switch export tất cả các MAC Address và lưu thành file MAC_TextFSM_Custom.CSV
- Chúng ta tự định nghĩa TextFSM template, các cột tiêu đề chúng ta cũng có thể đặt tên tùy thích và cũng có thể chọn ra/định nghĩa các vlan cần lấy ra trong file đó.

- Câu lệnh sử dụng trong bài:
+ show mac address-table

- Thư viện cần cài:
+ pip install textfsm
+ pip install pandas

'''
from netmiko import ConnectHandler
import textfsm
import pandas as pd
import os

path = os.getcwd()	# lấy đường dẫn hiện tại
file_name = "MAC_TextFSM_Custom.CSV" # tên file cần lưu
textfsm_template = 'show_mac_address.template' # tên template
# Thông tin thiết bị cần SSH vào (định nghĩa dictionnary)
Sw_1 = { 
	"host":"192.168.100.23",
	"username":"admin",
	"password":"admin1234",
	"device_type":"cisco_ios"
	}
	
print("Dang ket noi den thiet bi co IP: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = ConnectHandler(**Sw_1) 
print("Ket noi thanh cong!")

sh_mac_addr = "show mac address-table"
sh_mac_addr = net_connect.send_command(sh_mac_addr) # thực hiện lệnh show
try:
	with open(textfsm_template) as template: # Mở file show_mac_address.template vừa định nghĩa
		fsm = textfsm.TextFSM(template)
		sh_mac_addr = fsm.ParseText(sh_mac_addr)
	#print(fsm.header)
	#pprint(sh_mac_addr)
	df = pd.DataFrame(sh_mac_addr) # convert dữ liệu sang kiểu DataFrame
	df.to_csv(file_name, header = fsm.header, index = False) # Ghi dữ liệu vừa trích lọc vào file với header tương ứng và không cần điền thêm cột index	
	print (f"\n=====Tat ca MAC Address duoc luu vao file '{file_name}' tai '{path}'=====")
except:
	print (f"\n=====Kiem tra file template '{textfsm_template}' tai '{path}'=====")	


  • Kết quả:



Nhận xét:
Việc tự định nghĩa template chúng ta có thể tùy chọn các trường cần lấy và phần tiêu đề của các cột chúng ta có thể đặt tên tùy thích. Với kết quả trên chúng ta thấy trường Type và các dòng vlan không phải là số sẽ không được đưa vào file MAC_TextFSM_Custom.csv


Xong!


Network Automation #008 - Netmiko Finding Device IP Addresses Connected To Juniper - JunOS Switch

Nên tham khảo bài Juniper - JunOS (mục 2) trước khi xem bài này

YÊU CẦU: 

Dùng thư viện Netmiko trong python để SSH vào switch Juniper - JunOS để  tìm các thiết bị hiện tại đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó. Các địa chỉ IP cần tìm được lưu trữ trong file "device_list.csv". 

Kết quả tìm được in ra màn hình và lưu vào file "Show_arp_Ketqua_192.168.0.1.csv"

THỰC HIỆN:

1. Chuẩn bị file danh sách thiết bị có dạng


2. Code

'''
Tìm thiết bị đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó
Danh sách các IP cần tìm để trong file "device_list.csv"
(Điều kiện là thiết bị Juniper cần kết nối đã được cấu hình SSH)
Kết quả tìm được in ra màn hình và lưu vào file "Show_arp_Ketqua_192.168.0.1.csv"

Câu lệnh chính dùng trong bài:
- show arp hostname < địa chỉ ip cần tìm>
- show ethernet-switching table <địa chỉ mac cần tìm>

'''
import netmiko # import thư viện netmiko
import os 

# Thông tin thiết bị cần SSH vào (định nghĩa dictionnary)
Sw_1 = { 
	"host":"192.168.0.1",
	"username":"admin",
	"password":"admin1234@core",
	"device_type":"juniper_junos"
	}
print("Connecting to a host: " + Sw_1["host"] + "...") # Hiển thị thông báo kết nối tới
# dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary
net_connect = netmiko.ConnectHandler(**Sw_1) 
print("Connected successfully\n")


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

	keys = rfile.readline() # lấy dòng đầu tiên
	values = rfile.read() # các dòng còn lại là giá trị cần gán vào dict

# print(keys)
# print(values)
'''
để remove xuống dòng (newline) chúng ta có thể dùng
print(keys,end="")
'''
file_ketqua = "Show_arp_Ketqua_" + Sw_1["host"] + ".csv" # định nghĩa tên file cần ghi kết quả
file_header = keys.rstrip() + ",Vlan,Mac Address,MAC Flags,Logical Interface\n" # bỏ newline (\n) ở cuối dòng và nối thêm chuỗi để ghi vào file chuẩn bị để chứa kết quả show mac address và chèn newline vào cuối

f = open(file_ketqua,"w") 
# print(file_header)
f.write(file_header)
f.flush() # thực hiện ghi
f.close() # đóng file để giải phóng bộ nhớ

print ("*" * 20 + "KET QUA" + "*" * 20)
for values in values.splitlines(): # trả về một chuỗi tương ứng là một dòng trong biến values
	values = values.split(",") # mỗi dòng chuyển thành list
	ip_addr = values[0] # giá trị của cột đầu tiên là địa chỉ IP cần lấy ra
	ip_description = values[1]
	# print(ip_addr)
	# print(ip_description)
	# print(values)
	print("*" + ip_addr + ":") # In ra IP đang cần show

	net_connect.send_command("ping" + " " + ip_addr + " " + "count 4") # ping (ping 4 gói) địa chỉ IP cần kiểm tra để switch cập nhật vào bảng MAC 
	show_arp = "show arp" + " " + "hostname" + " " + ip_addr
	show_arp = net_connect.send_command(show_arp) # thực hiện lênh show arp với chính IP cần tìm

	#print (show_arp)
	# In ra dòng thứ nhì trong chuỗi
	# print (show_arp.splitlines()[1])

	# lấy dòng thứ nhì và phân ra từng cụm
	fields = show_arp.splitlines()[1].split()

	# lấy cụm đầu tiên (là địa chỉ MAC) tính từ trái sang
	mac_addr = fields[0]

	# print (mac_addr)

	show_mac_addr = "show ethernet-switching table" + " " + mac_addr
	show_mac_addr = net_connect.send_command(show_mac_addr) # thực hiện lệnh show
	print(show_mac_addr)
	show_mac_addr = show_mac_addr.splitlines()[8].split() # lấy dòng thứ 8 chuyển thành list
	#print(show_mac_addr) # In kết quả show ra màn hình
	print() # In ra dòng trắng 
	#print(type(show_mac_addr))
	#print(type(values))
	
	for i in [6,5,3]:  
		del show_mac_addr[i] # thực hiện xóa các phần tử không cần lấy

	show_mac_addr = values + show_mac_addr # thực hiện nối thông tin ban đầu và kết quả 
	
	#print(show_mac_addr)
	show_mac_addr = ",".join(show_mac_addr) + "\n" # convert list sang string và thêm "," vào giữa mỗi cụm
	f = open(file_ketqua,"a") 
	f.write(show_mac_addr) # thực hiện ghi thêm kết quả vào file kết quả
path = os.getcwd() # lấy đường dẫn hiện tại

print("*" * 20 + "KẾT QUẢ ĐƯỢC LƯU TẠI" + "*" * 20)
print(r"{}".format(path))
print(file_ketqua)
print("*" * 60 + "\n")

3. Kết quả:

Connecting to a host: 192.168.0.1...
Connected successfully

********************KET QUA********************
*172.16.125.11:
MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC
           SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC)


Ethernet switching table : 109 entries, 109 learned
Routing instance : default-switch
    Vlan                MAC                 MAC         Age    Logical                NH        RTR 
    name                address             flags              interface              Index     ID
    vlan-125            c0:74:ad:32:2d:3c   D             -   ge-1/0/1.0             0         0       


*172.16.126.11:
MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC
           SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC)


Ethernet switching table : 109 entries, 109 learned
Routing instance : default-switch
    Vlan                MAC                 MAC         Age    Logical                NH        RTR 
    name                address             flags              interface              Index     ID
    vlan-126            d4:f5:ef:09:c0:1e   D             -   ge-1/0/3.0             0         0       


********************KẾT QUẢ ĐƯỢC LƯU TẠI********************
C:\vck\LAB
Show_arp_Ketqua_192.168.0.1.csv
************************************************************

[Finished in 17.5s]

Nội dung của file Show_arp_Ketqua_192.168.0.1.csv có dạng


Xong!

Network Automation #000 - Netmiko Basic SSH To Router With Command Show

SƠ ĐỒ LAB:
YÊU CẦU: 

Dùng thư viện netmiko trên python SSH vào thiết bị và thực hiện những lệnh show căn bản


THỰC HIỆN:
1. Chuẩn bị cấu hình trên Router

conf t
hostname R_1
ip domain name NETMIKO.lab
no ip domain-lookup
banner motd #===R_1 NETMIKO LAB===#

username admin privilege 15 password admin1234
service password-encryption
 
line con 0
logging synchronous
login local
exit
line vty 0 4
login local
transport input all
crypto key generate rsa general-keys modulus 1024
ip ssh version 2
 
interface Et0/0
no shutdown
ip address 192.168.0.1 255.255.255.0
description ===Connect to PC===
exit
!
end
wri   
Tham khảo cấu hình mẫu/cấu hình cơ bản tại đây


2. Python script Netmiko SSH connection

#!/usr/bin/env python3
import netmiko

# Định nghĩa thông tin thiết bị trong dictionary (thông tin cấu hình trong phần chuẩn bị cấu hình)
device_info = {
    "host": "192.168.0.1",
    "port": 22,
    "username": "admin",
    "password": "admin1234",
    "device_type": "cisco_ios"
}

print("Connecting to {}...".format(device_info["host"])) # print ra dong Connecting to + IP được định nghĩa ở trong dictionnary

net_connect = netmiko.ConnectHandler(**device_info) # Dùng hàm ConnectHandler trong thư viện netmiko để kế nối đến thiết bị

print("Connected successfully") # in ra dòng kết nối thành công
net_connect.enable() # vào mode enable
#net_connect.config_mode() # vào mode config terminal 

 
while True: 
    hostname = net_connect.find_prompt() # Trả về dấu nhắc hiện tại
    command = input(hostname) # in ra những gì trước dấu nhắc (trường hợp này là hostname)
    if command != "exit" and command != "quit": # nếu không không phải là exit hay quit thì thực hiện lệnh show
        output = net_connect.send_command(command) # thực hiện lệnh show vừa gõ
        print(output) # in qa kết quả thực hiện lênh show
    else:   
        break   # kết thúc vòng lặp while (khi chúng ta gõ exit hay quit)

net_connect.disconnect()
P/s: copy nội dung trên lưu thành file Demo.py lưu vào C:\Python\Demo.py

3. Kiểm tra kết nối và thực hiện lệnh show

  • Thực hiện ở Command Prompt
c:\Python>python Demo.py
Connecting to 192.168.0.1...
Connected successfully
R_1#

  • Tiếp tục thực hiện lênh show ip int bri 
R_1#show ip int bri
Interface                  IP-Address      OK? Method Status                Protocol
Ethernet0/0                192.168.0.1     YES NVRAM  up                    up
Ethernet0/1                unassigned      YES NVRAM  administratively down down
Ethernet0/2                unassigned      YES NVRAM  administratively down down
Ethernet0/3                unassigned      YES NVRAM  administratively down down
R_1#

  • Hoặc thực hiện bất cứ lệnh show nào bạn thích
Nói chung các bạn có thể dùng netmiko thay thế cho các công cụ remote khác nếu bạn thích.
  • Chụp hình kết quả thực hiện


Xong!

Network Automation #007 - Netmiko - Tìm Và Cấu Hình Description Cho Interface Khi Biết IP Address

Nên xem các bài trước khi xem bài này


Sơ đồ LAB:


YÊU CẦU

Dùng Netmiko SSH vào switch sau đó thực hiện các yêu cầu như bên dưới khi biết thông tin về IP address và phần mô tả của thiết bị trong file cho trước "devices_list.csv"

  1. In kết quả tìm được IP nào đang kết nối vào port nào ra màn hình và ghi thông tin kết nối chi tiết vào file
  2. Cấu hình description cho interface với thông tin trong file devices_list.csv

THỰC HIỆN:

  • Chuẩn bị 
a. File danh sách thiết bị device_list.csv có dạng


b. Cấu hình trên switch cisco:


1. In kết quả tìm được IP nào đang kết nối vào port nào ra màn hình và ghi thông tin kết nối chi tiết vào file

  • Code:

'''
Tìm thiết bị đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó Danh sách các IP cần tìm để trong file "device_list.csv" (Điều kiện là thiết bị cisco cần kết nối đã được cấu hình SSH) Kết quả tìm được in ra màn hình và lưu vào file "Show_arp_Ketqua_192.168.0.1.csv" Câu lệnh chính dùng trong bài: - show arp <ip cần tìm> - show mac address-table address <địa chỉ mac cần tìm> ''' import netmiko # import thư viện netmiko import os # Thông tin thiết bị cần SSH vào (định nghĩa dictionnary) Sw_1 = { "host":"192.168.0.1", "username":"admin", "password":"admin1234@core", "device_type":"cisco_ios" } print("Connecting to a host: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới # dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary net_connect = netmiko.ConnectHandler(**Sw_1) with open ("device_list.csv","r") as rfile: # mở file keys = rfile.readline() # lấy dòng đầu tiên values = rfile.read() # các dòng còn lại là giá trị cần gán vào dict # print(keys) # print(values) ''' để remove xuống dòng (newline) chúng ta có thể dùng print(keys,end="") ''' file_ketqua = "Show_arp_Ketqua_" + Sw_1["host"] + ".csv" # định nghĩa tên file cần ghi kết quả file_header = keys.rstrip() + ",Vlan,Mac Address,Type,Port\n" # bỏ newline (\n) ở cuối dòng và nối thêm chuỗi để ghi vào file chuẩn bị để chứa kết quả show mac address và chèn newline vào cuối f = open(file_ketqua,"w") # print(file_header) f.write(file_header) f.flush() # thực hiện ghi f.close() # đóng file để giải phóng bộ nhớ for values in values.splitlines(): # trả về một chuỗi tương ứng là một dòng trong biến values values = values.split(",") # mỗi dòng chuyển thành list ip_addr = values[0] # giá trị của cột đầu tiên là địa chỉ IP cần lấy ra ip_description = values[1] # print(ip_addr) # print(ip_description) # print(values) print("*" + ip_addr + ":") # In ra IP đang cần show net_connect.send_command("ping" + " " + ip_addr) # ping địa chỉ IP cần kiểm tra để switch cập nhật vào bảng MAC show_arp = "show arp" + " " + ip_addr show_arp = net_connect.send_command(show_arp) # thực hiện lênh show arp với chính IP cần tìm # In ra dòng thứ nhì trong chuỗi # print (show_arp.splitlines()[1]) # lấy dòng thứ nhì và phân ra từng cụm fields = show_arp.splitlines()[1].split() # lấy cụm thứ 4 (là địa chỉ MAC) tính từ trái sang, sau đó sẽ thực hiện lệnh show mac với MAC này mac_addr = fields[3] # print (mac_addr) show_mac_addr = "show mac address-table address" + " " + mac_addr show_mac_addr = net_connect.send_command(show_mac_addr) # thực hiện lệnh show show_mac_addr = show_mac_addr.splitlines()[5].split() # lấy dòng thứ 6 chuyển thành list print(show_mac_addr) # In kết quả show ra màn hình print() # In ra dòng trắng show_mac_addr = values + show_mac_addr # thực hiện nối thông tin ban đầu và kết quả #print(show_mac_addr) show_mac_addr = ",".join(show_mac_addr) + "\n" # convert list sang string và thêm "," vào giữa mỗi cụm f = open(file_ketqua,"a") f.write(show_mac_addr) # thực hiện ghi thêm kết quả vào file kết quả path = os.getcwd() # lấy đường dẫn hiện tại print("*" * 20 + "KẾT QUẢ ĐƯỢC LƯU TẠI" + "*" * 20) print(r"{}".format(path)) print(file_ketqua) print("*" * 60 + "\n")

  • Kết quả:

Connecting to a host: 192.168.0.1...

*192.168.0.101:
['1', '0050.7966.6803', 'DYNAMIC', 'Et0/1']

*192.168.0.102:
['1', '0050.7966.6805', 'DYNAMIC', 'Et0/2']

*192.168.0.103:
['1', '0050.7966.6806', 'DYNAMIC', 'Et0/3']

*192.168.0.104:
['1', '0050.7966.6804', 'DYNAMIC', 'Et1/3']

*192.168.0.105:
['1', '0050.7966.6802', 'DYNAMIC', 'Et1/2']

********************KẾT QUẢ ĐƯỢC LƯU TẠI********************
C:\vck\LAB
Show_arp_Ketqua_192.168.0.1.csv
************************************************************

[Finished in 19.5s]

Nội dung file show_arp_Ketqua có dạng


2. Cấu hình description cho interface với thông tin trong file devices_list.csv

  • Code:

'''
Tìm thiết bị đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó Danh sách các IP cần tìm để trong file "device_list.csv" (Điều kiện là thiết bị cisco cần kết nối đã được cấu hình SSH) Kết quả tìm được in ra màn hình và lưu vào file "Show_arp_Ketqua_192.168.0.1.csv" Câu lệnh chính dùng trong bài: - show arp <ip cần tìm> - show mac address-table address <địa chỉ mac cần tìm> - int <tên interface> - description <nội dung cần chú thích> ''' import netmiko # import thư viện netmiko import os # Thông tin thiết bị cần SSH vào (định nghĩa dictionnary) Sw_1 = { "host":"192.168.0.1", "username":"admin", "password":"admin1234@core", "device_type":"cisco_ios" } print("Connecting to a host: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới # dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary net_connect = netmiko.ConnectHandler(**Sw_1) with open ("device_list.csv","r") as rfile: # mở file keys = rfile.readline() # lấy dòng đầu tiên values = rfile.read() # các dòng còn lại là giá trị cần gán vào dict # print(keys) # print(values) ''' để remove xuống dòng (newline) chúng ta có thể dùng print(keys,end="") ''' file_config = Sw_1["host"] + ".txt" # định nghĩa tên file config f = open(file_config,"w") # khởi tạo file config rỗng f.flush() # thực hiện ghi f.close() # đóng file để giải phóng bộ nhớ for values in values.splitlines(): # trả về một chuỗi tương ứng là một dòng trong biến values values = values.split(",") # mỗi dòng chuyển thành list ip_addr = values[0] # giá trị của cột đầu tiên là địa chỉ IP cần lấy ra ip_description = values[1] # print(ip_addr) # print(ip_description) # print(values) # print("*" + ip_addr + ":") # In ra IP đang cần show net_connect.send_command("ping" + " " + ip_addr) # ping địa chỉ IP cần kiểm tra để switch cập nhật vào bảng MAC show_arp = "show arp" + " " + ip_addr show_arp = net_connect.send_command(show_arp) # thực hiện lênh show arp với chính IP cần tìm # In ra dòng thứ nhì trong chuỗi # print (show_arp.splitlines()[1]) # lấy dòng thứ nhì và phân ra từng cụm fields = show_arp.splitlines()[1].split() # lấy cụm thứ 4 (là địa chỉ MAC) tính từ trái sang, sau đó sẽ thực hiện lệnh show mac với MAC này mac_addr = fields[3] # print (mac_addr) show_mac_addr = "show mac address-table address" + " " + mac_addr show_mac_addr = net_connect.send_command(show_mac_addr) # thực hiện lệnh show show_mac_addr = show_mac_addr.splitlines()[5].split() # lấy dòng thứ 6 chuyển thành list # print(show_mac_addr) # In kết quả show ra màn hình int_port = show_mac_addr[3] # lấy tên interface # print(int_port) ''' Đưa các thông tin cần cấu hình cho interface vào file cấu hình mẫu ''' f = open(file_config,"a") f.write("interface " + " " + int_port + "\n") f.write("description " + " ===Link to " + ip_addr + " " + ip_description + "===\n") f.write("exit\n") f.flush() # thực hiện ghi f.close() # đóng file để giải phóng bộ nhớ net_connect.send_config_from_file(file_config) # thực hiện cấu hình từ file cấu hình mẫu net_connect.save_config() # lưu cấu hình ''' Kiểm tra sau khi cấu hình ''' show_int_des = "show interface description" show_int_des = net_connect.send_command(show_int_des) print(show_int_des)


  • Kết quả:
Connecting to a host: 192.168.0.1...

Interface                      Status         Protocol Description
Et0/0                          up             up       
Et0/1                          up             up       ===Link to 192.168.0.101 IP Phone===
Et0/2                          up             up       ===Link to 192.168.0.102 Wireless Controller===
Et0/3                          up             up       ===Link to 192.168.0.103 Juniper===
Et1/0                          up             up       
Et1/1                          up             up       
Et1/2                          up             up       ===Link to 192.168.0.105 PC===
Et1/3                          up             up       ===Link to 192.168.0.104 Linux Server===
Vl1                            up             up       
[Finished in 35.4s]

Xong!

Network Automation #006 - Netmiko How To Find Which Switch Port A Device Is Plugged Into Base on IP Address

Nên đọc bài  LAB #001 trước khi xem bài này

Sơ đồ Lab:


Yêu cầu:  Dùng Netmiko để SSH vào switch sau đó tìm thiết bị có IP 192.168.0.101 đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó:
1. Thực hiện trên Cisco - IOS
2. Thực hiện trên Juniper - JunOS

Thực hiện:
1. Thực hiện trên Cisco - IOS

  • Chuẩn bị (cấu hình trên Cisco switch ):

  • Code:
'''
Tìm thiết bị đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó (Điều kiện là thiết bị cisco cần kết nối đã được cấu hình SSH) Câu lệnh chính dùng trong bài: - show arp <ip cần tìm> - show mac address-table address <địa chỉ mac cần tìm> ''' import netmiko # import thư viện netmiko # Thông tin thiết bị cần SSH vào (định nghĩa dictionnary) Sw_1 = { "host":"192.168.0.1", "username":"admin", "password":"admin1234@core", "device_type":"cisco_ios" } print("Connecting to a host: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới # dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary net_connect = netmiko.ConnectHandler(**Sw_1) ip_addr = "192.168.0.101" # địa chỉ ip cần tìm net_connect.send_command("ping" + " " + ip_addr) # ping địa chỉ IP cần kiểm tra để switch cập nhật vào bảng MAC show_arp = "show arp" + " " + ip_addr show_arp = net_connect.send_command(show_arp) # thực hiện lênh show arp với chính IP cần tìm # In ra dòng thứ nhì trong chuỗi # print (show_arp.splitlines()[1]) # lấy dòng thứ nhì và phân ra từng cụm fields = show_arp.splitlines()[1].split() # lấy cụm thứ 4 (là địa chỉ MAC) tính từ trái sang, sau đó sẽ thực hiện lệnh show mac với MAC này mac_addr = fields[3] # print (mac_addr) show_mac_addr = "show mac address-table address" + " " + mac_addr show_mac_addr = net_connect.send_command(show_mac_addr) # thực hiện lệnh show print ("*" * 20 + "KET QUA" + "*" * 20) print(show_mac_addr)

  • Kết quả:

Connecting to a host: 192.168.0.1...

********************KET QUA********************
Mac Address Table
-------------------------------------------

Vlan    Mac Address       Type        Ports
----    -----------       --------    -----
   1    0050.7966.6807    DYNAMIC     Et0/0
Total Mac Addresses for this criterion: 1
[Finished in 8.8s]

Kết quả cho chúng ta thấy IP 192.168.0.101 được kết nối vào port Et0/0 của switch 192.168.0.1

2. Thực hiện trên Juniper - JunOS
  • Chuẩn bị (cấu hình trên Juniper switch ):
Tham khảo cấu hình Juniper tại link 

Noted: Lab Juniper mình làm trên thiết bị thật, nên port sẽ không giống như hình ở trên
  • Code:
''' Tìm thiết bị đang gắng vào port nào trên local switch khi biết địa chỉ IP của nó (Điều kiện là thiết bị Juniper cần kết nối đã được cấu hình SSH) Câu lệnh chính dùng trong bài: - show arp hostname <ip cần tìm> - show ethernet-switching table <địa chỉ mac cần tìm> ''' import netmiko # import thư viện netmiko # Thông tin thiết bị cần SSH vào (định nghĩa dictionnary) Sw_1 = { "host":"192.168.0.1", "username":"admin", "password":"admin1234@core", "device_type":"juniper_junos" } print("Connecting to a host: " + Sw_1["host"] + "...\n") # Hiển thị thông báo kết nối tới # dùng hàm ConnectHandler trong thư viện netmiko để kết nối với Sw_1 với các thông tin đã định nghĩa trong dictionnary net_connect = netmiko.ConnectHandler(**Sw_1) ip_addr = "192.168.0.101" # địa chỉ ip cần tìm net_connect.send_command("ping" + " " + ip_addr + " " + "count 4") # ping (ping 4 gói) địa chỉ IP cần kiểm tra để switch cập nhật vào bảng MAC show_arp = "show arp" + " " + "hostname" + " " + ip_addr show_arp = net_connect.send_command(show_arp) # thực hiện lênh show arp với chính IP cần tìm # print (show_arp) # In ra dòng thứ nhì trong chuỗi # print (show_arp.splitlines()[1]) # lấy dòng thứ nhì và phân ra từng cụm fields = show_arp.splitlines()[1].split() # lấy cụm đầu tiên (là địa chỉ MAC) tính từ trái sang mac_addr = fields[0] # print (mac_addr) show_mac_addr = "show ethernet-switching table" + " " + mac_addr show_mac_addr = net_connect.send_command(show_mac_addr) # thực hiện lệnh show print ("*" * 20 + "KET QUA" + "*" * 20) print(show_mac_addr)

  • Kết quả:

Connecting to a host: 192.168.0.1...

********************KET QUA********************
MAC flags (S - static MAC, D - dynamic MAC, L - locally learned, P - Persistent static, C - Control MAC
           SE - statistics enabled, NM - non configured MAC, R - remote PE MAC, O - ovsdb MAC)

Ethernet switching table : 87 entries, 87 learned
Routing instance : default-switch
    Vlan                MAC                 MAC         Age    Logical                NH        RTR 
    name                address             flags              interface              Index     ID
    vlan-11                  d4:f5:ef:09:c0:1e   D             -   ge-1/0/0.0             0         0       

[Finished in 13.1s]

Thiết bị có IP 192.168.0.101 được nối vào port ge-1/0/0 của switch 192.168.0.1
 

Xong!

Network Automation #003 - Netmiko Backup VLAN Configuration on Cisco IOS Switch

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


Sơ đồ lab:


Yêu cầu:

Dùng thư viện netmiko để SSH vào và thực hiện backup cấu vlan trên switch


Chuẩn bị:

        Sw:

enable
conf t
hostname Sw1
ip domain name netmiko.lab

username admin privilege 15 password admin1234@sw1

line vty 0 4
login local
transport input ssh
crypto key generate rsa general-keys modulus 1024
ip ssh version 2

interface vlan 1
no shutdown
ip address 192.168.0.8 255.255.255.0
exit

vlan 10-20
do wri


Thực hiện:

from netmiko import ConnectHandler 
from datetime import datetime

bk_device = { 
	"host":"192.168.0.8",
	"username":"admin",
	"password":"admin1234@sw1",
	"device_type":"cisco_ios" 
	}

tftpserver = "192.168.0.48" 

def cisco_ios_sw(txt): # định nghĩa hàm backup VLAN cho switch cisco ios
	
	cmd = "copy vlan.dat tftp:"
	filename = txt + "vlan.dat"
	
	net_connect = ConnectHandler(**bk_device)

	output = net_connect.send_command_timing(cmd)
	if "Address or name of remote host []" in  output:
		output += net_connect.send_command_timing(tftpserver)
	if "Destination filename" in output:
		output += net_connect.send_command_timing(filename)

	print(output)
	print("-" * 80)	


print(f"Dang ket noi vao IP:'{bk_device['host']}' voi Username: '{bk_device['username']}'")	

now = datetime.now().strftime("%Y-%b-%d_%H%M%S")
filename = now + "_" + bk_device["device_type"] + "_" + bk_device["host"] 

cisco_ios_sw(filename)


  • Kết quả:

C:\python>python Demo.py

Dang ket noi vao IP:'192.168.0.8' voi Username: 'admin'

Address or name of remote host []? Destination filename [vlan.dat]? !!

2076 bytes copied in 0.025 secs (83040 bytes/sec)

--------------------------------------------------------------------------------

C:\python>


Xong!

Network Automation #005 - Netmiko Config Changes - OSPF Multiple Areas

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


Sơ đồ lab:

                  

Yêu Cầu:

Dùng thư viện Netmiko SSH vào các route để cấu hình OSPF đảm bảo mạng hội tụ (tất cả các IP sơ đồ có thể ping thấy nhau)


Chuẩn bị:

  • Đấu nối interface management: Các interface Et0/0 của tất cả các router nối vào lớp mạng 192.168.0.0/24, lớp mạng này chỉ dùng trong việc quản lý thiết bị, không tham gia vào quá trình định tuyến của các router trong sơ đồ mạng.

  • Cấu hình căn bản: trên các router đảm bảo netmiko: 192.168.0.48 có thể ssh vào được các router


Thực hiện:

  • Chuẩn bị file cấu hình mẫu:
R1.txt
interface e0/2
ip address 192.168.14.1 255.255.255.0
no shutdown
exit
interface e0/3
ip address 192.168.13.1 255.255.255.0
no shutdown
exit
interface e0/1
ip address 192.168.123.1 255.255.255.0
no shutdown
exit
interface Lo0
ip address 172.16.1.1 255.255.255.0
no shutdown
exit
!
router ospf 1
router-id 1.1.1.1
exit
!
int rang e0/1 ,e0/3, lo 0
ip ospf 1 are 0
exit
int rang e0/2
ip ospf 1 are 1
exit
end
wri

R2.txt
interface e0/1
ip address 192.168.123.2 255.255.255.0
no shutdown
exit
interface Lo0
ip address 172.16.2.1 255.255.255.0
no shutdown
exit
!
router ospf 1
router-id 2.2.2.2
exit
!
int rang e0/1 
ip ospf 1 are 0
exit
int lo 0
ip ospf 1 are 2
exit
end
wri
R3.txt
interface e0/3
ip address 192.168.13.3 255.255.255.0
no shutdown
exit
interface e0/1
ip address 192.168.123.3 255.255.255.0
no shutdown
exit
interface Lo0
ip address 172.16.3.1 255.255.255.0
no shutdown
exit
!
router ospf 1
router-id 3.3.3.3
exit
!
int rang e0/1 ,e0/3, lo 0
ip ospf 1 are 0
exit
end
wri

R4.txt
interface e0/2
ip address 192.168.14.4 255.255.255.0
no shutdown
exit
interface Lo0
ip address 8.8.8.8 255.255.255.0
no shutdown
exit
!
router ospf 1
router-id 4.4.4.4
exit
!
int rang e0/2
ip ospf 1 are 1
exit
int lo 0
ip ospf 1 are 1
exit
end
wri

  • Code:
from netmiko import ConnectHandler 
'''
Thực hiện import file cấu hình:
- R1.txt vào R1
- R2.txt vào R2
- R3.txt vào R3
- R4.txt vào R4
'''

ios_device = {} 				# định nghĩa dictionnay rỗng
cfg_device = "R1,R2,R3,R4"		# danh sách các Router cần cấu hình
cfg_device = cfg_device.split(",")

def send_config_file(txt):
	
	print(f"Dang ket noi vao IP:'{values[1]}' voi Username: '{values[2]}'")	

	net_connect = ConnectHandler(**ios_device)			# khởi tạo kết nối đến router
	output = net_connect.send_config_from_file(txt) 	# thực hiện import cấu hình vào router
	print(f"Da import file cau hinh:'{txt}' OSPF vao IP: '{values[1]}' thanh cong!")
	print("-" * 80)
	#print(txt)       
      
with open ("device_listOSPF.csv","r") as rfile: 
	keys = rfile.readline().split(",")
	values = rfile.read()
	x = 0  # khởi tạo biến đếm
	for values in values.splitlines(): 
		values = values.split(",") 
		for i in range(1,len(keys)-1,1): 
			ios_device[keys[i]] = values[i]  
		
		send_config_file(cfg_device[x] + ".txt")
		x += 1


  • Kết quả:
C:\python>python Demo.py
Dang ket noi vao IP:'192.168.0.1' voi Username: 'admin'
Da import file cau hinh:'R1.txt' OSPF vao IP: '192.168.0.1' thanh cong!
--------------------------------------------------------------------------------
Dang ket noi vao IP:'192.168.0.2' voi Username: 'admin'
Da import file cau hinh:'R2.txt' OSPF vao IP: '192.168.0.2' thanh cong!
--------------------------------------------------------------------------------
Dang ket noi vao IP:'192.168.0.3' voi Username: 'admin'
Da import file cau hinh:'R3.txt' OSPF vao IP: '192.168.0.3' thanh cong!
--------------------------------------------------------------------------------
Dang ket noi vao IP:'192.168.0.4' voi Username: 'admin'
Da import file cau hinh:'R4.txt' OSPF vao IP: '192.168.0.4' thanh cong!
--------------------------------------------------------------------------------
[Finished in 32.6s]


Các common thường sử dụng trong phương thức netmiko:

  • net_connect.send_command() - Send command down the channel, return output back (pattern based)
  • net_connect.send_command_timing() - Send command down the channel, return output back (timing based)
  • net_connect.send_config_set() - Send configuration commands to remote device
  • net_connect.send_config_from_file() - Send configuration commands loaded from a file
  • net_connect.save_config() - Save the running-config to the startup-config
  • net_connect.enable() - Enter enable mode
  • net_connect.find_prompt() - Return the current router prompt
  • net_connect.commit() - Execute a commit action on Juniper and IOS-XR
  • net_connect.disconnect() - Close the connection
  • net_connect.write_channel() - Low-level write of the channel
  • net_connect.read_channel() - Low-level write of the channel
Xong!

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!

    /*header slide*/