1

I am using the following script to log into various cisco devices and configure them:

from netmiko import ConnectHandler
import time
import json
import yaml
import sys


with open("devices.yml") as d:
    all_devices = yaml.safe_load(d)


with open("snmp_configs.txt") as c:
    lines = c.read().splitlines()

with open("exception_log.txt", "w") as log:


    for devices in all_devices:

        try:
            net_connect = ConnectHandler(**devices)
            output = net_connect.send_config_set(lines)
            print("Configuring Device")
            time.sleep(5)

        #except BaseException as ex:
            #ex_value = sys.exc_info()
            #print(ex_value)

        except:
            print ("An Exception Occurred, Skipping")
            traceback.print_exc(file=log)
            continue

The Script uses a yaml file for the devices that looks like this:

-device_type: cisco_ios
 ip: 192.168.122.71
 username: admin
 password: cisco
-device_type: cisco_ios
 ip: 192.168.122.81
 username: admin
 password: cisco

The question I have is this. If I had dozens or even hundreds of devices that used the same exact username and password, is there a way to not have to repeat the username, password and device type info over and over again in the file? I'm wondering if there is a way to only have to enter the username and password one time in the file and then the rest of the file is just the IP addresses of the devices?

I hope this is making sense.

Thank you.

ccsmooth
  • 37
  • 3

1 Answers1

1

You can use dynamic inventory as in the example I shared below.

myhelper.py takes care parsing the inventory.yml file. Make sure this script is in the same location as any of the script in ths repo.

inventory.yml

all:
  vars:
    username: admin
    password: admin
  sites:
    - name: am3
      hosts:
        - hostname: am3-srx-fw-1
          host: 10.1.1.1
          device_type_netmiko: juniper_junos
          device_type: srx
          device_role: edge
       - hostname: ld5-srx-fw-1
          host: 10.2.2.2
          device_type_netmiko: juniper_junos
          device_type: srx
          device_role: edge

myhelper.py

    import yaml
    import os
    
    #SITES = {"sjc": 1, "bru": 2}
    
    #DEVICE_TYPES = {"csr1000v": 1, "iosv-l2": 2}
    
    #DEVICE_ROLES = {"access": 1, "edge": 2, "core": 3}
    
    #site_name="opc"
    
    path="inventory.yml"
    
    def read_yaml(path="inventory.yml"):
         with open(path) as f:
              yaml_content = yaml.load(f.read())
              return yaml_content
    
    def form_connection_params_from_yaml(parsed_yaml):
        global_params = parsed_yaml["all"]["vars"]
        found = False
        for site_dict in parsed_yaml["all"]["sites"]:
            for host in site_dict["hosts"]:
                    #print(host)
                    host_dict = {}
                    if "device_type_netmiko" in host:
                        host["device_type"] = host.pop("device_type_netmiko")
                    host_dict.update(global_params)
                    host_dict.update(host)
                    host_dict.pop("device_role")
                    host_dict.pop("hostname")
                    found = True
                    yield host_dict
    
    #if site_name is not None and not found:
       #raise KeyError(
         # "Site {} is not specified in inventory YAML file".format(site_name)
       #)   
    
    #def main():
    #parsed_yaml = read_yaml()
    #connection_params = form_connection_params_from_yaml(parsed_yaml, site_name="opc")
    #print(connection_params)

network.sanity.py

import netmiko
from myhelper import read_yaml, form_connection_params_from_yaml
import logging

logging.basicConfig(filename='dynamic.log', level=logging.DEBUG)
logger = logging.getLogger("netmiko")


path = raw_input("Enter the name of commandi file:")
COMMANDS_LIST = open(path).readlines()


def collect_outputs(devices, commands):
    """
    Collects commands from the dictionary of devices
    Args:
        devices (dict): dictionary, where key is the hostname, value is
            netmiko connection dictionary
        commands (list): list of commands to be executed on every device
    Returns:
        dict: key is the hostname, value is string with all outputs
    """
    for device in devices:
        hostname = device.pop("hostname")
        connection = netmiko.ConnectHandler(**device)
        print(hostname)

        with open(hostname , "a") as f:
             for command in commands:
                  print(command)
                  command_result = connection.send_command(command, delay_factor=10)
           # with open(hostname , "a") as f:
                  f.write(command)
                  f.write(command_result)
                  connection.disconnect
                  yield command_result

def getdevicename(parsed_yaml):
     parsed_yaml = read_yaml()
     for site_dict in parsed_yaml["all"]["sites"]:
         for host in site_dict["hosts"]:
              device_name = host.get('hostname')
              yield device_name


def main():
    parsed_yaml = read_yaml()
    connection_params = form_connection_params_from_yaml(parsed_yaml)
    for device_output in collect_outputs(connection_params, COMMANDS_LIST):
        #print(device_output)  
        print("Capturing output to a file named after device in your local directory")
              

if __name__ == "__main__":
    main()

Ref. https://github.com/rajaramanlala/netmiko-with-dynamic-inventory

Baris Sonmez
  • 477
  • 2
  • 8