| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Net::Appliance::Session; |
|
2
|
|
|
|
|
|
|
{ $Net::Appliance::Session::VERSION = '4.300005' } |
|
3
|
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
163257
|
use Moo; |
|
|
1
|
|
|
|
|
11071
|
|
|
|
1
|
|
|
|
|
4
|
|
|
5
|
1
|
|
|
1
|
|
1892
|
use Sub::Quote; |
|
|
1
|
|
|
|
|
4608
|
|
|
|
1
|
|
|
|
|
83
|
|
|
6
|
1
|
|
|
1
|
|
570
|
use MooX::Types::MooseLike::Base qw(Any Bool Int Str HashRef InstanceOf); |
|
|
1
|
|
|
|
|
6346
|
|
|
|
1
|
|
|
|
|
108
|
|
|
7
|
1
|
|
|
1
|
|
42425
|
use Net::CLI::Interact; |
|
|
1
|
|
|
|
|
410599
|
|
|
|
1
|
|
|
|
|
719
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
with 'Net::Appliance::Session::Transport'; |
|
10
|
|
|
|
|
|
|
with 'Net::Appliance::Session::Engine'; |
|
11
|
|
|
|
|
|
|
with 'Net::Appliance::Session::Async'; |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# import Try::Tiny try/catch/finally into caller's namespace |
|
14
|
|
|
|
|
|
|
sub import { |
|
15
|
1
|
|
|
1
|
|
11
|
my $caller = caller; |
|
16
|
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
7
|
eval <<ENDEVAL; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
25
|
|
|
|
1
|
|
|
|
|
68
|
|
|
18
|
|
|
|
|
|
|
package $caller; |
|
19
|
|
|
|
|
|
|
use Class::Load (); |
|
20
|
|
|
|
|
|
|
Class::Load::load_class('Try::Tiny'); |
|
21
|
|
|
|
|
|
|
Try::Tiny->import(); |
|
22
|
|
|
|
|
|
|
ENDEVAL |
|
23
|
|
|
|
|
|
|
|
|
24
|
1
|
50
|
|
|
|
15
|
die $@ if $@; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
foreach my $slot (qw/ |
|
28
|
|
|
|
|
|
|
logged_in |
|
29
|
|
|
|
|
|
|
in_privileged_mode |
|
30
|
|
|
|
|
|
|
in_configure_mode |
|
31
|
|
|
|
|
|
|
privileged_paging |
|
32
|
|
|
|
|
|
|
close_called |
|
33
|
|
|
|
|
|
|
/) { |
|
34
|
|
|
|
|
|
|
has $slot => ( |
|
35
|
|
|
|
|
|
|
is => 'rw', |
|
36
|
|
|
|
|
|
|
isa => Bool, |
|
37
|
|
|
|
|
|
|
required => 0, |
|
38
|
|
|
|
|
|
|
default => quote_sub('0'), |
|
39
|
|
|
|
|
|
|
); |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
foreach my $slot (qw/ |
|
43
|
|
|
|
|
|
|
do_paging |
|
44
|
|
|
|
|
|
|
do_login |
|
45
|
|
|
|
|
|
|
do_privileged_mode |
|
46
|
|
|
|
|
|
|
do_configure_mode |
|
47
|
|
|
|
|
|
|
/) { |
|
48
|
|
|
|
|
|
|
has $slot => ( |
|
49
|
|
|
|
|
|
|
is => 'rw', |
|
50
|
|
|
|
|
|
|
isa => Bool, |
|
51
|
|
|
|
|
|
|
required => 0, |
|
52
|
|
|
|
|
|
|
default => quote_sub('1'), |
|
53
|
|
|
|
|
|
|
); |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
has wake_up => ( |
|
57
|
|
|
|
|
|
|
is => 'rw', |
|
58
|
|
|
|
|
|
|
isa => Int, |
|
59
|
|
|
|
|
|
|
required => 0, |
|
60
|
|
|
|
|
|
|
default => quote_sub('1'), |
|
61
|
|
|
|
|
|
|
); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
foreach my $slot (qw/ |
|
64
|
|
|
|
|
|
|
username |
|
65
|
|
|
|
|
|
|
password |
|
66
|
|
|
|
|
|
|
privileged_password |
|
67
|
|
|
|
|
|
|
/) { |
|
68
|
|
|
|
|
|
|
has $slot => ( |
|
69
|
|
|
|
|
|
|
is => 'rw', |
|
70
|
|
|
|
|
|
|
isa => Str, |
|
71
|
|
|
|
|
|
|
required => 0, |
|
72
|
|
|
|
|
|
|
predicate => 1, |
|
73
|
|
|
|
|
|
|
reader => "get_$slot", |
|
74
|
|
|
|
|
|
|
writer => "set_$slot", |
|
75
|
|
|
|
|
|
|
); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
foreach my $slot (qw/ |
|
79
|
|
|
|
|
|
|
transport |
|
80
|
|
|
|
|
|
|
personality |
|
81
|
|
|
|
|
|
|
/) { |
|
82
|
|
|
|
|
|
|
has $slot => ( |
|
83
|
|
|
|
|
|
|
is => 'rw', |
|
84
|
|
|
|
|
|
|
isa => Str, |
|
85
|
|
|
|
|
|
|
required => 1, |
|
86
|
|
|
|
|
|
|
); |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
foreach my $slot (qw/ |
|
90
|
|
|
|
|
|
|
host |
|
91
|
|
|
|
|
|
|
app |
|
92
|
|
|
|
|
|
|
/) { |
|
93
|
|
|
|
|
|
|
has $slot => ( |
|
94
|
|
|
|
|
|
|
is => 'ro', |
|
95
|
|
|
|
|
|
|
isa => Str, |
|
96
|
|
|
|
|
|
|
required => 0, |
|
97
|
|
|
|
|
|
|
predicate => 1, |
|
98
|
|
|
|
|
|
|
); |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
has 'add_library' => ( |
|
102
|
|
|
|
|
|
|
is => 'ro', |
|
103
|
|
|
|
|
|
|
isa => Any, |
|
104
|
|
|
|
|
|
|
required => 0, |
|
105
|
|
|
|
|
|
|
predicate => 1, |
|
106
|
|
|
|
|
|
|
); |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
has 'timeout' => ( |
|
109
|
|
|
|
|
|
|
is => 'ro', |
|
110
|
|
|
|
|
|
|
isa => Int, |
|
111
|
|
|
|
|
|
|
required => 0, |
|
112
|
|
|
|
|
|
|
predicate => 1, |
|
113
|
|
|
|
|
|
|
); |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
has 'connect_options' => ( |
|
116
|
|
|
|
|
|
|
is => 'ro', |
|
117
|
|
|
|
|
|
|
isa => HashRef, |
|
118
|
|
|
|
|
|
|
required => 0, |
|
119
|
|
|
|
|
|
|
default => sub { {} }, |
|
120
|
|
|
|
|
|
|
); |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
has 'nci_options' => ( |
|
123
|
|
|
|
|
|
|
is => 'ro', |
|
124
|
|
|
|
|
|
|
isa => HashRef, |
|
125
|
|
|
|
|
|
|
required => 0, |
|
126
|
|
|
|
|
|
|
default => sub { {} }, |
|
127
|
|
|
|
|
|
|
); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
has 'nci' => ( |
|
130
|
|
|
|
|
|
|
is => 'lazy', |
|
131
|
|
|
|
|
|
|
isa => InstanceOf['Net::CLI::Interact'], |
|
132
|
|
|
|
|
|
|
required => 1, |
|
133
|
|
|
|
|
|
|
predicate => 1, |
|
134
|
|
|
|
|
|
|
clearer => 1, |
|
135
|
|
|
|
|
|
|
handles => [qw/ |
|
136
|
|
|
|
|
|
|
cmd |
|
137
|
|
|
|
|
|
|
macro |
|
138
|
|
|
|
|
|
|
last_prompt |
|
139
|
|
|
|
|
|
|
last_response |
|
140
|
|
|
|
|
|
|
set_phrasebook |
|
141
|
|
|
|
|
|
|
set_global_log_at |
|
142
|
|
|
|
|
|
|
prompt_looks_like |
|
143
|
|
|
|
|
|
|
find_prompt |
|
144
|
|
|
|
|
|
|
/], |
|
145
|
|
|
|
|
|
|
); |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub _build_nci { |
|
148
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
149
|
0
|
0
|
|
|
|
|
$self->connect_options->{host} = $self->host |
|
150
|
|
|
|
|
|
|
if $self->has_host; |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my $nci = Net::CLI::Interact->new({ |
|
153
|
|
|
|
|
|
|
transport => $self->transport, |
|
154
|
|
|
|
|
|
|
personality => $self->personality, |
|
155
|
|
|
|
|
|
|
connect_options => $self->connect_options, |
|
156
|
|
|
|
|
|
|
($self->has_app ? (app => $self->app) : ()), |
|
157
|
|
|
|
|
|
|
($self->has_add_library ? (add_library => $self->add_library) : ()), |
|
158
|
|
|
|
|
|
|
($self->has_timeout ? (timeout => $self->timeout) : ()), |
|
159
|
0
|
0
|
|
|
|
|
%{ $self->nci_options }, |
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
}); |
|
161
|
|
|
|
|
|
|
|
|
162
|
0
|
|
0
|
|
|
|
$nci->logger->log('engine', 'notice', |
|
163
|
|
|
|
|
|
|
sprintf "NAS loaded, version %s", ($Net::Appliance::Session::VERSION || 'devel')); |
|
164
|
0
|
|
|
|
|
|
return $nci; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
1; |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=pod |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head1 NAME |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Net::Appliance::Session - Run command-line sessions to network appliances |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
use Net::Appliance::Session; |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
my $s = Net::Appliance::Session->new({ |
|
180
|
|
|
|
|
|
|
personality => 'ios', |
|
181
|
|
|
|
|
|
|
transport => 'SSH', |
|
182
|
|
|
|
|
|
|
host => 'hostname.example', |
|
183
|
|
|
|
|
|
|
privileged_paging => 1, # only if using ASA/PIX OS 7+ |
|
184
|
|
|
|
|
|
|
# and there are other behaviour options, see below |
|
185
|
|
|
|
|
|
|
}); |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
try { |
|
188
|
|
|
|
|
|
|
$s->connect({ username => 'username', password => 'loginpass' }); |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$s->begin_privileged({ password => 'privilegedpass' }); |
|
191
|
|
|
|
|
|
|
print $s->cmd('show access-list'); |
|
192
|
|
|
|
|
|
|
$s->end_privileged; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
catch { |
|
195
|
|
|
|
|
|
|
warn "failed to execute command: $_"; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
finally { |
|
198
|
|
|
|
|
|
|
$s->close; |
|
199
|
|
|
|
|
|
|
}; |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
or, try the bundled C<nas> helper script (beta feature!): |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
nas --help |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Use this module to establish an interactive command-line session with a |
|
208
|
|
|
|
|
|
|
network appliance. There is special support for moving into "privileged" mode |
|
209
|
|
|
|
|
|
|
and "configure" mode, along with the ability to send commands to the connected |
|
210
|
|
|
|
|
|
|
device and retrieve returned output. |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
There are other CPAN modules that cover similar ground, but they are less |
|
213
|
|
|
|
|
|
|
robust and do not handle native SSH, Telnet and Serial Line connections with a |
|
214
|
|
|
|
|
|
|
single interface on both Unix and Windows platforms. |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Built-in commands come from a phrasebook which supports many network device |
|
217
|
|
|
|
|
|
|
vendors (Cisco, HP, etc) or you can install a new phrasebook. Most phases of |
|
218
|
|
|
|
|
|
|
the connection are configurable for different device behaviours. |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head1 METHODS |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
As in the synopsis above, the first step is to create a new instance. |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
Recommended practice is to wrap all other calls (except C<close()>) in a |
|
225
|
|
|
|
|
|
|
C<try> block, to catch errors (typically time-outs waiting for CLI response). |
|
226
|
|
|
|
|
|
|
This module exports the C<try/catch/finally> methods (from L<Try::Tiny>) into |
|
227
|
|
|
|
|
|
|
your namespace as a simpler alternative to using C<eval()>. |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
For a full demonstration of usage, see the example script shipped with this |
|
230
|
|
|
|
|
|
|
distribution. |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head2 Net::Appliance::Session->new( \%options ) |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
my $s = Net::Appliance::Session->new({ |
|
235
|
|
|
|
|
|
|
personality => 'ios', |
|
236
|
|
|
|
|
|
|
transport => 'SSH', |
|
237
|
|
|
|
|
|
|
host => 'hostname.example', |
|
238
|
|
|
|
|
|
|
}); |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Prepares a new session for you, but will not connect to any device. Some |
|
241
|
|
|
|
|
|
|
options are required, others optional: |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=over 4 |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item C<< personality => $name >> (required) |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Tells the module which "language" to use when talking to the connected device, |
|
248
|
|
|
|
|
|
|
for example C<ios> for Cisco IOS devices. There's a list of all the supported |
|
249
|
|
|
|
|
|
|
platforms in the L<Phrasebook|Net::CLI::Interact::Manual::Phrasebook> |
|
250
|
|
|
|
|
|
|
documentation. It's also possible to write new phrasebooks. |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=item C<< transport => $backend >> (required) |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
The name of the transport backend used for the session, which may be one of |
|
255
|
|
|
|
|
|
|
L<Telnet|Net::CLI::Interact::Transport::Telnet>, |
|
256
|
|
|
|
|
|
|
L<SSH|Net::CLI::Interact::Transport::SSH>, or |
|
257
|
|
|
|
|
|
|
L<Serial|Net::CLI::Interact::Transport::Serial>. |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=item C<< app => $location >> (required on Windows) |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
On Windows platforms, you B<must> download the C<plink.exe> program, and pass |
|
262
|
|
|
|
|
|
|
its location in this parameter. |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=item C<< host => $hostname >> (required for Telnet and SSH transports) |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
When using the Telnet and SSH transports, you B<must> provide the IP or host |
|
267
|
|
|
|
|
|
|
name of the target device in this parameter. |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=item C<< timeout => $seconds >> |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Configures a global default timeout value, in seconds, for interaction with |
|
272
|
|
|
|
|
|
|
the remote device. The default is 10 seconds. You can also set timeout on a |
|
273
|
|
|
|
|
|
|
per-command or per-macro call (see below). |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=item C<< connect_options => \%options >> |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Some of the transport backends can take their own options. For example with a |
|
278
|
|
|
|
|
|
|
serial line connection you might specify the port speed, etc. See the |
|
279
|
|
|
|
|
|
|
respective manual pages for each transport backend for further details |
|
280
|
|
|
|
|
|
|
(L<SSH|Net::CLI::Interact::Transport::SSH>, |
|
281
|
|
|
|
|
|
|
L<Telnet|Net::CLI::Interact::Transport::Telnet>, |
|
282
|
|
|
|
|
|
|
L<Serial|Net::CLI::Interact::Transport::Serial>). |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=item C<< add_library => $directory | \@directories >> |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
If you've added to the built-in phrasebook with your own macros, then use |
|
287
|
|
|
|
|
|
|
this option to load your new phrasebook file(s). The path here should be the |
|
288
|
|
|
|
|
|
|
directory within which all your personalities are located, such as: |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
${directory}/cisco/ios/pb |
|
291
|
|
|
|
|
|
|
${directory}/other/device/pb |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
Usually the phrasebook files are called "C<pb>" and to the C<personality> |
|
294
|
|
|
|
|
|
|
option you pass the containing directory name, for example C<ios> or C<device> |
|
295
|
|
|
|
|
|
|
in the examples shown. See L<Net::CLI::Interact::Manual::Tutorial> for |
|
296
|
|
|
|
|
|
|
further details. |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=item C<< nci_options => \%options >> |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Should you wish to reconfigure the L<Net::CLI::Interact> instance used inside |
|
301
|
|
|
|
|
|
|
of C<Net::Appliance::Session>, perhaps for an option not supported above, this |
|
302
|
|
|
|
|
|
|
generic setting is available. |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=back |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head2 connect( \%options ) |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
$s->connect({ username => $myname, password => $mysecret }); |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
To establish a connection to the device, and possibly also log in, call this |
|
311
|
|
|
|
|
|
|
method. Following a successful connection, paging of device output will be |
|
312
|
|
|
|
|
|
|
disabled using commands appropriate to the platform. This feature can be |
|
313
|
|
|
|
|
|
|
suppressed (see L</"CONFIGURATION">, below). |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
Options available to this method, sometimes required, are: |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
=over 4 |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=item C<< username => $name >> |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
The login username for the device. Whether this is required depends both on |
|
322
|
|
|
|
|
|
|
how the device is configured, and how you have configured this module to act. |
|
323
|
|
|
|
|
|
|
If it looks like the device presented a Username prompt. and you don't pass |
|
324
|
|
|
|
|
|
|
the username a Perl exception will be thrown. |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
The username is cached within the module for possible use later on when |
|
327
|
|
|
|
|
|
|
entering "privileged" mode. |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=item C<< password => $secret >> |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
The login password for the device. Whether this is required depends both on |
|
332
|
|
|
|
|
|
|
how the device is configured, and how you have configured this module to act. |
|
333
|
|
|
|
|
|
|
If it looks like the device presented a Username prompt. and you don't pass |
|
334
|
|
|
|
|
|
|
the username a Perl exception will be thrown. |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
The password is cached within the module for possible use later on when |
|
337
|
|
|
|
|
|
|
entering "privileged" mode. |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=item C<< privileged_password => $secret >> (optional) |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
In the situation where you've activated "privileged paging", yet your device |
|
342
|
|
|
|
|
|
|
uses a different password for privileged mode than login, you'll need to set |
|
343
|
|
|
|
|
|
|
that other password here. |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
Otherwise, because the module tries to disable paging, it first goes into |
|
346
|
|
|
|
|
|
|
privileged mode as you instructed, and fails with the wrong (login) password. |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=back |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 begin_privileged and end_privileged |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
$s->begin_privileged; |
|
353
|
|
|
|
|
|
|
# do some work |
|
354
|
|
|
|
|
|
|
$s->end_privileged; |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
Once you have connected to the device, change to "privileged" mode by calling |
|
357
|
|
|
|
|
|
|
the C<begin_privileged> method. The appropriate command will be issued for |
|
358
|
|
|
|
|
|
|
your device platform, from the phrasebook. Likewise to exit "privileged" mode |
|
359
|
|
|
|
|
|
|
call the C<end_privileged> method. |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Sometimes authentication is required to enter "privileged" mode. In that case, |
|
362
|
|
|
|
|
|
|
the module defaults to using the username and password first passed in the |
|
363
|
|
|
|
|
|
|
C<connect> method. However to either override those or set them in case they |
|
364
|
|
|
|
|
|
|
were not passed to C<connect>, use either or both of the following options to |
|
365
|
|
|
|
|
|
|
C<begin_privileged>: |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
$s->begin_privileged({ username => $myname, password => $mysecret }); |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 begin_configure and end_configure |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
$s->begin_configure; |
|
372
|
|
|
|
|
|
|
# make some changes |
|
373
|
|
|
|
|
|
|
$s->end_configure; |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
To enter "configuration" mode for your device platform, call the |
|
376
|
|
|
|
|
|
|
C<begin_configure> method. This checks you are already in "privileged" mode, |
|
377
|
|
|
|
|
|
|
as the module assumes this is necessary. If it isn't necessary then see |
|
378
|
|
|
|
|
|
|
L</"CONFIGURATION"> below to modify this behaviour. Likewise to exit |
|
379
|
|
|
|
|
|
|
"configure" mode, call the C<end_configure> method. |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head2 cmd( $command ) |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
my $config = $s->cmd('show running-config'); |
|
384
|
|
|
|
|
|
|
my @interfaces = $s->cmd('show interfaces brief'); |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Execute a single command statement on the connected device. The statement is |
|
387
|
|
|
|
|
|
|
executed verbatim on the device, with a newline appended. |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
In scalar context the response is returned as a single string. In list context |
|
390
|
|
|
|
|
|
|
the gathered response is returned as a list of lines. In both cases your local |
|
391
|
|
|
|
|
|
|
platform's newline character will end all lines. |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
You can also call the C<last_response> method which returns the same data with |
|
394
|
|
|
|
|
|
|
the same contextual behaviour. |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
This method accepts a hashref of options following the C<$command>, which can |
|
397
|
|
|
|
|
|
|
include a C<timeout> value to permit long running commands to have all their |
|
398
|
|
|
|
|
|
|
output gathered. |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
To handle more complicated interactions, for example commands which prompt for |
|
401
|
|
|
|
|
|
|
confirmation or optional parameters, you should use a Macro. These are set up |
|
402
|
|
|
|
|
|
|
in the phrasebook and issued via the C<< $s->macro($name) >> method call. See |
|
403
|
|
|
|
|
|
|
the L<Phrasebook|Net::CLI::Interact::Phrasebook> and |
|
404
|
|
|
|
|
|
|
L<Cookbook|Net::CLI::Interact::Manual::Cookbook> manual pages for further |
|
405
|
|
|
|
|
|
|
details. |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
If you receive response text with a "mangled" copy of the issued command at |
|
408
|
|
|
|
|
|
|
the start, then it's likely you need to set the terminal width. This prevents |
|
409
|
|
|
|
|
|
|
the connected device from line-wrapping long commands. Issue something like: |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
$s->begin_privileged; |
|
412
|
|
|
|
|
|
|
$s->cmd('terminal width 510'); |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=head2 close |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
$s->close; |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
Once you have finished work with the device, call this method. It attempts to |
|
419
|
|
|
|
|
|
|
back out of any "privileged" or "configuration" mode you've entered, re-enable |
|
420
|
|
|
|
|
|
|
paging (unless suppressed) and then disconnect. |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
If a macro named C<"disconnect"> exists in the loaded phrasebook then it's |
|
423
|
|
|
|
|
|
|
called just before disconnection. This allows you to issue a command such as |
|
424
|
|
|
|
|
|
|
C<"exit"> to cleanly log out. |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=head1 CONFIGURATION |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Each of the entries below may either be passed as a parameter in the options |
|
429
|
|
|
|
|
|
|
to the C<new> method, or called as a method in its own right and passed the |
|
430
|
|
|
|
|
|
|
appropriate setting. If doing the latter, it should be before you call the |
|
431
|
|
|
|
|
|
|
C<connect> method. |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=over |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=item do_login |
|
436
|
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
Defaults to true. Pass a zero (false) to disable logging in to the device with |
|
438
|
|
|
|
|
|
|
a username and password, should you get a command prompt immediately upon |
|
439
|
|
|
|
|
|
|
connection. |
|
440
|
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=item do_privileged_mode |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
Defaults to true. If on connecting to the device your user is immediately in |
|
444
|
|
|
|
|
|
|
"privieleged" mode, then set this to zero (false), which permits immediate |
|
445
|
|
|
|
|
|
|
access to "configure" mode. |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=item do_configure_mode |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Defaults to true. If you set this to zero (false), the module assumes you're |
|
450
|
|
|
|
|
|
|
in "configure" mode immediately upon entering "privileged" mode. I can't think |
|
451
|
|
|
|
|
|
|
why this would be useful but you never know. |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=item do_paging |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Defaults to true. Pass a zero (false) to disable the post-login |
|
456
|
|
|
|
|
|
|
reconfiguration of a device which avoids paged command output. If you cleanly |
|
457
|
|
|
|
|
|
|
C<close> the device connection then paging is re-enabled. Use this option to |
|
458
|
|
|
|
|
|
|
suppress these steps. |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=item privileged_paging |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
Defaults to false. On some series of devices, in particular the Cisco ASA and |
|
463
|
|
|
|
|
|
|
PIXOS7+ you must be in privileged mode in order to alter the pager. If that is |
|
464
|
|
|
|
|
|
|
the case for your device, call this method with a true value to instruct the |
|
465
|
|
|
|
|
|
|
module to better manage the situation. |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=item pager_enable_lines |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
Defaults to 24. The command issued to re-enable paging (on disconnect) |
|
470
|
|
|
|
|
|
|
typically takes a parameter which is the number of lines per page. If you want |
|
471
|
|
|
|
|
|
|
a different value, set it in this option. |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=item pager_disable_lines |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
Defaults to zero. The command issued to disable paging typically takes a |
|
476
|
|
|
|
|
|
|
parameter which is the number of lines per page (zero begin to disable |
|
477
|
|
|
|
|
|
|
paging). If your device uses a different number here, set it in this option. |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=item wake_up |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
When first connecting to the device, the most common scenario is that a |
|
482
|
|
|
|
|
|
|
Username (or some other) prompt is shown. However if no output is forthcoming |
|
483
|
|
|
|
|
|
|
and nothing matches, the "enter" key is pressed, in the hope of triggering the |
|
484
|
|
|
|
|
|
|
display of a new prompt. This is typically most useful on Serial connected |
|
485
|
|
|
|
|
|
|
devices. |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
Set this configuration option to zero to suppress this behaviour, or to the |
|
488
|
|
|
|
|
|
|
number of times "enter" should be pressed and output waited for. The default |
|
489
|
|
|
|
|
|
|
is to press "enter" once. |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=back |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head1 ASYNCHRONOUS BEHAVIOUR |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
The standard, and recommended way to use this module is as above, whereby the |
|
496
|
|
|
|
|
|
|
application is blocked waiting for command response. It's also possible to |
|
497
|
|
|
|
|
|
|
send a command, and separately return to ask for output at a later time. |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
$s->say('show clock'); |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
This will send the command C<show clock> to the connected device, followed by |
|
502
|
|
|
|
|
|
|
a newline character. |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
$s->gather(); |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
This will gather and return output, with similar behaviour to C<cmd()>, above. |
|
507
|
|
|
|
|
|
|
That is, it blocks waiting for output and a prompt, will timeout, and accepts |
|
508
|
|
|
|
|
|
|
the same options. |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
You can still use C<last_response> after calling C<gather>, however be aware |
|
511
|
|
|
|
|
|
|
that the command (from C<say>) may be echoed at the start of the output, |
|
512
|
|
|
|
|
|
|
depending on device and connection transport. |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head1 DIAGNOSTICS |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
To see a log of all the processes within this module, and a copy of all data |
|
517
|
|
|
|
|
|
|
sent to and received from the device, call the following method: |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
$s->set_global_log_at('notice'); |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
In place of C<notice> you can have other log levels (e.g. C<debug> for more, |
|
522
|
|
|
|
|
|
|
or C<info> for less), and via the embedded |
|
523
|
|
|
|
|
|
|
L<Logger|Net::CLI::Interact::Logger> at C<< $s->nci->logger >> it's possible |
|
524
|
|
|
|
|
|
|
to finely control the diagnostics. |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=head1 INTERNALS |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
See L<Net::CLI::Interact>. |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=head1 THANKS |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
Over several years I have received many patches and suggestions for |
|
533
|
|
|
|
|
|
|
improvement from users of this module. My heartfelt thanks to all, for their |
|
534
|
|
|
|
|
|
|
contributions. |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=head1 AUTHOR |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
Oliver Gorwits <oliver@cpan.org> |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
This software is copyright (c) 2019 by Oliver Gorwits. |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
545
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=cut |
|
548
|
|
|
|
|
|
|
|