/cablemodem_check.py
Python | 223 lines | 121 code | 39 blank | 63 comment | 32 complexity | 794239fc949bcab64b6a29626785920a MD5 | raw file
- #!/usr/bin/python
- # cablemodem_check.py - A Python plugin for Nagious to retrieve data from a
- # Motorola SB6121 Cable Modem
- # Copyright (C) 2016 Michael Greene <mikeos2@gmail.com>
- #
- # This program is free software: you can redistribute it and/or modify it
- # under the terms of the GNU General Public License version 3, as published
- # by the Free Software Foundation.
- #
- # This program is distributed in the hope that it will be useful, but
- # WITHOUT ANY WARRANTY; without even the implied warranties of
- # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
- # PURPOSE. See the GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- # My modem info:
- # Model Name: SB6121
- # Vendor Name: Motorola
- # Firmware Name: SB_KOMODO-1.0.6.14-SCM03-NOSH
- # Boot Version: PSPU-Boot(25CLK) 1.0.12.18m3
- # Hardware Version: 5.0
- # Firmware Build Time: Jan 22 2015 14:31:03
- import sys
- import argparse
- import socket
- import urllib2
- # Nagios Plugin Return Codes
- # https://nagios-plugins.org/doc/guidelines.html#PLUGOUTPUT
- Nagios_OK = 0 # define the exit code if status is OK
- Nagios_WARNING = 1 # define the exit code if status is Warning
- Nagios_CRITICAL = 2 # define the exit code if status is Critical
- Nagios_UNKNOWN = 3 # define the exit code if status is Unknown
- try:
- from bs4 import BeautifulSoup
- except ImportError:
- print "Error: (" + str(Nagios_UNKNOWN) + ") install BeautifulSoup!"
- sys.exit(Nagios_UNKNOWN)
- class SnmpCalls:
- def __init__(self, host, oprtype):
- self.opr_type = oprtype
- # modem info pages
- self.modem_page_status = "http://" + host + "/indexData.htm"
- self.modem_page_logs = "http://" + host + "/cmLogsData.htm"
- self.current_status = Nagios_OK
- self.error_msg = "None"
- # Pull page and return, I think all errors are covered
- def _get_page(self, url):
- try:
- page = urllib2.urlopen(url, timeout = 2).read()
- except socket.timeout, error:
- self.current_status = Nagios_CRITICAL
- self.error_msg = str(error)
- return "Error"
- except urllib2.URLError, error:
- self.current_status = Nagios_CRITICAL
- self.error_msg = str(error)
- return "Error"
- return BeautifulSoup(page)
- # get tables from page
- def _get_pagetables(self, _page):
- # get the status page from the modem
- soup = self._get_page(_page)
- # if there was an error getting the page then
- # just get out and return the error
- if self.current_status != Nagios_OK:
- return self.current_status, self.error_msg
- page_list = list()
- for table_rows in soup.find_all('tr'):
- table_cell = table_rows.find_all('td')
- if self.opr_type < 3:
- # skips the format stuff and throw everything into a list
- if len(table_cell) != 0:
- page_list.append(table_cell[0].text)
- page_list.append(table_cell[1].text)
- # At this point all the items and status are in the list
- # of 20 elements with the items in the following order:
- # [index, description]
- #
- # 0 DOCSIS Downstream Channel Acquisition
- # 2 DOCSIS Ranging
- # 4 Establish IP Connectivity using DHCP
- # 6 Establish Time Of Day
- # 8 Transfer Operational Parameters through TFTP
- # 10 Register Connection
- # 12 Cable Modem Status
- # 14 Initialize Baseline Privacy
- # 16 Current Time and Date
- # 18 System Up Time
- # Get logs
- elif self.opr_type == 3:
- if len(table_cell) != 0:
- for temp in range(4):
- page_list.append(table_cell[temp].text)
- return page_list
- # Get modem status + misc info
- def modem_status(self):
- page_list = self._get_pagetables(self.modem_page_status)
- # Element 13 is the operational status, set Nagios
- # return to Crit if not operational otherwise
- # leave it OK
- if page_list[13] != "Operational":
- self.current_status = Nagios_CRITICAL
- # Set up the return message in the correct order
- modem_status = list()
- modem_status.append(page_list[12] + ": " + page_list[13])
- modem_status.append(page_list[0] + ": " + page_list[1])
- modem_status.append(page_list[2] + ": " + page_list[3])
- modem_status.append(page_list[4] + ": " + page_list[5])
- modem_status.append(page_list[6] + ": " + page_list[7])
- modem_status.append(page_list[8] + ": " + page_list[9])
- modem_status.append(page_list[10] + ": " + page_list[11])
- modem_status.append(page_list[14] + ": " + page_list[15])
- return self.current_status, modem_status
- # Get modem uptime
- def modem_uptime(self):
- page_list = self._get_pagetables(self.modem_page_status)
- # Uptime is elements 18 and 19 in the list
- ret_msg = page_list[18] + ": " + page_list[19]
- return self.current_status, ret_msg
- # Not sure what I will do with this but it pulls the
- # modem logs
- def modem_logs(self):
- page_list = self._get_pagetables(self.modem_page_logs)
- modem_logs = list()
- for temp in range(0, (len(page_list) - 1), 4):
- modem_logs.append(page_list[temp] +
- " " + '{0: <10}'.format(page_list[temp+1]) +
- " " + '{0: <6}'.format(page_list[temp+2]) +
- " " + page_list[temp+3])
- return self.current_status, modem_logs
- # ********** Main Entry **********
- #
- def main(snmpcalls):
- if snmpcalls.opr_type == 0 or snmpcalls.opr_type == 1:
- ret_status, ret_type = snmpcalls.modem_uptime()
- # Assume no errors can happen if we have got here so
- # no error checking - bad assumption?
- if snmpcalls.opr_type == 0:
- print str(ret_status) + " " + ret_type
- else:
- print ret_type
- return ret_status
- if snmpcalls.opr_type == 0 or snmpcalls.opr_type == 2:
- ret_status, ret_type = snmpcalls.modem_status()
- if snmpcalls.opr_type == 0:
- print "****** Return code: " + str(ret_status) + "******"
- for temp in range(len(ret_type)):
- print ret_type[temp]
- else:
- for temp in range(len(ret_type)):
- print ret_type[temp]
- return ret_status
- if snmpcalls.opr_type == 3:
- ret_status, ret_type = snmpcalls.modem_logs()
- for temp in range(len(ret_type)):
- print ret_type[temp]
- return ret_status
- if __name__ == "__main__":
- parser = argparse.ArgumentParser(
- description='Nagios command to retrieve Motorola SB6121 Cable Modem data.',
- usage='%(prog)s host type',
- epilog="Types: uptime, status")
- parser.add_argument('host', help='hostname')
- parser.add_argument('type', help='Type to check')
- args = parser.parse_args()
- # Just use brut force option selection
- if args.type == "debug":
- opr_type = 0 # do everything
- # no range checks for all
- args.warn = -1
- args.critical = -1
- elif args.type == "uptime":
- opr_type = 1 # uptime
- elif args.type == "status":
- opr_type = 2 # status and info
- elif args.type == "logs":
- opr_type = 3 # status and info
- else:
- print "Error: Bad operation type (" + args.type + ")." # bad operation
- sys.exit(Nagios_UNKNOWN)
- options = SnmpCalls(args.host, opr_type)
- sys.exit(main(options))