pyMultiChange and pyRouterLib Updates

I recently had a request to combine the SSH and TELNET functionality on my pyMultiChange scripts, as they share a lot of code. I thought that this was a reasonable request, so I started that process today.

First off, I updated the pyRouterLib to be more pep8 complaint. Once that was updated, I tossed the library into the pyMultiChange project, for consumption.

Currently, ‘telnet-multi.py’ and ‘ssh-multi.py’ are still available, but I plan on phasing them out, after I test ‘multi.py’ more.

Here is the code of the new ‘args’ library:

import argparse

hosts_file = ''
command_file = ''
protocol = 'ssh'
command_output = False
verbose = False


def default_args(hosts_file, command_file, protocol, command_output, verbose):
    parser = argparse.ArgumentParser(description='Managing Cisco routers/switches with Python')
    parser.add_argument('-d', '--hosts', help='Specifies a host file')
    parser.add_argument('-c', '--commands',  help='Specifies a commands file', required=True)
    parser.add_argument('-s', '--ssh', help='Default: Use the SSH protocol', nargs='?', const='ssh')
    parser.add_argument('-t', '--telnet', help='Use the Telnet protocol', nargs='?', const='telnet')
    parser.add_argument('-o', '--output', help='Be verbose with command output', nargs='?', const=True)
    parser.add_argument('-v', '--verbose', help='Debug script output', nargs='?', const=True)

    args = vars(parser.parse_args())

    if args['hosts']:
        hosts_file = args['hosts']
    if args['commands']:
        command_file = args['commands']
    if args['telnet']:
        protocol = 'telnet'
    if args['ssh']:
        protocol = 'ssh'
    if args['output']:
        command_output = args['output']
    if args['verbose']:
        verbose = args['verbose']

    return hosts_file, command_file, protocol, command_output, verbose

Next, Here is the combined functionality of the multi change script, called multi.py:

#!/usr/bin/env python

from lib.new_args import default_args
from lib.new_args import hosts_file
from lib.new_args import command_file
from lib.new_args import protocol
from lib.new_args import command_output
from lib.new_args import verbose
from lib.pyRouterLib import RouterLib

import os
import time
import sys

access_params = ''


def access(method):
    global access_params
    if method == 'ssh':
        access_params = access_method.use_ssh(host, RouterLib.username,
                                              RouterLib.password)
    elif method == 'telnet':
        access_params = access_method.use_telnet(host, RouterLib.username,
                                                 RouterLib.password)
    else:
        access_paams = ''
        return """
        You must use a proper connection method.
        Currently telnet and ssh are supported.
        """

    return method, access_params


if __name__ == '__main__':
    args = default_args(hosts_file, command_file, protocol, command_output,
                        verbose)
    hosts_file = args[0]
    command_file = args[1]
    protocol = args[2].lower()
    command_output = args[3]
    verbose = args[4]

    if not os.path.isfile(hosts_file):
        print "Error: Invalid Hosts File"
        exit(1)
    if not os.path.isfile(command_file):
        print "Error: Invalid Commands File"
        exit(1)
    if verbose is True:
        import logging
        logging.basicConfig(level=logging.DEBUG)
    access_method = RouterLib()
    hosts = open(hosts_file, 'r')
    if verbose is True:
        logging.debug(' Reading hosts file.')
    for host in hosts:
        host = host.strip()
        if verbose is True:
            logging.debug(' Reading %s from the hosts file.' % host)
        """
        Set up the connection using SSH (default) or Telnet.
        """
        if protocol == 'ssh':
            if verbose is True:
                logging.debug(' Attempting to access %s via SSH.' % host)
            try:
                if verbose is True:
                    logging.debug(' Establishing ssh connection to %s.' % host)
                access(method='ssh')
                access_cmd = access_params[-1]
                access_shell = access_cmd.invoke_shell()
                shell_output = access_shell.recv(1000)
                if '>' in shell_output:
                    if verbose is True:
                        logging.debug(' Entering enable credentials')
                    access_shell.send('enable\n')
                    time.sleep(1)
                    shell_output = access_shell.recv(1000)
                    if 'Password:' in shell_output:
                        access_shell.send(RouterLib.enable + '\n')
                        time.sleep(1)
                        shell_output = access_shell.recv(1000)
                        if '#' in shell_output:
                            if verbose is True:
                                logging.debug(' Successfully entered enable mode.')
                            access_shell.send('terminal length 0\n')
                            shell_output = access_shell.recv(1000)
                            if verbose is True:
                                logging.debug(' Setting an unlimited terminal buffer.')
                    else:
                        if verbose is True:
                            logging.debug(' Unable to enter enable mode.')
                elif '#' in shell_output:
                    access_shell.send('terminal length 0\n')
                    shell_output = access_shell.recv(1000)
                    if verbose is True:
                        logging.debug(' Setting an unlimited terminal buffer.')
            except:
                logging.debug(' SKIPPING: %s doesn\'t support SSH.' % host)
                exit(1)
        elif protocol == 'telnet':
            if verbose is True:
                logging.debug(' Attempting to access %s via Telnet.' % host)
            try:
                if verbose is True:
                    logging.debug(' Establishing telnet connection to %s.' % host)
                access(method='telnet')
                access_cmd = access_params[-1]
            except:
                logging.debug(' SKIPPING: %s doesn\'t support Telnet.' % host)
                exit(1)
        else:
            access(method='none')
        """
        Run through the commands in the commands files.
        """
        cmds = open(command_file, 'r')
        if verbose is True:
            logging.debug(' Reading the commands file.')
        for command in cmds:
            command = command.strip()
            if verbose is True:
                logging.debug(' Executing: %s' % command)
            if protocol == 'ssh':
                access_shell.send(command + '\n')
                time.sleep(2)
                shell_output = access_shell.recv(1000000)
                if command_output is True:
                    print shell_output
            if protocol == 'telnet':
                access_cmd.write(command + '\n')
                shell_output = access_cmd.read_until('#', 2)
                if verbose is True:
                    logging.debug(' Executing: %s' % command)
                if command_output is True:
                    print shell_output
        """
        Close the sessions and files.
        """
        access_cmd.close()
        if verbose is True:
            logging.debug(' Closing connection to %s.' % host)
        cmds.close()
        if verbose is True:
            logging.debug(' Closing commands file.')
    hosts.close()
    if verbose is True:
        logging.debug(' Closing hosts file.')

Feel free to fork it, make changes, and submit pull requests to either project. I welcome any feedback!