line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mnet; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# version number used by Makefile.PL |
4
|
|
|
|
|
|
|
# these should be set to "dev", expect when creating a new release |
5
|
|
|
|
|
|
|
# refer to developer build notes in Makefile.PL for more info |
6
|
|
|
|
|
|
|
our $VERSION = "5.25_01"; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 NAME |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
Mnet - Testable network automation and reporting |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 SYNOPSIS |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# sample.pl script to report Loopback0 ip on cisco devices |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# demonstrates typical use of all major Mnet modules |
17
|
|
|
|
|
|
|
# |
18
|
|
|
|
|
|
|
# --help to list all options, also --help |
19
|
|
|
|
|
|
|
# --device to connect to device with logging |
20
|
|
|
|
|
|
|
# --username and --password should be set if necessary |
21
|
|
|
|
|
|
|
# --debug to generate extra detailed logging outputs |
22
|
|
|
|
|
|
|
# --batch to process multiple --device lines |
23
|
|
|
|
|
|
|
# --report csv: to create an output csv file |
24
|
|
|
|
|
|
|
# --record to create replayable test file |
25
|
|
|
|
|
|
|
# --test --replay for regression test output |
26
|
|
|
|
|
|
|
# |
27
|
|
|
|
|
|
|
# refer to various Mnet modules' perldoc for more info |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# load needed modules |
30
|
|
|
|
|
|
|
use warnings; |
31
|
|
|
|
|
|
|
use strict; |
32
|
|
|
|
|
|
|
use Mnet::Batch; |
33
|
|
|
|
|
|
|
use Mnet::Expect::Cli::Ios; |
34
|
|
|
|
|
|
|
use Mnet::IP; |
35
|
|
|
|
|
|
|
use Mnet::Log qw(DEBUG INFO WARN FATAL); |
36
|
|
|
|
|
|
|
use Mnet::Opts::Cli; |
37
|
|
|
|
|
|
|
use Mnet::Report::Table; |
38
|
|
|
|
|
|
|
use Mnet::Stanza; |
39
|
|
|
|
|
|
|
use Mnet::Test; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# define --device, --username, --password, and --report cli options |
42
|
|
|
|
|
|
|
# record, redact, default, and help option attributes are shown |
43
|
|
|
|
|
|
|
Mnet::Opts::Cli::define({ getopt => "device=s", record => 1 }); |
44
|
|
|
|
|
|
|
Mnet::Opts::Cli::define({ getopt => "username=s" }); |
45
|
|
|
|
|
|
|
Mnet::Opts::Cli::define({ getopt => "password=s", redact => 1 }); |
46
|
|
|
|
|
|
|
Mnet::Opts::Cli::define({ getopt => "report=s", default => undef, |
47
|
|
|
|
|
|
|
help_tip => "specify report output, csv, json, sql, etc", |
48
|
|
|
|
|
|
|
help_text => "perldoc Mnet::Report::Table for more info", |
49
|
|
|
|
|
|
|
}); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# create object to access command line options and Mnet env variable |
52
|
|
|
|
|
|
|
# export Mnet="--password ''" env var from secure file |
53
|
|
|
|
|
|
|
my $cli = Mnet::Opts::Cli->new("Mnet"); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# define output --report table, will include first of any errors |
56
|
|
|
|
|
|
|
# use --report cli opt to output data as csv, json, or sql, etc |
57
|
|
|
|
|
|
|
my $report = Mnet::Report::Table->new({ |
58
|
|
|
|
|
|
|
columns => [ |
59
|
|
|
|
|
|
|
device => "string", |
60
|
|
|
|
|
|
|
error => "error", |
61
|
|
|
|
|
|
|
ip => "string", |
62
|
|
|
|
|
|
|
], |
63
|
|
|
|
|
|
|
output => $cli->report, |
64
|
|
|
|
|
|
|
}); |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# fork children if in --batch mode, cli opts set for current child |
67
|
|
|
|
|
|
|
# process one device or ten thousand devices with the same script |
68
|
|
|
|
|
|
|
# exit --batch parent process here when finished forking children |
69
|
|
|
|
|
|
|
$cli = Mnet::Batch::fork($cli); |
70
|
|
|
|
|
|
|
exit if not $cli; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# output report row for device error if script dies before finishing |
73
|
|
|
|
|
|
|
$report->row_on_error({ device => $cli->device }); |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# call logging function, also create log object for current --device |
76
|
|
|
|
|
|
|
FATAL("missing --device") if not $cli->device; |
77
|
|
|
|
|
|
|
my $log = Mnet::Log->new({ log_id => $cli->device }); |
78
|
|
|
|
|
|
|
$log->info("processing device"); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# uncomment the push commands below to skip ssh host key checks |
81
|
|
|
|
|
|
|
# ideally host keys are already accepted, perhaps via manual ssh |
82
|
|
|
|
|
|
|
my @ssh = qw(ssh); |
83
|
|
|
|
|
|
|
#push @ssh, qw(-o StrictHostKeyChecking=no); |
84
|
|
|
|
|
|
|
#push @ssh, qw(-o UserKnownHostsFile=/dev/null); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# create an expect ssh session to current --device |
87
|
|
|
|
|
|
|
# log ssh login/auth prompts as info, instead of default debug |
88
|
|
|
|
|
|
|
# password_in set to prompt for password if --password opt not set |
89
|
|
|
|
|
|
|
# for non-ios devices refer to perldoc Mnet::Expect::Cli |
90
|
|
|
|
|
|
|
my $ssh = Mnet::Expect::Cli::Ios->new({ |
91
|
|
|
|
|
|
|
spawn => [ @ssh, "$cli->{username}\@$cli->{device}" ], |
92
|
|
|
|
|
|
|
log_id => $cli->{device}, |
93
|
|
|
|
|
|
|
log_login => "info", |
94
|
|
|
|
|
|
|
password => $cli->password, |
95
|
|
|
|
|
|
|
password_in => 1, |
96
|
|
|
|
|
|
|
}); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# retrieve ios config using ssh command, warn otherwise |
99
|
|
|
|
|
|
|
my $config = $ssh->command("show running-config"); |
100
|
|
|
|
|
|
|
WARN("unable to read config") if not $config; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# parse interface loopack0 stanza from device config |
103
|
|
|
|
|
|
|
# returns int loop0 line and lines indented under int loop0 |
104
|
|
|
|
|
|
|
# see perldoc Mnet::Stanza for more ios config templating info |
105
|
|
|
|
|
|
|
my $loop = Mnet::Stanza::parse($config, qr/^interface Loopback0$/); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# parse primary ip address and mask from loopback config stanza |
108
|
|
|
|
|
|
|
my ($ip, $mask) = (undef, undef); |
109
|
|
|
|
|
|
|
($ip, $mask) = ($1, $2) if $loop =~ /^ ip address (\S+) (\S+)$/m; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# calculate cidr value from dotted decimal mask |
112
|
|
|
|
|
|
|
my $cidr = Mnet::IP::cidr($mask); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# report on parsed loopback0 interface ip address and cidr value |
115
|
|
|
|
|
|
|
$report->row({ device => $cli->device, ip => $ip, cidr => $cidr }); |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# finished |
118
|
|
|
|
|
|
|
exit; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head1 DESCRIPTION |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
The L modules are for perl programmers who want to create testable |
123
|
|
|
|
|
|
|
network automation and/or reporting scripts as simply as possible. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
The main features are: |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=over |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=item * |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
L module can record and replay L script options, connected |
132
|
|
|
|
|
|
|
expect sessions, and compare outputs, speeding development and allowing for |
133
|
|
|
|
|
|
|
integration and regression testing of complex automation scripts. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item * |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
L and L modules for reliable |
138
|
|
|
|
|
|
|
automation of cisco ios and other command line sessions, including |
139
|
|
|
|
|
|
|
authentication and command prompt handling. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item * |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
L module for templated config parsing and generation on cisco ios |
144
|
|
|
|
|
|
|
devices and other similar indented stanza text data. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=item * |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
L can run automation scripts in batch mode to concurrently process |
149
|
|
|
|
|
|
|
a list of devices, using command line arguments and a device list file. |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item * |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
L and L modules facilitate easy log, debug, alert and |
154
|
|
|
|
|
|
|
error output from automation scripts, along with redirection to per-device |
155
|
|
|
|
|
|
|
output files. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=item * |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
L module for config settings via command line, environment |
160
|
|
|
|
|
|
|
variable, and/or batch scripts, with help, tips, and password redaction. |
161
|
|
|
|
|
|
|
device list files. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item * |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
L module for aggregating report data from scripts, |
166
|
|
|
|
|
|
|
supporting output in formats such as csv, json, and sql. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=back |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Most of the L sub-modules can be used independently of each other, |
171
|
|
|
|
|
|
|
unless otherwise noted. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Refer to the individual modules listed in the SEE ALSO section below |
174
|
|
|
|
|
|
|
for more detail. |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head1 INSTALLATION |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
The L perl modules should work in just about any unix perl environment, |
179
|
|
|
|
|
|
|
some modules require perl 5.12 or newer. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
The latest release can be installed from CPAN |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
cpan install Mnet |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
Or download and install from L |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
tar -xzf Mnet-X.y.tar.gz |
188
|
|
|
|
|
|
|
cd Mnet-X.y |
189
|
|
|
|
|
|
|
perl Makefile.PL # INSTALL_BASE=/specify/path |
190
|
|
|
|
|
|
|
make test |
191
|
|
|
|
|
|
|
make install |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Check your PERL5LIB environment variable if INSTALL_BASE was used, or if you |
194
|
|
|
|
|
|
|
copied the lib/Mnet directory somewhere instead of using the included |
195
|
|
|
|
|
|
|
Makefile.PL script. Refer to L for more information |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 FAQ |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Below are answers to some frequently asked questions. |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head2 How should I get started? |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Copy the sample script code from the SYNOPSIS above to a new .pl file, read |
204
|
|
|
|
|
|
|
through the comments, make changes as necessary, use the --debug cli option to |
205
|
|
|
|
|
|
|
troubleshoot execution. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head2 What's the easiest way to get more log output? |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Use both the L and L modules in your script |
210
|
|
|
|
|
|
|
for more output, mostly from other Mnet modules unless you add L |
211
|
|
|
|
|
|
|
calls, which are a compatible subset of log4perl calls, to your script. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head2 How should passwords be secured? |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Environment variables should be used to provide passwords for scripts, not |
216
|
|
|
|
|
|
|
command line options. Command line options can be seen in the system process |
217
|
|
|
|
|
|
|
list by other users. |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
The L new method allows a named environment variable to be |
220
|
|
|
|
|
|
|
specified that will also be parsed for command line options. Your script can |
221
|
|
|
|
|
|
|
be called from a shell script containing authentication, which is accessible |
222
|
|
|
|
|
|
|
only to authorized users, such as in the example below: |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
#!/bin/sh |
225
|
|
|
|
|
|
|
# sample.sh script, chmod 700 to restrict access to current user |
226
|
|
|
|
|
|
|
# works with Mnet::Opts calls in above SYNOPISIS sample.pl script |
227
|
|
|
|
|
|
|
# "$@" passes throuh all command line options, modify as needed |
228
|
|
|
|
|
|
|
export Mnet='--username --password ' |
229
|
|
|
|
|
|
|
perl -- sample.pl "$@" |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
The L module define function has a redact property that should |
232
|
|
|
|
|
|
|
be set for password options so that the value of the option is value is always |
233
|
|
|
|
|
|
|
redacted form L outputs. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Also note that the L module log_expect method is used by the |
236
|
|
|
|
|
|
|
L modules to temporarily disable expect session logging |
237
|
|
|
|
|
|
|
during password entry. Any user code bypassing the L |
238
|
|
|
|
|
|
|
modules to send passwords directly, using the expect method in the |
239
|
|
|
|
|
|
|
L module, may need to do the same. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 Why should I use the Mnet::Expect module? |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
The L module works with the L and L |
244
|
|
|
|
|
|
|
modules, for easy logging of normal L module activity, with extra |
245
|
|
|
|
|
|
|
options for logging, debugging, raw pty, and session tty rows and columns. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
However, you still have to handle all the expect session details, including |
248
|
|
|
|
|
|
|
send and expect calls for logging in, detecting of command prompts, capturing |
249
|
|
|
|
|
|
|
output, etc. It's easier to use the L module which handles |
250
|
|
|
|
|
|
|
all of this, if you can. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 Why should I use the Mnet::Expect::Cli module? |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
The L module makes it easy to login and obtain outputs from |
255
|
|
|
|
|
|
|
command line interfaces, like ssh. This module builds on the L |
256
|
|
|
|
|
|
|
module mentioned above, adding features to handle a variety of typical username |
257
|
|
|
|
|
|
|
and password prompts, command prompts, pagination prompts on long outputs, and |
258
|
|
|
|
|
|
|
caching of session command output. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
This module also works with the L module, allowing expect session |
261
|
|
|
|
|
|
|
activity to be recorded and replayed while offline. This can be of tremendous |
262
|
|
|
|
|
|
|
value, both during development, and for sustainability. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Refer also the the L module mentioned below, which has |
265
|
|
|
|
|
|
|
a couple of features relevant when working with cisco ios and other similar |
266
|
|
|
|
|
|
|
devices. |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=head2 Why should I use the Mnet::Expect::Cli::Ios module? |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
The L builds on the L module |
271
|
|
|
|
|
|
|
mentioned above, also handling enable mode authentication, the prompt changes |
272
|
|
|
|
|
|
|
going from user to enable mode, and the prompt changes in configuration modes. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head1 AUTHOR |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
The L perl distribution has been created and is maintained by Mike Menza. |
277
|
|
|
|
|
|
|
Feedback and bug reports are welcome, feel free to contact Mike via email |
278
|
|
|
|
|
|
|
at with any comments or questions. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Copyright 2006 Michael J. Menza Jr. |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
L is free software: you can redistribute it and/or modify it under |
285
|
|
|
|
|
|
|
the terms of the GNU General Public License as published by the Free Software |
286
|
|
|
|
|
|
|
Foundation, either version 3 of the License, or (at your option) any later |
287
|
|
|
|
|
|
|
version. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY |
290
|
|
|
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
291
|
|
|
|
|
|
|
PARTICULAR PURPOSE. See the GNU General Public License for more details. |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with |
294
|
|
|
|
|
|
|
this program. If not, see L |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head1 SEE ALSO |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
L |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
L |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
L |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
L |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
L |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
L |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
L |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
L |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
L |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=cut |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# required modules |
319
|
|
|
|
|
|
|
# note that cpan complians if use strict is missing |
320
|
|
|
|
|
|
|
# perl 5.12 or higer required for some Mnet modules, they all use this module |
321
|
|
|
|
|
|
|
# perl 5.8.9 warning: use of "shift" without parentheses is ambiguous |
322
|
|
|
|
|
|
|
# see 'use x.xxx' commands in other modules for additional info |
323
|
|
|
|
|
|
|
# update Makefile.PL and INSTALLATION in this perldoc if changed |
324
|
35
|
|
|
35
|
|
235
|
use warnings; |
|
35
|
|
|
|
|
67
|
|
|
35
|
|
|
|
|
1141
|
|
325
|
35
|
|
|
35
|
|
174
|
use strict; |
|
35
|
|
|
|
|
74
|
|
|
35
|
|
|
|
|
734
|
|
326
|
35
|
|
|
35
|
|
814
|
use 5.012; |
|
35
|
|
|
|
|
131
|
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# normal end of package |
329
|
|
|
|
|
|
|
1; |
330
|
|
|
|
|
|
|
|