SSH and config code help

The following is my code to remotely connect to a network device (cisco router), It currently is not functional, but I don’t see any errors. It also needs to be able to "Configure a loopback and at least one other interface with an appropriate IP address on a router within your topology. Configure OSPF protocol on a network device within the topology and advertise appropriately.

I have tried to run the code on Netlab to connect to the router remoutly, the connection intially works, but times out. I assume the commands I am sending over are coded incorrectly.

When running the code and after entering the username, password and ssh choice, I received this response. INFO:paramiko.transport:Connected (version 1.99, client Cisco-1.25) INFO:paramiko.transport:Authentication (password) successful! INFO:root:Connection established ERROR:root:An error occurred: Timed-out reading channel, data not available. INFO:root:The connection has concluded

I am also reviving the message the the line of net_connect.disconect() might be undefined.

Any help would be greatly appreciated

#Getting imports

from netmiko import ConnectHandler
import getpass
import difflib
import logging

#Logging

logging.basicConfig(level=logging.INFO)

#Saving config

def save_config_to_file(config, filename):
    with open(filename, 'w') as config_file:
        config_file.write(config)
    logging.info(f'Configuration saved to {filename}')

#Displaying differences

def show_differences(config1, config2):
    difference = difflib.Differ()
    diff = list(difference.compare(config1.splitlines(), config2.splitlines()))

    for line in diff:
        if line.startswith('- '):
            logging.info(f'Present in ({config1}): {line[2:]}')
        elif line.startswith('+ '):
            logging.info(f'Present in ({config2}): {line[2:]}')

#Config commands

def configure_device(net_connect):
    loopback_config = [
        'en\n'
        'conf t\n'
        'interface Loopback0\n',
        'ip address 192.168.57.101 255.255.255.0\n',
        'exit\n'
    ]

    acl_config = [
        'ip access-list extended MY_ACL\n',
        'permit ip 192.168.56.130 255.255.255.0 any\n',
        'deny ip any any\n',
        'exit\n'
    ]

    interface0_config = [
        'interface GigabitEthernet0/0\n',
        'ip address 192.168.58.101 255.255.255.0\n',
        'exit\n'
    ]

    interface1_config = [
        'interface GigabitEthernet0/1\n',
        'ip address 192.168.59.101 255.255.255.0\n',
        'exit\n'
    ]
    configs = loopback_config + acl_config + interface0_config + interface1_config
    output = net_connect.send_config_set(configs)
    print(output)

#User info and choice of connection type

def main():
    host = '192.168.56.101'
    username = input('Please enter your username: ')
    password = getpass.getpass('Please enter your password: ')
    secret = 'cisco'

    choice = input('Would you like to connect by using telnet or ssh? ')

    if choice.lower() == 'telnet':
        device_type = 'cisco_ios_telnet'
    elif choice.lower() == 'ssh':
        device_type = 'cisco_ios'
    else:
        raise ValueError('Invalid - Please choose either telnet or ssh: ')

    device = {
        'device_type': device_type,
        'host': host,
        'username': username,
        'password': password,
        'secret': secret,
        'port': 22 if device_type == 'cisco_ios' else 23,
        'timeout': 100,
    }

#Connecting to device

    try:
        with ConnectHandler(**device) as net_connect:
            logging.info('Connection established')

#Sending config commands

            configure_device(net_connect)

# Saving config
            running_configuration = net_connect.send_command('show running-config')
            local_config_file_name = 'local_config.txt'
            save_config_to_file(running_configuration, local_config_file_name)
            logging.info(f'The configuration has been saved to {local_config_file_name}')

#comaprign config

            local_config_file_name = 'local_config.txt'

            try:
                with open(local_config_file_name, 'r') as local_config_file:
                    local_config = local_config_file.read()

                if running_configuration and local_config:
                    if running_configuration == local_config:
                        logging.info('The running configuration is the same as the local configuration')
                    else:
                        logging.warning('The running configuration does not match the local configuration: ')
                        show_differences(running_configuration, local_config)
                else:
                    logging.error('Failed to access configurations')

            except FileNotFoundError:
                logging.error(f'The local configurations file, ({local_config_file_name}), could not be found')

    except Exception as e:
        logging.error(f'An error occurred: {e}')

#Ending connection

    logging.info('The connection has concluded')
    net_connect.disconnect()
    
if __name__ == "__main__":
    main()

Incase its easier, this is the link to code on github - https://github.com/louisw16/Programming-For-Networking-Engineers/blob/main/A3.py

2 Likes

It looks like there might be a couple of issues with your code that could be causing the timeout when connecting to the Cisco router remotely. Let’s address them one by one:

  1. Typo in Config Commands: In the loopback_config, there is a missing comma between ‘en\n’ and ‘conf t\n’. This might be causing the commands to be concatenated, resulting in a syntax error.
loopback_config = [
    'en\n',
    'conf t\n',
    'interface Loopback0\n',
    'ip address 192.168.57.101 255.255.255.0\n',
    'exit\n'
]

  1. Undefined Variable net_connect: You are correct in suspecting that the net_connect.disconnect() line might be causing issues. If an exception occurs before the with ConnectHandler(**device) as net_connect block, net_connect will be undefined. You should move the net_connect definition outside the with block, so you can still access it later.
net_connect = ConnectHandler(**device)
try:
    with net_connect as connection:
        # rest of the code
except Exception as e:
    logging.error(f'An error occurred: {e}')
finally:
    logging.info('The connection has concluded')
    net_connect.disconnect()

  1. Logging Configuration: The logging.basicConfig(level=logging.INFO) statement sets the logging level to INFO globally. It might be helpful to set the logging level to DEBUG temporarily to get more detailed information about the issue.
logging.basicConfig(level=logging.DEBUG)

After making these changes, run your code again and see if the issues persist. If the problem continues, you might want to check the router’s configuration and verify if the commands sent remotely are correct and well-formed. Additionally, consider checking the Netlab environment for any specific requirements or restrictions that might be affecting your remote connection.

1 Like