filter log/ filenames into sw.command
[dell-switch] / dell-switch.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5
6 # example usage as pipe:
7 # ./ips | sed 's/^/ping /' | NO_LOG=1 ./dell-switch.pl sw-dpc
8
9 use Net::OpenSSH;
10 use Data::Dump qw(dump);
11 use Time::HiRes qw(sleep);
12
13 our $login;
14 our $passwd;
15 our $debug = $ENV{DEBUG} || 0;
16
17 use lib '.';
18 require 'config.pl';
19
20 #$Net::OpenSSH::debug = ~0;
21
22 my $ip = shift @ARGV || die "usage: $0 IP command[ command ...]\n";
23 $ip = $1 if `host $ip` =~ m/has address (\S+)/;
24 my @commands = @ARGV;
25 if ( ! @commands && ! -t STDIN && -p STDIN ) { # we are being piped into
26         while(<>) {
27                 push @commands, $_;
28         }
29 } else {
30         @commands = <DATA> unless @commands;
31 }
32
33 warn "\n## ssh $ip\n";
34 my $ssh = Net::OpenSSH->new($ip, user => $login, passwd => $passwd, 
35     ssh_cmd => '/usr/bin/ssh1', # apt-get install openssh-client-ssh1
36     master_opts => [
37         -o => "StrictHostKeyChecking=no",
38         -F => '/home/dpavlin/dell-switch/ssh1-config'
39         ],
40     default_ssh_opts => [
41         -o => "StrictHostKeyChecking=no",
42         -F => '/home/dpavlin/dell-switch/ssh1-config'
43         ],
44 );
45 my ($pty ,$pid) = $ssh->open2pty();
46 if ( ! $pty ) {
47         warn "ERROR: can't connect to $ip, skipping";
48         exit 0;
49 }
50
51 my $buff;
52
53 sub send_pty {
54         my $string = shift;
55         sleep 0.05; # we really need to wait for slow PowerConnect 5324
56         foreach (split //, $string) {
57                 print STDERR "[$_]" if $debug;
58                 syswrite $pty, $_;
59                 #$pty->flush;
60                 sleep 0.01;
61
62                 sysread $pty, my $echo, 1;
63                 print STDERR $echo;
64                 $buff .= $echo;
65         }
66 }
67
68 mkdir 'log' unless -d 'log';
69
70 chdir 'log';
71
72 sub save_log {
73         my ($ip, $hostname, $command, $buff) = @_;
74
75         return unless $command;
76         return if $ENV{NO_LOG};
77         
78         my $file = "${ip}_${hostname}_${command}.log";
79         open my $log, '>', $file;
80         $buff =~ s/\r//gs; # strip CR, leave LF only
81         print $log $buff;
82         if ( -e '.git' ) {
83                 system 'git', 'add', $file;
84                 system 'git', 'commit', '-m', "$ip $hostname", $file;
85         }
86 }
87
88 my $command;
89 my @commands_while = ( @commands );
90
91 while() {
92         my $data;
93         my $read = sysread($pty, $data, 1);
94         print STDERR $data;
95         $buff .= $data;
96         if ( $buff =~ m/User Name:/ ) {
97                 send_pty "$login\n";
98                 $buff = '';
99         } elsif ( $buff =~ m/Password:/ ) {
100                 send_pty "$passwd\n";
101                 $buff = '';
102         } elsif ( $buff =~ m/[\n\r\b]([\w\-\(\)\/]+)#\s*$/ ) {
103                 # config interface needs / in prompt
104                 my $hostname = $1;
105                 if ( $buff ) {
106                         save_log $ip, $hostname, $command, $buff;
107                         $buff = '';
108                 }
109                 if ( $command = shift @commands_while ) {
110                         $command =~ s/[\n\r]+$//;
111                         send_pty "$command\n";
112                         $buff = '';
113                 } else  {
114                         send_pty "exit\n";
115                         close($pty);
116                         last;
117                 }
118         } elsif ( $buff =~ m/% Unrecognized command/ ) {
119                 exit 1;
120         } elsif ( $buff =~ m/% Invalid input detected at .* marker/ ) {
121
122                 # try to rewrite command differences
123
124                 if ( $command =~ m/show lldp neighbors/ ) {
125                         unshift @commands_while, 'show lldp remote-device all';
126                         undef $command; # don't save this command
127                         $buff = '';
128                 }
129
130                 warn "# commands_while = ",dump( \@commands_while );
131
132         } elsif ( $buff =~ s{More: <space>,  Quit: q.*One line: <return>\s*}{} ) {
133                 send_pty " ";
134         } elsif ( $buff =~ s{\Q--More-- or (q)uit\E}{} ) {
135                 send_pty " ";
136         } elsif ( $buff =~ s{\r\s{18}\r}{} ) {
137                 # strip spaces delete after more prompt
138         } elsif ( $buff =~ s{\e\[0m\s*\r\s+\r}{} ) {
139                 # nop
140         } elsif ( $buff =~ m/^[\r\n]+[\w\-]+>$/ ) {
141                 send_pty "enable\n";
142         } elsif ( $buff =~ m{\QOverwrite file [startup-config] ?[Yes/press any key for no]....\E} ) {
143                 send_pty "y";
144                 $buff = '';
145         } elsif ( $buff =~ s{Management access will be blocked for the duration of the transfer.*Are you sure you want to start\? \(y/n\) }{}s ) {
146                 send_pty 'y';
147         } elsif ( $buff =~ s{\QThis command will reset the whole system and disconnect your current session.\E}{}s ) { # reload
148                 warn "\nRELOAD detected\n";
149                 sleep 0.5;
150                 send_pty 'y';
151         } elsif ( $buff =~ m{MikroTik RouterOS} ) {
152                 warn "\nERROR: don't know how to talk to MicroTik - ABORTING";
153                 exit 0;
154         }
155 }
156
157 __DATA__
158 show system
159 show arp
160 show vlan
161 show running-config
162 show bridge address
163 show interfaces status