ИТ-инфраструктуры становятся все более сложными, теперь мы обычно работаем с десятками и сотнями коммутаторов, маршрутизаторов и межсетевых экранов.
Еслитовые файлы, но с Python и netmiko мы можем объединить вывод нескольких разных команд, записав только нужную нам информацию в один выходной CSV-файл.
Почему CSV? CSV-файл удобен, потому что мы можем открыть его в Excel, и легко скрыть ненужные нам столбцы, сгруппировать или упорядочить по нужным нам столбцам.
Если мы будем ежедневно создавать один такой файл со всех коммутаторов, мы легко сможем увидеть разницу в состоянии подключенных устройств, просто открыв два файла в редакторе Not
Моя программа на Python обращается ко всем коммутаторам из набора, выполняет все три командочень простую инфраструктуру, состоящую из двух коммутаторов и нескольких подключенных устройств.

Выходной файл выглядит так
python программа
#!/usr/bin/python3 # d=True, help = ' Path to the Ansible hosts file ') parser.add_argument('--group', required=True, help = ' Group of routers to connect to from Ansible hosts file ') return parser.parse_args() def ping_ip(ip_address): # Use ping command to check if switch alive param = '-c' # for linux os command = ['ping', param, '2', ip_address] # Build the ping command t global_vars = hosts_data['all']['vars'] # Extract global variables # Extract router details for the specified group if args.group not in hosts_data: print(f"Group {args.group} not found in hosts file.") return routers = hosts_data[args.group]['hosts'] # Extract group of devices output_filed = args.group + '_inter_des.csv' # output_filec = args.group + '_inter_cdp.csv' # output_filema = args.group + '_inter_mac.csv' # STRd = "Hostname,IP_address,Interface,State,Description,Vlan" # column names status with open(output_filed, "w", newline="") as out_filed: writer = csv.writer(out_filed) out_filed.write(STRd) out_filed.write('\n') STRc = "Hostname,IP_address,Interface,New_Description" # column names cdp with open(output_filec, "w", newline="") as out_filec: writer = csv.writer(out_filec) else: print( ' switch online --------- ', router_name,' ',router_info['ansible_host']) de_type = '' if global_vars['ansible_network_os'] == 'ios': # check if cisco ios de_type = 'cisco_ios' netmiko_connection = { # Create Netmiko connection dictionary 'device_type': de_type, 'host': router_info['ansible_host'], 'username': global_vars['ansible_user'], 'password': global_vars['ansible_password'], 'secret': global_vars['ansible_become_password'], } # exclude router from switches outputd2 = connection.send_command(comm2) outputd31 = connection.send_command(comm3, use_textfsm=True) # mac textfsm connection.disconnect() # Disconnect from device print(f" ------------ Output from {router_name} ({router_info['ansible_host']}):") # Print the output print(' mac textfsm ------- ', type(outputd31)) print(outputd31) # mac textfsm print(" ------------") lines = outputd1.strip().split('\n') #### parse 'show interface status' lines = lines[1:] for line in lines: if (line == '') or (line.startswith("Port")): continue swi=router_name ipad= router_info['ansible_host'] for line in lines1: if (line == '') or (line.startswith("Devic")): continue por1 = por[0:2]+por[3:33] # remove 3rd char from port name por=por1.replace(' ', '') swi=router_name ipad= router_info['ansible_host'] print("switch ",swi," port ",por, " Descr ", ndes ) STRc = swi + "," + ipad + "," + por +"," + ndes # switch name with ip with open(output_filec, 'a') as f: f.write(STRc) f.write('\n') print(f" ------------ end") ###### --------------------------------------------- #### parse 'show mac address-table' texfsm for entry in outputd31: # Remove square brackets from 'destination_port' values entry['destination_port'] = entry['destination_port'][0] outputd31_sorted = sorted(outputd31, key=lambda x: x['destination_port']) # Sort the list by 'destination_port' unique_data31 = [] ports_seen = {} # Count occurrences of each port for entry in outputd31_sorted: port = entry['destination_port'] if port in ports_seen: ports_seen[port] += 1 else: ports_seen[port] = 1 # Keep only ports that appear once unique_data31 = [entry for entry in outputd31_sorted if ports_seen[entry['destination_port']] == 1] # Output the result for entry in unique_data31: print(entry) STRm = swi + "," + ipad + "," +entry['destination_port'] + "," +entry['destination_address'] + "," + entry['vlan_id'] # with open(output_filema, 'a') as f: f.write(STRm) f.write('\n') output_filem = args.group + '_merg.csv' # mrge 2 in 1 with open(output_filed, mode='r') as file: reader = csv.DictReader(file) sw_inter_des_data = list(reader) # Read descr file into a list of dictionaries with open(output_filec, mode='r') as file: reader = csv.DictReader(file) sw_inter_cdp_data = list(reader) # Read cdp file into a list of dictionaries with open(output_filema, mode='r') as file: reader = csv.DictReader(file) sw_inter_mac_data = list(reader) # Read mac file into a list of dictionaries cdp_lookup = { # Create a lookup dictionary for sw_inter_cdp_data based on Hostname, IP_address, and Interface (row['Hostname'], row['IP_address'], row['Interface']): row['New_Description'] for row in sw_inter_cdp_data } mac_lookup = { # Create a lookup dictionary for sw_inter_cdp_data based on Hostname, IP_address, and Interface (row['Hostname'], row['IP_address'], row['Interface']): row['mac'] for row in sw_inter_mac_data } for row in sw_inter_des_data: key = (row['Hostname'], row['IP_address'], row['Interface']) row['New_Description'] = cdp_lookup.get(key, '') # Add the New_Description to sw_inter_des_data row['mac'] = mac_lookup.get(key, '') # Add mac with #################### Entry point of the main if __name__ == '__main__': main()
