cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
6053
Views
0
Helpful
32
Replies

Asynchronous TCL Scripting

mmoles001
Level 1
Level 1

I am trying to write some Asynchronous TCL code to make things more efficent.   This is just a simple example, but in reality it will SSH into a device, run a command, do some math, and write the output to the switch.

The whole "after" thing is throwing me off.  When i run it locally trough tclsh86 , i need to run the "update" command to follow up with the results.   How and what do i need to do to get this to work?

#***************************************CODE**********************************************************

::cisco::eem::event_register_timer watchdog time 15 maxrun 15

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*

proc checkDevice { interface tempName aNumber waitTime} {

puts "  "

puts "$tempName - Start"

after $waitTime

puts "$tempName - After"

if [catch {cli_write $interface "event manager environment tempName $aNumber"} _cli_result] {

error $_cli_result $errorInfo

}

puts "$tempName - EXIT"

}

if [catch {cli_open} result] {

error $result $errorInfo

} else {

array set cli1 $result

}

if [catch {cli_exec $cli1(fd) "enable"} _cli_result] {

error $_cli_result $errorInfo

}

after 0 checkDevice $cli1(fd) A 11 1000

after 0 checkDevice $cli1(fd) B 22 200

after 0 checkDevice $cli1(fd) C 33 4000

after 0 checkDevice $cli1(fd) D 44 1000

if [catch {cli_exec $cli1(fd) "exit"} _cli_result] {

error $_cli_result $errorInfo

}

catch {cli_close $cli1(fd) $cli1(tty_id)} result

32 Replies 32

Post your full script as an attachment (not pasted in line).  You still have a typo somewhere.

I had to re-add the poll_timer thing otherwise it would error out right away saying that exiting is never set and would run indefinetly.   In the prior config with the recursion instead of the while loop, it did not have that problem.

::cisco::eem::event_register_timer watchdog time 20 maxrun 20

namespace import ::cisco::eem::*

namespace import ::cisco::lib::*

set exiting 0

set poll_timer 10

set poll_q {}

proc checkDevice { interface tempName aNumber waitTime} {   

    puts "$tempName - Start"

    after $waitTime procDevice $interface $tempName $aNumber $waitTime

}

proc procDevice { interface tempName aNumber waitTime } {

    puts "$tempName"

    while{1} {

        global poll_q

        puts "$tempName $tempName $tempName"

        if [catch {cli_exec $interface "#ping 1.1.4.1 size 15000  repeat $waitTime"} _cli_result] {

            error $_cli_result $errorInfo

        }

    }

    puts "This shouldnt appear"

#after $waitTime procDevice $interface $tempName $aNumber $waitTime

}

proc check_q { } {

    global poll_timer poll_q exiting

    if { $poll_q != "" } {

        puts "Q : $poll_q"

        if { $poll_q == "DIE" } {

            set exiting 1

        }

        set poll_q {}

    }

    after $poll_timer {::check_q}

}

puts "Start"

if [catch {cli_open} result] {

    error $result $errorInfo

} else {

    array set cli1 $result

}

if [catch {cli_exec $cli1(fd) "enable"} _cli_result] {

    error $_cli_result $errorInfo

}

#if [catch {cli_exec $cli1(fd) "config t"} _cli_result] {

#    error $_cli_result $errorInfo

#}

puts "Before"

after 0 procDevice $cli1(fd) A 111 100

after 0 procDevice $cli1(fd) B 222 20

after 0 procDevice $cli1(fd) C 333 400

after 0 procDevice $cli1(fd) D 444 100

puts "After"

after $poll_timer {::check_q}

puts "After Timer"

vwait exiting

puts "After vwait"

if [catch {cli_exec $cli1(fd) "exit"} _cli_result] {

    error $_cli_result $errorInfo

}

catch {cli_close $cli1(fd) $cli1(tty_id)} result

Message was edited by: Michael Moles  - removed excess tab.

Can you attach this as a file using the advanced editor?

Here is the file as requested.

Try this version.         

Note, because of the "while" loop, you will only see this run for A, but it should run.

Nope, its actually only going trough A.  I set A and B to 1 PC, and C and D are on different PCs.  It is interesting it doesnt error out and blow up at the end though.   I guess the if you commented out was the culpret.

I cleared the counters on the switch and tested it out.

3560_Switch2#show int g 0/5 | inc packets [i|o]

     1 packets input, 64 bytes, 0 no buffer

     15 packets output, 1050 bytes, 0 underruns

3560_Switch2#show int G 0/6 | inc packets [i|o]

     1 packets input, 64 bytes, 0 no buffer

     15 packets output, 1050 bytes, 0 underruns

3560_Switch2#show int G 0/7 | inc packets [i|o]

     5112 packets input, 6575736 bytes, 0 no buffer

     4700 packets output, 6560534 bytes, 0 underruns

Mar 30 02:44:00.738: %HA_EM-6-LOG: SSHTest3.tcl: Start

Mar 30 02:44:01.084: %HA_EM-6-LOG: SSHTest3.tcl: Before

Mar 30 02:44:01.084: %HA_EM-6-LOG: SSHTest3.tcl: After

Mar 30 02:44:01.084: %HA_EM-6-LOG: SSHTest3.tcl: After Timer

Mar 30 02:44:01.084: %HA_EM-6-LOG: SSHTest3.tcl: A

Mar 30 02:44:01.084: %HA_EM-6-LOG: SSHTest3.tcl: A A A

Mar 30 02:44:03.999: %HA_EM-6-LOG: SSHTest3.tcl: A A A

Mar 30 02:44:06.788: %HA_EM-6-LOG: SSHTest3.tcl: A A A

Mar 30 02:44:09.824: %HA_EM-6-LOG: SSHTest3.tcl: A A A

Mar 30 02:44:13.106: %HA_EM-6-LOG: SSHTest3.tcl: A A A

Mar 30 02:44:17.924: %HA_EM-6-LOG: SSHTest3.tcl: A A A

Mar 30 02:44:19.581: %HA_EM-6-LOG: SSHTest3.tcl: After vwait

Yes.  As I said in my follow-up reply, because you are using a while loop, only A will run.  If you go back to using the after, you will get iterations for all of your instances.

I believe this will give you what you want.

I made a couple changes and put back in my ping because the delay is more inline on what im trying to do.   When I run my status command on the device it will take a second or so.  Use the after as the only delay could and does make it act differently.

Its failing hard again... i guess it wasnt the exit from before.   Should i just remove the close considering this should never stop running?

Mar 30 03:15:58.232: %HA_EM-6-LOG: SSHTest4.tcl: Start

Mar 30 03:15:58.568: %HA_EM-6-LOG: SSHTest4.tcl: Before

Mar 30 03:15:58.568: %HA_EM-6-LOG: SSHTest4.tcl: After

Mar 30 03:15:58.568: %HA_EM-6-LOG: SSHTest4.tcl: After Timer

Mar 30 03:15:58.568: %HA_EM-6-LOG: SSHTest4.tcl: A A A

Mar 30 03:16:03.407: %HA_EM-6-LOG: SSHTest4.tcl: B B B

Mar 30 03:16:04.230: %HA_EM-6-LOG: SSHTest4.tcl: C C C

Mar 30 03:16:14.716: %HA_EM-6-LOG: SSHTest4.tcl: D D D

Mar 30 03:16:17.107: %HA_EM-6-LOG: SSHTest4.tcl: After vwait

Mar 30 03:16:17.107: %HA_EM-6-LOG: SSHTest4.tcl: Process Forced Exit- MAXRUN timer expired.

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:     while executing

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: "catch {cli_close $cli1(fd) $cli1(tty_id)} result"

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:     invoked from within

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: "$slave eval $Contents"

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:     (procedure "eval_script" line 7)

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:     invoked from within

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: "eval_script slave $scriptname"

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:     invoked from within

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: "if {$security_level == 1} {       #untrusted script

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:      interp create -safe slave

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:      interp share {} stdin slave

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:      interp share {} stdout slave

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: ..."

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl:     (file "tmpsys:/lib/tcl/base.tcl" line 50)

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: Tcl policy execute failed:

Mar 30 03:16:17.112: %HA_EM-6-LOG: SSHTest4.tcl: Process Forced Exit- MAXRUN timer expired.

The constant reply seems to have chopped the text space a bunch by now... Here is a repost from above.  (couldnt see a way to fix the one above)

Mar 30 03:16:18.360: %HA_EM-6-LOG: SSHTest4.tcl: Start

Mar 30 03:16:18.800: %HA_EM-6-LOG: SSHTest4.tcl: Before

Mar 30 03:16:18.800: %HA_EM-6-LOG: SSHTest4.tcl: After

Mar 30 03:16:18.800: %HA_EM-6-LOG: SSHTest4.tcl: After Timer

Mar 30 03:16:18.800: %HA_EM-6-LOG: SSHTest4.tcl: A A A

Mar 30 03:16:21.605: %HA_EM-6-LOG: SSHTest4.tcl: B B B

Mar 30 03:16:22.344: %HA_EM-6-LOG: SSHTest4.tcl: C C C

Mar 30 03:16:33.223: %HA_EM-6-LOG: SSHTest4.tcl: D D D

Mar 30 03:16:35.913: %HA_EM-6-LOG: SSHTest4.tcl: A A A

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: After vwait

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: Process Forced Exit- MAXRUN timer expired.

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:     while executing

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: "catch {cli_close $cli1(fd) $cli1(tty_id)} result"

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:     invoked from within

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: "$slave eval $Contents"

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:     (procedure "eval_script" line 7)

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:     invoked from within

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: "eval_script slave $scriptname"

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:     invoked from within

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: "if {$security_level == 1} {       #untrusted script

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:      interp create -safe slave

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:      interp share {} stdin slave

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:      interp share {} stdout slave

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: ..."

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl:     (file "tmpsys:/lib/tcl/base.tcl" line 50)

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: Tcl policy execute failed:

Mar 30 03:16:37.197: %HA_EM-6-LOG: SSHTest4.tcl: Process Forced Exit- MAXRUN timer expired.

It appears to be working.  The MAXRUN termination is expected since your maxrun is so low.  The "close" is not the problem.  The problem is you need to increase your maxrun to allow the policy to run longer.  Increase it to 120, and you should see the policy live for two minutes before encountering the same forcible termination.

If you look at the timestamps you can see that they are running one after another and not parallel.   A and B should be firing off multiple times before C completes.   The message fires off before the ping command goes off, so  D waited 15 seconds before even starting.

I'm not sure what script you're using now, but each invocation has different wait times (and thus different delays if you're using that ping).  And remember, the next one doesn't start until the first one completes.  You don't have different threads here.  You're essentially scheduling four things to run asynchronously from the invocation, but in series.  You're adding them to the wait loop, but that is still a single loop.

I was just about to give up... BUT i think i have an idea.

The reason why my code will run slow is that i am waiting for the output.   So, what if i did cli_write instead of exec?

Each device will be on a seperate interface.  So, if I do a write, i could just push the command to all of them at the same time.  Then i could do a cli_read_pattern to read the data back.   Is this possible, or does the read need to start before the output starts?

If not, do you think its even possible to acomplish this with a single tcl script?

Review Cisco Networking for a $25 gift card