The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Net::Appliance::Session - Run command-line sessions to network appliances

VERSION

This document refers to version 1.33 of Net::Appliance::Session.

SYNOPSIS

 use Net::Appliance::Session;
 my $s = Net::Appliance::Session->new('hostname.example');

 eval {
     $s->connect(Name => 'username', Password => 'loginpass');
     $s->begin_privileged('privilegedpass');
     print $s->cmd('show access-list');
     $s->end_privileged;
 };
 if ($@) {
     $e = Exception::Class->caught();
     ref $e ? $e->rethrow : die $e;
 }

 $s->close;

DESCRIPTION

Use this module to establish an interactive command-line session with a network appliance. There is special support for moving into privileged mode and configure mode, with all other commands being sent through a generic call to your session object.

There are other CPAN modules that cover similar ground, including Net::SSH and Net::Telnet::Cisco, but they are less robust or do not handle SSH properly. Objects created by this module are based upon Net::Telnet so the majority of your interaction will be with methods in that module. It is recommended that you read the Net::Telnet manual page for further details.

This module natively supports connections via SSH, Telnet and a Serial Port. All commands can be overridden from the built-in Cisco defaults in order to support other target devices; the connection process (user log-in) is similarly configurable.

METHODS

Objects created by this module are based upon Net::Telnet so the majority of your interaction will be with methods in that module.

Net::Appliance::Session->new

Like Net::Telnet you can supply either a single parameter to this method which is used for the target device hostname, or a list of named parameters as listed in the Net::Telnet documentation. Do not use Net::Telnet's Errmode parameter, because it will be overridden by this module.

The significant difference with this module is that the actual connection to the remote device is delayed until you connect().

Named Parameters, passed as a hash to this constructor, are optional. Some are described in "TRANSPORTS", "DIAGNOSTICS", and "CONFIGURATION" below. Any others are passed directly to Net::Telnet (which dies on unknown parameters).

This method returns a new Net::Appliance::Session object.

connect

When you instantiate a new Net::Appliance::Session object the module does not actually establish a connection with the target device. This behaviour is slightly different to Net::Telnet and is because the Transport may need to have login credentials before a connection is made (e.g. in the case of SSH). Use this method to establish that interactive session.

Parameters to this method are determined by the Transport (SSH, Telnet, etc) that you are running. See the Net::Appliance::Session::Transport manual page for further details.

In addition to logging in, connect will also disable paging in the output for its interactive session. This means that unlike Net::Telnet::Cisco no special page scraping logic is required in this module's code. This feature can be disabled (see "CONFIGURATION", below).

begin_privileged

To enter privileged mode on the device use this method. Of course you must be connected to the device using the connect method, first.

All parameters are optional, and if none are given then the login password will be used as the privileged password.

If one parameter is given then it is assumed to be the privileged password.

If two parameters are given then they are assumed to be the privileged username and password, respectively.

If more than two parameters are given then they are interepreted as a list of named parameters using the key names Name and Password for the privileged username and password, respectively.

end_privileged

To leave privileged mode and return to the unpriviledged shell then use this method.

in_privileged_mode

This method will return True if your interactive session is currently in privileged (or configure) mode, and False if it is not.

Also, you can pass a True or False value to this method to "trick" the module and alter its behaviour. This is useful for performing secondary logins (see CPAN Forum).

begin_configure

In order to enter configure mode, you must first have entered privileged mode, using the begin_privileged method described above.

To enter configure mode on the device use this method.

end_configure

To leave configure mode and return to privileged mode the use this method.

in_configure_mode

This method will return True if your interactive session is currently in configure mode, and False if it is not.

Also, you can pass a True or False value to this method to "trick" the module and alter its behaviour (see CPAN Forum).

cmd

Ordinarily, you might use this Net::Telnet method in scalar context to observe whether the command was successful on the target appliance. However, this module's version dies if it doesn't think everything went well. See "DIAGNOSTICS" for tips on managing this using an eval{} construct.

The following error conditions are checked on your behalf:

  • Incomplete command output, it was cut short for some reason

  • Timeout waiting for command response

  • EOF or other anomaly received in the command response

  • Error message from your appliance in the response

If any of these occurs then you will get an exception with appropriately populated fields. Otherwise, in array context this method returns the command response, just as Net::Telnet would. In scalar context the object itself returned.

The only usable method arguments are String, Output and Timeout, plus as a special case, Match. The Match named argument takes in an array reference a list of one or more strings representing valid Perl pattern match operators (e.g. /foo/). Therefore, the cmd() method can check against the default command prompt, built-in error strings, and also a custom response of your choice at the same time.

Being overridden in this way means you should have less need for the print() and waitfor() methods of Net::Telnet, although they are of course still available should you want them.

close

This Net::Telnet method has been overridden to automatically back out of configure and/or privilege mode, as well as re-enable paging mode on your behalf, as necessary.

error

Rather than following the Net::Telnet documentation, this method now creates and throws an exception, setting the field values for you. See "DIAGNOSTICS" below for more information, however under most circumstances it will be called automatically for you by the overridden cmd() method.

TRANSPORTS

This module supports interactive connections to devices over SSH, Telnet and via a Serial Port. The default is to use SSH, so to select an alternative, pass an optional Transport parameter to the new() constructor:

 my $s = Net::Appliance::Session->new(
     Host      => 'hostname.example',
     Transport => 'Serial',
 );

Whatever transport you are using, it is highly recommended that you read the relevant manual page. The Net::Appliance::Session::Transport manual is a good starting place.

CONFIGURATION

Log-in

In the default case, which is SSH to a Cisco IOS device, both a Username and Password are required and a full log-in is made (i.e. the device presents a Password prompt, and so on).

However, some devices require no login. Examples of this might be a Public Route Server, or a device connected via a Serial Port. In that situation, use the following object method before calling connect():

do_login

Passing any False value to this method prevents connect() from expecting to have to negotiate a log-in to the device. Most Transports in that case do not require the Password parameter, although a Username might still be required. By default log-in negotiation is enabled.

Paging

In the default case, Net::Appliance::Session expects that command output paging is enabled on the device. This is where response to commands is "paged", having only (e.g.) 24 lines printed at a time, and you press the Enter or Space key to see more.

With automated interaction this is useless, and error-prone, so Net::Appliance::Session by default will send a command to disable paging straight after it connects, and re-enable it as part of close().

To override the pager management command itself, you will need to edit the phrasebook (see below). The following object methods alter other aspects of pager management:

do_paging

Passing any False value to this method prevents connect() and close() from respectively disabling and re-enabling paging on the device. By default paging management is enabled.

enable_paging and disable_paging

If you have an installation which requires manual issueing of paging commands to the device, then call these methods to take that action. Note that do_paging must have been passed a True value otherwise these methods will short-circuit thinking you don't want paging.

In other words, to page manually, set do_paging to False at the start of your session, before connecting, and then set it to True as you call either of these methods. This dancing around will probably be fixed in a forthcoming release of Net::Appliance::Session.

set_pager_disable_lines

Net::Appliance::Session assumes that the command to disable the pager just re-sets the number of paging lines. Pass this method a new value for that number, which has a default of zero in the module.

set_pager_enable_lines

Likewise, to re-enable paging Net::Appliance::Session will call the pager management command with a value for the number of output lines per page. Pass this method a value to override the default of 24.

Command mode

If your target device does not have the concept of "privileged exec" or "configure" mode, then just don't call the methods to change into those modes.

However, there is a catch. If your device separates only configure mode, then when you try to call begin_configure() straight after a log-in, the module will complain, because it thinks you need to ask for a begin_privileged first. Also, when disconnecting, Net::Appliance::Session will attempt to step out of privileged and configure modes, so if they don't apply you will want to disable those steps.

To alter all this behaviour, use the following object methods.

If you are trying to subvert this module to just automate interaction with a CLI via SSH, Telnet or Serial Line on a strange kind of device, then these methods will be useful (as well as do_paging, above).

do_privileged_mode

If you pass a False value to this method, then Net::Appliance::Session will believe you are in some kind of privileged mode as soon as you log in. The net effect is that you can now safely call begin_configure(). The default is to actively gatekeep access to privileged mode.

do_configure_mode

By passing a False value to this method you also make Net::Appliance::Session believe you are in configure mode straight after entering privileged mode (or after log in if do_privileged_mode is also False). The default is to actively gatekeep access to configure mode.

Commands and Prompts

Various models of network device, either from one vendor such as Cisco or between vendors, will naturally use alternate command and command prompt syntax. Net::Appliance::Session does not hard-code any of these commands or pattern matches in its source. They are all loaded at run-time from an external phrasebook (a.k.a. dictionary), which you may of course override.

The default operation of Net::Appliance::Session is to assume that the target is running a form of Cisco's IOS, so if this is the case you should not need to modify any settings.

Limited support is also available, via the Net::Appliance::Phrasebook module, for the following operating systems:

 IOS     # the default
 Aironet # currently the same as the default

 CATOS   # for older, pre-IOS Cisco devices
 PIXOS   # for PIX OS-based devices (including FWSM Release 2.x)
 FWSM    # currently the same as 'PIXOS'
 FWSM3   # for FWSM Release 3.x devices (slightly different to FWSM 2.x)

To select a phrasebook, pass an optional Platform parameter to the new method like so:

 my $s = Net::Appliance::Session->new(
     Host     => 'hostname.example',
     Platform => 'FWSM3',
 );

If you want to add a new phrasebook, or override an existing one, there are two options. Either submit a patch to the maintaner of the Net::Appliance::Phrasebook module, or read the manual page for that module to find out how to use a local phrasebook rather than the builtin one via the Source parameter (which is accepted by this module and passed on verbatim).

 my $s = Net::Appliance::Session->new(
     Host     => 'hostname.example',
     Source   => '/path/to/file.yml',
     Platform => 'MYDEVICE',
 );

In this way, you can fix bugs in the standard command set, adjust them for your own devices, or "port" this module onto a completely different appliance platform (that happens to provide an SSH, Telnet or Serial Port CLI).

Some sanity checking takes place at certain points to make sure the phrasebook contains necessary phrases. If overriding the phrasebook, you'll need to provide at least the basic_phrases as set in this module's source code. If using Privileged and Configure mode, there are privileged_phrases and configure_phrases that will be required, also. Paging requires a pager_cmd phrase to be available. See the source code of Net::Appliance::Phrasebook for examples.

If you fancy yourself as a bit of a cowboy, then there is an option to new() that disables this checking of phrasebook entries:

 my $s = Net::Appliance::Session->new(
     Host     => 'hostname.example',
     Platform => 'MYDEVICE',
     Source   => '/path/to/file.yml', # override phrasebook completely
     CheckPB  => 0, # squash errors about missing phrasebook entries
 );

You better have read the source and checked what phrases you need before disabling CheckPB. Don't say I didn't warn you.

DIAGNOSTICS

Firstly, if you want to see a copy of everything sent to and received from the appliance, then something like the following will probably do what you want:

 $s->input_log(*STDOUT);

All errors returned from Net::Appliance::Session methods are Perl exceptions, meaning that in effect die() is called and you will need to use eval {}. The rationale behind this is that you should have taken care to script interactive sessions robustly, and tested them thoroughly, so if a prompt is not returned or you supply incorrect parameters then it's an exceptional error.

Recommended practice is to wrap your interactive session in an eval block like so:

 eval {
     $s->begin_privileged('password');
     print $s->cmd('show version');
     # and so on...
 };
 if ( UNIVERSAL::isa($@,'Net::Appliance::Session::Exception') ) {
     print $@->message, "\n";  # fault description from Net::Appliance::Session
     print $@->errmsg, "\n";   # message from Net::Telnet
     print $@->lastline, "\n"; # last line of output from your appliance
     # perform any other cleanup as necessary
 }
 $s->close;

Exceptions belong to the Net::Appliance::Session::Exception class if they result from errors internal to Net::Telnet such as lack of returned prompts, command timeouts, and so on.

Alternatively exceptions will belong to Net::Appliance::Session::Error if you have been silly (for example missed a method parameter or tried to enter configure mode without having first entered privileged mode).

All exception objects are created from Exception::Class and so stringify correctly and support methods as described in the manual page for that module.

Net::Appliance::Session::Exception exception objects have two additional methods (a.k.a. fields), errmsg and lastline which contain output from Net::Telnet diagnostics.

Using a Devel::REPL shell

This module supports an additional mode of failure which can be useful when debugging Net::Appliance::Session scripts. Instead of having an exception thrown as described above, you can be dropped into an interactive shell at the connected device, if possible, instead.

A Devel::REPL shell is used, which means you also have the bonus of a full Perl environment from which you can execute Perl code, test network device commands, and save and load data from disk. Further information on how to use the shell and its features is given in the Devel::REPL::Plugin::NAS manual page.

As well as installing the Devel::REPL and Devel::REPL::Plugin::NAS modules, you'll need to change the call to new() for this module, like so:

 my $s = Net::Appliance::Session->new(
     Host => 'hostname.example',
     REPL => 1,
 );

INTERNALS

The guts of this module are pretty tricky, although I would also hope elegant, in parts ;-) In particular, the following Net::Telnet method has been overridden to modify behaviour:

fhopen

The killer feature in Net::Telnet is that it allows you to swap out the builtin I/O target from a standard TELNET connection, to another filehandle of your choice. However, it does so in a rather intrusive way to the poor object, so this method is overridden to safeguard our instance's private data.

DEPENDENCIES

Other than the contents of the standard Perl distribution, you will need the following:

You can also make use of certain features by installing the following optional modules:

AUTHOR

Oliver Gorwits <oliver.gorwits@oucs.ox.ac.uk>

ACKNOWLEDGEMENTS

Parts of this module are based on the work of Robin Stevens and Roger Treweek. The command spawning code was based on that in Expect.pm and is copyright Roland Giersig and/or Austin Schutz.

COPYRIGHT & LICENSE

Copyright (c) The University of Oxford 2008.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.