File Coverage

lib/App/Tel/Color/Cisco.pm
Criterion Covered Total %
statement 97 105 92.3
branch 44 54 81.4
condition 16 24 66.6
subroutine 14 14 100.0
pod 1 1 100.0
total 172 198 86.8


line stmt bran cond sub pod time code
1             package App::Tel::Color::Cisco;
2 2     2   1347 use parent 'App::Tel::Color::Base';
  2         230  
  2         6  
3 2     2   94 use Term::ANSIColor;
  2         2  
  2         73  
4 2     2   7 use Scalar::Util qw ( looks_like_number );
  2         3  
  2         63  
5 2     2   5 use strict;
  2         23  
  2         26  
6 2     2   6 use warnings;
  2         3  
  2         1623  
7              
8             =head1 NAME
9              
10             App::Tel::Cisco - Colors for show interface and other commands
11              
12             =head2 METHODS
13              
14             =cut
15              
16             sub _c {
17             # if not a number then return the original text
18 7     7   97 my $val = shift;
19 7 100       39 return $val if (!looks_like_number($val));
20 5 100       10 if ($val > 0) {
21 1         3 return colored($val, 'red');
22             }
23 4         9 return colored($val, 'green');
24             }
25              
26              
27             # not kidding, this will be crazy.
28             # it simulates s/blah (\d+) blah/sprintf("blah %s blah", c($1))/e;
29             sub _crazy {
30 24     24   21 my $text = shift;
31 24         49 my @strings = @_;
32              
33 24         25 foreach my $s (@strings) {
34 336         268 my $substring = $s;
35             # (?
36             # for \\ (the escape \ before a parenthesis)
37 336         1105 my $count = $substring =~ s/(?
38              
39 336         245 my $args = '';
40 336         329 for (1..$count) { $args .= ",_c(\$$_)" }
  816         795  
41              
42 336         308 my $eval = 'sprintf("'.$substring.'"'.$args.')';
43              
44             # in theory this is safer than the old external eval. The reason
45             # being all the evaluated data is part of the defined strings passed
46             # to the _crazy function. That means no data coming from a router can
47             # be evaluated.
48 336         2797 $text =~ s/$s/eval $eval/e;
  3         188  
49             }
50              
51 24         46 return $text;
52             }
53              
54             sub _uspwr {
55 6     6   7 my $pwr = shift;
56 6         4 my $color = 'red';
57 6 50 66     59 if ( $pwr < 30 ) { $color = 'red'; }
  0 100 66     0  
    100 66        
    100          
    50          
58 1         2 elsif ( $pwr >= 30 && $pwr <= 33 ) { $color = 'yellow'; }
59 1         1 elsif ( $pwr >= 33 && $pwr <= 45 ) { $color = 'green'; }
60 1         2 elsif ( $pwr >= 45 && $pwr <= 50 ) { $color = 'yellow'; }
61 3         3 elsif ( $pwr > 50 ) { $color = 'red'; }
62 6         14 return colored($pwr, $color);
63             }
64              
65             sub _ussnr {
66 6     6   118 my $snr = shift;
67 6         5 my $color = 'red';
68 6 100 66     31 if ( $snr < 20 ) { $color = 'red'; }
  1 100       2  
    50          
69 1         2 elsif ( $snr >= 20 && $snr <= 25 ) { $color = 'yellow'; }
70 4         5 elsif ( $snr > 25 ) { $color = 'green'; }
71 6         10 return colored($snr, $color);
72             }
73              
74             sub _dspwr {
75 6     6   91 my $input = shift;
76 6         5 my $pwr = $input;
77 6         14 $pwr =~ s/ //g; # remove all spaces, leaving possible negative sign and value
78 6         7 my $color = 'red';
79 6 100 66     47 if ( $pwr < -15 ) { $color = 'red'; }
  1 100 66     2  
    100 66        
    100          
    50          
80 1         2 elsif ( $pwr >= -15 && $pwr <= -9 ) { $color = 'yellow'; }
81 1         2 elsif ( $pwr >= -9 && $pwr <= 9 ) { $color = 'green'; }
82 1         2 elsif ( $pwr >= 9 && $pwr <= 15 ) { $color = 'yellow'; }
83 2         2 elsif ( $pwr > 15 ) { $color = 'red'; }
84 6         51 return colored($input, $color);
85             }
86              
87             sub _dssnr {
88 6     6   97 my $input = shift;
89 6         6 my $snr = $input;
90 6         11 $snr =~ s/ //g; # remove all spaces, leaving possible negative sign and value
91 6         6 my $color = 'red';
92 6 100 66     30 if ( $snr eq '-----' ) { $color = 'yellow'; }
  1 100       2  
    100          
    50          
93 1         1 elsif ( $snr < 35 ) { $color = 'red'; }
94 1         1 elsif ( $snr >= 35 && $snr <= 35 ) { $color = 'yellow'; }
95 3         3 elsif ( $snr > 35 ) { $color = 'green'; }
96 6         11 return colored($input, $color);
97             }
98              
99             sub _cpu {
100 6     6   73 my $cpu = shift;
101 6         6 my $color = 'green';
102 6 100       15 if ($cpu > 0) { $color = 'yellow'; }
  2         3  
103 6 100       8 if ($cpu > 1) { $color = 'red'; }
  1         2  
104 6         10 return colored($cpu, $color);
105             }
106              
107             sub _interface {
108             # without knowing syntax, this will automatically handle err-disable and
109             # any other weird corner cases by defaulting to red.
110 2     2   38 my $color = 'red';
111 2 100       6 if ($_[0] eq 'up') {
112 1         1 $color = 'green';
113             }
114 2         5 return colored($_[0], $color);
115             }
116              
117             =head2 colorize
118              
119             my $output = $self->colorize($input);
120              
121             Given a line of text from a cisco router, this will try to colorize it.
122              
123             =cut
124              
125             sub colorize {
126 24     24 1 25 my ($self, $text) = @_;
127 24         20 my $CISCO_MAC = q{(?:[a-f0-9]{4}\.){2}[a-f0-9]{4}};
128 24         12 my $CABLE_INT = q{C\d+/\d+/U\d+};
129 24         17 my $F = q{\d+\.\d+}; # 00.00 floating point number
130 24         17 my $NEG = q{(?:\s+\-?)};
131              
132              
133 24         30 $text =~s/(\S+) is (.*), line protocol is (\S+)/sprintf("%s is %s, line protocol is %s", colored($1, 'magenta'),
  1         4  
134             _interface($2), _interface($3))/eg;
135              
136             # sh cable modem phy
137 24         179 $text =~ s#($CISCO_MAC $CABLE_INT\s+\d+\s+)($F)(\s+)($F)(\s+\!?\d+)($NEG$F)($NEG$F|\s+\-{5})#
138 6         10 sprintf("%s%s%s%s%s%s%s", $1, _uspwr($2), $3, _ussnr($4), $5, _dspwr($6), _dssnr($7))#eg;
139              
140             # more show interface
141 24         426 $text =~ s/Full-duplex/colored('Full-duplex', 'green')/eg;
  0         0  
142 24         20 $text =~ s/Half-duplex/colored('Half-duplex', 'yellow')/eg;
  0         0  
143              
144             # sh proc cpu
145 24         98 $text =~ s#(\s+\d+\s+\d+\s+\d+\s+\d+\s+)($F)(%\s+)($F)(%\s+)($F)#
146 1         3 sprintf("%s%s%s%s%s%s", $1, _cpu($2), $3, _cpu($4), $5, _cpu($6))#eg;
147              
148             # 4500x sh proc cpu
149 24         172 $text =~ s#((?
150 1         3 sprintf("%s%s%s%s%s%s%s", $1, _cpu($2), $3, _cpu($4), $5, _cpu($6), $7)#eg;
151              
152             # parts of sh run
153 24 50       126 if ($text =~ /^(ip|ipv6) route /) {
    50          
    50          
    50          
    50          
154 0         0 $text = colored($text, 'yellow');
155             } elsif ($text =~ /^aaa/) {
156 0         0 $text = colored($text, 'green');
157             } elsif ($text =~ /^(?:(?:no )?tacacs-server|radius-server|ntp)/) {
158 0         0 $text = colored($text, 'magenta');
159             } elsif ($text =~ /^(?:mac )?access-list/) {
160 0         0 $text = colored($text, 'cyan');
161             } elsif ($text =~ /^snmp-server/) {
162 0         0 $text = colored($text, 'bright_white');
163             }
164              
165 24         35 $text = _crazy($text,
166             '(\d+) runts, (\d+) giants, (\d+) throttles',
167             '(\d+) input errors, (\d+) CRC, (\d+) frame, (\d+) overrun, (\d+) ignored',
168             '(\d+) input packets with dribble condition detected',
169             'Total output drops: (\d+)',
170             '(\d+) output errors, (\d+) interface resets',
171             '(\d+) output errors, (\d+) collisions, (\d+) interface resets',
172             '(\d+) output buffer failures, (\d+) output buffers swapped out',
173             '(\d+) carrier transitions',
174             'Output queue (\S+), (\d+) drops; input queue (\S+), (\d+) drops',
175             '(\d+)\/(\d+) \(size\/max\/drops\/flushes\)\;',
176             '(\d+) (pause input|watchdog|underruns|no buffer|pause output|abort)',
177             '(\d+) output errors, (\d+) collisions, (\d+) interface resets',
178             '(\d+) babbles, (\d+) late collision, (\d+) deferred',
179             '(\d+) lost carrier, (\d+) no carrier',
180             );
181              
182 24         68 return $text;
183             }
184              
185             1;