#!/usr/bin/python2 import sys, getopt, httplib, xml.etree.ElementTree, subprocess, re, pdb, traceback, datetime, urlparse, urllib import simplejson as json import pwd, os nagios_codes = { 'OK' : 0, 'WARNING' : 1, 'CRITICAL' : 2, 'UNKNOWN' : 3, 'DEPENDENT' : 4 } def nagios_return(code, response) : """ prints the response message and exits the script with one of the defined exit codes DOES NOT RETURN """ print code + ": " + response sys.exit(nagios_codes[code]) def nagios_return_complex(results, reporter) : def deal_with_result(result, reporter) : print "[" + reporter + "] " + result['code'] + ": " + result['message'] return result['code'] #pdb.set_trace() # Scan all condition/status check results and create a list of appropriate exit codes. exit_code_keys = map(lambda result : deal_with_result(result, reporter), results) suggested_exit_codes = list(map(lambda key : nagios_codes[key], exit_code_keys)) # Exit with the highest suggested exit code, because the higher the exit code the more problematic the status is and problems have priority over harmony. sys.exit(max(suggested_exit_codes)) def usage(command_line_parameters_usage_string) : """ returns Nagios status UNKNOWN with a one line usage description usage() calls nagios_return() """ nagios_return('UNKNOWN', "command line usage: \n" + sys.argv[0] + command_line_parameters_usage_string) def generic_validator(data, descriptive_string, kwargs, special_validator) : special_plugin_file_name = kwargs['special_plugin_file_name'] # X- timestamp = datetime.datetime.today().isoformat() valid = False try : valid = special_validator(data, descriptive_string, kwargs) except : traceback_string = traceback.format_exc() #pdb.set_trace() err_log_file_path = os.path.normpath("/tmp/" + special_plugin_file_name + "_err_generic_validator__" + descriptive_string.replace('/' , '%2F') + "__" + timestamp + ".log") with open(name = err_log_file_path, mode = "wt") as debugging_output_file : debugging_output_file.write(traceback_string) #sys.exit(999) # X- exit with some special error status return valid def check_HTML_wellformedness(data, descriptive_string, **kwargs) : # X- def special_validator(data, descriptive_string, kwargs) : pattern = '.*.+.*' pattern_regex = re.compile(pattern, re.MULTILINE | re.IGNORECASE | re.DOTALL) results = pattern_regex.search(data) # special_plugin_file_name if results is not None : return True else : return False #pdb.set_trace() # X- Do PROPER wellformedness check - once the tools are availble. wellformedness = generic_validator(data, descriptive_string, kwargs, special_validator) return wellformedness def check_JSON_wellformedness(data, descriptive_string, **kwargs) : def special_validator(data, descriptive_string, kwargs) : try : json.loads(data) except JSONDecodeError : valid = False else : valid = True return valid wellformedness = generic_validator(data, descriptive_string, kwargs, special_validator) return wellformedness def check_XML_validity(data, descriptive_string, **kwargs) : def special_validator(data, descriptive_string, kwargs) : try : data_tree_root_element = xml.etree.ElementTree.XML(text = data) if data_tree_root_element.tag == kwargs['valid_root_element_tag'] : return True else : return False except : return False wellformedness = generic_validator(data, descriptive_string, kwargs, special_validator) return wellformedness def check_LDAP_validity(data, descriptive_string, **kwargs) : def special_validator(data, descriptive_string, kwargs) : try : return True # X- except : return False wellformedness = generic_validator(data, descriptive_string, kwargs, special_validator) return wellformedness def check_ldap(host, bind_DN) : OpenDJ_directory_path = '/srv/LDAP/OpenDJ-2.5.0-Xpress1/' base_DN = 'dc=clarin,dc=eu' query = '(objectClass=CLARINPerson)' command = [OpenDJ_directory_path + "/bin/ldapsearch", '--port', '10389', '--baseDN', base_DN, '--useStartTLS', '--trustAll', '--hostname', host, '--bindDN', bind_DN, "--bindPasswordFile", '/root/LDAP_passwdfile', query, 'isMemberOf'] # Run OpenDJ's "ldapsearch" command line utility #pdb.set_trace() OpenDJ_uid = pwd.getpwnam('opendj')[2] Nagios_uid = pwd.getpwnam('nagios')[2] #import multiprocessing def LDAP_query(OpenDJ_uid, command) : #pdb.set_trace() try : os.setuid(0) # OpenDJ_uid except OSError, e : raise e else : process = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE) #print " ".join(command) stdout, stderr = process.communicate() if process.returncode == 0 : return True #LDAP_result_queue.put(True) else : return False #LDAP_result_queue.put(False) # LDAP_result_queue = multiprocessing.Queue() # LDAP_query_process = multiprocessing.Process(target = LDAP_query, args = (OpenDJ_uid, command, LDAP_result_queue)) # LDAP_query_process.start() # result = LDAP_result_queue.get() # LDAP_query_process.join() result = LDAP_query(OpenDJ_uid, command) if result == True: return { "code" : "OK", "message" : 'Host %s is up and responds as expected to a query "%s" with base DN "%s".' % (host, query, base_DN) } else : return { "code" : "CRITICAL", "message" : 'Host %s is not up or does not respond as expected to a query "%s" with base DN "%s".' % (host, query, base_DN) } # current_process_ID = os.fork() # if current_process_ID == 0 : # ## Child process code # os._exit(0) # ## Parent process code. Wait for ldapsearch child process. # os.waitpid(current_process_ID, 0) # try : # os.setuid(Nagios_uid) # except OSError, e : # raise e #print stdout #print stderr #pdb.set_trace() return result def check_condition(host, http_path, protocol, HTTP_method, port_number, authorize, validator, **validator_arguments) : #pdb.set_trace() # X- remove implicit argument values #if port_number is None : port_number = 80 #if authorize is None : authorize = True try : port_number = int(port_number) except ValueError : return { "code" : "CRITICAL", "message" : 'The port number specified, "{0}", cannot be converted to an integer.'.format(port_number) } except TypeError : port_number = None def handle_connection_failure(problem_description) : err_log_file_path = os.path.normpath("/tmp/" + special_plugin_file_name + "_err_connection_failure__" + http_path.replace('/' , '%2F') + "__" + timestamp + ".log") with open(name = err_log_file_path, mode = "wt") as debugging_output_file : debugging_output_file.write(problem_description) special_plugin_file_name = validator_arguments['special_plugin_file_name'] # X- #http_path = str(urllib.quote_plus(http_path)) timestamp = datetime.datetime.today().isoformat() try : if protocol == 'http' : conn = httplib.HTTPConnection(host = host, port = port_number, strict = True) elif protocol == 'https' : conn = httplib.HTTPSConnection(host = host, port = port_number, strict = True) request = conn.request(HTTP_method, http_path) except : traceback_string = traceback.format_exc() handle_connection_failure(traceback_string + "\nThis problem originates from location 1 in '" + special_plugin_file_name + "'.\n") return { "code" : "CRITICAL", "message" : '{protocol} connection on port {port_number} to host "{host}" failed.'.format(protocol = protocol, port_number = port_number, host = host) } else : try : response = conn.getresponse() data = response.read() conn.close() except : traceback_string = traceback.format_exc() handle_connection_failure(traceback_string + "\nThis problem originates from location 2 in '" + special_plugin_file_name + "'.\n") else : redirecting_responses = frozenset([ httplib.MOVED_PERMANENTLY, httplib.FOUND, httplib.SEE_OTHER, httplib.TEMPORARY_REDIRECT, ]) if response.status == httplib.OK : # HTTP status codes 200 and 302 # X- Resolve redirect in case of HTTP status == 302 well_formed = validator(data = data, descriptive_string = http_path, **validator_arguments) # ['validator_arguments']) if well_formed : return { "code" : "OK", "message" : 'Host "{host}" is up and returns well-formed data at "{http_path}".'.format(host = host, http_path = http_path) } else : return { "code" : "CRITICAL", "message" : 'Host "{host}" is up but returns non-well-formed data at "{http_path}".'.format(host = host, http_path = http_path) } elif response.status in redirecting_responses : new_location_URL = dict(response.getheaders())['location'] parsed_new_location_URL = urlparse.urlsplit(new_location_URL) new_http_path = parsed_new_location_URL.path if parsed_new_location_URL.query != '' : new_http_path = new_http_path + '?' + parsed_new_location_URL.query if parsed_new_location_URL.scheme == protocol and host == parsed_new_location_URL.netloc and http_path == new_http_path : return { "code" : "CRITICAL", "message" : 'Host "{host}" is up but the response to GET "{http_path}" implies an infinite redirection to itself.'.format(host = host, http_path = http_path) } else : #pdb.set_trace() return check_condition(host = parsed_new_location_URL.netloc, http_path = new_http_path, protocol = parsed_new_location_URL.scheme, HTTP_method = HTTP_method, port_number = parsed_new_location_URL.port, authorize = authorize, validator = validator, **validator_arguments) # special_plugin_file_name = validator_arguments['special_plugin_file_name'] elif response.status == httplib.UNAUTHORIZED and authorize == False : return { "code" : "OK", "message" : 'Host "{host}" is up and requests authorization at "{http_path}".'.format(host = host, http_path = http_path) } else : #pdb.set_trace() handle_connection_failure("Unreachable URL! HTTP response code: " + str(response.status) + "\nThis problem originates from location 3 in '" + special_plugin_file_name + "'.\n") return { "code" : "CRITICAL", "message" : 'Host "{host}" has a problem with the URL path component "{http_path}".'.format(host = host, http_path = http_path) } def main(special_main_subroutine, command_line_parameters) : ## Process plugin-specific command line parameters. command_line_parameters_getopt_string = command_line_parameters_usage_string = "\\ \n" for (parameter, description) in command_line_parameters : command_line_parameters_usage_string = command_line_parameters_usage_string + parameter + " " + description + "\\ \n" command_line_parameters_getopt_string = command_line_parameters_getopt_string + parameter.lstrip("-") + ":" try : opts = filter(None, getopt.getopt(sys.argv[1:], command_line_parameters_getopt_string)) if len(opts) > 0 : opts = opts[0] except getopt.GetoptError, err : usage(command_line_parameters_usage_string) else : if len(command_line_parameters) == len(opts) : ## main_subroutine_argument_values is based on the argument order of special_main_subroutine(). They are not mapped to the argument names! ## Therefore, command_line_parameters must be in the same order as special_main_subroutine()'s arguments. main_subroutine_argument_values = [parameter_value for parameter_name, parameter_value in opts] # pdb.set_trace() special_main_subroutine(*main_subroutine_argument_values) else : usage(command_line_parameters_usage_string) if __name__ == "__main__" : main()