cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Announcements
35071
Views
15
Helpful
13
Replies
jszapipes
Beginner

Python to issue CLI commands over SSH

Hello,

I am attempting to create a Python script that will establish an SSH connection to and restart our CUCM servers. If I can get this working it will prevent me from having to sign on to 20 + servers and issue the command manually. The below script appears to partially work as it establishes an SSH connection, initiates a shell, and displays the MOTD banner while calling the script from Windows command prompt. However, the "utils system restart" command does not get executed and the process finishes with exit code 0. Can someone who is knowledgeable please take a look and tell me what I am missing? Thanks in advance.

Regards,

JP

import paramiko
import time

time.sleep(1)

ip = "10.x.x.x"
host = ip
username = "myusername"
password = "mypassword"

remote_conn_pre = paramiko.SSHClient()
remote_conn_pre
remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy())
remote_conn_pre.connect(ip, username=username, password=password, look_for_keys=False, allow_agent=False)
print("SSH connection established to " + host)

remote_conn = remote_conn_pre.invoke_shell()
print("Interactive SSH session established")

output = remote_conn.recv(1000)
print(output)

remote_conn.send("\n")
remote_conn.send("utils system restart\n")
time.sleep(5)

output = remote_conn.recv(5000)
print(output)



13 REPLIES 13
Joseph W. Doherty
Hall of Fame Expert

From Paramiko's FAQ:

Paramiko doesn’t work with my Cisco, Windows or other non-Unix system!

In an ideal world, the developers would love to support every possible target system. Unfortunately, volunteer development time and access to non-mainstream platforms are limited, meaning that we can only fully support standard OpenSSH implementations such as those found on the average Linux distribution (as well as on Mac OS X and *BSD.)

The problem might just be Windows.  It will be interesting to see if anyone does report a Python/Paramiko working setup on a Windows platform.

Personally, I was able to access Cisco CLI, via SSH, using Python (3.6) and Windows (7) while using PuTTY's plink program.  The tricky part was doing it interactively, and for that, I had to override Windows default queue buffering while "conversing" with plink.

aflores05
Beginner

Hi, my script is functional en cisco_ios, test and your CUCM.

 

They are two scrip, one executes the task other has to host list.

1.

import warnings
with warnings.catch_warnings(record=True) as w:
    import paramiko

import multiprocessing
from datetime import datetime

import sys
from getpass import getpass

import netmiko
from netmiko.ssh_exception import NetMikoTimeoutException, NetMikoAuthenticationException

# DEVICE_CREDS contains the devices to connect to
from DEVICE_CREDS import all_devices

def print_output(results):

    print "\nDevices:"
    for a_res in results:
        for identifier,v in a_res.iteritems():
            (success, out_string) = v['error']
            if success:
                print 'Device failed = {0}'.format(identifier)
                print '\n\tError: '.out_string
            else:
                print '\n'
                print '#' * 80
                print 'Device success = {0}\n'.format(identifier)
                for c,r in v['results'].iteritems():
                    print '\tCommand: ' +   c
                    print '\n\tResult: '+ r
                print '#' * 80

    print "\nEnd time: " + str(datetime.now())
    print

def worker_configuration(a_device, mp_queue):

    try:
        a_device['conf']['port']
    except KeyError:
        a_device['conf']['port'] = 22

    r_time = datetime.now()
    save_command = 'show running-config'
    identifier = '{ip}'.format(**a_device['conf'])
    return_data = {}

    SSHClass = netmiko.ssh_dispatcher(a_device['conf']['device_type'])

    try:
        #print 'Device: ' + a_device['conf']['device_type'];
        a_dev = a_device['conf']
        net_connect = SSHClass(**a_dev)
        return_data[identifier] = {}
        return_data[identifier]['results'] = {}
        #print '\nPrompt: ' + net_connect.find_prompt()
        for command in a_device['commands']:
            #print '\nCommand: ' + command
            result = net_connect.send_command(command)
            #print '\nResult: ' + result
            return_data[identifier]['results'][command] = result
            if command == save_command:
                f= open('/home/Firewalls-Backup/'+identifier+'.txt',"w+")
                f.write(result)
                f.close()
        return_data[identifier]['error'] = (False, 'Success')
        net_connect.disconnect()
    except (NetMikoTimeoutException, NetMikoAuthenticationException) as e:
        return_data[identifier]['error'] = (True, e)

        # Add data to the queue (for parent process)
        mp_queue.put(return_data)
        return None
    mp_queue.put(return_data)
def main():

    #user = raw_input("Enter Cisco user: ")
    #passwd =  getpass("Insert password: ")
    mp_queue = multiprocessing.Queue()
    processes = []

    print "\nStart time: " + str(datetime.now())

    for a_device in all_devices:
        #a_device['conf']['username']  = user
        #a_device['conf']['password'] =  passwd
        p = multiprocessing.Process(target=worker_configuration, args=(a_device, mp_queue))
        processes.append(p)
        # start the work process
        p.start()

    # wait until the child processes have completed
    for p in processes:
        p.join()

    # retrieve all the data from the queue
    results = []

    for p in processes:
        results.append(mp_queue.get())


    print_output(results)


if __name__ == '__main__':

    main()

2.

hostname1 ={
	'conf':{
	'device_type': 'cisco_ios',
	'ip': '1.1.1.2',
	'username': 'test',
	'password': 'test',
	'secret': 'secret',
	'verbose': False},
	'commands':['enable','pager 0','show run','pager 24','exit',]
}
hostname2 ={
	'conf':{
	'device_type': 'cisco_ios',
	'ip': '1.1.1.2',
	'username': 'test',
	'password': 'test',
	'secret': 'secret',
	'verbose': False},
	'commands':['enable','pager 0','show run','pager 24','exit',]
}
all_devices = [
hostname1,
hostname2,
]

I have test with 40 switch,  and it lasts less than 1 minute depending on the size of the configuration.

* have installed

python2.7 pip

pip install paramiko

pip install netmiko 

pip install ipaddress

pip install cryptography

pip install enum34

pip install cffi

 

Flavio Miranda
Advisor

Hi,

 This remainder me when I was writing a python script to access script to access Cisco WLC. I totally failed.

 The way I have found to overcome it was written my script in Expect.

 

 

derek.fraser
Beginner

Hi jszapipes,

 

Not sure if you found a solution but if you're not tied to using paramiko I was able to develop a script that reboots/restarts UC servers with pexpect from Dragan's info in the thread below.  I use this method with cron to schedule reboots, maint windows, etc.  Has been tested on 8.6 and 11.5 UC systems (CUCM, CUC, CCX, IMP).

 

https://supportforums.cisco.com/t5/ip-telephony/schedule-restart-of-cucm-service-in-cli-or-gui/td-p/1347232

 

 

I have a similar script that runs config commands using the tcl shell.  Hope this helps.

 

http://netscriptwiki.com/index.php?title=Configure_switch_interface,_display_before/after_config

 

https://asciinema.org/a/177308

 

-Mike

In order to send config commands on the cli you should probably invoke the tcl shell by first sending the tclsh command.  Then send the config commands in "" as such:

 

remote_conn.send("tclsh\r")
remote_conn.send('ios_config "int g0/1" "des LINK" "switchport mode access" "switc acce vla 375" "spanning-tree portf" "no shut" \r')
remote_conn.send("show run int g0/1\r")

zerocool443
Cisco Employee

My cli query on this case is show perf query counter "Cisco XCP CM"  "CmConnectedSockets"

 

The same quer works perfectly fine over the shell in imp node.

 

But fails to get the output here,

Try:

remote_conn.send("show perf query counter "Cisco XCP CM" "CmConnectedSockets" \r")
time.sleep(3)
output = remote_conn.recv(5000)
print output


remote_conn.send("show perf query counter "Cisco XCP CM" "CmConnectedSockets" \r")

I wonder if this would get interpreted correctly by python. 

 

My code editor already warns me of this. Check the attached file.

 

What i did was escape the " with \" . This works fine till the process of giving this command to shell. After that shell says this is an invalid command.

 

 

Any other tuts i can try to solve this.

 

 

Seb Rupik
VIP Advisor

Hi there,

When you execute the command utils system restart manually via the CLI does it ask you to confirm the action or return you back to the command prompt? Your problem could be two-fold, either it is waiting for you to send another newline char to proceed, or the current command prompt structure no longer looks like 'hostname#' and paramiko has hung.

 

cheers,

Seb.

I actually had a similar issue and gave up on paramiko and uses the PAWS API to do this.

I published the script if you go to the cisco code exchange and look search for PAWS it should come up.

Gregory Brunn
Collaborator

PCD is suppose to be able to do this now however check out this script I created one night

https://developer.cisco.com/codeexchange/github/repo/TinCanTango/PAWSRestartService

 

Not sure if this problem still exist for you... But this was my solution when paramiko wouldn't do what I wanted.