At work, we have a few hundred Linux servers, and with that amount
of hardware it is important to keep track of when the hardware support
contract expire for each server. We have a machine (and service)
register, which until recently did not contain much useful besides the
machine room location and contact information for the system owner for
each machine. To make it easier for us to track support contract
status, I've recently spent time on extending the machine register to
include information about when the support contract expire, and to tag
machines with expired contracts to make it easy to get a list of such
machines. I extended a perl script already being used to import
information about machines into the register, to also do some screen
scraping off the sites of Dell, HP and IBM (our majority of machines
are from these vendors), and automatically check the support status
for the relevant machines. This make the support status information
easily available and I hope it will make it easier for the computer
owner to know when to get new hardware or renew the support contract.
The result of this work documented that 27% of the machines in the
registry is without a support contract, and made it very easy to find
them. 27% might seem like a lot, but I see it more as the case of us
using machines a bit longer than the 3 years a normal support contract
last, to have test machines and a platform for less important
services. After all, the machines without a contract are working fine
at the moment and the lack of contract is only a problem if any of
them break down. When that happen, we can either fix it using spare
parts from other machines or move the service to another old
machine.
I believe the code for screen scraping the Dell site was originally
written by Trond Hasle Amundsen, and later adjusted by me and Morten
Werner Forsbring. The HP scraping was written by me after reading a
nice article in ;login: about how to use WWW::Mechanize, and the IBM
scraping was written by me based on the Dell code. I know the HTML
parsing could be done using nice libraries, but did not want to
introduce more dependencies. This is the current incarnation:
use LWP::Simple;
use POSIX;
use WWW::Mechanize;
use Date::Parse;
[...]
sub get_support_info {
my ($machine, $model, $serial, $productnumber) = @_;
my $str;
if ( $model =~ m/^Dell / ) {
# fetch website from Dell support
my $url = "http://support.euro.dell.com/support/topics/topic.aspx/emea/shared/support/my_systems_info/no/details?c=no&cs=nodhs1&l=no&s=dhs&ServiceTag=$serial";
my $webpage = get($url);
return undef unless ($webpage);
my $daysleft = -1;
my @lines = split(/\n/, $webpage);
foreach my $line (@lines) {
next unless ($line =~ m/Beskrivelse/);
$line =~ s/<[^>]+?>/;/gm;
$line =~ s/^.+?;(Beskrivelse;)/$1/;
my @f = split(/\;/, $line);
@f = @f[13 .. $#f];
my $lastend = "";
while ($f[3] eq "DELL") {
my ($type, $startstr, $endstr, $days) = @f[0, 5, 7, 10];
my $start = POSIX::strftime("%Y-%m-%d",
localtime(str2time($startstr)));
my $end = POSIX::strftime("%Y-%m-%d",
localtime(str2time($endstr)));
$str .= "$type $start -> $end ";
@f = @f[14 .. $#f];
$lastend = $end if ($end gt $lastend);
}
my $today = POSIX::strftime("%Y-%m-%d", localtime(time));
tag_machine_unsupported($machine)
if ($lastend lt $today);
}
} elsif ( $model =~ m/^HP / ) {
my $mech = WWW::Mechanize->new();
my $url =
'http://www1.itrc.hp.com/service/ewarranty/warrantyInput.do';
$mech->get($url);
my $fields = {
'BODServiceID' => 'NA',
'RegisteredPurchaseDate' => '',
'country' => 'NO',
'productNumber' => $productnumber,
'serialNumber1' => $serial,
};
$mech->submit_form( form_number => 2,
fields => $fields );
# Next step is screen scraping
my $content = $mech->content();
$content =~ s/<[^>]+?>/;/gm;
$content =~ s/\s+/ /gm;
$content =~ s/;\s*;/;;/gm;
$content =~ s/;[\s;]+/;/gm;
my $today = POSIX::strftime("%Y-%m-%d", localtime(time));
while ($content =~ m/;Warranty Type;/) {
my ($type, $status, $startstr, $stopstr) = $content =~
m/;Warranty Type;([^;]+);.+?;Status;(\w+);Start Date;([^;]+);End Date;([^;]+);/;
$content =~ s/^.+?;Warranty Type;//;
my $start = POSIX::strftime("%Y-%m-%d",
localtime(str2time($startstr)));
my $end = POSIX::strftime("%Y-%m-%d",
localtime(str2time($stopstr)));
$str .= "$type ($status) $start -> $end ";
tag_machine_unsupported($machine)
if ($end lt $today);
}
} elsif ( $model =~ m/^IBM / ) {
# This code ignore extended support contracts.
my ($producttype) = $model =~ m/.*-\[(.{4}).+\]-/;
if ($producttype && $serial) {
my $content =
get("http://www-947.ibm.com/systems/support/supportsite.wss/warranty?action=warranty&brandind=5000008&Submit=Submit&type=$producttype&serial=$serial");
if ($content) {
$content =~ s/<[^>]+?>/;/gm;
$content =~ s/\s+/ /gm;
$content =~ s/;\s*;/;;/gm;
$content =~ s/;[\s;]+/;/gm;
$content =~ s/^.+?;Warranty status;//;
my ($status, $end) = $content =~ m/;Warranty status;([^;]+)\s*;Expiration date;(\S+) ;/;
$str .= "($status) -> $end ";
my $today = POSIX::strftime("%Y-%m-%d", localtime(time));
tag_machine_unsupported($machine)
if ($end lt $today);
}
}
}
return $str;
}
Here are some examples on how to use the function, using fake
serial numbers. The information passed in as arguments are fetched
from dmidecode.
print get_support_info("hp.host", "HP ProLiant BL460c G1", "1234567890"
"447707-B21");
print get_support_info("dell.host", "Dell Inc. PowerEdge 2950", "1234567");
print get_support_info("ibm.host", "IBM eserver xSeries 345 -[867061X]-",
"1234567");
I would recommend this approach for tracking support contracts for
everyone with more than a few computers to administer. :)
Update 2009-03-06: The IBM page do not include extended support
contracts, so it is useless in that case. The original Dell code do
not handle extended support contracts either, but has been updated to
do so.