From 9abf312833948f45160f8ef6b76ebedaf8bcc671 Mon Sep 17 00:00:00 2001 From: Maksym Buz Date: Mon, 15 Dec 2025 17:31:51 +0100 Subject: [PATCH] Remove migrated files: agent-backup-tool, config-mover, .gitignore --- .gitignore | 6 - agent-backup-tool/README.md | 167 -------- agent-backup-tool/REFACTORING_NOTES.md | 100 ----- agent-backup-tool/agent_tool_linux.py | 401 ------------------ agent-backup-tool/simple_agent_tool.py | 108 ----- agent-backup-tool/zabbix_agentd.conf | 537 ------------------------- config-mover/README.md | 81 ---- config-mover/config_exporter.py | 102 ----- config-mover/config_exporter_legacy.py | 127 ------ config-mover/config_importer.py | 178 -------- config-mover/get_host_ids.py | 56 --- config-mover/get_host_ids_legacy.py | 72 ---- config-mover/run_export.sh | 15 - config-mover/run_export_legacy.sh | 16 - config-mover/run_get_ids.sh | 13 - config-mover/run_get_ids_legacy.sh | 14 - config-mover/run_import.sh | 14 - 17 files changed, 2007 deletions(-) delete mode 100644 .gitignore delete mode 100644 agent-backup-tool/README.md delete mode 100644 agent-backup-tool/REFACTORING_NOTES.md delete mode 100755 agent-backup-tool/agent_tool_linux.py delete mode 100755 agent-backup-tool/simple_agent_tool.py delete mode 100644 agent-backup-tool/zabbix_agentd.conf delete mode 100644 config-mover/README.md delete mode 100755 config-mover/config_exporter.py delete mode 100644 config-mover/config_exporter_legacy.py delete mode 100644 config-mover/config_importer.py delete mode 100644 config-mover/get_host_ids.py delete mode 100644 config-mover/get_host_ids_legacy.py delete mode 100755 config-mover/run_export.sh delete mode 100755 config-mover/run_export_legacy.sh delete mode 100755 config-mover/run_get_ids.sh delete mode 100755 config-mover/run_get_ids_legacy.sh delete mode 100755 config-mover/run_import.sh diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 21d9487..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -__pycache__/ -venv/ -export/ -*_host_ids.txt -*.log -backups/ \ No newline at end of file diff --git a/agent-backup-tool/README.md b/agent-backup-tool/README.md deleted file mode 100644 index 9ce00a5..0000000 --- a/agent-backup-tool/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# Zabbix Agent Management Tool - -A comprehensive Python script for managing Zabbix agent configurations, including backup, restore, and upgrade operations. - -## Features - -- **Backup**: Create timestamped backups of all Zabbix agent configuration files -- **Restore**: Restore configuration files from previous backups -- **Upgrade**: Upgrade Zabbix agent while preserving custom configurations -- **List Backups**: View all available backups with timestamps and details - -## Requirements - -- Python 3.6+ -- Root/sudo privileges for system operations -- Zabbix agent installed on the system - -## Quick Start - -```bash -# Make the script executable -chmod +x agent_tool_linux.py - -# See all available options -./agent_tool_linux.py --help - -# Most common use case - upgrade agent safely -./agent_tool_linux.py upgrade -``` - -## Usage - -### Basic Commands - -```bash -# Create a backup of current configurations -./agent_tool_linux.py backup - -# List all available backups -./agent_tool_linux.py list-backups - -# Restore from a specific backup -./agent_tool_linux.py restore --backup-path /path/to/backup/directory - -# Upgrade agent while preserving custom settings -./agent_tool_linux.py upgrade - -# Enable verbose logging -./agent_tool_linux.py backup --verbose -``` - -### Examples - -1. **Create a backup before making changes:** - ```bash - ./agent_tool_linux.py backup - ``` - -2. **Upgrade the agent (recommended workflow):** - ```bash - # The upgrade command automatically creates a backup first - ./agent_tool_linux.py upgrade - ``` - -3. **Restore from the most recent backup:** - ```bash - # First, list available backups - ./agent_tool_linux.py list-backups - - # Then restore from a specific backup - ./agent_tool_linux.py restore --backup-path ./backups/backup_20250925_143022 - ``` - -## How It Works - -### Backup Process -- Automatically detects all Zabbix agent configuration files in `/etc/zabbix/` -- Supports both `zabbix_agentd.conf` and `zabbix_agent2.conf` files -- Creates timestamped backup directories -- Generates a backup manifest with metadata - -### Restore Process -- Restores configuration files from backup directories -- Creates safety backups of current files before restoration -- Automatically restarts the Zabbix agent service - -### Upgrade Process -1. **Backup**: Creates a backup of current configurations -2. **Parse**: Extracts all uncommented (custom) settings from current configs -3. **Upgrade**: Updates the Zabbix agent package using the appropriate package manager -4. **Merge**: Integrates custom settings into new configuration files -5. **Diff**: Saves differences showing what was added to new configs -6. **Restart**: Restarts the Zabbix agent service - -### Distribution Support -- **Debian-based**: Ubuntu, Debian (uses `apt`) -- **RHEL-based**: CentOS, RHEL, Fedora (uses `yum`/`dnf`) - -## File Structure - -``` -zbx-agent-backup/ -├── agent_tool_linux.py # Main script -├── zabbix_agentd.conf # Default/template configuration -├── backups/ # Backup storage directory -│ ├── backup_20250925_143022/ # Timestamped backup -│ │ ├── zabbix_agentd.conf # Backed up config -│ │ ├── backup_manifest.txt # Backup metadata -│ │ └── *.diff # Configuration differences (after upgrade) -└── agent_tool.log # Script execution log -``` - -## Configuration Files Handled - -The script automatically detects and handles: -- `/etc/zabbix/zabbix_agentd.conf` -- `/etc/zabbix/zabbix_agent2.conf` -- `/etc/zabbix/zabbix_agentd*.conf` (any variant) -- `/etc/zabbix/zabbix_agent*.conf` (any variant) - -## Logging - -- All operations are logged to `agent_tool.log` -- Console output shows important status messages -- Use `--verbose` flag for detailed debug information -- Log rotation is handled automatically - -## Safety Features - -- **Pre-restoration backup**: Current configs are backed up before restoration -- **Manifest files**: Each backup includes metadata and file listings -- **Diff files**: Upgrade process saves differences showing what was changed -- **Service management**: Automatically handles service restart and enabling -- **Error handling**: Comprehensive error checking and logging - -## Troubleshooting - -### Common Issues - -1. **Permission denied**: Make sure to run with sudo for system operations -2. **No config files found**: Verify Zabbix agent is installed and configs exist -3. **Service restart failed**: Check if Zabbix agent service is properly installed -4. **Package upgrade failed**: Verify package repositories are configured - -### Debug Mode -```bash -./agent_tool_linux.py backup --verbose -``` - -### Manual Service Restart -If automatic service restart fails: -```bash -sudo systemctl restart zabbix-agent2 -# or -sudo systemctl restart zabbix-agent -``` - -## Security Considerations - -- Script requires sudo privileges for package management and service control -- Configuration files may contain sensitive information -- Backup files are stored locally and should be protected appropriately -- Log files may contain system information - -## License - -This script is provided as-is for system administration purposes. diff --git a/agent-backup-tool/REFACTORING_NOTES.md b/agent-backup-tool/REFACTORING_NOTES.md deleted file mode 100644 index f0468da..0000000 --- a/agent-backup-tool/REFACTORING_NOTES.md +++ /dev/null @@ -1,100 +0,0 @@ -# Code Refactoring Summary - -## Overview -The Zabbix Agent Management Tool has been refactored to improve code simplicity, maintainability, and readability while preserving all functionality. - -## Major Improvements Made - -### 1. **Distribution Detection (`_detect_distro_family`)** -- **Before**: Multiple if-elif statements with repetitive file checking logic -- **After**: Data-driven approach using detection rules in a loop -- **Benefits**: More maintainable, easier to add new distributions, 40% less code - -### 2. **Command Execution (`_run_command`)** -- **Before**: Verbose logging with multiple conditional statements -- **After**: Streamlined with optional output logging parameter -- **Benefits**: Cleaner code, better parameter control, reduced noise in logs - -### 3. **Configuration File Discovery (`_get_config_files`)** -- **Before**: Manual loop over patterns with separate list building -- **After**: List comprehension with pattern flattening -- **Benefits**: More Pythonic, 50% fewer lines, easier to read - -### 4. **Configuration Parsing (`_parse_config_file`)** -- **Before**: Manual loop with temporary list building -- **After**: Single list comprehension -- **Benefits**: More concise, functional programming approach, 60% fewer lines - -### 5. **Backup Operations (`backup_configs`)** -- **Before**: Mixed backup logic and manifest creation -- **After**: Separated concerns with dedicated `_create_backup_manifest` method -- **Benefits**: Better separation of concerns, easier to maintain - -### 6. **Service Management (`_restart_zabbix_agent`)** -- **Before**: Verbose try-catch with repeated logging -- **After**: Streamlined logic with single success path -- **Benefits**: Cleaner flow, reduced verbosity, same functionality - -### 7. **Agent Upgrade (`upgrade_agent`)** -- **Before**: Step-by-step comments and verbose variable assignments -- **After**: Inline operations with dictionary comprehension -- **Benefits**: More concise, fewer intermediate variables - -### 8. **Package Upgrade (`_upgrade_zabbix_package`)** -- **Before**: If-elif blocks with hardcoded commands -- **After**: Data-driven approach with command dictionary -- **Benefits**: Easier to add new distributions, more maintainable - -### 9. **Configuration Merging (`_merge_custom_settings`)** -- **Before**: Complex nested loops and manual list management -- **After**: Streamlined processing with `pop()` for efficient key handling -- **Benefits**: Clearer logic flow, more efficient, easier to understand - -### 10. **Configuration Restore (`restore_configs`)** -- **Before**: Verbose logging and error handling -- **After**: Simplified flow with essential logging only -- **Benefits**: Cleaner output, same functionality, better readability - -## Code Quality Improvements - -### Lines of Code Reduction -- **Before**: ~390 lines -- **After**: ~320 lines -- **Reduction**: ~18% fewer lines while maintaining all functionality - -### Readability Improvements -- Eliminated redundant comments and verbose logging -- Used more Pythonic constructs (list comprehensions, dictionary methods) -- Better separation of concerns with helper methods -- Consistent error handling patterns - -### Maintainability Improvements -- Data-driven approaches for distribution detection and package management -- Single responsibility principle better applied -- Reduced code duplication -- More descriptive variable names where needed - -## Preserved Functionality -✅ All original features work exactly the same -✅ Same command-line interface -✅ Same error handling and logging capabilities -✅ Same backup/restore/upgrade workflows -✅ Same configuration file handling -✅ Same service management - -## Testing Results -- ✅ Syntax validation passed -- ✅ Help command works correctly -- ✅ List-backups functionality verified -- ✅ Verbose mode functions properly -- ✅ No breaking changes introduced - -## Benefits Summary -1. **Easier to maintain**: Less code to maintain and debug -2. **More readable**: Cleaner logic flow and Pythonic constructs -3. **Better organized**: Improved separation of concerns -4. **More efficient**: Better algorithm choices (e.g., using `pop()` in merge operations) -5. **Extensible**: Data-driven approaches make it easier to add new features -6. **Same reliability**: All original functionality preserved with comprehensive testing - -The refactored code maintains the same robust functionality while being significantly more maintainable and readable. diff --git a/agent-backup-tool/agent_tool_linux.py b/agent-backup-tool/agent_tool_linux.py deleted file mode 100755 index 9d66780..0000000 --- a/agent-backup-tool/agent_tool_linux.py +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/env python3 -""" -Zabbix Agent Management Tool -============================ - -This script provides functionality to: -1. Backup Zabbix agent configuration files -2. Restore Zabbix agent configuration files -3. Upgrade Zabbix agent while preserving custom configurations - -Author: GitHub Copilot -Date: September 2025 -""" - -import os -import sys -import argparse -import subprocess -import shutil -import glob -import difflib -import logging -from datetime import datetime -from pathlib import Path -import re - -# Configuration -ZABBIX_CONFIG_DIR = "/etc/zabbix" -SCRIPT_DIR = Path(__file__).parent.absolute() -DEFAULT_CONFIG_FILE = SCRIPT_DIR / "zabbix_agentd.conf" -BACKUP_DIR = SCRIPT_DIR / "backups" -LOG_FILE = SCRIPT_DIR / "agent_tool.log" - -# Logging setup -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler(LOG_FILE), - logging.StreamHandler(sys.stdout) - ] -) -logger = logging.getLogger(__name__) - - -class ZabbixAgentTool: - def __init__(self): - self.distro_family = self._detect_distro_family() - self.backup_dir = BACKUP_DIR - self.backup_dir.mkdir(exist_ok=True) - - def _detect_distro_family(self): - """Detect if the system is Debian-based or RHEL-based""" - # Detection rules: (file_path, keywords_for_debian, keywords_for_rhel) - detection_rules = [ - ('/etc/debian_version', True, False), - ('/etc/redhat-release', False, True), - ('/etc/centos-release', False, True), - ('/etc/os-release', ['debian', 'ubuntu'], ['centos', 'rhel', 'fedora']) - ] - - for file_path, debian_check, rhel_check in detection_rules: - if not os.path.exists(file_path): - continue - - try: - if isinstance(debian_check, bool): - return 'debian' if debian_check else 'rhel' - - # For os-release, check content - with open(file_path, 'r') as f: - content = f.read().lower() - if any(keyword in content for keyword in debian_check): - return 'debian' - elif any(keyword in content for keyword in rhel_check): - return 'rhel' - except Exception as e: - logger.debug(f"Error reading {file_path}: {e}") - continue - - logger.warning("Unknown distribution family, defaulting to debian") - return 'debian' - - def _get_config_files(self): - """Find all Zabbix agent configuration files""" - patterns = [f"{ZABBIX_CONFIG_DIR}/zabbix_agent*.conf"] - return [f for pattern in patterns for f in glob.glob(pattern)] - - def _run_command(self, command, check=True, log_output=False): - """Run a shell command and return the result""" - logger.info(f"Running: {command}") - try: - result = subprocess.run(command, shell=True, capture_output=True, text=True, check=check) - if log_output and result.stdout: - logger.debug(f"Output: {result.stdout.strip()}") - return result - except subprocess.CalledProcessError as e: - logger.error(f"Command failed: {command}") - if e.stderr: - logger.error(f"Error: {e.stderr.strip()}") - raise - - def _parse_config_file(self, config_path): - """Parse configuration file and extract uncommented settings""" - try: - with open(config_path, 'r') as f: - return [line.strip() for line in f if line.strip() and not line.strip().startswith('#')] - except Exception as e: - logger.error(f"Error parsing config file {config_path}: {e}") - raise - - def backup_configs(self): - """Backup existing Zabbix agent configuration files""" - config_files = self._get_config_files() - if not config_files: - logger.warning("No Zabbix agent configuration files found to backup") - return None - - # Create backup directory - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - backup_subdir = self.backup_dir / f"backup_{timestamp}" - backup_subdir.mkdir(exist_ok=True) - - # Backup files and track results - backed_up_files = [] - for config_file in config_files: - try: - backup_file = backup_subdir / Path(config_file).name - shutil.copy2(config_file, backup_file) - logger.info(f"Backed up {config_file}") - backed_up_files.append((config_file, str(backup_file))) - except Exception as e: - logger.error(f"Failed to backup {config_file}: {e}") - - # Create manifest - self._create_backup_manifest(backup_subdir, backed_up_files) - logger.info(f"Backup completed: {backup_subdir}") - return str(backup_subdir) - - def _create_backup_manifest(self, backup_dir, backed_up_files): - """Create backup manifest file""" - manifest_file = backup_dir / "backup_manifest.txt" - with open(manifest_file, 'w') as f: - f.write(f"Backup created: {datetime.now()}\n") - f.write(f"Distribution family: {self.distro_family}\n") - f.write("Backed up files:\n") - for original, backup in backed_up_files: - f.write(f" {original} -> {backup}\n") - - def restore_configs(self, backup_path): - """Restore Zabbix agent configuration files from backup""" - backup_dir = Path(backup_path) - if not backup_dir.exists(): - raise FileNotFoundError(f"Backup directory not found: {backup_path}") - - # Log manifest if available - manifest_file = backup_dir / "backup_manifest.txt" - if manifest_file.exists(): - logger.info(f"Restoring from backup: {backup_path}") - with open(manifest_file, 'r') as f: - logger.info(f"Manifest:\n{f.read()}") - - # Find and restore config files - backup_configs = list(backup_dir.glob("zabbix_agent*.conf")) - if not backup_configs: - raise FileNotFoundError("No configuration files found in backup directory") - - restored_files = [] - for backup_file in backup_configs: - try: - target_file = Path(ZABBIX_CONFIG_DIR) / backup_file.name - - # Backup current file if it exists - if target_file.exists(): - shutil.copy2(target_file, target_file.with_suffix(".conf.pre-restore")) - - shutil.copy2(backup_file, target_file) - logger.info(f"Restored {backup_file.name}") - restored_files.append(str(target_file)) - except Exception as e: - logger.error(f"Failed to restore {backup_file}: {e}") - - self._restart_zabbix_agent() - logger.info(f"Restore completed. Files: {[Path(f).name for f in restored_files]}") - return restored_files - - def _restart_zabbix_agent(self): - """Restart Zabbix agent service""" - services = ['zabbix-agent2', 'zabbix-agent', 'zabbix-agentd'] - - for service in services: - try: - # Check if service exists and restart it - if self._run_command(f"systemctl list-unit-files {service}.service", check=False).returncode == 0: - self._run_command(f"sudo systemctl restart {service}") - self._run_command(f"sudo systemctl enable {service}") - logger.info(f"Successfully restarted {service}") - return - except Exception as e: - logger.debug(f"Could not restart {service}: {e}") - - logger.warning("Could not restart any Zabbix agent service") - - def upgrade_agent(self): - """Upgrade Zabbix agent while preserving custom configurations""" - logger.info("Starting Zabbix agent upgrade process") - - # Backup and extract custom settings - backup_path = self.backup_configs() - if not backup_path: - raise Exception("Failed to create backup before upgrade") - - custom_settings = {Path(f).name: self._parse_config_file(f) for f in self._get_config_files()} - - # Upgrade package - self._upgrade_zabbix_package() - - # Merge custom settings into new configs - for config_file in self._get_config_files(): - config_name = Path(config_file).name - if config_name in custom_settings: - self._merge_custom_settings(config_file, custom_settings[config_name], backup_path) - - self._restart_zabbix_agent() - logger.info("Zabbix agent upgrade completed successfully") - return backup_path - - def _upgrade_zabbix_package(self): - """Upgrade Zabbix agent package based on distribution family""" - logger.info(f"Upgrading Zabbix agent on {self.distro_family}-based system") - - if self.distro_family == 'debian': - # Simple apt upgrade - self._run_command("sudo apt update") - self._run_command("sudo apt upgrade -y") - - elif self.distro_family == 'rhel': - # Simple yum/dnf upgrade - try both - try: - self._run_command("sudo yum update -y") - except: - try: - self._run_command("sudo dnf update -y") - except Exception as e: - logger.warning(f"Could not upgrade packages: {e}") - else: - raise Exception(f"Unsupported distribution family: {self.distro_family}") - - def _merge_custom_settings(self, new_config_file, custom_settings, backup_path): - """Merge custom settings into new configuration file""" - logger.info(f"Merging custom settings into {new_config_file}") - - # Parse custom settings into key-value pairs - custom_params = {} - for setting in custom_settings: - if '=' in setting: - key, value = setting.split('=', 1) - custom_params[key.strip()] = value.strip() - - # Read and process configuration file - with open(new_config_file, 'r') as f: - lines = f.readlines() - - original_lines = lines.copy() - updated_lines = [] - - # Process each line - for line in lines: - stripped = line.strip() - if not stripped or stripped.startswith('#'): - updated_lines.append(line) - elif '=' in stripped: - key = stripped.split('=', 1)[0].strip() - if key in custom_params: - updated_lines.append(f"{key}={custom_params.pop(key)}\n") - else: - updated_lines.append(line) - else: - updated_lines.append(line) - - # Add remaining custom parameters - if custom_params: - updated_lines.extend(["\n# Custom parameters added during upgrade\n"] + - [f"{k}={v}\n" for k, v in custom_params.items()]) - - # Write updated configuration and save diff - with open(new_config_file, 'w') as f: - f.writelines(updated_lines) - - self._save_config_diff(new_config_file, original_lines, updated_lines, backup_path) - logger.info(f"Custom settings merged into {new_config_file}") - - def _save_config_diff(self, config_file, original_lines, updated_lines, backup_path): - """Save the differences between original and updated configuration""" - config_name = Path(config_file).name - diff_file = Path(backup_path) / f"{config_name}.diff" - - diff = difflib.unified_diff( - original_lines, - updated_lines, - fromfile=f"{config_name}.original", - tofile=f"{config_name}.updated", - lineterm='' - ) - - with open(diff_file, 'w') as f: - f.writelines(diff) - - logger.info(f"Configuration differences saved to {diff_file}") - - def list_backups(self): - """List available backups""" - if not self.backup_dir.exists(): - logger.info("No backups directory found") - return [] - - backup_dirs = [d for d in self.backup_dir.iterdir() if d.is_dir() and d.name.startswith('backup_')] - backup_dirs.sort(key=lambda x: x.name, reverse=True) # Most recent first - - backups = [] - for backup_dir in backup_dirs: - manifest_file = backup_dir / "backup_manifest.txt" - info = {"path": str(backup_dir), "timestamp": backup_dir.name.replace('backup_', '')} - - if manifest_file.exists(): - try: - with open(manifest_file, 'r') as f: - content = f.read() - info["manifest"] = content - except Exception as e: - info["manifest"] = f"Error reading manifest: {e}" - - backups.append(info) - - return backups - - -def main(): - parser = argparse.ArgumentParser(description="Zabbix Agent Management Tool") - parser.add_argument( - 'action', - choices=['backup', 'restore', 'upgrade', 'list-backups'], - help='Action to perform' - ) - parser.add_argument( - '--backup-path', - help='Path to backup directory (required for restore action)' - ) - parser.add_argument( - '--verbose', - action='store_true', - help='Enable verbose logging' - ) - - args = parser.parse_args() - - if args.verbose: - logging.getLogger().setLevel(logging.DEBUG) - - try: - tool = ZabbixAgentTool() - - if args.action == 'backup': - backup_path = tool.backup_configs() - if backup_path: - print(f"Backup created successfully: {backup_path}") - else: - print("No configuration files found to backup") - - elif args.action == 'restore': - if not args.backup_path: - print("Error: --backup-path is required for restore action") - sys.exit(1) - - restored_files = tool.restore_configs(args.backup_path) - print(f"Restore completed successfully. Restored files: {restored_files}") - - elif args.action == 'upgrade': - backup_path = tool.upgrade_agent() - print(f"Upgrade completed successfully. Backup created: {backup_path}") - - elif args.action == 'list-backups': - backups = tool.list_backups() - if not backups: - print("No backups found") - else: - print("Available backups:") - for backup in backups: - print(f"\nBackup: {backup['path']}") - print(f"Timestamp: {backup['timestamp']}") - if 'manifest' in backup: - print("Manifest:") - print(backup['manifest']) - - except Exception as e: - logger.error(f"Error: {e}") - sys.exit(1) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/agent-backup-tool/simple_agent_tool.py b/agent-backup-tool/simple_agent_tool.py deleted file mode 100755 index afc3e08..0000000 --- a/agent-backup-tool/simple_agent_tool.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple Zabbix Agent Backup/Upgrade Tool - PoC -""" - -import os -import sys -import argparse -import subprocess -import shutil -from datetime import datetime -from pathlib import Path - -ZABBIX_CONFIG_DIR = "/etc/zabbix" -SCRIPT_DIR = Path(__file__).parent.absolute() -BACKUP_DIR = SCRIPT_DIR / "backups" - -def run_command(cmd): - """Run command and return result""" - print(f"Running: {cmd}") - result = subprocess.run(cmd, shell=True, capture_output=True, text=True) - if result.returncode != 0: - print(f"ERROR: {result.stderr.strip()}") - sys.exit(1) - return result - -def backup_configs(): - """Backup zabbix configs""" - BACKUP_DIR.mkdir(exist_ok=True) - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - backup_dir = BACKUP_DIR / f"backup_{timestamp}" - backup_dir.mkdir() - - config_files = list(Path(ZABBIX_CONFIG_DIR).glob("zabbix_agent*.conf")) - if not config_files: - print("No config files found") - return None - - for config_file in config_files: - shutil.copy2(config_file, backup_dir / config_file.name) - print(f"Backed up: {config_file.name}") - - print(f"Backup saved to: {backup_dir}") - return str(backup_dir) - -def restore_configs(backup_path): - """Restore configs from backup""" - backup_dir = Path(backup_path) - if not backup_dir.exists(): - print(f"Backup not found: {backup_path}") - sys.exit(1) - - config_files = list(backup_dir.glob("zabbix_agent*.conf")) - for config_file in config_files: - target = Path(ZABBIX_CONFIG_DIR) / config_file.name - shutil.copy2(config_file, target) - print(f"Restored: {config_file.name}") - - # Restart service - services = ['zabbix-agent2', 'zabbix-agent'] - for service in services: - try: - run_command(f"sudo systemctl restart {service}") - print(f"Restarted: {service}") - break - except: - continue - -def upgrade_system(): - """Simple system upgrade""" - if os.path.exists('/etc/debian_version'): - run_command("sudo apt update") - run_command("sudo apt upgrade -y") - else: - try: - run_command("sudo yum update -y") - except: - run_command("sudo dnf update -y") - -def main(): - parser = argparse.ArgumentParser(description="Simple Zabbix Agent Tool") - parser.add_argument('action', choices=['backup', 'restore', 'upgrade']) - parser.add_argument('--backup-path', help='Backup path for restore') - args = parser.parse_args() - - if args.action == 'backup': - backup_path = backup_configs() - if backup_path: - print(f"SUCCESS: Backup created at {backup_path}") - - elif args.action == 'restore': - if not args.backup_path: - print("ERROR: --backup-path required") - sys.exit(1) - restore_configs(args.backup_path) - print("SUCCESS: Restore completed") - - elif args.action == 'upgrade': - print("Creating backup before upgrade...") - backup_path = backup_configs() - print("Upgrading system...") - upgrade_system() - print("Restoring configs...") - restore_configs(backup_path) - print(f"SUCCESS: Upgrade completed. Backup at {backup_path}") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/agent-backup-tool/zabbix_agentd.conf b/agent-backup-tool/zabbix_agentd.conf deleted file mode 100644 index e64cbe0..0000000 --- a/agent-backup-tool/zabbix_agentd.conf +++ /dev/null @@ -1,537 +0,0 @@ -# This is a configuration file for Zabbix agent daemon (Unix) -# To get more information about Zabbix, visit http://www.zabbix.com - -############ GENERAL PARAMETERS ################# - -### Option: PidFile -# Name of PID file. -# -# Mandatory: no -# Default: -# PidFile=/tmp/zabbix_agentd.pid - -### Option: LogType -# Specifies where log messages are written to: -# system - syslog -# file - file specified with LogFile parameter -# console - standard output -# -# Mandatory: no -# Default: -# LogType=file - -### Option: LogFile -# Log file name for LogType 'file' parameter. -# -# Mandatory: yes, if LogType is set to file, otherwise no -# Default: -# LogFile= - -LogFile=/tmp/zabbix_agentd.log - -### Option: LogFileSize -# Maximum size of log file in MB. -# 0 - disable automatic log rotation. -# -# Mandatory: no -# Range: 0-1024 -# Default: -# LogFileSize=1 - -### Option: DebugLevel -# Specifies debug level: -# 0 - basic information about starting and stopping of Zabbix processes -# 1 - critical information -# 2 - error information -# 3 - warnings -# 4 - for debugging (produces lots of information) -# 5 - extended debugging (produces even more information) -# -# Mandatory: no -# Range: 0-5 -# Default: -# DebugLevel=3 - -### Option: SourceIP -# Source IP address for outgoing connections. -# -# Mandatory: no -# Default: -# SourceIP= - -### Option: AllowKey -# Allow execution of item keys matching pattern. -# Multiple keys matching rules may be defined in combination with DenyKey. -# Key pattern is wildcard expression, which support "*" character to match any number of any characters in certain position. It might be used in both key name and key arguments. -# Parameters are processed one by one according their appearance order. -# If no AllowKey or DenyKey rules defined, all keys are allowed. -# -# Mandatory: no - -### Option: DenyKey -# Deny execution of items keys matching pattern. -# Multiple keys matching rules may be defined in combination with AllowKey. -# Key pattern is wildcard expression, which support "*" character to match any number of any characters in certain position. It might be used in both key name and key arguments. -# Parameters are processed one by one according their appearance order. -# If no AllowKey or DenyKey rules defined, all keys are allowed. -# Unless another system.run[*] rule is specified DenyKey=system.run[*] is added by default. -# -# Mandatory: no -# Default: -# DenyKey=system.run[*] - -### Option: EnableRemoteCommands - Deprecated, use AllowKey=system.run[*] or DenyKey=system.run[*] instead -# Internal alias for AllowKey/DenyKey parameters depending on value: -# 0 - DenyKey=system.run[*] -# 1 - AllowKey=system.run[*] -# -# Mandatory: no - -### Option: LogRemoteCommands -# Enable logging of executed shell commands as warnings. -# 0 - disabled -# 1 - enabled -# -# Mandatory: no -# Default: -# LogRemoteCommands=0 - -##### Passive checks related - -### Option: Server -# List of comma delimited IP addresses, optionally in CIDR notation, or DNS names of Zabbix servers and Zabbix proxies. -# Incoming connections will be accepted only from the hosts listed here. -# If IPv6 support is enabled then '127.0.0.1', '::127.0.0.1', '::ffff:127.0.0.1' are treated equally -# and '::/0' will allow any IPv4 or IPv6 address. -# '0.0.0.0/0' can be used to allow any IPv4 address. -# Example: Server=127.0.0.1,192.168.1.0/24,::1,2001:db8::/32,zabbix.example.com -# -# Mandatory: yes, if StartAgents is not explicitly set to 0 -# Default: -# Server= - -Server=127.0.0.1 - -### Option: ListenPort -# Agent will listen on this port for connections from the server. -# -# Mandatory: no -# Range: 1024-32767 -# Default: -# ListenPort=10050 - -### Option: ListenIP -# List of comma delimited IP addresses that the agent should listen on. -# First IP address is sent to Zabbix server if connecting to it to retrieve list of active checks. -# -# Mandatory: no -# Default: -# ListenIP=0.0.0.0 - -### Option: StartAgents -# Number of pre-forked instances of zabbix_agentd that process passive checks. -# If set to 0, disables passive checks and the agent will not listen on any TCP port. -# -# Mandatory: no -# Range: 0-100 -# Default: -# StartAgents=3 - -##### Active checks related - -### Option: ServerActive -# Zabbix server/proxy address or cluster configuration to get active checks from. -# Server/proxy address is IP address or DNS name and optional port separated by colon. -# Cluster configuration is one or more server addresses separated by semicolon. -# Multiple Zabbix servers/clusters and Zabbix proxies can be specified, separated by comma. -# More than one Zabbix proxy should not be specified from each Zabbix server/cluster. -# If Zabbix proxy is specified then Zabbix server/cluster for that proxy should not be specified. -# Multiple comma-delimited addresses can be provided to use several independent Zabbix servers in parallel. Spaces are allowed. -# If port is not specified, default port is used. -# IPv6 addresses must be enclosed in square brackets if port for that host is specified. -# If port is not specified, square brackets for IPv6 addresses are optional. -# If this parameter is not specified, active checks are disabled. -# Example for Zabbix proxy: -# ServerActive=127.0.0.1:10051 -# Example for multiple servers: -# ServerActive=127.0.0.1:20051,zabbix.domain,[::1]:30051,::1,[12fc::1] -# Example for high availability: -# ServerActive=zabbix.cluster.node1;zabbix.cluster.node2:20051;zabbix.cluster.node3 -# Example for high availability with two clusters and one server: -# ServerActive=zabbix.cluster.node1;zabbix.cluster.node2:20051,zabbix.cluster2.node1;zabbix.cluster2.node2,zabbix.domain -# -# Mandatory: no -# Default: -# ServerActive= - -ServerActive=127.0.0.1 - -### Option: Hostname -# List of comma delimited unique, case sensitive hostnames. -# Required for active checks and must match hostnames as configured on the server. -# Value is acquired from HostnameItem if undefined. -# -# Mandatory: no -# Default: -# Hostname= - -Hostname=Zabbix server - -### Option: HostnameItem -# Item used for generating Hostname if it is undefined. Ignored if Hostname is defined. -# Does not support UserParameters or aliases. -# -# Mandatory: no -# Default: -# HostnameItem=system.hostname - -### Option: HostMetadata -# Optional parameter that defines host metadata. -# Host metadata is used at host auto-registration process. -# An agent will issue an error and not start if the value is over limit of 255 characters. -# If not defined, value will be acquired from HostMetadataItem. -# -# Mandatory: no -# Range: 0-255 characters -# Default: -# HostMetadata= - -### Option: HostMetadataItem -# Optional parameter that defines an item used for getting host metadata. -# Host metadata is used at host auto-registration process. -# During an auto-registration request an agent will log a warning message if -# the value returned by specified item is over limit of 255 characters. -# This option is only used when HostMetadata is not defined. -# -# Mandatory: no -# Default: -# HostMetadataItem= - -### Option: HostInterface -# Optional parameter that defines host interface. -# Host interface is used at host auto-registration process. -# An agent will issue an error and not start if the value is over limit of 255 characters. -# If not defined, value will be acquired from HostInterfaceItem. -# -# Mandatory: no -# Range: 0-255 characters -# Default: -# HostInterface= - -### Option: HostInterfaceItem -# Optional parameter that defines an item used for getting host interface. -# Host interface is used at host auto-registration process. -# During an auto-registration request an agent will log a warning message if -# the value returned by specified item is over limit of 255 characters. -# This option is only used when HostInterface is not defined. -# -# Mandatory: no -# Default: -# HostInterfaceItem= - -### Option: RefreshActiveChecks -# How often list of active checks is refreshed, in seconds. -# -# Mandatory: no -# Range: 60-3600 -# Default: -# RefreshActiveChecks=120 - -### Option: BufferSend -# Do not keep data longer than N seconds in buffer. -# -# Mandatory: no -# Range: 1-3600 -# Default: -# BufferSend=5 - -### Option: BufferSize -# Maximum number of values in a memory buffer. The agent will send -# all collected data to Zabbix Server or Proxy if the buffer is full. -# -# Mandatory: no -# Range: 2-65535 -# Default: -# BufferSize=100 - -### Option: MaxLinesPerSecond -# Maximum number of new lines the agent will send per second to Zabbix Server -# or Proxy processing 'log' and 'logrt' active checks. -# The provided value will be overridden by the parameter 'maxlines', -# provided in 'log' or 'logrt' item keys. -# -# Mandatory: no -# Range: 1-1000 -# Default: -# MaxLinesPerSecond=20 - -############ ADVANCED PARAMETERS ################# - -### Option: Alias -# Sets an alias for an item key. It can be used to substitute long and complex item key with a smaller and simpler one. -# Multiple Alias parameters may be present. Multiple parameters with the same Alias key are not allowed. -# Different Alias keys may reference the same item key. -# For example, to retrieve the ID of user 'zabbix': -# Alias=zabbix.userid:vfs.file.regexp[/etc/passwd,^zabbix:.:([0-9]+),,,,\1] -# Now shorthand key zabbix.userid may be used to retrieve data. -# Aliases can be used in HostMetadataItem but not in HostnameItem parameters. -# -# Mandatory: no -# Range: -# Default: - -### Option: Timeout -# Spend no more than Timeout seconds on processing -# -# Mandatory: no -# Range: 1-30 -# Default: -# Timeout=3 - -### Option: AllowRoot -# Allow the agent to run as 'root'. If disabled and the agent is started by 'root', the agent -# will try to switch to the user specified by the User configuration option instead. -# Has no effect if started under a regular user. -# 0 - do not allow -# 1 - allow -# -# Mandatory: no -# Default: -# AllowRoot=0 - -### Option: User -# Drop privileges to a specific, existing user on the system. -# Only has effect if run as 'root' and AllowRoot is disabled. -# -# Mandatory: no -# Default: -# User=zabbix - -### Option: Include -# You may include individual files or all files in a directory in the configuration file. -# Installing Zabbix will create include directory in /usr/local/etc, unless modified during the compile time. -# -# Mandatory: no -# Default: -# Include= - -# Include=/usr/local/etc/zabbix_agentd.userparams.conf -# Include=/usr/local/etc/zabbix_agentd.conf.d/ -# Include=/usr/local/etc/zabbix_agentd.conf.d/*.conf - -####### USER-DEFINED MONITORED PARAMETERS ####### - -### Option: UnsafeUserParameters -# Allow all characters to be passed in arguments to user-defined parameters. -# The following characters are not allowed: -# \ ' " ` * ? [ ] { } ~ $ ! & ; ( ) < > | # @ -# Additionally, newline characters are not allowed. -# 0 - do not allow -# 1 - allow -# -# Mandatory: no -# Range: 0-1 -# Default: -# UnsafeUserParameters=0 - -### Option: UserParameter -# User-defined parameter to monitor. There can be several user-defined parameters. -# Format: UserParameter=, -# See 'zabbix_agentd' directory for examples. -# -# Mandatory: no -# Default: -# UserParameter= - -### Option: UserParameterDir -# Directory to execute UserParameter commands from. Only one entry is allowed. -# When executing UserParameter commands the agent will change the working directory to the one -# specified in the UserParameterDir option. -# This way UserParameter commands can be specified using the relative ./ prefix. -# -# Mandatory: no -# Default: -# UserParameterDir= - -####### LOADABLE MODULES ####### - -### Option: LoadModulePath -# Full path to location of agent modules. -# Default depends on compilation options. -# To see the default path run command "zabbix_agentd --help". -# -# Mandatory: no -# Default: -# LoadModulePath=${libdir}/modules - -### Option: LoadModule -# Module to load at agent startup. Modules are used to extend functionality of the agent. -# Formats: -# LoadModule= -# LoadModule= -# LoadModule= -# Either the module must be located in directory specified by LoadModulePath or the path must precede the module name. -# If the preceding path is absolute (starts with '/') then LoadModulePath is ignored. -# It is allowed to include multiple LoadModule parameters. -# -# Mandatory: no -# Default: -# LoadModule= - -####### TLS-RELATED PARAMETERS ####### - -### Option: TLSConnect -# How the agent should connect to server or proxy. Used for active checks. -# Only one value can be specified: -# unencrypted - connect without encryption -# psk - connect using TLS and a pre-shared key -# cert - connect using TLS and a certificate -# -# Mandatory: yes, if TLS certificate or PSK parameters are defined (even for 'unencrypted' connection) -# Default: -# TLSConnect=unencrypted - -### Option: TLSAccept -# What incoming connections to accept. -# Multiple values can be specified, separated by comma: -# unencrypted - accept connections without encryption -# psk - accept connections secured with TLS and a pre-shared key -# cert - accept connections secured with TLS and a certificate -# -# Mandatory: yes, if TLS certificate or PSK parameters are defined (even for 'unencrypted' connection) -# Default: -# TLSAccept=unencrypted - -### Option: TLSCAFile -# Full pathname of a file containing the top-level CA(s) certificates for -# peer certificate verification. -# -# Mandatory: no -# Default: -# TLSCAFile= - -### Option: TLSCRLFile -# Full pathname of a file containing revoked certificates. -# -# Mandatory: no -# Default: -# TLSCRLFile= - -### Option: TLSServerCertIssuer -# Allowed server certificate issuer. -# -# Mandatory: no -# Default: -# TLSServerCertIssuer= - -### Option: TLSServerCertSubject -# Allowed server certificate subject. -# -# Mandatory: no -# Default: -# TLSServerCertSubject= - -### Option: TLSCertFile -# Full pathname of a file containing the agent certificate or certificate chain. -# -# Mandatory: no -# Default: -# TLSCertFile= - -### Option: TLSKeyFile -# Full pathname of a file containing the agent private key. -# -# Mandatory: no -# Default: -# TLSKeyFile= - -### Option: TLSPSKIdentity -# Unique, case sensitive string used to identify the pre-shared key. -# -# Mandatory: no -# Default: -# TLSPSKIdentity= - -### Option: TLSPSKFile -# Full pathname of a file containing the pre-shared key. -# -# Mandatory: no -# Default: -# TLSPSKFile= - -####### For advanced users - TLS ciphersuite selection criteria ####### - -### Option: TLSCipherCert13 -# Cipher string for OpenSSL 1.1.1 or newer in TLS 1.3. -# Override the default ciphersuite selection criteria for certificate-based encryption. -# -# Mandatory: no -# Default: -# TLSCipherCert13= - -### Option: TLSCipherCert -# GnuTLS priority string or OpenSSL (TLS 1.2) cipher string. -# Override the default ciphersuite selection criteria for certificate-based encryption. -# Example for GnuTLS: -# NONE:+VERS-TLS1.2:+ECDHE-RSA:+RSA:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+SHA1:+CURVE-ALL:+COMP-NULL:+SIGN-ALL:+CTYPE-X.509 -# Example for OpenSSL: -# EECDH+aRSA+AES128:RSA+aRSA+AES128 -# -# Mandatory: no -# Default: -# TLSCipherCert= - -### Option: TLSCipherPSK13 -# Cipher string for OpenSSL 1.1.1 or newer in TLS 1.3. -# Override the default ciphersuite selection criteria for PSK-based encryption. -# Example: -# TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 -# -# Mandatory: no -# Default: -# TLSCipherPSK13= - -### Option: TLSCipherPSK -# GnuTLS priority string or OpenSSL (TLS 1.2) cipher string. -# Override the default ciphersuite selection criteria for PSK-based encryption. -# Example for GnuTLS: -# NONE:+VERS-TLS1.2:+ECDHE-PSK:+PSK:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+SHA1:+CURVE-ALL:+COMP-NULL:+SIGN-ALL -# Example for OpenSSL: -# kECDHEPSK+AES128:kPSK+AES128 -# -# Mandatory: no -# Default: -# TLSCipherPSK= - -### Option: TLSCipherAll13 -# Cipher string for OpenSSL 1.1.1 or newer in TLS 1.3. -# Override the default ciphersuite selection criteria for certificate- and PSK-based encryption. -# Example: -# TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 -# -# Mandatory: no -# Default: -# TLSCipherAll13= - -### Option: TLSCipherAll -# GnuTLS priority string or OpenSSL (TLS 1.2) cipher string. -# Override the default ciphersuite selection criteria for certificate- and PSK-based encryption. -# Example for GnuTLS: -# NONE:+VERS-TLS1.2:+ECDHE-RSA:+RSA:+ECDHE-PSK:+PSK:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+SHA1:+CURVE-ALL:+COMP-NULL:+SIGN-ALL:+CTYPE-X.509 -# Example for OpenSSL: -# EECDH+aRSA+AES128:RSA+aRSA+AES128:kECDHEPSK+AES128:kPSK+AES128 -# -# Mandatory: no -# Default: -# TLSCipherAll= - -####### For advanced users - TCP-related fine-tuning parameters ####### - -## Option: ListenBacklog -# The maximum number of pending connections in the queue. This parameter is passed to -# listen() function as argument 'backlog' (see "man listen"). -# -# Mandatory: no -# Range: 0 - INT_MAX (depends on system, too large values may be silently truncated to implementation-specified maximum) -# Default: SOMAXCONN (hard-coded constant, depends on system) -# ListenBacklog= \ No newline at end of file diff --git a/config-mover/README.md b/config-mover/README.md deleted file mode 100644 index cccbc52..0000000 --- a/config-mover/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Zabbix Configuration Export/Import Scripts - -Simple POC scripts for exporting and importing Zabbix host configurations and templates. - -## Files - -- `config_exporter.py` - Export hosts and templates -- `config_importer.py` - Import hosts and templates -- `run_export.sh` - Example export script -- `run_import.sh` - Example import script -- `requirements.txt` - Python dependencies - -## Setup - -1. Create virtual environment: -```bash -python3 -m venv venv -source venv/bin/activate -pip install -r requirements.txt -``` - -2. Set environment variables in run scripts - -## Export - -Exports hosts and their linked templates to organized directories: - -```bash -export ZABBIX_URL="https://your-zabbix.com/api_jsonrpc.php" -export BEARER_TOKEN="your_api_token" -export HOST_IDS="10591,10592,10593" # Comma-separated -export OUTPUT_DIR="/path/to/export" -./run_export.sh -``` - -### Output Structure -``` -export/ -├── 10591/ -│ ├── host_10591.xml -│ ├── template_Linux_by_Zabbix_agent.xml -│ └── template_Generic_SNMP.xml -└── 10592/ - ├── host_10592.xml - └── template_Windows_by_Zabbix_agent.xml -``` - -## Import - -Imports configurations from export directory structure: - -```bash -export ZABBIX_URL="https://your-zabbix.com/api_jsonrpc.php" -export BEARER_TOKEN="your_api_token" -export IMPORT_DIR="/path/to/export" # Directory with host subdirectories -./run_import.sh -``` - -### Import Rules - -- **Hosts/Templates**: Create new, update existing, never delete -- **Inside hosts/templates**: Create, update, and delete items/triggers/etc -- **Templates imported first**, then hosts (for proper linking) - -### Process - -1. Finds all numbered directories (10591, 10592, etc) -2. For each directory: - - Import all `template_*.xml` files first - - Import all `host_*.xml` files after -3. Reports success/failure per directory - -## Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `ZABBIX_URL` | Zabbix API endpoint | `http://localhost/api_jsonrpc.php` | -| `BEARER_TOKEN` | API token | Required | -| `HOST_IDS` | Comma-separated host IDs to export | `10591` | -| `OUTPUT_DIR` | Export base directory | `/opt/python/export` | -| `IMPORT_DIR` | Import base directory | `/opt/python/export` | \ No newline at end of file diff --git a/config-mover/config_exporter.py b/config-mover/config_exporter.py deleted file mode 100755 index d6a3469..0000000 --- a/config-mover/config_exporter.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 - -import os -import xml.etree.ElementTree as ET -from zabbix_utils import ZabbixAPI - -# Configuration from environment variables -ZABBIX_URL = os.environ.get("ZABBIX_URL", "http://localhost/api_jsonrpc.php") -BEARER_TOKEN = os.environ.get("BEARER_TOKEN") -HOST_IDS = os.environ.get("HOST_IDS", "10591") -OUTPUT_DIR = os.environ.get("OUTPUT_DIR", "/opt/python/export") - - -def get_template_names(xml_data): - """Extract template names from host XML.""" - try: - root = ET.fromstring(xml_data) - return [name.text for name in root.findall('.//hosts/host/templates/template/name')] - except ET.ParseError: - return [] - - -def export_templates(zapi, template_names, output_dir): - """Export templates to XML files.""" - if not template_names: - return - - templates = zapi.template.get(output=['templateid', 'host'], filter={'host': template_names}) - - for template in templates: - name = template['host'] - template_id = template['templateid'] - - xml_data = zapi.configuration.export(options={'templates': [template_id]}, format='xml') - - if xml_data: - safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '_', '-')).strip() - filename = f"template_{safe_name}.xml" - filepath = os.path.join(output_dir, filename) - - with open(filepath, 'w', encoding='utf-8') as f: - f.write(xml_data) - print(f" Exported: {filename}") - - -def export_host(zapi, host_id, base_dir): - """Export single host and its templates.""" - host_dir = os.path.join(base_dir, str(host_id)) - os.makedirs(host_dir, exist_ok=True) - - print(f"Exporting host {host_id}...") - - # Export host - host_xml = zapi.configuration.export(options={'hosts': [host_id]}, format='xml') - if not host_xml: - print(f" Failed to export host {host_id}") - return - - # Save host XML - host_file = os.path.join(host_dir, f"host_{host_id}.xml") - with open(host_file, 'w', encoding='utf-8') as f: - f.write(host_xml) - print(f" Host saved: host_{host_id}.xml") - - # Export templates - template_names = get_template_names(host_xml) - if template_names: - print(f" Found {len(template_names)} templates") - export_templates(zapi, template_names, host_dir) - - -def main(): - if not BEARER_TOKEN: - print("Error: BEARER_TOKEN not set") - return - - host_ids = [h.strip() for h in HOST_IDS.split(',') if h.strip()] - if not host_ids: - print("Error: No HOST_IDS provided") - return - - # Connect to Zabbix - zapi = ZabbixAPI(url=ZABBIX_URL) - zapi.login(token=BEARER_TOKEN) - print(f"Connected to Zabbix at {ZABBIX_URL}") - - # Create output directory - os.makedirs(OUTPUT_DIR, exist_ok=True) - - # Export each host - for host_id in host_ids: - try: - export_host(zapi, host_id, OUTPUT_DIR) - except Exception as e: - print(f"Error exporting host {host_id}: {e}") - - print(f"Export complete. Results in: {OUTPUT_DIR}") - - -if __name__ == "__main__": - main() - diff --git a/config-mover/config_exporter_legacy.py b/config-mover/config_exporter_legacy.py deleted file mode 100644 index 3e1dffa..0000000 --- a/config-mover/config_exporter_legacy.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python3 -""" -Legacy Zabbix Configuration Exporter -==================================== -Uses username/password authentication instead of Bearer tokens. -Note: This script is designed for Zabbix 5.0 and older versions! -Please do not use with Zabbix 6.0 and newer! Use token-based method instead. -""" - -import os -import xml.etree.ElementTree as ET -from zabbix_utils import ZabbixAPI - -# Configuration from environment variables -ZABBIX_URL = os.environ.get("ZABBIX_URL") -ZABBIX_USER = os.environ.get("ZABBIX_USER") -ZABBIX_PASSWORD = os.environ.get("ZABBIX_PASSWORD") -HOST_IDS = os.environ.get("HOST_IDS") -OUTPUT_DIR = os.environ.get("OUTPUT_DIR", "/opt/python/export") - - -def get_template_names(xml_data): - """Extract template names from host XML.""" - try: - root = ET.fromstring(xml_data) - return [name.text for name in root.findall('.//hosts/host/templates/template/name')] - except ET.ParseError: - return [] - - -def export_templates(zapi, template_names, output_dir): - """Export templates to XML files.""" - if not template_names: - return - - templates = zapi.template.get(output=['templateid', 'host'], filter={'host': template_names}) - - for template in templates: - name = template['host'] - template_id = template['templateid'] - - xml_data = zapi.configuration.export(options={'templates': [template_id]}, format='xml') - - if xml_data: - safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '_', '-')).strip() - filename = f"template_{safe_name}.xml" - filepath = os.path.join(output_dir, filename) - - with open(filepath, 'w', encoding='utf-8') as f: - f.write(xml_data) - - -def export_host(zapi, host_id, base_dir): - """Export single host and its templates.""" - host_dir = os.path.join(base_dir, str(host_id)) - os.makedirs(host_dir, exist_ok=True) - - # Export host - host_xml = zapi.configuration.export(options={'hosts': [host_id]}, format='xml') - if not host_xml: - return False - - # Save host XML - host_file = os.path.join(host_dir, f"host_{host_id}.xml") - with open(host_file, 'w', encoding='utf-8') as f: - f.write(host_xml) - - # Export templates - template_names = get_template_names(host_xml) - if template_names: - export_templates(zapi, template_names, host_dir) - - return True - - -def main(): - # Check required environment variables - if not ZABBIX_USER or not ZABBIX_PASSWORD or not HOST_IDS: - print("Error: ZABBIX_USER, ZABBIX_PASSWORD, and HOST_IDS must be set") - return - - host_ids = [h.strip() for h in HOST_IDS.split(',') if h.strip()] - if not host_ids: - print("Error: No valid HOST_IDS provided") - return - - # Connect to Zabbix - try: - zapi = ZabbixAPI(url=ZABBIX_URL) - zapi.login(user=ZABBIX_USER, password=ZABBIX_PASSWORD) - print(f"Connected to Zabbix. Processing {len(host_ids)} hosts...") - except Exception as e: - print(f"Failed to connect: {e}") - return - - # Create output directory - os.makedirs(OUTPUT_DIR, exist_ok=True) - - # Export hosts - successful = 0 - failed = 0 - - for i, host_id in enumerate(host_ids, 1): - try: - if export_host(zapi, host_id, OUTPUT_DIR): - successful += 1 - else: - failed += 1 - except Exception: - failed += 1 - - # Progress indicator for large batches - if i % 50 == 0 or i == len(host_ids): - print(f"Progress: {i}/{len(host_ids)} ({successful} ok, {failed} failed)") - - print(f"Export complete: {successful} successful, {failed} failed") - print(f"Results in: {OUTPUT_DIR}") - - # Logout - try: - zapi.logout() - except: - pass - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/config-mover/config_importer.py b/config-mover/config_importer.py deleted file mode 100644 index 14df49c..0000000 --- a/config-mover/config_importer.py +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env python3 - -import os -import glob -from zabbix_utils import ZabbixAPI - -# Configuration from environment variables -ZABBIX_URL = os.environ.get("ZABBIX_URL", "http://localhost/api_jsonrpc.php") -BEARER_TOKEN = os.environ.get("BEARER_TOKEN") -IMPORT_DIR = os.environ.get("IMPORT_DIR", "/opt/python/export") - - -def get_import_rules(): - """Define import rules based on requirements.""" - return { - # Host/Template level - only create/update, never delete - "hosts": { - "createMissing": True, - "updateExisting": True - }, - "templates": { - "createMissing": True, - "updateExisting": True - }, - "host_groups": { - "createMissing": True, - "updateExisting": True - }, - "template_groups": { - "createMissing": True, - "updateExisting": True - }, - # Inside host/template - allow all changes including deletion - "items": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "triggers": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "discoveryRules": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "graphs": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "httptests": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "valueMaps": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "templateDashboards": { - "createMissing": True, - "updateExisting": True, - "deleteMissing": True - }, - "templateLinkage": { - "createMissing": True, - "deleteMissing": False # Don't unlink templates - } - } - - -def import_file(zapi, file_path, file_type): - """Import a single XML file.""" - try: - with open(file_path, 'r', encoding='utf-8') as f: - xml_content = f.read() - - print(f" Importing {file_type}: {os.path.basename(file_path)}") - - result = zapi.configuration.import_( - format='xml', - source=xml_content, - rules=get_import_rules() - ) - - if result: - print(f" Success: {os.path.basename(file_path)}") - else: - print(f" Failed: {os.path.basename(file_path)}") - - return result - - except Exception as e: - print(f" Error importing {file_path}: {e}") - return False - - -def import_host_directory(zapi, host_dir): - """Import all files from a single host directory.""" - host_id = os.path.basename(host_dir) - print(f"Importing configuration for host directory: {host_id}") - - # Get all template and host files - template_files = glob.glob(os.path.join(host_dir, "template_*.xml")) - host_files = glob.glob(os.path.join(host_dir, "host_*.xml")) - - if not template_files and not host_files: - print(f" No XML files found in {host_dir}") - return False - - success_count = 0 - total_count = 0 - - # Import templates first - for template_file in sorted(template_files): - total_count += 1 - if import_file(zapi, template_file, "template"): - success_count += 1 - - # Import hosts after templates - for host_file in sorted(host_files): - total_count += 1 - if import_file(zapi, host_file, "host"): - success_count += 1 - - print(f" Host {host_id}: {success_count}/{total_count} files imported successfully") - return success_count == total_count - - -def main(): - if not BEARER_TOKEN: - print("Error: BEARER_TOKEN not set") - return - - if not os.path.exists(IMPORT_DIR): - print(f"Error: Import directory does not exist: {IMPORT_DIR}") - return - - # Connect to Zabbix - try: - zapi = ZabbixAPI(url=ZABBIX_URL) - zapi.login(token=BEARER_TOKEN) - print(f"Connected to Zabbix at {ZABBIX_URL}") - except Exception as e: - print(f"Failed to connect to Zabbix: {e}") - return - - # Find all host directories - host_dirs = [ - d for d in glob.glob(os.path.join(IMPORT_DIR, "*")) - if os.path.isdir(d) and os.path.basename(d).isdigit() - ] - - if not host_dirs: - print(f"No host directories found in {IMPORT_DIR}") - return - - host_dirs.sort(key=lambda x: int(os.path.basename(x))) - print(f"Found {len(host_dirs)} host directories to import") - - # Import each host directory - successful_hosts = 0 - for host_dir in host_dirs: - try: - if import_host_directory(zapi, host_dir): - successful_hosts += 1 - except Exception as e: - print(f"Error processing {host_dir}: {e}") - - print(f"\nImport completed! Successfully processed {successful_hosts}/{len(host_dirs)} host directories.") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/config-mover/get_host_ids.py b/config-mover/get_host_ids.py deleted file mode 100644 index 5643b76..0000000 --- a/config-mover/get_host_ids.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 - -import os -from datetime import datetime -from zabbix_utils import ZabbixAPI - -# Configuration from environment variables -ZABBIX_URL = os.environ.get("ZABBIX_URL", "http://localhost/api_jsonrpc.php") -BEARER_TOKEN = os.environ.get("BEARER_TOKEN") - - -def main(): - if not BEARER_TOKEN: - print("Error: BEARER_TOKEN not set") - return - - # Connect to Zabbix - try: - zapi = ZabbixAPI(url=ZABBIX_URL) - zapi.login(token=BEARER_TOKEN) - print(f"Connected to Zabbix at {ZABBIX_URL}") - except Exception as e: - print(f"Failed to connect to Zabbix: {e}") - return - - # Get all host IDs - try: - hosts = zapi.host.get(output=['hostid']) - - if not hosts: - print("No hosts found") - return - - # Extract host IDs - host_ids = [host['hostid'] for host in hosts] - host_ids.sort(key=int) # Sort numerically - - print(f"Found {len(host_ids)} hosts") - - # Generate filename with current date - current_date = datetime.now().strftime("%Y%m%d") - filename = f"{current_date}_host_ids.txt" - - # Write host IDs to file (comma-separated on single line) - with open(filename, 'w') as f: - f.write(','.join(host_ids)) - - print(f"Host IDs saved to: {filename}") - print(f"Host IDs: {', '.join(host_ids)}") - - except Exception as e: - print(f"Error retrieving host IDs: {e}") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/config-mover/get_host_ids_legacy.py b/config-mover/get_host_ids_legacy.py deleted file mode 100644 index d3e2f0c..0000000 --- a/config-mover/get_host_ids_legacy.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -""" -Legacy ID Retriever -=============================== -Uses username/password authentication instead of tokens. -Note: This script is designed for Zabbix 5.0 and older versions! -Please do not use with Zabbix 6.0 and newer! Use token-based get_host_ids.py instead. -""" - -import os -from datetime import datetime -from zabbix_utils import ZabbixAPI - -# Configuration from environment variables -ZABBIX_URL = os.environ.get("ZABBIX_URL", "http://localhost/api_jsonrpc.php") -ZABBIX_USER = os.environ.get("ZABBIX_USER") -ZABBIX_PASSWORD = os.environ.get("ZABBIX_PASSWORD") - - -def main(): - # Check required environment variables - if not ZABBIX_USER or not ZABBIX_PASSWORD: - print("Error: ZABBIX_USER and ZABBIX_PASSWORD environment variables must be set") - return - - # Connect to Zabbix using username/password - try: - zapi = ZabbixAPI(url=ZABBIX_URL) - zapi.login(user=ZABBIX_USER, password=ZABBIX_PASSWORD) - print(f"Connected to Zabbix at {ZABBIX_URL}") - print(f"Authenticated as user: {ZABBIX_USER}") - except Exception as e: - print(f"Failed to connect to Zabbix: {e}") - return - - # Get all host IDs - try: - hosts = zapi.host.get(output=['hostid', 'host']) - - if not hosts: - print("No hosts found") - return - - # Extract host IDs - host_ids = [host['hostid'] for host in hosts] - host_ids.sort(key=int) # Sort numerically - - print(f"Found {len(host_ids)} hosts") - - # Generate filename with current date - current_date = datetime.now().strftime("%Y%m%d") - filename = f"{current_date}_host_ids_legacy.txt" - - # Write host IDs to file (comma-separated on single line) - with open(filename, 'w') as f: - f.write(','.join(host_ids)) - - print(f"Host IDs saved to: {filename}") - - except Exception as e: - print(f"Error retrieving host IDs: {e}") - - finally: - # Logout from Zabbix - try: - zapi.logout() - print("Logged out from Zabbix") - except: - pass # Ignore logout errors - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/config-mover/run_export.sh b/config-mover/run_export.sh deleted file mode 100755 index da88e74..0000000 --- a/config-mover/run_export.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# Example script to run the Zabbix configuration exporter -# Replace the values below with your actual Zabbix configuration - -# Set environment variables -export ZABBIX_URL="https://zabbix.mbuz.uk/api_jsonrpc.php" -export BEARER_TOKEN="7b7a372ef46f924f41f2eb163edcb04b99ea2a7a8683e891f531ff7b212adeff" -export HOST_IDS="10084,10584,10591,10595,10596,10607,10618,10623,10624,10637,10659" # Comma-separated list of host IDs -export OUTPUT_DIR="/opt/python/export" - -# Activate virtual environment and run the script -cd /opt/python -source venv/bin/activate -python3 config_exporter.py \ No newline at end of file diff --git a/config-mover/run_export_legacy.sh b/config-mover/run_export_legacy.sh deleted file mode 100755 index c1889ad..0000000 --- a/config-mover/run_export_legacy.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Legacy script to run the Zabbix configuration exporter for older Zabbix versions -# Replace the values below with your actual Zabbix configuration - -# Set environment variables -export ZABBIX_URL="https://your.zabbix/api_jsonrpc.php" -export HOST_IDS="10084,10584,10591,10595" # Comma-separated list of host IDs -export OUTPUT_DIR="/opt/python/export" -export ZABBIX_USER="your_username" -export ZABBIX_PASSWORD="your_password" - -# Activate virtual environment and run the script -cd /opt/python -source venv/bin/activate -python3 config_exporter_legacy.py \ No newline at end of file diff --git a/config-mover/run_get_ids.sh b/config-mover/run_get_ids.sh deleted file mode 100755 index 428e67a..0000000 --- a/config-mover/run_get_ids.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Example script to run the Zabbix host IDs retriever -# Replace the values below with your actual Zabbix configuration - -# Set environment variables -export ZABBIX_URL="https://zabbix.mbuz.uk/api_jsonrpc.php" -export BEARER_TOKEN="7b7a372ef46f924f41f2eb163edcb04b99ea2a7a8683e891f531ff7b212adeff" - -# Activate virtual environment and run the script -cd /opt/python -source venv/bin/activate -python3 get_host_ids.py \ No newline at end of file diff --git a/config-mover/run_get_ids_legacy.sh b/config-mover/run_get_ids_legacy.sh deleted file mode 100755 index 9e48104..0000000 --- a/config-mover/run_get_ids_legacy.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Example script to run the Zabbix host IDs retriever for older Zabbix versions -# Replace the values below with your actual Zabbix configuration - -# Set environment variables -export ZABBIX_URL="https://your.zabbix/api_jsonrpc.php" -export ZABBIX_USER="your_username" -export ZABBIX_PASSWORD="your_password" - -# Activate virtual environment and run the script -cd /opt/python -source venv/bin/activate -python3 get_host_ids_legacy.py \ No newline at end of file diff --git a/config-mover/run_import.sh b/config-mover/run_import.sh deleted file mode 100755 index 1403c11..0000000 --- a/config-mover/run_import.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Example script to run the Zabbix configuration importer -# Replace the values below with your actual Zabbix configuration - -# Set environment variables -export ZABBIX_URL="http://10.0.0.101:8887/api_jsonrpc.php" -export BEARER_TOKEN="c785634354e760a6843055ba4581bc7b6cd6eb2ec75f7c2a79f251c1719933f7" -export IMPORT_DIR="/opt/python/export" # Directory containing host subdirectories - -# Activate virtual environment and run the script -cd /opt/python -source venv/bin/activate -python3 config_importer.py \ No newline at end of file