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::Cookbook::Recipe07 - Changing Device Configurations

NOTE

This Cookbook was contributed to the Net::Appliance::Session project by Nigel Bowden. Source code from the Cookbook is shipped in the examples folder of this module's distribution.

PROBLEM

You need to be able to access a Cisco device to update its configuration.

SOLUTION

Here is the solution to apply device configuration updates to a Cisco IOS device.

Again, for simplicity, it is assumed that after login, the user account being used is dropped in to privilege level 15 (enable). The login username and password are also hard-coded in to the script for simplicity of demonstrating this technique.

Also, it is assumed that this script will be passed the IP address of the target IOS device via the command line, as a command line parameter.

In addition, the configuration commands that need to be executed are also passed in via the command line. Note that each IOS command passed to the script via the command line needs to be wrapped in quotes - this is to prevent the shell from splitting the commands up and passing them incorrectly to the script.

A simple example of usage from the command line would be:

 perl Recipe_07.pl 10.250.249.215 "snmp-server location London" "snmp-server contact Network Ops"

This would send two commands to the device at 10.250.249.215 that would update the snmp configuration of that device (it just adds a location name and contact details in this instance).

 use strict;
 use warnings;
 
 use Net::Appliance::Session;
 
 my $device_ip = shift @ARGV; # get the IP address from the command line
 my @cmd       = @ARGV; # get the commands from the command line
 
 # check we have passed at least one command
 unless ($cmd[0]) {
     print qq(Usage : Recipe_07.pl <device_ip> "<ios_conf_command>" );
     print qq([ "<ios_conf_command>" .. "<ios_conf_command>" ]\n);
     exit 1;
 }
 
 # common username and password for all devices
 my $ios_username        = 'cisco';
 my $ios_password        = 'cisco';
 
 my $session_obj = Net::Appliance::Session->new(
     Host      => $device_ip,
     Transport => 'Telnet',
 );
 
 $session_obj->input_log(*STDOUT);
 
 # tell our object we'll be in privileged mode straight after login
 $session_obj->do_privileged_mode(0);    
 
 # start eval block to trap errors in interactive session
 eval {
     
     # try to login to the ios device, ignoring host check
     $session_obj->connect(Name => $ios_username, Password => $ios_password);
     
     # go in to conf mode (i.e. 'conf t')
     $session_obj->begin_configure;
     
     for my $conf_cmd (@cmd) {
         $session_obj->cmd($conf_cmd);
     }
     
     # uncomment these lines to write the changes to the startup config
     #$session_obj->end_configure;
     #$session_obj->cmd("write memory");
     
 };
 
 # close down our session
 $session_obj->close;
 
 # did we get an error ?
 if ($@) {
     print error_report($@, $device_ip);
 }
     
 sub error_report {
     
     # standard subroutine used to extract failure info when
     # interactive session fails
     
     my $err         = shift or croak("No err !");
     my $device_name = shift or croak("No device name !");
     
     my $report; # holder for report message to return to caller
     
     if ( UNIVERSAL::isa($err, 'Net::Appliance::Session::Exception') ) {
             
         # fault description from Net::Appliance::Session
         $report  =  "We had an error during our Telnet/SSH session to device  : $device_name \n"; 
         $report .= $err->message . " \n";
             
         # message from Net::Telnet
         $report .= "Net::Telnet message : " . $err->errmsg . "\n"; 
             
         # last line of output from your appliance  
         $report .=  "Last line of output from device : " . $err->lastline . "\n\n";
 
     }
     elsif (UNIVERSAL::isa($err, 'Net::Appliance::Session::Error') ) {
         
         # fault description from Net::Appliance::Session
         $report  = "We had an issue during program execution to device : $device_name \n";
         $report .=  $err->message . " \n";
 
     }
     else {
         
         # we had some other error that wasn't a deliberately created exception
         $report  = "We had an issue when accessing the device : $device_name \n";
         $report .= "The reported error was : $err \n";
     }
         
     return $report;
 }

DISCUSSION

If you've read through the the previous recipes in this section of the cookbook, you shouldn't have too many issues following the flow of this particular example.

We start by taking some command line arguments to give us the IP address of the device we want to make changes on, together with the commands that we wish to process :

 my $device_ip = shift @ARGV; # get the IP address from the command line
 my @cmd       = @ARGV; # get the commands from the command line

The first argument passed in is the IP address of our target device, and any subsequent arguments are assumed to be IOS commands that will be applied to the device, once we have logged into it.

As stated previously (but I'll say it again in case you didn't read that part), each command should be wrapped in quotes, otherwise any space characters in the IOS commands will assumed to be parameter delimiters and the script will try to send each indiviudual word as an IOS command (which obviously won't work).

If we find that we haven't passed any IOS commands to the script, we output a helpful little message and the script terminates :

 # check we have passed at least one command
 unless ($cmd[0]) {   
     print qq(Usage : Recipe_07.pl <device_ip> "<ios_conf_command>" );
     print qq([ "<ios_conf_command>" .. "<ios_conf_command>" ]\n);
     exit 1;
 }

Once we get into our eval segment, where we execute our interactive commands, we see a few things which we haven't met before :

 # go in to conf mode (i.e. 'conf t')
 $session_obj->begin_configure;
 
 for my $conf_cmd (@cmd) {
     $session_obj->cmd($conf_cmd);
 }
 
 # uncomment these lines to write the changes to the startup config
 #$session_obj->end_configure;
 #$session_obj->cmd("wr m");

The begin_configure method takes us in to the configuration mode for our device - its the equivilent of a conf t command (in fact that's what Net::Session::Appliance does in the background). Note that in this example we have previously executed $session_obj->do_privileged_mode(0) to tell our session object that we are already in enable mode when we logged in to our device.

We then proceed to execute the commands that were passed via the command line, that have been stored in the @cmd array. Don't forget, if any of the commands fail (e.g. due to a syntax error), an exception will be generated and no subsequent commands will be executed.

 # uncomment these lines to write the changes to the startup config
 #$session_obj->end_configure;
 #$session_obj->cmd("write memory");

After the commands have been executed, the configuration changes are only applied to running configuration of the device. If we want to make the changes permanent we need to write them to the startup configuration of the device. To do this, we have to first drop out of config mode using the end_configure method.

Next, we need to execute the write memory command (I know there are quite a few variations to this command: wr m, write mem, copy run start etc. - use whichever you feel most comfortable with).

I left these two lines commented out in the script so that if you are experimenting with it, and you inadvertently send anything which you later regret, you will be able to go back to the original configuration by rebooting the device or doing a copy startup-config running-config command on the device.

Although this script is quite crude, it demonstrates the principles required to change an IOS device configuration. By using some of techniques demonstrated in previous recipes, some powerful scripts could be created for managing configuration changes across IOS devices on your network.

SEE ALSO

Net::Appliance::Session

AUTHOR

Nigel Bowden, with POD formatting by Oliver Gorwits.

COPYRIGHT & LICENSE

Copyright (c) Nigel Bowden 2007. All Rights Reserved.

You may distribute and/or modify this documentation under the same terms as Perl itself.