Welcome to the VanDyke Software Forums

Join the discussion today!


Go Back   VanDyke Software Forums > Scripting

Notices

Reply
 
Thread Tools Rate Thread Display Modes
  #1  
Old 05-26-2016, 05:23 PM
andymc andymc is offline
Registered User
 
Join Date: Sep 2015
Posts: 14
crt.session.disconnect hangs

hi,

Version 7.2.5 (x64 build 550) - Official Release - June 5, 2014


my scripts connect to X amount of devices, run some commands, get the output, write to file, simple.

I will either connect to Cisco router or Adtran Modem.

For some reason when i connect to certain Adtran's my script crashes, but i can connect to other Atrans fine ???

my code - see my comment :: # THIS IS WHERE THE CODE HANGS
Any ideas would be greatly appreciated

Code:
# $language = "python"
# $interface = "1.0"
import re

user1 = "xxx"
passwd1 = "xxx"

user2 = "xxx"
passwd2 = "xxx"

user3 = "xxx"
passwd3 = "xxx"

global objTab
objTab = crt.GetScriptTab()
	
def main():
	
	
	crt.Screen.Synchronous = True
	# Prepare the host file and XML Doc
	hosts = readHostsAndPrepareXMLfile()
	num = 0
	
	
	for each_node in hosts:
	
		
		# Try and conect to the current node 
		errcode = connector(each_node)
		finalString = ""
		
		if errcode == 0 : 								# We are connected 
				
			modem = GetTextLeftOfCursor()
			#crt.Dialog.MessageBox(str(modem))
			
			if "#" in modem:							# This means we are assuming we are not connected to a modem 

				# Do something that you are now connected to a Cisco device 

				num += 1
				
				if crt.Session.Connected: 
					crt.Session.Disconnect()						

			else:

				# Dont do anything becuase you are connected to a Modem

				num += 1
				
				if crt.Session.Connected: 				# THIS IS WHERE THE CODE HANGS 
					crt.Session.Disconnect()	
				
			
		elif errcode == 333 :							# Node down
		
			# Report back that the node timed out 

				if crt.Session.Connected: 
					crt.Session.Disconnect()
				
		elif errcode == 666 :							

			# Report back that we could not log in

				if crt.Session.Connected: 
					crt.Session.Disconnect()

	file = open('results.xml' , 'a')
	file.write("</results>\n")
	file.close()
	
	crt.Dialog.MessageBox("Thats me all done.")


def GetTextLeftOfCursor():
    global objTab
    nRow = objTab.Screen.CurrentRow
    nCol = objTab.Screen.CurrentColumn - 1
    strTextLeftOfCursor = objTab.Screen.Get(nRow, 1, nRow, nCol)
    return strTextLeftOfCursor	


def readHostsAndPrepareXMLfile():


	# Open the results.txt file and start writing the XML document 
	file = open('results.xml' , 'w')
	file.write("<?xml version=\"1.0\"?>\n")
	file.write("<results>\n")
	file.close()

	file = open('hosts.txt', 'r')
	hosts = file.readlines()
	file.close()	
	return hosts

def connector(each_node) :

	try:
		# Make sure we are not connected to anything before we try and connect to something
		if crt.Session.Connected: 
			crt.Session.Disconnect()

		# try and log in with the first credentials
		cmd = "/SSH2 /L %s /ACCEPTHOSTKEYS /PASSWORD %s /C 3DES /M SHA1 %s" % (user1, passwd1, each_node.rstrip())
		crt.Session.Connect(cmd, False)

		
		# look for string "Password authentication failed", for 5 seconds only, if we dont see it, then move on
		# if we see this string we should disconnect. This moves us on to the next try statement 
		if (crt.Screen.WaitForString("Password authentication failed", 5) == True):
			#crt.Dialog.MessageBox("Failed to detect login!")
			crt.Session.Disconnect()
		
		# If we managed to connect then Return, this stops us trying any more usernames and passwords
		if crt.Session.Connected:
			# We return the errcode 0, becuase this is the safe connection.
			return 0
		
	except ScriptError:
		# return 333, this can be picked up by the calling method, and we know the node is down.
		return 333

	
	try:
		if crt.Session.Connected: 
			crt.Session.Disconnect()

		cmd = "/SSH2 /L %s /ACCEPTHOSTKEYS /PASSWORD %s /C 3DES /M SHA1 %s" % (user2, passwd2, each_node.rstrip())
		crt.Session.Connect(cmd, False)

		if (crt.Screen.WaitForString("Password authentication failed", 5) == True):
			crt.Session.Disconnect()		
		
		if crt.Session.Connected: 
			return 0
		
	except ScriptError:
		return 333
		
	try:
		if crt.Session.Connected: 
			crt.Session.Disconnect()

		cmd = "/SSH2 /L %s /ACCEPTHOSTKEYS /PASSWORD %s /C 3DES /M SHA1 %s" % (user3, passwd3, each_node.rstrip())
		crt.Session.Connect(cmd, False)

		if (crt.Screen.WaitForString("Password authentication failed", 5) == True):
			crt.Session.Disconnect()		
		
		if crt.Session.Connected: 
			return 0
		
	except ScriptError:
		return 333

	# if we get here then all three passwords have been tried and the node is not down, we have a bigger issue at hand, call an engineer 
	return 666
		
main()

Last edited by andymc; 05-26-2016 at 05:27 PM.
Reply With Quote
  #2  
Old 05-26-2016, 06:53 PM
jdev's Avatar
jdev jdev is offline
VanDyke Technical Support
 
Join Date: Nov 2003
Location: Albuquerque, NM
Posts: 1,099
A crash is not a hang and a hang is not a crash.

A crash would mean you get an error or the script stops unexpectedly (Script -> Cancel is not enabled, meaning your script is no longer running), or SecureCRT crashes.

A hang would mean that your script continues to run (Script -> Cancel menu item is enabled and when you select it, SecureCRT cancels the script and tells you a line number associated with the time at which the cancel occurred).

Is your script "crashing" or is your script "hanging"?

One thing to note is that when running in a script, script execution goes MUCH faster than you would expect, and in comparison to when you do things manually you might not get what you expect if you don't account for this speed.

For instance, you are calling connector(each_node) to get connected to a node.

After that returns and errorcode == 0, you're assuming that there's going to be some text actually displayed to the screen. This is not always (rarely) going to be the case because your script may have executed so quickly that there hasn't been time for the remote system to even send data to SecureCRT for displaying to the screen, or SecureCRT might not have had the chance to actually display data received to the terminal screen. The script thread runs asynchronous to the SecureCRT application's screen display, so you have to be prepared to bring things into synch because of the speed of script execution.

The GetTextLeftOfCursor() function you're calling was written using Screen.Get(). However, because you've set Screen.Synchronous = True earlier on, text received won't get displayed to the screen until a Screen.WaitFor*() or a Screen.ReadString() call is made.

This mixture of using Screen.Synchronous = True, and crt.Screen.Get() calls can result in erratic, unreliable, and confusing behavior.

If you're going to use Screen.Get, you'll need to turn OFF Screen.Synchronous so that you can guarantee that data gets displayed to the Screen (so that you can "Get" it).

If you're going to use Screen.WaitFor*() and Screen.ReadString(), you'll need to make sure that crt.Screen.Synchronous = True before you crt.Screen.Send(command_that_generates_output_you_will_wait_for_or_read_until)

A technique to consider is to use the WaitForScreenContentsToStopChanging() example, which will wait for a specified number of milliseconds and check to see if new data has arrived to the screen (whilst Synchronous is off, by the way) and loop again with another wait if new data has arrived. This is typically done in situations where you need to have a good "starting" point... like after you first connect to a host.

Manually, when you first connect to a host, you see the shell prompt there, and your eyes send signals to your brain which (based on your experiences and training) helps you quickly recognize "Hey! I've got a shell prompt! I can move forward with sending commands, now!"

However, with scripting, you don't have the luxury of programming in an AI to perform that same recognition. So, you have to make some adjustments and dumb things down a bit in order to get to a least common denominator.

If you don't know before-hand what the shell prompt is going to look like, you should:
  • Connect
  • WaitForScreenContentsToStopChanging (this requires Screen.Synchronous to be off|False)
  • Then get text left of cursor. Put this into some var, like strPrompt
  • Then you have a shell prompt you can use for subsequent WaitFor*() and ReadString() calls to know when to stop so you...
  • crt.Screen.Synchronous = True
  • crt.Screen.Send(cmd + "\r")
  • crt.Screen.WaitForString(cmd + "\r") # 'cause we don't care to capture the command itself, just its output
  • strResults = crt.Screen.ReadString(strPrompt) # 'cause we're interested in the command output
  • etc...

We don't have a good python example yet of how to wait for the screen contents to stop changing, but there exists on in VBScript form and you can feel free to convert it as your expertise allows.

If time and resources allow, we'll post a follow-up with a python example...

--Jake
__________________
Jake Devenport
VanDyke Software
Technical Support
YouTube Channel: https://www.youtube.com/vandykesoftware
Email: support@vandyke.com
Web: https://www.vandyke.com/support
Reply With Quote
  #3  
Old 05-26-2016, 06:57 PM
jdev's Avatar
jdev jdev is offline
VanDyke Technical Support
 
Join Date: Nov 2003
Location: Albuquerque, NM
Posts: 1,099
Here's the VBScript form of WaitForScreenContentsToStopChanging()

Code:
' -----------------------------------------------------------------------------
Sub WaitForScreenContentsToStopChanging(nMsDataReceiveWindow)
    ' This function relies on new data received being different from the
    ' data that was already received.  It won't work if, as one example, you
    ' have a screenful of 'A's and more 'A's arrive (because one screen
    ' "capture" will look exactly like the previous screen "capture").
    Dim bOrig
    
    ' Store Synch flag for later restoration
    bOrig = crt.Screen.Synchronous
    ' Turn Synch off since speed is of the essence; we'll turn it back on (if
    ' it was already on) at the end of this function
    crt.Screen.Synchronous = False
    
    strLastScreen = crt.Screen.Get(1,1,crt.Screen.Rows,crt.Screen.Columns)
    Do
        crt.Sleep nMsDataReceiveWindow
        
        strNewScreen = crt.Screen.Get(1,1,crt.Screen.Rows, crt.Screen.Columns)
        If strNewScreen = strLastScreen Then Exit Do

        strLastScreen = strNewScreen
    Loop
    
    ' Restore the Synch setting
    crt.Screen.Synchronous = bOrig
End Sub
__________________
Jake Devenport
VanDyke Software
Technical Support
YouTube Channel: https://www.youtube.com/vandykesoftware
Email: support@vandyke.com
Web: https://www.vandyke.com/support
Reply With Quote
  #4  
Old 06-08-2016, 01:51 PM
jdev's Avatar
jdev jdev is offline
VanDyke Technical Support
 
Join Date: Nov 2003
Location: Albuquerque, NM
Posts: 1,099
Here is a python translation of the WaitForScreenContentsToStopChanging() example code:

Code:
#-----------------------------------------------------------------------------
def WaitForScreenContentsToStopChanging(nMsDataReceiveWindow):
    # This function relies on new data received being different from the
    # data that was already received.  It won't work if, as one example, you
    # have a screenful of 'A's and more 'A's arrive (because one screen
    # "capture" will look exactly like the previous screen "capture").
    
    # Store Synch flag for later restoration
    bOrig = crt.Screen.Synchronous
    # Turn Synch off since speed is of the essence; we'll turn it back on (if
    # it was already on) at the end of this function
    crt.Screen.Synchronous = False
    
    # Get a the text currently on the screen:
    strLastScreen = crt.Screen.Get(1,1,crt.Screen.Rows,crt.Screen.Columns)
    
    # Now, enter a loop cycling every nMsDataReceiveWindow milliseconds,
    # scraping the screen and comparing it to what was there last time
    # we checked... if it's the same, then no data has arrived w/in our
    # window of specified time, so we consider that the screen has stopped
    # changing.
    while True:
        crt.Sleep(nMsDataReceiveWindow)
        strNewScreen = crt.Screen.Get(1,1,crt.Screen.Rows, crt.Screen.Columns)
        if strNewScreen == strLastScreen:
            break
        else:
            strLastScreen = strNewScreen
    
    # Restore the Synch setting
    crt.Screen.Synchronous = bOrig
__________________
Jake Devenport
VanDyke Software
Technical Support
YouTube Channel: https://www.youtube.com/vandykesoftware
Email: support@vandyke.com
Web: https://www.vandyke.com/support
Reply With Quote
  #5  
Old 06-08-2016, 02:39 PM
jdev's Avatar
jdev jdev is offline
VanDyke Technical Support
 
Join Date: Nov 2003
Location: Albuquerque, NM
Posts: 1,099
Here's an example of it in use within a demo script:

Code:
import time

# WaitForScreenContentsToStopChanging.py
#   Last Modified:
#     03 Jun, 2016
#       - Initial revision
#
# Description:
# ---------------------------------------------------------------------
# Example of a "WaitForScreenContentsToStopChanging()" method used as one
# way to determine if there's any new data arriving from the remote within
# a specified window of milliseconds.
#
# The method protrayed in this example will work in situations where lines of
# data coming from the remote are each unique, or the data you're waiting to
# receive is the initial data received in the session and the number of lines
# of data you're waiting to recieve has fewer lines than the number of rows
# on the terminal screen.

MsgBox = crt.Dialog.MessageBox
InputBox = crt.Dialog.Prompt

nMsDataReceiveWindow = "250"

strCommandThatGeneratesOutput = "DIR [...]"

#-----------------------------------------------------------------------------
def WaitForScreenContentsToStopChanging(nMsDataReceiveWindow):
    # This function relies on new data received being different from the
    # data that was already received.  It won't work if, as one example, you
    # have a screenful of 'A's and more 'A's arrive (because one screen
    # "capture" will look exactly like the previous screen "capture").
    
    # Store Synch flag for later restoration
    bOrig = crt.Screen.Synchronous
    # Turn Synch off since speed is of the essence; we'll turn it back on (if
    # it was already on) at the end of this function
    crt.Screen.Synchronous = False
    
    # Get a the text currently on the screen:
    strLastScreen = crt.Screen.Get(1,1,crt.Screen.Rows,crt.Screen.Columns)
    
    # Now, enter a loop cycling every nMsDataReceiveWindow milliseconds,
    # scraping the screen and comparing it to what was there last time
    # we checked... if it's the same, then no data has arrived w/in our
    # window of specified time, so we consider that the screen has stopped
    # changing.
    while True:
        crt.Sleep(nMsDataReceiveWindow)
        strNewScreen = crt.Screen.Get(1,1,crt.Screen.Rows, crt.Screen.Columns)
        if strNewScreen == strLastScreen:
            break
        else:
            strLastScreen = strNewScreen
    
    # Restore the Synch setting
    crt.Screen.Synchronous = bOrig

#---------------------------------------------------------------------
def Main():
    global nMsDataReceiveWindow, strCommandThatGeneratesOutput
    
    while True:
        while True:
            nMsDataReceiveWindow = InputBox(
                "Enter the max number of milliseconds the script " + 
                "should wait for data to arrive before timing out and " +
                "considering the data ""stopped"".",
                "Specify Data Receive Interval (ms)",
                nMsDataReceiveWindow)
            if nMsDataReceiveWindow == "":
                return
                
            if not nMsDataReceiveWindow.isnumeric():
                MsgBox("Please specify a valid number")
            else:
                break # break out of inner prompt loop only
        
        while True:
            strCommandThatGeneratesOutput = InputBox(
                "Enter the command you wish to run on the remote.",
                "Specify Remote Command",
                strCommandThatGeneratesOutput)
            if strCommandThatGeneratesOutput == "":
                return
                
            nResult = MsgBox("Sure you want to run this?\n\n\t{0}".format(
                strCommandThatGeneratesOutput), "Confirm", 4)
            if nResult == 6:
                break
        
        # Send the command to the remote, and wait for the command to be echoed
        # back to us, including the CR that indicates the command has been
        # received AND is being acted upon.
        crt.Screen.Send(strCommandThatGeneratesOutput + "\r")
        crt.Screen.WaitForString(strCommandThatGeneratesOutput)
        crt.Screen.WaitForString("\r")
        
        # Capture some timing information
        nStartTime = time.time()
        
        WaitForScreenContentsToStopChanging(int(nMsDataReceiveWindow))
        nEndTime = time.time()
        nElapsed = round(nEndTime - nStartTime, 2)
        MsgBox(
            "Took: {0} seconds with a data receive window/interval of {1}ms.".format(
                nElapsed, nMsDataReceiveWindow) +
            "\n\nIf new text shows up in the terminal window after this, it " +
            "is a strong indication that your interval is too short.")

#---------------------------------------------------------------------
Main()
__________________
Jake Devenport
VanDyke Software
Technical Support
YouTube Channel: https://www.youtube.com/vandykesoftware
Email: support@vandyke.com
Web: https://www.vandyke.com/support
Reply With Quote
Reply

Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -6. The time now is 08:29 AM.