#!/usr/bin/env python import sys import os import re import json import argparse import subprocess from datetime import datetime import time def parseArguments(): """ Parse arguments for monitor instance. """ parser = argparse.ArgumentParser() parser.add_argument('--config_folder', help='Path where json configuration/document will be read and write') parser.add_argument('--htpasswd_bin', help='Path apache htpasswd binary. Needed to write htpasswd file.') parser.add_argument('--output_cfg_file', help='Ouput parameters in cfg file.') return parser.parse_args() def fileWrite(file_path, content): if os.path.exists(file_path): try: with open(file_path, 'w') as wf: wf.write(content) return True except OSError, e: print "ERROR while writing changes to %s.\n %s" % (file_path, str(e)) return False def htpasswdWrite(htpasswd_bin, parameter_dict, value): if not os.path.exists(parameter_dict['file']): return False command = [htpasswd_bin, '-cb', parameter_dict['htpasswd'], parameter_dict['user'], value] process = subprocess.Popen( command, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) result = process.communicate()[0] if process.returncode != 0: print result return False with open(parameter_dict['file'], 'w') as pfile: pfile.write(value) return True def httpdCorsDomainWrite(httpd_cors_file, httpd_gracefull_bin, cors_domain): cors_string = "" cors_domain_list = cors_domain.split() old_httpd_cors_file = os.path.join( os.path.dirname(httpd_cors_file), 'prev_%s' % os.path.basename(httpd_cors_file) ) if os.path.exists(old_httpd_cors_file) and os.path.isfile(old_httpd_cors_file): try: with open(old_httpd_cors_file, 'r') as cors_file: if cors_file.read() == cors_domain: if os.path.exists(httpd_cors_file) and (os.stat(httpd_cors_file).st_size > 0 or (cors_domain == "" and os.stat(httpd_cors_file).st_size == 0)): # Skip if cors file is not empty return True except OSError, e: print "Failed to open file at %s. \n%s" % (old_httpd_cors_file, str(e)) for domain in cors_domain_list: if cors_string: cors_string += '|' cors_string += re.escape(domain) try: with open(httpd_cors_file, 'w') as file: file.write('SetEnvIf Origin "^http(s)?://(.+\.)?(%s)$" origin_is=$0\n' % cors_string) file.write('Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is') except OSError, e: print "ERROR while writing CORS changes to %s.\n %s" % (httpd_cors_file, str(e)) return False # Save current cors domain list try: with open(old_httpd_cors_file, 'w') as cors_file: cors_file.write(cors_domain) except OSError, e: print "Failed to open file at %s. \n%s" % (old_httpd_cors_file, str(e)) return False # Restart httpd process try: subprocess.call(httpd_gracefull_bin) except OSError, e: print "Failed to execute command %s.\n %s" % (httpd_gracefull_bin, str(e)) return False def applyEditChage(parser): parameter_tmp_file = os.path.join(parser.config_folder, 'config.tmp.json') config_file = os.path.join(parser.config_folder, 'config.json') parameter_config_file = os.path.join(parser.config_folder, 'config.parameters.json') if not os.path.exists(parameter_tmp_file) or not os.path.isfile(parameter_tmp_file): return {} if not os.path.exists(config_file): print "ERROR: Config file doesn't exist... Exiting" return {} new_parameter_list = [] parameter_list = [] description_dict = {} result_dict = {} try: with open(parameter_tmp_file) as tmpfile: new_parameter_list = json.loads(tmpfile.read()) except ValueError: print "Error: Couldn't parse json file %s" % parameter_tmp_file with open(parameter_config_file) as tmpfile: description_dict = json.loads(tmpfile.read()) for i in range(0, len(new_parameter_list)): key = new_parameter_list[i]['key'] if key != '': description_entry = description_dict[key] if description_entry['type'] == 'file': result_dict[key] = fileWrite(description_entry['file'], new_parameter_list[i]['value']) elif description_entry['type'] == 'htpasswd': result_dict[key] = htpasswdWrite(parser.htpasswd_bin, description_entry, new_parameter_list[i]['value']) elif description_entry['type'] == 'httpdcors': result_dict[key] = httpdCorsDomainWrite(description_entry['cors_file'], description_entry['gracefull_bin'], new_parameter_list[i]['value']) if (parser.output_cfg_file): try: with open(parser.output_cfg_file, 'w') as pfile: pfile.write('[public]\n') for parameter in new_parameter_list: if parameter['key']: pfile.write('%s = %s\n' % (parameter['key'], parameter['value'])) except OSError, e: print "Error failed to create file %s" % parser.output_cfg_file pass return result_dict if __name__ == "__main__": parser = parseArguments() parameter_tmp_file = os.path.join(parser.config_folder, 'config.tmp.json') config_file = os.path.join(parser.config_folder, 'config.json') # Run 4 times with sleep run_counter = 1 max_runn = 4 sleep_time = 15 while True: result_dict = applyEditChage(parser) if result_dict != {}: status = True for key in result_dict: if not result_dict[key]: status = False if status and os.path.exists(parameter_tmp_file): try: os.unlink(config_file) except OSError, e: print "ERROR cannot remove file: %s" % parameter_tmp_file else: os.rename(parameter_tmp_file, config_file) if run_counter == max_runn: break else: run_counter += 1 time.sleep(sleep_time)