Example #1
0
    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
Example #4
0
    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()
Example #5
0
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)