diff --git a/README.ru.md b/README.ru.md index 16152b0..498e30c 100644 --- a/README.ru.md +++ b/README.ru.md @@ -67,7 +67,7 @@ _packages/ispmanager-plugin-nginx_mod_rewrite_plugin-0.0.1-1.el9.x86_64.rpm Для установки нужно установить собранный в предыдущем пункте пакет: ``` -sudo rpm -ihv _packages/ispmanager-plugin-nginx_mod_rewrite_plugin-0.0.1-1.el9.x86_64.rpm +sudo dnf install _packages/ispmanager-plugin-nginx_mod_rewrite_plugin-0.0.1-1.el9.x86_64.rpm ``` Если вдруг установка провалилась, лог установки можно изучить здесь - `/usr/local/mgr5/var/nginx-mod-rewrite-plugin.log` diff --git a/ispmanager-plugin-nginx_mod_rewrite_plugin.spec b/ispmanager-plugin-nginx_mod_rewrite_plugin.spec index ad3e113..033f2ca 100644 --- a/ispmanager-plugin-nginx_mod_rewrite_plugin.spec +++ b/ispmanager-plugin-nginx_mod_rewrite_plugin.spec @@ -32,11 +32,14 @@ mkdir -p %{buildroot}/usr/local/ispmanager-mod_rewrite/utils wget -O %{buildroot}/usr/local/ispmanager-mod_rewrite/mod_rewrite.zip https://github.com/bayrepo/ngx_http_apache_rewrite_module/archive/refs/heads/main.zip cp utils/build_mod_rewrite.py %{buildroot}/usr/local/ispmanager-mod_rewrite/utils mkdir -p %{buildroot}/usr/local/ispmanager-mod_rewrite/settings +touch %{buildroot}/usr/local/ispmanager-mod_rewrite/.lock mkdir -p %{buildroot}/usr/local/ispmanager-mod_rewrite/patches cp payload/* %{buildroot}/usr/local/ispmanager-mod_rewrite/patches/ %triggerin -- nginx -/usr/local/ispmanager-mod_rewrite/utils/build_mod_rewrite.py --nodeps +if [ -e /usr/local/ispmanager-mod_rewrite/settings/installed.cfg ]; then + /usr/local/ispmanager-mod_rewrite/utils/build_mod_rewrite.py --nodeps +fi %posttrans killall core @@ -53,6 +56,7 @@ fi if [ "$1" == "0" ]; then rm -f /usr/share/nginx/modules/ngx_http_apache_rewrite_module.conf rm -f /usr/lib64/nginx/modules/ngx_http_apache_rewrite_module.so + rm -f /usr/local/ispmanager-mod_rewrite/settings/installed.cfg systemctl restart nginx fi @@ -69,6 +73,7 @@ fi %attr(644, root, root) /usr/local/mgr5/skins/common/plugin-logo/ispmanager-plugin-nginx_mod_rewrite_plugin.png %attr(600, root, root) /usr/local/ispmanager-mod_rewrite/patches/nginx-vhosts.template.patch %attr(600, root, root) /usr/local/ispmanager-mod_rewrite/patches/nginx-vhosts-ssl.template.patch +%attr(600, root, root) /usr/local/ispmanager-mod_rewrite/.lock %changelog * Mon Jun 29 2026 Alexey BayRepo - 0.0.1-1 diff --git a/usr/local/mgr5/addon/nginx_form_rewrite_plugin.py b/usr/local/mgr5/addon/nginx_form_rewrite_plugin.py index 6044d37..1bb27d1 100755 --- a/usr/local/mgr5/addon/nginx_form_rewrite_plugin.py +++ b/usr/local/mgr5/addon/nginx_form_rewrite_plugin.py @@ -8,6 +8,7 @@ import datetime from xml.dom import minidom import shutil import subprocess +import fcntl CONFIG_PATH = "/usr/share/nginx/modules/ngx_http_apache_rewrite_module.conf" MODULE_LINE = 'load_module "/usr/lib64/nginx/modules/ngx_http_apache_rewrite_module.so";' @@ -58,6 +59,74 @@ def dump_all_to_log(root): except Exception: pass +def unlock_plugin(): + """ + Release the lock on the plugin lock file. + + Returns: + bool: True if lock was successfully released, False otherwise (e.g., no lock held) + """ + lock_path = '/usr/local/ispmanager-mod_rewrite/.lock' + + try: + if not os.path.exists(lock_path): + return False + + with open(lock_path, 'r+') as lock_file: + fcntl.flock(lock_file, fcntl.LOCK_UN) + lock_file.truncate(0) + lock_file.seek(0) + return True + except Exception: + return False + + +def lock_plugin_with_to(): + """ + Acquire an exclusive (write) lock on the plugin lock file. + + Returns: + bool: True if lock was successfully acquired, False otherwise + """ + lock_path = '/usr/local/ispmanager-mod_rewrite/.lock' + + try: + if not os.path.exists(lock_path): + return False + + with open(lock_path, 'r+') as lock_file: + fcntl.flock(lock_file, fcntl.LOCK_EX) + # Add timestamp and PID to indicate this process holds the lock + lock_file.write(f'Locked by PID {os.getpid()} at {datetime.datetime.now()}\n') + lock_file.truncate(0) + return True + except Exception: + return False + + +def lock_plugin_with_to_read(): + """ + Acquire a shared (read) lock on the plugin lock file. + Allows multiple readers but prevents writers from acquiring exclusive lock. + + Returns: + bool: True if lock was successfully acquired, False otherwise + """ + lock_path = '/usr/local/ispmanager-mod_rewrite/.lock' + + try: + if not os.path.exists(lock_path): + return False + + with open(lock_path, 'r+') as lock_file: + fcntl.flock(lock_file, fcntl.LOCK_SH) + # Add timestamp to indicate this reader holds a shared lock + lock_file.write(f'Read lock by PID {os.getpid()} at {datetime.datetime.now()}\n') + lock_file.truncate(0) + return True + except Exception: + return False + def site_state(param): """ Get or set the state of a site in sites_settings.cfg. @@ -67,8 +136,10 @@ def site_state(param): config_path = "/usr/local/ispmanager-mod_rewrite/settings/sites_settings.cfg" if isinstance(param, str): + lock_plugin_with_to_read() param_name = param if not os.path.exists(config_path): + unlock_plugin() return "off" try: with open(config_path, 'r', encoding='utf-8') as f: @@ -79,17 +150,22 @@ def site_state(param): pattern = rf'^\s*{re.escape(param_name)}\s*=\s*(.*)$' m = re.match(pattern, line) if m: + unlock_plugin() return m.group(1).strip() except Exception: + unlock_plugin() return "off" + unlock_plugin() return "off" elif isinstance(param, dict): # Write mode + lock_plugin_with_to() dir_path = os.path.dirname(config_path) try: os.makedirs(dir_path, exist_ok=True) except Exception: + unlock_plugin() return None lines = [] if os.path.exists(config_path): @@ -97,6 +173,7 @@ def site_state(param): with open(config_path, 'r', encoding='utf-8') as f: lines = f.readlines() except Exception: + unlock_plugin() return None for key, val in param.items(): actual_value = 'on' if val == 'on' else 'off' @@ -116,7 +193,9 @@ def site_state(param): with open(config_path, 'w', encoding='utf-8') as f: f.writelines(lines) except Exception: + unlock_plugin() return None + unlock_plugin() return None else: return None @@ -133,9 +212,12 @@ def read_global_config(params): param_value = params.get('param_value') config_path = "/usr/local/ispmanager-mod_rewrite/settings/global_settings.cfg" + if param_value is None: + lock_plugin_with_to_read() # Read mode if not os.path.exists(config_path): + unlock_plugin() return None try: with open(config_path, 'r', encoding='utf-8') as f: @@ -146,16 +228,21 @@ def read_global_config(params): pattern = rf'^\s*{re.escape(param_name)}\s*=\s*(.*)$' m = re.match(pattern, line) if m: + unlock_plugin() return m.group(1).strip() except Exception: + unlock_plugin() return None + unlock_plugin() return None else: + lock_plugin_with_to() # Write mode dir_path = os.path.dirname(config_path) try: os.makedirs(dir_path, exist_ok=True) except Exception: + unlock_plugin() return None lines = [] found = False @@ -164,6 +251,7 @@ def read_global_config(params): with open(config_path, 'r', encoding='utf-8') as f: lines = f.readlines() except Exception: + unlock_plugin() return None for idx, line in enumerate(lines): stripped = line.strip() @@ -180,7 +268,9 @@ def read_global_config(params): with open(config_path, 'w', encoding='utf-8') as f: f.writelines(lines) except Exception: + unlock_plugin() return None + unlock_plugin() return None def check_nginx_rewrite_module(): @@ -188,6 +278,7 @@ def check_nginx_rewrite_module(): if not os.path.exists(CONFIG_PATH): _log(f"Config file {CONFIG_PATH} does not exist") return False + lock_plugin_with_to_read() try: with open(CONFIG_PATH, 'r') as f: for line in f: @@ -196,15 +287,19 @@ def check_nginx_rewrite_module(): continue if MODULE_PATTERN.match(line): _log("Module found and enabled in config") + unlock_plugin() return True _log("Module not found in config") + unlock_plugin() return False except Exception as e: _log(f"Error reading config file {CONFIG_PATH}: {e}") + unlock_plugin() return False def set_nginx_rewrite_module(enable: bool): _log(f"set_nginx_rewrite_module called with enable={enable}") + lock_plugin_with_to() if enable: if not os.path.exists(CONFIG_PATH): try: @@ -266,6 +361,7 @@ def set_nginx_rewrite_module(enable: bool): _log("No uncommented module line found to disable") except Exception as e: _log(f"Error disabling module in config file {CONFIG_PATH}: {e}") + unlock_plugin() def make_nginx_custom_template() -> bool: tmpl = "/usr/local/mgr5/etc/templates/nginx-vhosts.template" @@ -281,6 +377,8 @@ def make_nginx_custom_template() -> bool: default_ssl_tmpl = os.path.join(default_dir, "nginx-vhosts-ssl.template") target_dir = "/usr/local/mgr5/etc/templates" + lock_plugin_with_to() + # Copy default templates if they exist try: if os.path.exists(default_tmpl): @@ -296,6 +394,7 @@ def make_nginx_custom_template() -> bool: os.remove(f) except Exception: pass + unlock_plugin() return False # Ensure copied files exist @@ -307,6 +406,7 @@ def make_nginx_custom_template() -> bool: os.remove(f) except Exception: pass + unlock_plugin() return False patches_dir = "/usr/local/ispmanager-mod_rewrite/patches" @@ -316,6 +416,7 @@ def make_nginx_custom_template() -> bool: def apply_patch(target, patch_file): if not os.path.exists(patch_file): _log(f"Patch file {patch_file} does not exist.") + unlock_plugin() return False try: result = subprocess.run( @@ -326,10 +427,13 @@ def make_nginx_custom_template() -> bool: ) if result.returncode != 0: _log(f"Patch failed for {target}: {result.stderr.decode(errors='ignore')}") + unlock_plugin() return False + unlock_plugin() return True except Exception as e: _log(f"Exception applying patch to {target}: {e}") + unlock_plugin() return False patch_success = True @@ -346,8 +450,9 @@ def make_nginx_custom_template() -> bool: os.remove(f) except Exception: pass + unlock_plugin() return False - + unlock_plugin() read_global_config({'param_name': 'templates_created', 'param_value': 'on'}) _log("Success: Custom Nginx templates created and patched successfully.") return True diff --git a/usr/local/mgr5/addon/nginx_mod_rewrite_plugin.py b/usr/local/mgr5/addon/nginx_mod_rewrite_plugin.py index 6b9a355..5fedbb5 100755 --- a/usr/local/mgr5/addon/nginx_mod_rewrite_plugin.py +++ b/usr/local/mgr5/addon/nginx_mod_rewrite_plugin.py @@ -44,6 +44,11 @@ def BuildModule(): if result.returncode != 0: # Extract error message from stderr (already captured in stdout due to redirect) return f'Build utility failed with exit code {result.returncode}' + + installed_cfg_path = '/usr/local/ispmanager-mod_rewrite/settings/installed.cfg' + with open(installed_cfg_path, 'w') as cfg_file: + cfg_file.write('') + os.chmod(installed_cfg_path, 0o600) except Exception as exc: log_path_error = os.path.join(os.path.dirname(log_path), 'error.log') with open(log_path_error, 'a') as error_file: