#!/usr/bin/ruby
# munin plugin to retrieve connection statistics from the web admin interface
# on a Linksys AG241v2 ADSL modem
# Makes use of the http://modemaddress/ADSLCStatus.htm page

#This plugin has only been tested on a Debian testing system

# This modem also has some basic SNMP support so you can configure it
# as per the instructions on the munin wiki
# http://munin.projects.linpro.no/wiki/Using_SNMP_plugins
# By default the SNMP server is disabled, you can enable it in the web admin
# You will need to set up the "virtual node" configuration as detailed 
# for snmp plugins

# Plugin will require some configuration in /etc/munin/plugin-conf.d/ag241_MODEMADDRESS
# e.g.
# [ag241_vocume.stargate_*]
# env.user admin
# env.pass password
# #env.port 80

# Once you have the above config set you will need to symlink the plugin to
# /etc/munin/plugins/ag241_MODEMADDRESS_syncrate
# /etc/munin/plugins/ag241_MODEMADDRESS_attenutation
# /etc/munin/plugins/ag241_MODEMADDRESS_noise
# now restart munin-node.
# hopefully in 20-30mins you will have some nice graphs


#Some magical munin foo...
#%# family=manual
#%# capabilities=

# Require this module, it is part of the standard ruby lib AFAIK
require 'net/http'

#default parameters
host = nil 
port = ENV['port'] || 80
user = ENV['user'] || 'admin'
pass = ENV['pass'] || 'forhax' #dont remember what the default admin password was
stat = nil

# Check executeable "name" for parameter count
params = $0.split('_')
if params.size != 3
	puts "Incorrect number of parameters"
	exit 1
end

# first param after the plugin name is the host to query
# second is the statistic to query
host = params[1]
stat = params[2]

unless ENV['debug'].nil?
	puts "user = "+ user
	puts "pass = "+ pass
	puts "host = "+ host
	puts "port = "+ port
	puts "stat = "+ stat
end

# Dump the graph configuration data
if ARGV[0] == 'config'
	puts 'host_name ' + host
	puts 'graph_category network'

	case stat
		when 'syncrate'
			puts 'graph_info This graph shows the ADSL line sync rate.'
			puts 'graph_title ADSL line sync rate'
		        puts 'graph_vlabel connection rate bits / second'
			puts 'graph_args --base 1000 -l 0 '
		when 'attenuation'
			puts 'graph_info This graph shows the ADSL line attenuation.'
			puts 'graph_title ADSL line attenuation'
		        puts 'graph_vlabel attenuation dB'
		when 'margin','noise'
			puts 'graph_info This graph shows the ADSL SNR margin.'
			puts 'graph_title ADSL line SNR margin'
		        puts 'graph_vlabel noise margin dB'
	end
        puts 'down.label downstream'
        puts 'up.label upstream'
	exit 0
end

# Connect to the webadmin
http = Net::HTTP.start(host,port)
req = Net::HTTP::Get.new('/ADSLCStatus.htm')
# send the login info
req.basic_auth user, pass
response = http.request(req)
s = response.body

#Make sure we got the page successfully
if response.code != '200'
	puts "Getting web page failed:"
	case response.code
		when '401'
			puts 'Probably because the username and password are incorrect'
		#Looks like the modem respons with 200 when you try to access a page that doesnt exist >_>
		#when '404'
		#	puts 'Looks like the page this plugin needs isn\'t availible...'
		#	puts 'Check your modem make/model/version'
	end
	puts s
	exit 1
end

# Apply voodoo regex to the result HTML to get the data we want.
case stat
     when 'syncrate'
          a = s.scan(/.*share\.curstate.*\n.*share\.downstr[^0-9]*([0-9]+).*share\.upstr[^0-9]*([0-9]+).*$/)
          b,c = a[0]
          puts  'down.value '+ (b.to_i*1000).to_s + "\n" + 'up.value '+ (c.to_i*1000).to_s
	  exit 0
     when 'attenuation'
          a = s.scan(/.*share\.lineatt.*\n.*share\.down[^0-9]*([0-9]+).*share\.up[^0-9]*([0-9]+).*$/)
          b,c = a[0]
          puts 'down.value '+ (b.to_i).to_s + "\n" + 'up.value '+ (c.to_i).to_s
	  exit 0
     when 'margin','noise'
          a = s.scan(/.*share\.noise.*\n.*share\.down[^0-9]*([0-9]+).*share\.up[^0-9]*([0-9]+).*$/)
          b,c = a[0]
          puts 'down.value '+ (b.to_i).to_s + "\n" + 'up.value '+ (c.to_i).to_s
	  exit 0
     else
	puts 'Statistic ' + stat.to_s + ' not known, would you like me to fabricate it for you?'
	exit 1
end
