Cisco config backup via SSH

From Daco.tech Technical Documentation

This Python script will backup the running config of a Cisco device

Usage: Please provide a credentials.txt file, with your login/password, formatted like this:

login
password

Please also provide an ip_list.txt file formatted like this:

192.168.1.1
192.168.1.2
...

Code:

#!/usr/bin/env python
 
# Application to download the running-config from Cisco devices, using SSH
# Please provide a credentials.txt and a ip_list.txt files
# Usage:
 
 
import paramiko
import time
import sys
import re
 
 
def open_ssh_connection(ip):
    try:
        # Credentials
        #credentials_file = sys.argv[1]
        credentials_file = ('credentials.txt')
 
        # Read SSH credentials
        # .txt file must be formatted line by line, like this:
        # username
        # password
        credentials = []
        with open(credentials_file, 'r') as f:
            for line in f:
                line = line.rstrip()
                credentials.append(line)
 
        username, password = credentials[:]
 
 
        # Log into device
        session = paramiko.SSHClient()
 
        # Add device key
        session.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 
        # Important: If you have a key saved in your user's .ssh/ folder, paramiko will attempt to use this
        # key by default. We want to avoid this.
        # From my experience, using allow_agent=False will solve this problem (Paramiko will use the password method and ignore the local keys)
        # There's also the option look_for_keys=False , but that option alone didn't work for me.
        #
        session.connect(ip, username=username, password=password, allow_agent=False)
 
        # Following code could be useful for debugging connection problems on legacy Cisco IOS (12.x)
        # Found on http://stackoverflow.com/questions/31298529/python-paramiko-determine-what-ciphers-and-key-exchange-algorithms-are-availab
        # Legacy Cisco IOS uses obsolete diffie-hellman key exchange
        # These options must be allowed on your local client:
        # In your ~/.ssh/config file,
        # Add lines like this for each host:
        # Host 192.168.2.101
        #    KexAlgorithms +diffie-hellman-group1-sha1
 
        print "Supported key exchange methods on device:"
        print session.get_transport().get_security_options().kex, '\n'
 
        connection = session.invoke_shell()
 
        # Let's try to extract the device hostname, and remove the last character (#)
        # Result should a simple alphanumeric string, with or without hyphens and underscores, and without any newlines chars
        hostname = connection.recv(65535)
        hostname = re.search('[a-zA-Z0-9_-]+', hostname)
        if hostname:
            hostname = hostname.group()
        # print hostname
 
        # disable pagination:
        connection.send('Terminal length 0\n')
        time.sleep(1)
 
        # Let's do a show run and save it in a variable:
        connection.send('show run\n')
        time.sleep(1)
        output = connection.recv(65535)
        #print output
 
        # Let's save this output in a .txt file, using the hostname:
        with open(hostname + '.txt', 'w') as f:
            f.write(output)
            if f:
                print '###########################'
                print '%s running-config saved.' %hostname
                print '###########################\n'
 
 
 
    except paramiko.ssh_exception.NoValidConnectionsError:
       print 'Could not connect to target device. Make sure SSH is enabled.\n'
    except paramiko.AuthenticationException:
       print 'SSH connection error. Please check your credentials.\n'
    except paramiko.ssh_exception.SSHException:
       print 'SSH connection error. Is SSH allowed on the device?\n'
    # Put the IOError last, because it's a parent of all the previous errors, and we don't want it to catch everything.
    except IOError:
       print 'Input/output error. Make sure credentials.txt file exists.'
       print 'Check permissions for said file.\n'
 
def parse_ip_list():
    # This function goes through an ip_list.txt file, line by line.
    # Make sure file exists and is formatted like this:
    # 192.168.2.101
    # 192.168.2.102
    # ...
    try:
        with open('ip_list.txt', 'r') as f:
            for line in f:
                line = line.rstrip()
                if len(line) > 0:
                    print "Connecting to %s\n" %line
                    open_ssh_connection(line)
                elif len(line) == 0:
                    print 'Test: zero length line detected'
    except IOError:
        print 'Input/output error. Make sure ip_list.txt file exists.'
        print 'Check permissions for said file.'
 
parse_ip_list()