source: monitoring/plugins/mpi/generic_tla_monitoring.py @ 5319

Last change on this file since 5319 was 5319, checked in by Sander Maijers, 10 years ago
  • Recommit last working revision of this file.
File size: 16.0 KB
Line 
1#!/usr/bin/python2
2
3import sys, getopt, httplib, xml.etree.ElementTree, subprocess, re, pdb, traceback, datetime, urlparse, urllib
4import simplejson as json
5import pwd, os
6
7nagios_codes    = {
8                    'OK'        : 0,
9                    'WARNING'   : 1,
10                    'CRITICAL'  : 2,
11                    'UNKNOWN'   : 3,
12                    'DEPENDENT' : 4
13                    }
14
15def nagios_return(code, response) :
16    """ prints the response message
17        and exits the script with one
18        of the defined exit codes
19        DOES NOT RETURN
20    """
21    print code + ": " + response
22    sys.exit(nagios_codes[code])
23
24def nagios_return_complex(results, reporter) :
25    def deal_with_result(result, reporter) :
26        print "[" + reporter + "] " + result['code'] + ": " + result['message']
27        return result['code']
28
29    #pdb.set_trace()
30
31    # Scan all condition/status check results and create a list of appropriate exit codes.
32    exit_code_keys          = map(lambda result     : deal_with_result(result, reporter), results)
33    suggested_exit_codes    = list(map(lambda key   : nagios_codes[key], exit_code_keys))
34
35    # 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.
36    sys.exit(max(suggested_exit_codes))
37
38def usage(command_line_parameters_usage_string) :
39    """ returns Nagios status UNKNOWN with
40        a one line usage description
41        usage() calls nagios_return()
42    """
43    nagios_return('UNKNOWN',
44                  "command line usage: \n" + sys.argv[0] + command_line_parameters_usage_string)
45
46def generic_validator(data, 
47                      descriptive_string, 
48                      kwargs, 
49                      special_validator) :
50   
51    special_plugin_file_name = kwargs['special_plugin_file_name'] # X-
52
53    timestamp = datetime.datetime.today().isoformat()
54    valid = False
55
56    try :
57        valid = special_validator(data, 
58                                  descriptive_string, 
59                                  kwargs)
60    except :
61        traceback_string = traceback.format_exc()
62        #pdb.set_trace()
63
64        err_log_file_path = os.path.normpath("/tmp/" + special_plugin_file_name + "_err_generic_validator__" + descriptive_string.replace('/' , '%2F') + "__" + timestamp + ".log")
65
66        with open(name = err_log_file_path,
67                  mode = "wt") as debugging_output_file :
68            debugging_output_file.write(traceback_string)
69        #sys.exit(999) # X- exit with some special error status
70   
71    return valid
72
73
74def check_HTML_wellformedness(data, 
75                              descriptive_string, 
76                              **kwargs) : # X-
77
78    def special_validator(data, 
79                          descriptive_string, 
80                          kwargs) :
81        pattern                 = '.*<html.*>.+</html>.*'
82        pattern_regex           = re.compile(pattern, re.MULTILINE | re.IGNORECASE | re.DOTALL)
83        results                 = pattern_regex.search(data)
84
85        # special_plugin_file_name
86       
87        if results is not None :
88            return True
89        else :
90            return False
91
92    #pdb.set_trace()
93
94    # X- Do PROPER wellformedness check - once the tools are availble.
95    wellformedness = generic_validator(data, 
96                                       descriptive_string, 
97                                       kwargs, 
98                                       special_validator)
99
100    return wellformedness
101
102
103def check_JSON_wellformedness(data, 
104                              descriptive_string, 
105                              **kwargs) :
106    def special_validator(data, 
107                          descriptive_string, 
108                          kwargs) :
109
110        try :
111            json.loads(data)
112        except JSONDecodeError :
113            valid = False
114        else : 
115            valid = True
116
117        return valid
118
119    wellformedness = generic_validator(data, 
120                                       descriptive_string, 
121                                       kwargs, 
122                                       special_validator)
123
124    return wellformedness
125
126
127def check_XML_validity(data, 
128                       descriptive_string,
129                       **kwargs) :
130
131    def special_validator(data, 
132                          descriptive_string, 
133                          kwargs) :
134
135        try :           
136            data_tree_root_element = xml.etree.ElementTree.XML(text = data)
137               
138            if data_tree_root_element.tag == kwargs['valid_root_element_tag'] :
139                return True
140            else :
141                return False
142        except :
143            return False
144
145    wellformedness = generic_validator(data, 
146                                       descriptive_string, 
147                                       kwargs, 
148                                       special_validator)
149    return wellformedness
150
151
152def check_LDAP_validity(data, 
153                       descriptive_string,
154                       **kwargs) :
155
156    def special_validator(data, 
157                          descriptive_string, 
158                          kwargs) :
159        try :           
160            return True # X-
161        except :
162            return False
163
164    wellformedness = generic_validator(data, 
165                                       descriptive_string, 
166                                       kwargs, 
167                                       special_validator)
168    return wellformedness
169
170
171def check_ldap(host, 
172               bind_DN) :
173
174    OpenDJ_directory_path = '/srv/LDAP/OpenDJ-2.5.0-Xpress1/'
175
176    base_DN = 'dc=clarin,dc=eu'
177    query = '(objectClass=CLARINPerson)'
178
179    command = [OpenDJ_directory_path + "/bin/ldapsearch", 
180              '--port', '10389',
181              '--baseDN', base_DN,
182              '--useStartTLS',
183              '--trustAll',
184              '--hostname', host,
185              '--bindDN', bind_DN,
186              "--bindPasswordFile", '/root/LDAP_passwdfile',
187              query,
188              'isMemberOf']
189
190    # Run OpenDJ's "ldapsearch" command line utility
191    #pdb.set_trace()
192
193    OpenDJ_uid = pwd.getpwnam('opendj')[2]
194    Nagios_uid = pwd.getpwnam('nagios')[2]
195
196    #import multiprocessing
197
198    def LDAP_query(OpenDJ_uid, command) :
199
200        #pdb.set_trace()
201
202        try :
203            os.setuid(0) # OpenDJ_uid
204        except OSError, e :
205            raise e
206        else :
207            process = subprocess.Popen(command, 
208                                       stdout = subprocess.PIPE, 
209                                       stderr = subprocess.PIPE)
210
211            #print " ".join(command)
212
213            stdout, stderr = process.communicate()
214           
215            if process.returncode == 0 :
216                return True
217                #LDAP_result_queue.put(True)
218            else :
219                return False
220                #LDAP_result_queue.put(False)
221
222
223    # LDAP_result_queue = multiprocessing.Queue()
224    # LDAP_query_process = multiprocessing.Process(target = LDAP_query, args = (OpenDJ_uid, command, LDAP_result_queue))
225    # LDAP_query_process.start()
226    # result = LDAP_result_queue.get()
227    # LDAP_query_process.join()
228
229    result = LDAP_query(OpenDJ_uid, command)
230
231    if result == True:
232        return { "code"      : "OK", 
233                 "message"   : 'Host %s is up and responds as expected to a query "%s" with base DN "%s".' % (host, query, base_DN)
234               }
235    else :
236        return { "code"      : "CRITICAL", 
237                 "message"   : 'Host %s is not up or does not respond as expected to a query "%s" with base DN "%s".' % (host, query, base_DN)
238               }
239
240    # current_process_ID = os.fork()
241
242    # if current_process_ID == 0 :
243    #     ## Child process code
244       
245     
246
247    #     os._exit(0)
248     
249    # ## Parent process code. Wait for ldapsearch child process.
250    # os.waitpid(current_process_ID, 0)
251   
252    # try :
253    #     os.setuid(Nagios_uid)
254    # except OSError, e :
255    #     raise e
256
257    #print stdout
258    #print stderr
259    #pdb.set_trace()
260
261    return result
262
263
264def check_condition(host, 
265                    http_path, 
266                    protocol, 
267                    HTTP_method,
268                    port_number, 
269                    authorize,
270                    validator,
271                    **validator_arguments) :
272
273    #pdb.set_trace()
274    # X- remove implicit argument values
275    #if port_number is None : port_number = 80
276    #if authorize is None : authorize = True
277
278    try : 
279        port_number = int(port_number)
280    except ValueError : 
281        return { "code"      : "CRITICAL", 
282         "message"   : 'The port number specified, "{0}", cannot be converted to an integer.'.format(port_number)
283       }
284    except TypeError : 
285        port_number = None
286
287    def handle_connection_failure(problem_description) :
288        err_log_file_path = os.path.normpath("/tmp/" + special_plugin_file_name + "_err_connection_failure__" + http_path.replace('/' , '%2F') + "__" + timestamp + ".log")
289
290        with open(name = err_log_file_path, 
291                  mode = "wt") as debugging_output_file :
292           debugging_output_file.write(problem_description)
293
294    special_plugin_file_name = validator_arguments['special_plugin_file_name'] # X-
295   
296    #http_path  = str(urllib.quote_plus(http_path))   
297   
298    timestamp = datetime.datetime.today().isoformat()
299   
300    try : 
301        if protocol == 'http' : 
302            conn = httplib.HTTPConnection(host = host, 
303                                          port = port_number, 
304                                          strict = True)
305        elif protocol == 'https' :           
306            conn = httplib.HTTPSConnection(host = host, 
307                                           port = port_number, 
308                                           strict = True)
309        request = conn.request(HTTP_method, 
310                               http_path)
311    except : 
312        traceback_string = traceback.format_exc()
313
314        handle_connection_failure(traceback_string + "\nThis problem originates from location 1 in '" + special_plugin_file_name + "'.\n")
315
316        return {
317                "code"      : "CRITICAL", 
318                "message"   : '{protocol} connection on port {port_number} to host "{host}" failed.'.format(protocol = protocol, 
319                                                                                                            port_number = port_number, 
320                                                                                                            host = host)
321               }
322    else : 
323        try : 
324            response = conn.getresponse()
325
326            data = response.read()
327           
328            conn.close()
329        except : 
330            traceback_string = traceback.format_exc()
331
332            handle_connection_failure(traceback_string + "\nThis problem originates from location 2 in '" + special_plugin_file_name + "'.\n")
333        else : 
334
335            redirecting_responses = frozenset([
336                                            httplib.MOVED_PERMANENTLY,
337                                            httplib.FOUND,
338                                            httplib.SEE_OTHER,
339                                            httplib.TEMPORARY_REDIRECT,
340                                          ]) 
341
342            if response.status == httplib.OK : 
343                # HTTP status codes 200 and 302
344                # X- Resolve redirect in case of HTTP status == 302
345                well_formed = validator(data                   = data, 
346                                        descriptive_string     = http_path, 
347                                        **validator_arguments) # ['validator_arguments'])
348
349                if well_formed : 
350                    return {
351                            "code"      : "OK", 
352                            "message"   : 'Host "{host}" is up and returns well-formed data at "{http_path}".'.format(host = host, http_path = http_path)
353                           }
354                else :
355                    return {
356                            "code"      : "CRITICAL", 
357                            "message"   : 'Host "{host}" is up but returns non-well-formed data at "{http_path}".'.format(host = host, http_path = http_path)
358                            }
359
360            elif response.status in redirecting_responses :
361                new_location_URL = dict(response.getheaders())['location']
362
363                parsed_new_location_URL = urlparse.urlsplit(new_location_URL)
364                new_http_path = parsed_new_location_URL.path
365                if parsed_new_location_URL.query != '' : 
366                    new_http_path = new_http_path + '?' + parsed_new_location_URL.query
367               
368                if parsed_new_location_URL.scheme == protocol and host == parsed_new_location_URL.netloc and http_path == new_http_path :
369                    return {
370                              "code"    : "CRITICAL", 
371                              "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)
372                            }
373
374                else : 
375
376                    #pdb.set_trace()
377
378                    return check_condition(host        = parsed_new_location_URL.netloc, 
379                                           http_path   = new_http_path, 
380                                           protocol    = parsed_new_location_URL.scheme, 
381                                           HTTP_method = HTTP_method, 
382                                           port_number = parsed_new_location_URL.port, 
383                                           authorize   = authorize,
384                                           validator   = validator, 
385                                           **validator_arguments) # special_plugin_file_name = validator_arguments['special_plugin_file_name']
386
387            elif response.status == httplib.UNAUTHORIZED and authorize == False :
388                return {
389                        "code"      : "OK", 
390                        "message"   : 'Host "{host}" is up and requests authorization at "{http_path}".'.format(host = host, http_path = http_path)
391                       }
392
393            else :
394                #pdb.set_trace()
395                handle_connection_failure("Unreachable URL! HTTP response code: " + str(response.status) + 
396                                            "\nThis problem originates from location 3 in '" + special_plugin_file_name + "'.\n")
397
398                return {
399                        "code"      : "CRITICAL", 
400                        "message"   : 'Host "{host}" has a problem with the URL path component "{http_path}".'.format(host = host, http_path = http_path)
401                       }
402
403def main(special_main_subroutine, 
404         command_line_parameters) :
405   
406    ## Process plugin-specific command line parameters.
407    command_line_parameters_getopt_string = command_line_parameters_usage_string = "\\ \n"
408    for (parameter, description) in command_line_parameters :
409       command_line_parameters_usage_string = command_line_parameters_usage_string + parameter + "  " + description + "\\ \n"
410       command_line_parameters_getopt_string = command_line_parameters_getopt_string + parameter.lstrip("-")  + ":"
411
412    try :
413        opts = filter(None, getopt.getopt(sys.argv[1:], command_line_parameters_getopt_string))
414        if len(opts) > 0 : opts = opts[0]
415    except getopt.GetoptError, err :
416        usage(command_line_parameters_usage_string)
417    else : 
418        if len(command_line_parameters) == len(opts) :
419            ## main_subroutine_argument_values is based on the argument order of special_main_subroutine(). They are not mapped to the argument names!
420            ## Therefore, command_line_parameters must be in the same order as special_main_subroutine()'s arguments.
421            main_subroutine_argument_values = [parameter_value for parameter_name, parameter_value in opts]
422            # pdb.set_trace()
423            special_main_subroutine(*main_subroutine_argument_values)       
424        else :
425            usage(command_line_parameters_usage_string)
426   
427
428if __name__ == "__main__" :
429    main()
Note: See TracBrowser for help on using the repository browser.