def __init__(self, args={}): self.log = RevSysLogger(args["verbose_debug"]) self.conf = {} self.config_vars = {} self.rollbacks = [] self.require_reloading = False self._set_default_values() self._interpret_arguments(args) self.status = self._read_config_files() if self.status != 0: self.log.LOGE("Json configuration file has a problem!") if self.status == 1: sys.exit("The provided file is not in the correct json file") elif self.status == 2: sys.exit("The provided file doesn't exist") else: sys.exit() else: self._backup_rules() if self.config_vars['operation'] == "update": self._create_rules() self.require_reloading = True elif self.config_vars['operation'] == "update-batch": self._create_rules() self.require_reloading = False elif self.config_vars['operation'] == "delete": self.require_reloading = self._remove_rules() self.log.LOGD("Config values: " + json.dumps(self.conf)) self.log.LOGD("Config vars: " + json.dumps(self.config_vars))
def __init__(self, args={}): self.log = RevSysLogger(args["verbose_debug"]) self.nginx_conf = {} self._set_default_values() self._interpret_arguments(args) self.env = ImmutableSandboxedEnvironment(line_statement_prefix=None, trim_blocks=True, lstrip_blocks=True, undefined=StrictUndefined)
class ConfigSSL: """Class that sets up Nginx server SSL certs. Args: args (dict, optional): Optional External argument to overide defualt configuration file. Defualt is empty. Attributes: log (instance): Logging utility conf (dict): Configuration settings such as location, temp location and operation type. config_vars (dict): JSON file of configuration variables. rollback (list): List of roll back functions. status (bool): True if configuration settings are correct. False otherwise """ def __init__(self, args={}): self.log = RevSysLogger(args["verbose_debug"]) self.conf = {} self.config_vars = {} self.rollbacks = [] self.require_reloading = False self._set_default_values() self._interpret_arguments(args) self.status = self._read_config_files() if self.status != 0: self.log.LOGE("Json configuration file has a problem!") if self.status == 1: sys.exit("The provided file is not in the correct json file") elif self.status == 2: sys.exit("The provided file doesn't exist") else: sys.exit() else: self._backup_certs() if self.config_vars['operation'] == "update": self._create_certs() if self.config_vars['cert_type'] == "shared": self._create_symlink() self.require_reloading = True elif self.config_vars['operation'] == "update-batch": self._create_certs() if self.config_vars['cert_type'] == "shared": self._create_symlink() self.require_reloading = False elif self.config_vars['operation'] == "delete": self.require_reloading = self._remove_certs() self.log.LOGD("Config values: " + json.dumps(self.conf)) self.log.LOGD("Config vars: " + json.dumps(self.config_vars)) def _set_default_values(self): self.conf['location'] = script_configs.CERTS_FOLDER self.conf['tmp_location'] = script_configs.TMP_PATH self.conf['operation'] = None self.conf['cert'] = "public.crt" self.conf['key'] = "private.key" self.conf['passphrase'] = "pass.txt" self.conf['info'] = "info.txt" def _interpret_arguments(self, args): # override local arguments if a value was provided from outside for item in args: self.conf[item] = args[item] def _read_config_files(self): """ input: reads the content of the configuration json file output: returns a status code and populates self.config_vars if everything is ok - 0 - if no problems have been encountered - 1 - if the provided file is not in the correct json file - 2 - if the provided file doesn't exist - 3 - unknown error case """ self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) conf_full_path = self.conf["config_vars"] self.log.LOGD("Reading file from: " + conf_full_path) try: with open(conf_full_path) as f: try: self.config_vars = json.load(f) return 0 except ValueError as e: self.log.LOGE("Bad JSON format for file " + conf_full_path) self.log.LOGE(e) return 1 except BaseException: self.log.LOGE("Can't find file " + conf_full_path) return 2 def _backup_certs(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # make backup for this file try: self.run( lambda: run_cmd( "rm -Rf %srevsw-ssl-cert.tar && tar cf %srevsw-ssl-cert.tar %s" % (self.conf['tmp_location'], self.conf['tmp_location'], self.conf['location']), self.log, "Backing up existing certificates"), lambda: run_cmd( "rm -Rf %s && tar -C / -xf %srevsw-ssl-cert.tar" % (self.conf['location'], self.conf['tmp_location'] ), self.log, "Restoring certificates directory")) except BaseException: self.log.LOGE( "An error appeared while trying to backup the original files") raise def _create_certs(self): self.log.LOGI("Save certificates " + sys._getframe().f_code.co_name) files_patch = self.conf["location"] + self.config_vars["id"] + "/" if not os.path.exists(files_patch): os.makedirs(files_patch) with open(files_patch + self.conf['cert'], 'w+') as f: f.write(self.config_vars["public_ssl_cert"]) with open(files_patch + self.conf['key'], 'w+') as f: f.write(self.config_vars["private_ssl_key"]) with open(files_patch + self.conf['passphrase'], 'w+') as f: f.write(self.config_vars["private_ssl_key_passphrase"]) with open(files_patch + self.conf['info'], 'w+') as f: f.write(json.dumps(self.config_vars)) def _create_symlink(self): files_patch = self.conf["location"] + "default" if os.path.exists(files_patch): os.unlink(files_patch) os.symlink(self.conf["location"] + self.config_vars["id"] + "/", files_patch) self.log.LOGI("Created default symlink") def _remove_certs(self): self.log.LOGI("Starting removing process " + sys._getframe().f_code.co_name) # remove the active configuration file files_patch = self.conf["location"] + self.config_vars["id"] + "/" if os.path.isdir(files_patch): try: if os.path.exists(files_patch): # remove the directory with files shutil.rmtree(files_patch) return True except BaseException: self.log.LOGE( "An error appeared while removing the certificate file " + files_patch) return False else: self.log.LOGI("Directory not found") return False def _reload_nginx(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # check if configuration is correct p = subprocess.Popen('/etc/init.d/revsw-nginx configtest', shell=True) p.communicate() if p.returncode != 0: self.log.LOGE("Nginx configuration has a problem!") run_cmd( "rm -Rf %s && tar -C / -xf %srevsw-ssl-cert.tar" % (self.conf['location'], self.conf['tmp_location']), self.log, "Restoring certificates directory") return p.returncode # nginx reload configuration if there are no errors p = subprocess.Popen('/etc/init.d/revsw-nginx reload', shell=True) p.communicate() return p.returncode def rollback(self): """Executes rollback functions stored in instance variable rollbacks""" while self.rollbacks: self.rollbacks.pop()() def run(self, cmd_func, rollback_func=None): """Runs command and adds rollback function to rollbacks instance variable Args: cmd_func (function): Function to run on system. In this module we use the run_cmd function access shell on edge server. rollback_func(function, optional): Rollback function to add to rollbacks instance variable. Defaults to none. """ try: cmd_func() if rollback_func: self.rollbacks.append(rollback_func) except BaseException: self.log.LOGE("Transaction failed, rolling back") self.rollback() raise
parser = optparse.OptionParser() parser.add_option('-f', '--file', action="store", dest="config_vars", help="Specify the configuration file!" ) parser.add_option('-v', '--verbose', action="store_true", dest="verbose_debug", help="Specify the verbose flag to print more background info!" ) options, args = parser.parse_args() args = {} if options.config_vars: args["config_vars"] = options.config_vars else: RevSysLogger(1).LOGE("Bad request") exit() if getattr(options, 'config_vars'): args["verbose_debug"] = 1 else: args["verbose_debug"] = 0 conf_manager = ConfigWAF(args=args) if conf_manager.require_reloading: conf_manager._reload_nginx()
apache_gen_config_script = importlib.import_module("apache-gen-config-script") revsw_sdk_nginx_gen_config = importlib.import_module( "revsw-sdk-nginx-gen-config") pc_apache_config = importlib.import_module("pc-apache-config") revsw_waf_rule_manager = importlib.import_module("revsw-waf-rule-manager") revsw_ssl_cert_manager = importlib.import_module("revsw-ssl-cert-manager") # revsw_sdk_nginx_gen_config = __import__() # pc_apache_config = __import__("pc-apache-config") # from . import NginxConfigSDK # from .pc_apache_config import ConfigCommon # global log pc_apache_config.log = RevSysLogger(True) TEST_DIR = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "temporary_testing_files/") TEST_CONFIG_DIR = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "revsw-proxy-config/test_files/") revsw_apache_config._g_webserver_name = 'fdsdfsdfsd' revsw_apache_config._log = RevSysLogger() def redirect_to_test_dir(*args, **kwargs): return TEST_DIR
from mock import Mock, patch import revsw_apache_config import script_configs from revsw.logger import RevSysLogger from revsw_apache_config import WebServerConfig, ConfigTransaction, PlatformWebServer,\ VarnishConfig, NginxConfig, underscore_url, configure_all TEST_DIR = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "temporary_testing_files/") TEST_CONFIG_DIR = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "revsw-proxy-config/test_files") revsw_apache_config._g_webserver_name = 'fdsdfsdfsd' revsw_apache_config._log = RevSysLogger() def redirect_to_test_dir(*args, **kwargs): return TEST_DIR # Transaction class for testing class TestConfigTransaction(ConfigTransaction): def __init__(self): self.rollbacks = [] self.webserver_reload = False self.varnish_reload_cmd = None self.curr_idx = ConfigTransaction.file_idx ConfigTransaction.file_idx += 1
class NginxConfigSDK: """NginxConfigSDK refreshes the configuration of the Nginx server based on default or given values. Args: args (dict, optional): A dictionary of configuration parameters to overide default action of class. Default is empty. Attributes: log (instance): Logging utility. nginx_conf (dict): Configuration parameter dictionary. env (instance): Jinja Sandbox enivornment. """ def __init__(self, args={}): self.log = RevSysLogger(args["verbose_debug"]) self.nginx_conf = {} self._set_default_values() self._interpret_arguments(args) self.env = ImmutableSandboxedEnvironment(line_statement_prefix=None, trim_blocks=True, lstrip_blocks=True, undefined=StrictUndefined) # Sets default location of JSON and Jinja template def _set_default_values(self): self.nginx_conf["jinja_template"] = script_configs.JINJA_TEMPLATE self.nginx_conf["jinja_conf_vars"] = script_configs.JINJA_CONF_VARS self.nginx_conf["conf_name"] = script_configs.CONF_NAME self.nginx_conf["tmp_location"] = script_configs.TMP_PATH self.nginx_conf["final_location"] = script_configs.NGINX_FINAL_LOCATION self.nginx_conf[ "backup_location"] = script_configs.NGINX_BACKUP_LOCATION # Reads the options provided by the command line call def _interpret_arguments(self, args): # override local arguments if a value was provided from outside for item in args: self.nginx_conf[item] = args[item] # Read contents of Jinja template def _read_jinja_template(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) template_full_path = self.nginx_conf["jinja_template"] self.log.LOGD("Loading SDK Nginx template!") with open(template_full_path) as f: self.string_template = f.read() self.log.LOGD("Loaded SDK Nginx template: " + template_full_path) # Read JSON file and save them into class instance's config_vars variable def _read_sdk_config_files(self): """ input: reads the content of the configuration json file in class variable nginx_conf["jinja_conf_vars"] output: returns a status code and populates self.config_vars if everything is ok - 0 - if no problems have been encountered - 1 - if the provided file is not in the correct json file - 2 - if the provided file doesn't exist - 3 - unknown error case """ self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) conf_full_path = self.nginx_conf["jinja_conf_vars"] self.log.LOGD("Reading file from: " + conf_full_path) try: with open(conf_full_path) as f: try: self.config_vars = json.load(f) return 0 except BaseException: self.log.LOGE("Bad JSON format for file " + conf_full_path) return 1 except BaseException: self.log.LOGE("Can't find file " + conf_full_path) return 2 # Generates Nginx config file from jinja template stored in class variable # string_template and writes into final file. def _generate_final_nginx_config(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) key_list = self.config_vars["configs"] template = self.env.from_string(self.string_template) final_nginx_config = template.render( configs=key_list, bpname=socket.gethostname().split('.')[0]) final_file = self.nginx_conf["tmp_location"] + \ self.nginx_conf["conf_name"] with open(final_file, 'w+') as f: f.write(final_nginx_config) shutil.copy2( self.nginx_conf["tmp_location"] + self.nginx_conf["conf_name"], self.nginx_conf["final_location"] + self.nginx_conf["conf_name"]) # Backs up the current Nginx apps Configuration found in # /etc/nginx/conf.d/revsw-apps.conf on edge server. def _backup_active_sdk_nginx_config(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # make backup for this file conf_final_path = self.nginx_conf["final_location"] + \ self.nginx_conf["conf_name"] conf_backup_path = self.nginx_conf["backup_location"] + \ self.nginx_conf["conf_name"] try: if not os.path.exists(self.nginx_conf["backup_location"]): os.makedirs(self.nginx_conf["backup_location"]) if os.path.exists(conf_final_path): shutil.copy2(conf_final_path, conf_backup_path) except BaseException: self.log.LOGE( "An error appeared while trying to backup the original file " + conf_final_path + " to " + conf_backup_path) raise # Remove the current Nginx Configuration def _remove_active_sdk_nginx_config(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # remove the active configuration file conf_final_path = self.nginx_conf["final_location"] + \ self.nginx_conf["conf_name"] try: if os.path.exists(conf_final_path): # remove the file os.remove(conf_final_path) except BaseException: self.log.LOGE( "An error appeared while removing the configuration file " + conf_final_path) raise # Restores the backup Nginx configuration def _restore_sdk_nginx_from_backup(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # restore file from tmp backup location try: shutil.copy2( self.nginx_conf["backup_location"] + self.nginx_conf["conf_name"], self.nginx_conf["final_location"] + self.nginx_conf["conf_name"]) except BaseException: self.log.LOGE( "An error appeared while trying to get backup file! Stop processing" ) raise # Reloads the running Nginx process def _load_new_configuration(self): self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # check if configuration is correct p = subprocess.Popen('/etc/init.d/revsw-nginx configtest', shell=True) p.communicate() if p.returncode != 0: self.log.LOGE("Nginx configuration has a problem!") return p.returncode # nginx reload configuration if there are no errors p = subprocess.Popen('/etc/init.d/revsw-nginx reload', shell=True) p.communicate() return p.returncode def refresh_configuration(self): """Refreshes Nginx configuration based on Jinja template and JSON found in jinja_template and jinja_conf_vars class variables """ self.log.LOGI("Starting processing " + sys._getframe().f_code.co_name) # backup current configuration self._read_jinja_template() file_read_status = self._read_sdk_config_files() # in case that a problem appeared reading the configuration JSON file # remove the config file and reload nginx if file_read_status != 0: self._remove_active_sdk_nginx_config() result = self._load_new_configuration() if result != 0: exit(1) exit(0) flags_problem = 0 try: # check if configuration type is correct tmp = self.config_vars["configuration_type"] if tmp != "sdk_apps_config": self.log.LOGE("The provided configuration type is not valid!") raise except BaseException: self.log.LOGE("Key configuration_type must be defined!") flags_problem = 1 try: # check if operation is defined tmp = self.config_vars["operation"] except BaseException: self.log.LOGE("JSON file doesn't contain operation type!") flags_problem = 1 try: # check configs is defined tmp = self.config_vars["configs"] except BaseException: self.log.LOGE("JSON file doesn't contain configs parameter!") flags_problem = 1 if flags_problem == 1: self._remove_active_sdk_nginx_config() result = self._load_new_configuration() exit(1) if self.config_vars["operation"] != "app-update": self.log.LOGD( "Unknown operation was provided! Exiting gracefully!") exit(0) config_problem = 0 try: if not isinstance(self.config_vars["configs"], list): self.log.LOGE("Param configs should be a list!") raise if len(self.config_vars["configs"]) < 1: self.log.LOGE("At least one config should be defined!") raise except BaseException: config_problem = 1 if config_problem == 0: self._backup_active_sdk_nginx_config() self._generate_final_nginx_config() else: self._remove_active_sdk_nginx_config() result = self._load_new_configuration() if (result != 0) and (config_problem == 0): self.log.LOGE( "Problem loading new configuration - restoring original file") self._restore_sdk_nginx_from_backup() sys.exit(1)