fasteddye has asked for the wisdom of the Perl Monks concerning the following question:

When this script is triggered to run, its function is to login to our Cisco dialup router, make a dial up call to a remote router modem, login to the remote router, run some Cisco commands, and then send an XML formatted email to our ticketing system including the output from the commands it runs. Problem we are running into is if the Cisco dialup router does not make a successful connection to the far end router modem, the script does not send the email to our ticketing system. It seems the script must hang or just not complete at that point. If a success modem connection is made with the far end modem the script completes and the email is sent to ticketing system. This inherieted perl code and the original author is no longer reachable. This is section that makes the connection to the dialer and then makes the call to the far end modem. It seems that if it hits the timeout value in the if eval statement it does not proceed.

if ( $intcount>0 && $circid[0] ne "Not Defined" && $modemnumber ne "No +t Defined" && $modemdown eq "0") { #Create the connection to the NAS $session = Net::Telnet::Cisco->new(Host => $nashost, Port => $nasp +ort, Input_log => $logfile, Dump_Log => $dumpfile); # Login to the NAS and dial the OOB modem $session->waitfor('/Username:.*$/'); $session->print($nasuser); $session->waitfor('/Password:.*$/'); $session->print($naspass); $session->waitfor('/^$/'); $session->print("ATZ"); dial: if ($session->waitfor('/OK$/')) { $session->print("ATDT 91".$modemnumber); # Check for a connected status if (eval { $session->Net::Telnet::waitfor(Match => '/Username: +.*$/', Timeout => '60', Errmode => 'die'); 1 }) { if ($session->login(Name => $nasuser, Password => $naspass +)) { @command1 = "Interface Commands Output"; my $i = 0; while ($ifname[$i]) { push(@command1,("\n\n$caption>sh int $ifname[$i]\n +")); push(@command1,$session->cmd("sh int $ifname[$i]") +); $i++; } @command2 = "Routing Commands Output"; if ($wan eq "PIP") { push(@command2,("\n\n$caption>sh ip route\n")); push(@command2,$session->cmd("sh ip route")); push(@command2,("\n\n$caption>sh bgp summary\n")); push(@command2,$session->cmd("sh bgp summary")); push(@command2,("\n\n$caption>sh bgp\n")); push(@command2,$session->cmd("sh bgp")); } else { push(@command2,("\n\n$caption>sh ip route\n")); push(@command2,$session->cmd("sh ip route")); push(@command2,("\n\n$caption>sh ip ospf\n")); push(@command2,$session->cmd("sh ip ospf")); push(@command2,("\n\n$caption>sh ip ospf neigh\n") +); push(@command2,$session->cmd("sh ip ospf neigh")); } $session->close; $dialfailed = 0; } } } }

I can include more of the script if helpful, I just did not want to assume and paste the entire script (about 350 lines). Thanks in advance.

Replies are listed 'Best First'.
Re: If unsuccessful action (updated)
by 1nickt (Canon) on Apr 03, 2020 at 20:23 UTC

    Hi,

    " It seems that if it hits the timeout value in the if eval statement it does not proceed"

    Well, it does nothing further in the outer if block shown ... impossible to see from what you posted what happens after it. The behaviour is apparently by design because essentially the block says:

    if ( $outer_cond ) { if ( eval { func(); 1 } ) { do_something(); } }

    I would start by adding an else block to the inner if block and printing some debugging from there if hit. It would be most helpful to print the error message if present; you could just use:

    else { say "ERR $@"; }
    ... but I would replace the eval with Try::Tiny as it's so easy to do and so much better. Something like:
    use Try::Tiny; if ( $outer_cond ) { my $ok = try { func(); 1; # not needed if func() returns something on success } catch { say "ERR $_"; 0; }; $ok ? do_something() : do_something_different(); }

    Hope this helps!

    updated: to show better program flow


    The way forward always starts with a minimal test.
      Thanks for the reply and suggestions. I have been trying to figure out a way to get some more debugging and I like the start by adding an ELSE block to the inner IF block. would I only need to add the listed ELSE say ERR suggestion or would there be some more additional syntax?

        Hi again,

        It's of course up to you how you debug. I showed the simplest pseudo action I could, as an example. But note that say is only available in Perl version >= 5.10 (and must be imported with use feature 'say'; or use 5.010;. It's the equivalent of print "$str\n";).

        Since you are starting a big ex post facto debugging project, you might like to begin to implement a logging system (using Log::Any) so that once you've fixed your issues you can run at a higher log level and the log statements you entered to debug will be ignored, but still there for future use (and could use different output adapters in production than in beta/testing, for example). That's what I would do.

        For a more quick-and-dirty tool while really debugging, where you aren't going to want to keep the statement, there's a newly updated module XXX by the mad genius Ingy döt Net I noticed recently that might be helpful.

        Hope this helps!


        The way forward always starts with a minimal test.
Re: If unsuccessful action
by bliako (Abbot) on Apr 04, 2020 at 08:01 UTC

    or something more concrete along the lines of 1nickt's suggestion (untested of course):

    } else { print "login failed\n" } } else { print "eval failed: $@\n" } #<<< EDIT: eval's error i +n $@ (and not in $_) } else { print "waifor failed\n" } } else { print "$intcount>0 etc false\n" }