Index: /monitoring/plugins/mpi/generic_tla_monitoring.py
===================================================================
--- /monitoring/plugins/mpi/generic_tla_monitoring.py	(revision 5318)
+++ /monitoring/plugins/mpi/generic_tla_monitoring.py	(revision 5319)
@@ -0,0 +1,429 @@
+#!/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                 = '.*<html.*>.+</html>.*'
+        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()
