Tuesday 30 November 2010

Managing ProCurve firmware updates with PHP and SNMP

When you look after a large number of switches, it can become important to manage firmware updates effectively. I have created a quick script to run though a list of IP addresses, and check what is the latest available firmware. This is thanks in part to the open way ProCurve allow you obtain new firmware. Not like some other switch vendors... Anyway, I hope this can help a few people out. It certainly comes in handy for me when it comes to update time.

When appling it to you own situation you just need to edit the SNMP community you are using and put your own switch IPs into the device_list array. You can add as many extras as you need.

<?php
/*
 *      ProCurve Firmware Manager
 *
 *      An HRH Script.
 */

### Setup some varibales
$SNMP_COM = 'yourcommunity';
$SYS_DESC_OID = "1.3.6.1.2.1.1.1.0";
$SYS_UP_OID = "1.3.6.1.2.1.1.3.0";
$SYS_NAME_OID = "1.3.6.1.2.1.1.5.0";
$HP_BASE_URL = 'http://h10144.www1.hp.com/customercare/support/software/switches.htm';

## Create a list of the devices we are monitoring
$device_list[] = "10.0.0.254";
$device_list[] = "10.0.1.254";
$device_list[] = "10.0.2.254";
$device_list[] = "10.0.3.254";

# Which Firmware branches are we interested in
$firmware_branch[] = 'E';
$firmware_branch[] = 'F';
$firmware_branch[] = 'G';
$firmware_branch[] = 'H';
$firmware_branch[] = 'I';
$firmware_branch[] = 'K';
$firmware_branch[] = 'R';


# Declare some common functions

# @ Clean output
# A function to remove the unnecessary from SNMP GET otuput
function clean_output($string) {
    $clean_output = preg_replace("/[A-Za-z]*:[ ]/", "", $string);
    $clean_output = preg_replace("/[(][0-9]*[)][ ]/", "", $clean_output);    
    $clean_output = str_replace("Gauge32", "", $clean_output);
    $clean_output = str_replace("Counter32", "", $clean_output);
    $clean_output = preg_replace("/[(][0-9][)]/", "", $clean_output);
    return $clean_output;
}

# @ clean to firmware
# A function to show the procurves running firmware from its 
function clean_to_firmware($string) {
    $clean_output = $string;
    $clean_output = str_replace("revision", "", $clean_output);
    $clean_output = str_replace(" ", "", $clean_output);
    $parts = explode(",",$clean_output);
    return $parts[1];
}

## Get the latest Available firmwares from HP
# Collect the latest list of firmwares from the HP website
exec("wget $HP_BASE_URL 2> error.txt");

## Build the firmware array, with the links and versions of firmware available
if(!file_exists("switches.htm")) {
    echo "Unable to locate switches.htm. Check connectivity to the internet";
    exit();
} else { 
    foreach($firmware_branch as $branch) {
        $output = `cat switches.htm | grep -m 2 $branch.[0-9][0-9][.][0-9][0-9]*\<`;
        # strip the beginning a href, and other bits, to leave a url and version name.
        $output = preg_replace("/[<]a href=\"/", "", $output);
        $output = preg_replace("/\" class=\"[a-z]*\">/", "_", $output);
        $output = preg_replace("%</a><[/brtd]*>%", "", $output);
        $output = str_replace(" ", "", $output);
        $output = str_replace("</a><br>", "", $output);        
        $output = str_replace("</a><spanclass=\"newmarker\">Updated</span><br>", "", $output);
        $lines = explode("\n", $output);
        $bits_pri = explode("_", $lines[0]);
        $bits_sec = explode("_", $lines[1]);
        $firmwares[$branch]['new_ver'] = $bits_pri[1];
        $firmwares[$branch]['new_url'] = $bits_pri[0];
        $firmwares[$branch]['old_ver'] = $bits_sec[1];
        $firmwares[$branch]['old_url'] = $bits_sec[0];
    }

    # Finally remove the switches.htm file so we get it fresh next time
    unlink("switches.htm");
}
?>

<html>
<head><title>Lightweight Network Manager</title></head>
<body bgcolor="silver">
<font face="arial" size="2">
<!-- This is the main display screen !-->
<center>
<h2> Lightweight Network Manager </h2>
<br><br>
</center>
<table cellpadding=5 cellspacing=5>
<tr><th>Device IP</th>
      <th>Device Name</th>
      <th>Device Uptime</th>
      <th>Running Firmware</th>
      <th>Newest Online Firmware</th>
</tr>
<?php

#       This is where the main page content starts
foreach ( $device_list as $device ) 
{
    $running_firmware = clean_to_firmware(clean_output(snmpget($device,$SNMP_COM,$SYS_DESC_OID))) ;
    $temp = explode(".",$running_firmware);
    $branch = $temp[0];
    $newest_firmware = $firmwares[$branch]['new_ver'];
    $newest_url = $firmwares[$branch]['new_url'];

    # Build the line
    echo "<tr>";
    echo "<td>$device</td>";
    echo "<td>" . clean_output(snmpget($device,$SNMP_COM,$SYS_NAME_OID)) . "</td>";
    echo "<td>" . clean_output(snmpget($device,$SNMP_COM,$SYS_UP_OID)) . "</td>";
    echo "<td>" . $running_firmware . "</td>";
    echo '<td><a href="'.$HP_BASE_URL.$newest_url.'">'.$newest_firmware.'</a></td>';
    echo "</tr>";
}
echo "</table>";
?>
</body>
</html>

Running on Windows
Ok, I'm going to have to admit something here. I took two little shortcuts when writing this on two lines (56, and 64 in the code) PHP executes some shell commands which run some common Bash commands. (wget, cat and grep)
There is however no reason why PHP can't do these things. It just requires a little modification to make the download on line 56 dump to a variable, and a couple of filters to replace line 64 which looks for the first occurance of the firmware version in the source code.

If you are behind a proxy, you may want to check the pecl_http extension at:
http://pecl.php.net/package/pecl_http
Which will allow you to specify proxy values to PHP



Notes
  • PHP should be compiled with SNMP, I think this is a defualt on most installations
  • If you have a slow connection to the internet, or a large number of switches to monitor, this could take up to a minute to run. Possibly longer if switches are down as it expects to be able to contact each device.

1 comment:

  1. Hello. Your script looks like it would be a huge help to me. Does it still work for you as you have posted it or have you made any changes? Thanks.

    ReplyDelete