1

我正在尝试编写一个脚本,从文件中提取 IP 地址,连接到该 IP 地址的网络设备,对设备运行“显示运行”,将该配置导出到临时文件,然后解析该文件以确保命令。

我正在尝试编写一个函数,以便可以将设备 IP 地址传递给该函数,运行该函数并退出。然后它移动到下一个设备。

from netmiko import ConnectHandler
import getpass
import os.path
from ciscoconfparse import CiscoConfParse
import numpy as np

####Ask for username...will be displayed when typed
uname=input("Enter your username :")

###Ask for password...will not be displayed when typed
p = getpass.getpass(prompt="Enter your password: ")

###Ask for path to device list
filepath=("D:\Scripts\IOSDevices.csv")
hosts = open(filepath).read().splitlines()
#print (hosts) #verify host file is actually reading correctly
hostname = np.array(hosts)
print (hostname) #verify hosts are present in the array 

def run_parseconfig():
    pass
    cf = open(".\tmp_file_conf.txt", "w+")
    #Connect to IOS devices
    device = ConnectHandler(device_type='cisco_ios', ip=hostname, username=uname, password=p)

    output = device.send_command("show run")
    device.disconnect()
    print (output)
    cf.write (output + "\n")
        
    parse = CiscoConfParse(".\tmp_file_conf.txt")
    cf.close()
    output = " "
    hostname_objs = parse.find_objects("^hostname")
    service_objs = parse.find_objects("^service")
    #f = open(hostname+"_config.txt", "a+")
    f = open("D:\Scripts\IOS-DEVICES.txt", "a+")
    f.write ("**** " + hostname + " ****" +"\n\n")
    
    for h_obj in hostname_objs:
        print (h_obj.text)
        f.write (h_obj.text +"\n")
        h_obj = " "
    for s_obj in service_objs:
        print (s_obj.text)
        f.write (s_obj.text +"\n")
        s_obj = " "
    f.write ("\n" + "**** End of " + hostname +"'s Commands" + "\n")
    f.write ("\n")
    f.close()
    parse = " "
    
#for hostname in hosts 
run_parseconfig()

在我构建这个函数之前,它会在第一个设备上成功运行,然后在第二个设备上,它将运行配置发送到一个临时文件,但不会将其解析出来。这就是函数的用武之地。

4

2 回答 2

0

我认为这是一种简单的方法。

此脚本将打开名为“设备”的文件。(IP 地址写在单独的行中)

它将遍历每个 IP 地址并使用 RTR 中给出的用户名和密码连接到设备。

请注意,您可以制作user_input= input("Enter your username")并传递它,而不是硬编码传递它。同样可以用密码来完成。

Config 再次在单独的行中保存配置文件(命令)。output = net_connect.send_config_from_file(CONFIG) 这将打开文件并将命令从文件发送到设备。

我希望这是有帮助的。

from netmiko import ConnectHandler
from getpass import getpass
from netmiko.ssh_exception import NetMikoTimeoutException
from netmiko.ssh_exception import NetMikoAuthenticationException
from paramiko.ssh_exception import SSHException

IP_LIST=open('devices')
CONFIG='config'
for IP in IP_LIST:
    RTR = {
        'ip':IP,
        'username': 'test',
        'password': 'test',
        'device_type': 'cisco_ios',
    }
    print ('\n #### Connecting to the Device ' + IP.strip() + ' ####\n')
    try:
        net_connect = ConnectHandler(**RTR)
    except NetMikoTimeoutException:
        print('Device not reachable')
        continue
    except NetMikoAuthenticationException:
        print ('Authentication Failure')
        continue
    except SSHException:
        print('Make sure SSH is enabled')
        continue
    output = net_connect.send_config_from_file(CONFIG)
    print(output)
于 2021-11-17T11:02:02.367 回答
0

cf您在解析后关闭了文件,CiscoConfParse并不断将变量重置为空字符串,这是不必要的。尝试始终使用上下文管理器而不是open() .close().

我对你的原始代码做了一些修改,代码被注释了:

from getpass import getpass
from typing import Dict, Any

from ciscoconfparse import CiscoConfParse
from netmiko import ConnectHandler

username = input("Please enter your username: ").strip()
password = getpass("Please enter your password: ")

# Define a device dictionary
device = {
    "device_type": "cisco_ios",
    "ip": "192.168.1.1",
    "username": username,
    "password": password,
    "fast_cli": False,
}

# Now run_parse_config takes one argument and it's the device dictionary
def run_parse_config(net_device: Dict[str, Any]):
    # Connect to the device
    with ConnectHandler(**device) as conn:
        # Get the running config
        run_cfg: str = conn.send_command(command_string="show running-config")

    # At this indentation level (4 spaces), you are automatically disconnected.
    # No need to call conn.disconnect()

    # Save the config to a tmp file
    # (I don't think this is necessary)
    # You can convert the run_cfg to a list and skip the tmp_file step

    # for a one liner solution, you can use the map() function:
    # run_cfg = list(map(str.strip, run_cfg.split("\n")))
    with open(file="tmp_file_conf.txt", mode="w+") as tmp_file:
        tmp_file.write(f"{run_cfg.strip()}\n")

    # Parse the running config with CiscoConfParse
    # If you converted the run_cfg to a list, pass it in the keyword arg config. 
    # Ex: `parsed_conf = CiscoConfParse(config=run_cfg)`
    parse = CiscoConfParse(config="tmp_file_conf.txt")

    # Find hostname and services objetcts
    hostname_objs = parse.find_objects("^hostname")
    service_objs = parse.find_objects("^service")

    # Append the filtered objects to a file
    with open(file="IOS-DEVICES.txt", mode="a+") as f:
        f.write(f"*** Start of {device['ip']}'s Commands ***\n\n")
        # write hostname object
        for obj in hostname_objs:
            print(obj.text)
            f.write(f"{obj.text}\n")
        # write services object
        for obj in service_objs:
            print(obj.text)
            f.write(f"{obj.text}\n")
        f.write(f"\n*** End of {device['ip']}'s Commands ***\n\n")


# Run the function
run_parse_config(net_device=device)
于 2021-09-30T11:50:06.553 回答