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

I've a script which establishes a SSH connection and execute few bash commands. All these activities are getting logged in a log file. I'm using Net::Telnet to achieve the same. The script is working fine on Fedora 20, however if I run the same script of CentOS 7.5, it is running into a issue where it is unable to log the command sent to a file. Could you please take a look and let me know what went wrong and how to fix it. Please find the code snipped below-
#!/usr/bin/perl use strict; use warnings; use api::Telnet; use Data::Dumper; my $host_prompt = '/[\$%#>] $/'; my $owner = &open_pty ( user_name => "root", user_pswd => "a", ip_addr => "127.0.0.1", prompt => $host_prompt, log_file => 'Log/Owner', dump_log => 'Log/dump_log', # input_log => 'Log/input_log', ); my @output = $owner->cmd ( String => "date", Prompt => $host_prompt ); print "Output is @output\n";
open_pty function definition -
package api::Telnet; use strict; use warnings; use Net::Telnet; use Exporter; use Carp; our @ISA = qw (Exporter); our @EXPORT = qw ( &open_pty &close_pty ); # Constant global variables use constant SSH_TIMEOUT => 1800; sub spwan_pty { my (@cmd) = @_; my ($pid, $tty, $tty_fd); # Create a new pseudo terminal use IO::Pty (); my $pty = new IO::Pty or die $!; # Execute the program in another process # Child process unless ($pid = fork) { die "problem spawning program: $!\n" unless defined $pid; # Disassociate process from existing controlling terminal use POSIX (); POSIX::setsid or die "setsid failed: $!"; # Associate process with new controlling terminal $pty->make_slave_controlling_terminal; $pty->set_raw(); $tty = $pty->slave(); $tty_fd = $tty->fileno; close $pty; # Make stdio use the new controlling terminal open STDIN, "<&$tty_fd" or die $!; open STDOUT, ">&$tty_fd" or die $!; open STDERR, ">&STDOUT" or die $!; close $tty; exec @cmd or die "problem executing $cmd[0]\n"; } # end child process $pty; } sub open_pty { my (%args) = @_; # Start ssh program. my $pty = &spwan_pty("ssh", "-l", $args{user_name}, "-e", "none", "-F", "/dev/null", "-o", "PreferredAuthentications=password", "-o", "NumberOfPasswordPrompts=1", "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", $args{ip_addr} ); # Create a Net::Telnet object to perform I/0 on ssh's tty my $ssh = new Net::Telnet ( -fhopen => $pty, -prompt => $args{prompt}, -telnetmode => 0, -cmd_remove_mode => 1, -timeout => SSH_TIMEOUT, -output_record_separator => "\r", #-errmode => sub { print "Telnet FAIL\n"; } ); # Wait for the password prompt and send password. $ssh->waitfor(-match => '/password: ?$/i', -errmode => "return") or die "problem connecting to \"$args{ip_addr}\": ", $ssh->las +tline; $ssh->print($args{user_pswd}); # Wait for the shell prompt. my (undef, $match) = $ssh->waitfor( -match => $ssh->prompt, -match => '/^Permission denied/m', -errmode => "return" ) or return $ssh->error("login failed: expected shell prompt ", "d +oesn't match actual\n"); return $ssh->error("login failed: bad login-name or password\n") i +f $match =~ /^Permission denied/m; # logging $ssh->input_log($args{log_file}); $ssh->cmd("ifconfig"); $ssh->cmd("date"); return $ssh; } sub close_pty { my ($tty) = shift; $tty->close(); } 1;
Log File (Owner) when execute on Fedora 20
[root@n3fips-346 ~]# date Wed Jul 3 14:33:03 IST 2019
Dump Log when executed on Fedora 20
< 0x00000: 5b 72 6f 6f 74 40 6e 33 66 69 70 73 2d 33 34 36 [root@n +3fips-346 < 0x00010: 20 7e 5d 23 20 ~]# > 0x00000: 64 61 74 65 0d date. < 0x00000: 64 61 74 65 0d 0a date.. < 0x00000: 57 65 64 20 4a 75 6c 20 20 33 20 31 34 3a 33 33 Wed Jul + 3 14:33 < 0x00010: 3a 30 33 20 49 53 54 20 32 30 31 39 0d 0a :03 IST + 2019.. < 0x00000: 1b 5d 30 3b 72 6f 6f 74 40 6e 33 66 69 70 73 2d .]0;roo +t@n3fips- < 0x00010: 33 34 36 3a 7e 07 346:~. < 0x00000: 5b 72 6f 6f 74 40 6e 33 66 69 70 73 2d 33 34 36 [root@n +3fips-346 < 0x00010: 20 7e 5d 23 20 ~]#
Log File (Owner) when executed on CentOS 7.5
[root@hyd1658 ~]# Wed Jul 3 14:39:47 IST 2019
Dump log when executed on CentOS
< 0x00000: 5b 72 6f 6f 74 40 68 79 64 31 36 35 38 20 7e 5d [root@h +yd1658 ~] < 0x00010: 23 20 # > 0x00000: 64 61 74 65 0d date. < 0x00000: 57 65 64 20 4a 75 6c 20 20 33 20 31 34 3a 33 39 Wed Jul + 3 14:39 < 0x00010: 3a 34 37 20 49 53 54 20 32 30 31 39 0a :47 IST + 2019. < 0x00000: 1b 5d 30 3b 72 6f 6f 74 40 68 79 64 31 36 35 38 .]0;roo +t@hyd1658 < 0x00010: 3a 7e 07 :~. < 0x00000: 5b 72 6f 6f 74 40 68 79 64 31 36 35 38 20 7e 5d [root@h +yd1658 ~] < 0x00010: 23 20 #
  • Comment on Command sent via Net::Telnet is not getting logged in CentOS. However, the same is getting logged in Fedora 20
  • Select or Download Code

Replies are listed 'Best First'.
Re: Command sent via Net::Telnet is not getting logged in CentOS. However, the same is getting logged in Fedora 20
by hippo (Archbishop) on Jul 03, 2019 at 10:12 UTC

    Unfortunately your code as posted does not compile:

    $ perl -I. -cw 11102335.pl Global symbol "$host_prompt" requires explicit package name at 1110233 +5.pl line 14. Global symbol "$host_prompt" requires explicit package name at 1110233 +5.pl line 20. 11102335.pl had compilation errors.

    Without digging further, the value of $host_prompt might be key to your problem as described, but we can't tell that for sure if you don't provide an SSCCE.

      I missed uncommenting $host_prompt variable. Could you please set $host_prompt as-
      my $host_prompt = '/[\$%#>] $/';
Re: Command sent via Net::Telnet is not getting logged in CentOS. However, the same is getting logged in Fedora 20
by VinsWorldcom (Prior) on Jul 03, 2019 at 11:06 UTC

    From the difference in dumps provided, it's pretty clear the command isn't getting echoed back so the first place I'd look is Net::Telnet->cmd_remove_mode(). While this may (or may not) be needed on one system (i.e., Fedora) it may (or may not) be needed on another (i.e., CentOS). I've seen quirks on Cisco routers where different modes / prompts need to be set to let Net::Telnet::Cisco work with them.

      You're right. command_remove_mode does have an impact. For instance on CentOS at the time of initialization Net::Telnet object, if I'm setting cmd_remove_mode as 0, then I'm able to get command output without command. Here are the logs for the same
      my $ssh = new Net::Telnet ( -fhopen => $pty, -prompt => $args{prompt}, -telnetmode => 0, -cmd_remove_mode => 1, -timeout => SSH_TIMEOUT, -output_record_separator => "\r", #-errmode => sub { print "Telnet FAIL\n"; } ); Output of script execution [root@hyd1658 attribute_template]# perl test_centos.pl output is Thu Jul 4 11:18:18 IST 2019 [root@hyd1658 ~]
      However, if I set cmd_remove_mode as 1 then the output is getting choped. Here are the logs-
      my $ssh = new Net::Telnet ( -fhopen => $pty, -prompt => $args{prompt}, -telnetmode => 0, -cmd_remove_mode => 1, -timeout => SSH_TIMEOUT, -output_record_separator => "\r", #-errmode => sub { print "Telnet FAIL\n"; } ); Output of script execution [root@hyd1658 attribute_template]# perl test_centos.pl output is [root@hyd1658 ~]
      This(chopping of 1 line of output) does make sense from the following piece of code of Net::Telnet
      sub cmd { . . . ## Determine if we should remove the first line of output based ## on the assumption that it's an echoed back command. if ($cmd_remove_mode eq "auto") { ## See if remote side told us they'd echo. $telopt_echo = $self->option_state(&TELOPT_ECHO); $remove_echo = $telopt_echo->{remote_enabled}; } else { # user explicitly told us how many lines to remove. $remove_echo = $cmd_remove_mode; } ## Get rid of possible echo back command. while ($remove_echo--) { shift @$output; } . . .
      But in either case, the command sent should have been echoed in the output, which in this case is not happening. Do you have any suggestion on what could be its root cause or what piece of code is responsible for this.
Re: Command sent via Net::Telnet is not getting logged in CentOS. However, the same is getting logged in Fedora 20
by Anonymous Monk on Jul 03, 2019 at 09:39 UTC
    looks like you reinvented Net::OpenSSH, just use that instead
      Thanks, but unfortunately it might not be possible for me; as I've a fully fledged automation framework which uses this