Cisco Error Lookup Tool Scraper

From Internetworkpro

Jump to: navigation, search

Contents

[edit] NAME

CiscoErrorTool - Scrape CCO Error Lookup took and return the results

[edit] SYNOPSIS

use Data::Dumper;
 
  my $cet = new CiscoErrorTool->new(cco_user => 'username',
                                    cco_pass => 'pass',
                                    cache_file => 'C:\\tmp\\cisco_err_dec.dbm',
                                    cookie_file => 'C:\\tmp\\cisco_err_cookie.txt');
 
  print Dumper($cet->query("%AT-6-NODEWRONG"));

[edit] DESCRIPTION

CiscoErrorTool allows you to pass a syslog error from a Cisco device and return the results in a hash.

To prevent hammering of the Cisco servers a local cache is used to store the results and is used for each subsequent lookup of the error

This tool can be used with a syslog server to provide some addition information into your router and switch logs.

[edit] CAVEATS

The connection to Cisco's website can be a bit slow at times.

I do not take any responsibility with the program. If you run this 500 times and hammer Cisco's webserver and get your CCO revoked don't come crying to me

Some queries will return multiple results. The first time you query a string that returns multiple results, you will see them all. The second time, when it hits the cache, it will only return a single result. This is a known issue and we may switch to using something like SQLite to get around the limitations/complexity of trying to make a "relational database" with MLDBM.

[edit] METHODS

new - create new CiscoErrorTool object 
$cet = CiscoErrorTool->new(
        [cco_user                 => $username,] 
        [cco_pass         => $password,]
        [url              => $uri,]      # http://www.cisco.com/cgi-bin/Support/Errordecoder/index.cgi
        [cache_file       => $filepath,] # /var/tmp/CiscoErrorTool.dbm
        [cookie_file      => $filepath,] # /tmp/CiscoErrorTool.cookiejar
        [use_cache        => $boolean,]  # 1
    );

Creates a new object. Read `perldoc perlboot` if you don't understand that.

query - run the query again Cisco's website 
$results = $cet->query();
 
    $results = $cet->query($error_string);

Passing of the error string is optional if you set it using new() or query_string() functions A hash reference is retured with the following fields: RLnk # Related documents Vars # The variables in the syslog message Desc # A detailed description of the error message Name # Name of the error, should be the same as the string passed above Link # A recomended action link

[edit] SUPPORT

No official support for this module, but please email the author or chat with him on irc.

[edit] AUTHOR

Brandon Bennett <bennetb@gmail.com>

nemith on #cisco@irc.freenode.net

Let me know if you have any ideas or suggestions on how to make this tool better

[edit] THANKS

Thank you very much to Michael J. Freeman <mfreeman451@gmail.com> who added the caching portion of code and helped toss around some ideas.

[edit] COPYRIGHT AND LICENSE

Copyright (c) 2006 Brandon Bennett All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

[edit] Code

package CiscoErrorTool;
 
#-----------------------------------------------------------------
# CiscoErrorTool - Scrape CCO Error Lookup took and return the results
#
# Todo: 
#   * Add a syslog parser and return an array of results
#   * Make POD documentation better
#
#
# POD documentation at end of file.
#
#----------------------------------------------------------------
 
use strict;
use Carp;
use URI;	
use LWP;
use HTML::TokeParser;
 
$VERSION  = '1.0';
$DEBUG    = 0;
 
#------------------------------
# Public Methods
#------------------------------
 
sub new {
    my $class = shift; 
 
	my $self = {
		_cco_user     => '',
	    _cco_pass     => '',
		_query_string => '',
		_url          => 'http://www.cisco.com/cgi-bin/Support/Errordecoder/index.cgi',
		_cache_file   => '/var/tmp/cisco_err_dec.dbm',
		_cookie_file  => '/tmp/cisco_err_cookie.txt',
		_use_cache	  => 1
	};
 
    my %args = @_;
 
	bless $self, ref($class) || $class;
 
     # Parse named args.
     while (my ($k, $v) = each %args) {
		 if ($k =~ /^-?cco_user$/i) {
			 $self->cco_user($v);
		 } elsif ($k =~ /^-?cco_pass$/i) {
			 $self->cco_pass($v);
		 } elsif ($k =~ /^-?query_string$/i) {
			 $self->query_string($v);
		 } elsif ($k =~ /^-?url$/i) {
			 $self->url($v);
		 } elsif ($k =~ /^-?cache_file$/i) {
			 $self->cache_file($v);
		 } elsif ($k =~ /^-?cookie_file$/i) {
			 $self->cookie_file($v);
		 } elsif ($k =~ /^-?use_cache$/i) {
			 $self->use_cache($v);
		}
	 }
 
	 $self;
} # end sub new
 
sub query {
	my $self = shift;
	my $arg = shift;
 
	my %query_hash;
    my $result;
 
	if ($self->{_use_cache} && $self->{_cache_file}) {
	  use MLDBM 'DB_File';
 
 
	  tie %query_hash, "MLDBM", $self->{_cache_file} # Open database, to be accessed
	    or die "Can't open $self->{_cache_file}: $!\n";
    }
 
	$self->{_query_string} = $arg if $arg;
 
    if (exists $query_hash{$self->{_query_string}}) {
		print "Cached!\n";
		$result = $query_hash{$self->{_query_string}};
	} else {
		my $url = URI->new($self->{_url});
 
 	    $url->query_form(
 	      'action'  => 'search',
 	      'locale'  => 'en',
 	      'index'   => 'all', 
 	      'query'	=> $self->{_query_string},
 	      'paging'  => '5',
 	      'counter' => '0',
 	      'links'   => 'reference',
 	      'sa'      => 'Submit',
 	    );
 
	   my $browser = LWP::UserAgent->new;
 
 	   $browser->agent("Mozilla/5.0");
 	   $browser->cookie_jar({ file => $self->{_cookie_file} });
 
 	   $browser->credentials(
 	     'www.cisco.com:80',
 	     'CCO',
 	     $self->{_cco_user} => $self->{_cco_pass}
 	   );
 
 	   $browser->env_proxy;
 
 	   my $response = $browser->get($url);
 
 	   die "$url error: ", $response->status_line
 	       unless $response->is_success;  
 	   die "Weird content type at $url -- ", $response->content_type
 	       unless $response->content_type eq 'text/html';
 
 	   my $html = HTML::TokeParser->new(\$response->content) 
 	   	or die $!;
 
 	   while ( my $tag = $html->get_tag("tr") ) {
 	       if ($tag->[1]{bgcolor} and $tag->[1]{bgcolor} eq '#ffffff') {
 
 	        	# NAME
 	        	$tag = $html->get_tag("span");
 	        	$tag = $html->get_tag("span");
 	        	my $name = $html->get_trimmed_text("/span");
 	        	# /NAME
 
 	        	# VARS
 	        	$tag = $html->get_tag("tt");
 	        	my $vars = $html->get_trimmed_text("/tt");
 	        	# /VARS
 
 	        	# DESC
 	        	$tag = $html->get_tag("p");
 	        	my $desc = $html->get_trimmed_text("br");
 	        	# /DESC
 
 	        	# LINK
 	        	$tag = $html->get_tag("b");
 	        	my $link = $html->get_trimmed_text("br");
 	        	# /LINK
 
 	        	# RELATEDLINKS
 	        	$tag = $html->get_tag("b");
 	        	my $rel_links = $html->get_trimmed_text("br");
 	        	#/RELATEDLINKS
 
 	        	$query_hash{$self->{_query_string}} = { Name => $name,
 	        							Vars => $vars,
 	        							Desc => $desc,
 	        							Link => $link,
 	        							RLnk => $rel_links,
 	        							};
			}
		}
	} 
 
 
	if ($self->{_use_cache} && $self->{_cache_file}) {
	  $result = $query_hash{$self->{_query_string}};
      untie %query_hash;
    }
 
	return $result;
}
 
 
#-----------------------------
# Accessor Functions
#----------------------------- 
 
# Typical get/set method.
sub cco_user {
    my ($self, $arg) = @_;
    $self->{_cco_user} = $arg if defined $arg;
    return $self->{_cco_user};
}
 
# Typical get/set method.
sub cco_pass {
    my ($self, $arg) = @_;
    $self->{_cco_pass} = $arg if defined $arg;
    return $self->{_cco_pass};
}
 
# Typical get/set method.
sub query_string {
    my ($self, $arg) = @_;
    $self->{_query_string} = $arg if defined $arg;
    return $self->{_query_string};
}
 
# Typical get/set method.
sub url {
    my ($self, $arg) = @_;
    $self->{_url} = $arg if defined $arg;
    return $self->{_url};
}
 
# Typical get/set method.
sub cache_file {
    my ($self, $arg) = @_;
    $self->{_cache_file} = $arg if defined $arg;
    return $self->{_cache_file};
}
 
# Typical get/set method.
sub cookie_file {
    my ($self, $arg) = @_;
    $self->{_cookie_file} = $arg if defined $arg;
    return $self->{_cookie_file};
}
 
# Typical get/set method.
sub use_cache {
    my ($self, $arg) = @_;
    $self->{_use_cache} = $arg if defined $arg;
    return $self->{_use_cache};
}
 
1;
 
 
 
#------------------------------------------------------------
# Docs
#------------------------------------------------------------
 
=head1 NAME 
 
CiscoErrorTool - Scrape CCO Error Lookup took and return the results 
 
=head1 SYNOPSIS
 
  use Data::Dumper;
 
  my $cet = new CiscoErrorTool->new(cco_user => 'username',
	                                cco_pass => 'pass',
		  					        cache_file => 'C:\\tmp\\cisco_err_dec.dbm',
								    cookie_file => 'C:\\tmp\\cisco_err_cookie.txt');
 
  print Dumper($cet->query("%AT-6-NODEWRONG"));
 
=head1 DESCRIPTION
 
CiscoErrorTool allows you to pass a syslog error from a Cisco device and
return the results in a hash.
 
To prevent hammering of the Cisco servers a local cache is used to store 
the results and is used for each subsequent lookup of the error
 
This tool can be used with a syslog server to provide some addition information
into your router and switch logs.
 
=head1 CAVEATS
 
The connection to Cisco's website can be a bit slow at times. 
 
I do not take any responsibility with the program.  If you run this 500 times 
and hammer Cisco's webserver and get your CCO revoked don't come crying to me 
 
Some queries will return multiple results. The first time you query a string that
returns multiple results, you will see them all. The second time, when it hits the
cache, it will only return a single result. This is a known issue and we may switch
to using something like SQLite to get around the limitations/complexity of trying
to make a "relational database" with MLDBM.
 
=head1 METHODS
 
=over 4
 
=item B<new> - create new CiscoErrorTool object
 
    $cet = CiscoErrorTool->new(
	[cco_user		  => $username,] 
	[cco_pass         => $password,]
	[url              => $uri,]      # http://www.cisco.com/cgi-bin/Support/Errordecoder/index.cgi
	[cache_file       => $filepath,] # /var/tmp/CiscoErrorTool.dbm
	[cookie_file      => $filepath,] # /tmp/CiscoErrorTool.cookiejar
	[use_cache        => $boolean,]  # 1
    );
 
Creates a new object. Read `perldoc perlboot` if you don't understand that.
 
=item B<query> - run the query again Cisco's website
 
    $results = $cet->query();
 
	$results = $cet->query($error_string); 
 
Passing of the error string is optional if you set it using new() or query_string()
functions
 
A hash reference is retured with the following fields:
   RLnk  # Related documents
   Vars  # The variables in the syslog messagf
   Desc  # A detailed description of the error message
   Name  # Name of the error, should be the same as the string passed above
   Link  # A recomended action link
 
=back
 
=head1 SUPPORT
 
No official support for this module, but please email the author or chat with him on irc.
 
=head1 AUTHOR
 
Brandon Bennett <bennetb@gmail.com>
 
nemith on #cisco@irc.freenode.net
 
Let me know if you have any ideas or suggestions on how to make this tool better
 
=head1 THANKS
 
Thank you very much to Michael J. Freeman <mfreeman451@gmail.com>
who added the caching portion of code and helped toss around some ideas.
 
=head1 COPYRIGHT AND LICENSE
 
Copyright (c) 2006 Brandon Bennett 
All rights reserved. This program is free software; you
can redistribute it and/or modify it under the same terms
as Perl itself.
Personal tools