Thursday, February 24, 2011

Connecting to HP ProCurve switches from Perl

I recently needed to get various information out of our switches, but didn't feel like manually logging into each one to get it. I tried to google up something that did it for me and failed, so I rolled my own script to connect to a number of HP ProCurve switches and get information from them using the Perl module Net::Telnet.

This is a simple example of how it can be done, hopefully to the help of the next person googling this. The below script makes various assumptions that are probably wrong for your network, like that all switches are reachable via domain names like sw12345.mgmt.

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;
use Net::Telnet;

my $swpw = "hackmenot"; # Assumes same password for all switches.
my @switches = ("sw12345", "sw12346", "sw12347", "sw12348");

# Firmware versions that don't have the "Press any key" prompt.
my %nopress = (
"K.14.47" => 1,
"W.14.49" => 1,
);

foreach my $sw (@switches) {
my ($model, $version, $string, $trunks) = &get_information($sw);
printf "%s: %s (%s)\n loop-protect: %s\n trunks: %s\n\n",
$sw, $model, $version, $string, $trunks;
}


sub get_information {
my ($switch) = @_;

my @output;

my $session = new Net::Telnet(Timeout => 5,
Telnetmode => 0,
Prompt => '/'.$switch.'.*?# /',
Dump_log => "/tmp/procurve.txt", # Debug log.
Host => "$switch.mgmt"
);

# Figure out what model the switch is. To make this more exciting, HP has
# varied the output between different versions.
my ($prematch, $match) = $session->waitfor('/ProCurve.*?Switch.*\n/');
my $model = $match;
$model =~ s/[\r\n]//g;
$model =~ s/ProCurve //i;
$model =~ s/\s*J\d+[AB]\s*//i;
$model =~ s/\s*Switch\s*//i;

($prematch, $match) =
$session->waitfor('/(Firmware|Software) revision.*\n/');
$match =~ m/(Software|Firmware) revision (.*)/i;
my $version = $2 || "";
$version =~ s/[\r\n]//g;

# Some versions of the firmware don't have this prompt.
if (!$nopress{$version}) {
$session->waitfor('/Press any key to continue/');
$session->print("");
}

$session->waitfor('/Password: /');
$session->print($swpw);

$session->waitfor('/'.$switch.'.*?# /');

# Avoid the "more" prompt for long output.
@output = $session->cmd(String => "terminal length 1000");

# List the configuration to see what ports have loop-protect set.
@output = $session->cmd(String => "show running");
@output = grep(/loop-protect/, @output);
my $loop = join(", ", @output) || "";
$loop =~ s/[\r\n]//g;
$loop =~ s/loop-protect\s*//i;

# Check what ports are used for trunks.
@output = $session->cmd(String => "show trunks");
@output = grep(/Trk/, @output);
my $trunks =
join(" ", map { $_ =~ m/\s+(\d+)\s.*\s(Trk\d+)\s/ && $1 } @output);

$session->close;

return ($model, $version, $loop, $trunks);
}