457 lines
19 KiB
Bash
457 lines
19 KiB
Bash
#!/bin/bash
|
|
|
|
# --- Paths to the files created by the Nagios export script ---
|
|
# These are passed as environment variables to the embedded Python script.
|
|
export ZABBIX_HOSTGROUPS_FILE="zabbix_hostgroups.txt"
|
|
export ZABBIX_HOSTS_FILE="zabbix_hosts.txt"
|
|
export ZABBIX_COMMANDS_FILE="zabbix_commands.txt"
|
|
export ZABBIX_SERVICES_RAW_FILE="zabbix_services_raw.txt"
|
|
|
|
echo "--- Zabbix Automatic Import Script (Bash wrapper for Python) ---"
|
|
echo " Attempting to ensure all Python dependencies are met."
|
|
echo ""
|
|
|
|
# --- OS Detection for package manager ---
|
|
DETECTED_OS=""
|
|
if [ -f /etc/os-release ]; then
|
|
. /etc/os-release
|
|
if [[ "$ID" == "debian" || "$ID_LIKE" == "debian" ]]; then
|
|
DETECTED_OS="debian"
|
|
elif [[ "$ID" == "ubuntu" ]]; then
|
|
DETECTED_OS="ubuntu"
|
|
elif [[ "$ID" == "centos" || "$ID" == "rhel" || "$ID_LIKE" == "fedora" || "$ID" == "fedora" ]]; then
|
|
DETECTED_OS="redhat"
|
|
fi
|
|
fi
|
|
|
|
install_package() {
|
|
local package_name="$1"
|
|
local install_cmd=""
|
|
|
|
case "$DETECTED_OS" in
|
|
"debian"|"ubuntu")
|
|
install_cmd="sudo apt update && sudo apt install -y $package_name"
|
|
;;
|
|
"redhat")
|
|
if command -v dnf &> /dev/null; then
|
|
install_cmd="sudo dnf install -y $package_name"
|
|
else
|
|
install_cmd="sudo yum install -y $package_name"
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Error: Unsupported operating system for automatic package installation." >&2
|
|
echo "Please install '$package_name' manually." >&2
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
echo "Attempting to install '$package_name' using: $install_cmd"
|
|
if eval "$install_cmd"; then
|
|
echo "'$package_name' installed successfully."
|
|
return 0
|
|
else
|
|
echo "Error: Installation of '$package_name' failed. Please try installing it manually." >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# --- Check and install Python3 if missing ---
|
|
echo "Checking for 'python3'..."
|
|
if ! command -v python3 &> /dev/null; then
|
|
echo "---------------------------------------------------------"
|
|
echo "WARNING: 'python3' is not found on your system."
|
|
echo "This script requires Python 3 to run."
|
|
echo ""
|
|
read -p "Do you want to attempt to install 'python3' now? (y/N): " -n 1 -r REPLY_PYTHON
|
|
echo
|
|
if [[ $REPLY_PYTHON =~ ^[Yy]$ ]]; then
|
|
if install_package "python3"; then
|
|
echo "'python3' installed. Verifying..."
|
|
if ! command -v python3 &> /dev/null; then
|
|
echo "Error: Python 3 not found even after installation. Please check your system PATH." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Python 3 installation failed. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Python 3 installation skipped. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "'python3' found."
|
|
fi
|
|
|
|
# --- Determine the correct pip command (pip3 preferred) ---
|
|
PIP_CMD=""
|
|
if command -v pip3 &> /dev/null; then
|
|
PIP_CMD="pip3"
|
|
elif command -v pip &> /dev/null; then
|
|
PIP_CMD="pip"
|
|
fi
|
|
|
|
# --- Check and install pip (or python3-pip) if missing ---
|
|
echo "Checking for 'pip' (Python package installer)..."
|
|
if [[ -z "$PIP_CMD" ]]; then
|
|
echo "---------------------------------------------------------"
|
|
echo "WARNING: Neither 'pip3' nor 'pip' command found."
|
|
echo "Python package installer (pip) is required to install 'pyzabbix'."
|
|
echo ""
|
|
read -p "Do you want to attempt to install 'python3-pip' now? (y/N): " -n 1 -r REPLY_PIP
|
|
echo
|
|
if [[ $REPLY_PIP =~ ^[Yy]$ ]]; then
|
|
if install_package "python3-pip"; then
|
|
echo "'python3-pip' installed. Verifying..."
|
|
if command -v pip3 &> /dev/null; then
|
|
PIP_CMD="pip3"
|
|
elif command -v pip &> /dev/null; then
|
|
PIP_CMD="pip"
|
|
fi
|
|
if [[ -z "$PIP_CMD" ]]; then
|
|
echo "Error: pip not found even after installation. Please check your system PATH or pip setup." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Pip installation failed. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Pip installation skipped. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "'$PIP_CMD' found."
|
|
fi
|
|
|
|
|
|
# --- Function to check if pyzabbix is installed ---
|
|
check_pyzabbix() {
|
|
python3 -c "import pyzabbix" &> /dev/null
|
|
}
|
|
|
|
# --- Check and potentially install pyzabbix ---
|
|
echo "Checking for 'pyzabbix' library..."
|
|
if ! check_pyzabbix; then
|
|
echo "---------------------------------------------------------"
|
|
echo "WARNING: The 'pyzabbix' Python library is not found."
|
|
echo "This script requires 'pyzabbix' to interact with the Zabbix API."
|
|
echo ""
|
|
read -p "Do you want to attempt to install 'pyzabbix' now using '$PIP_CMD'? (y/N): " -n 1 -r REPLY_PYZABBIX
|
|
echo
|
|
if [[ $REPLY_PYZABBIX =~ ^[Yy]$ ]]
|
|
then
|
|
echo "Attempting to install 'pyzabbix'..."
|
|
if "$PIP_CMD" install pyzabbix; then
|
|
echo "'pyzabbix' installed successfully."
|
|
else
|
|
echo "Installation failed. This often requires elevated privileges (sudo)."
|
|
read -p "Do you want to try installing 'pyzabbix' with 'sudo $PIP_CMD'? (y/N): " -n 1 -r REPLY_SUDO
|
|
echo
|
|
if [[ $REPLY_SUDO =~ ^[Yy]$ ]]
|
|
then
|
|
if sudo "$PIP_CMD" install pyzabbix; then
|
|
echo "'pyzabbix' installed successfully with sudo."
|
|
else
|
|
echo "Error: 'pyzabbix' installation failed even with sudo." >&2
|
|
echo "Please install it manually using: sudo $PIP_CMD install pyzabbix" >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Automatic installation skipped. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Verify installation after attempt
|
|
if ! check_pyzabbix; then
|
|
echo "Error: 'pyzabbix' is still not found after installation attempt. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Automatic installation skipped. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "'pyzabbix' library found. Proceeding..."
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# --- Check if export files exist ---
|
|
REQUIRED_FILES=("$ZABBIX_HOSTGROUPS_FILE" "$ZABBIX_HOSTS_FILE" "$ZABBIX_COMMANDS_FILE" "$ZABBIX_SERVICES_RAW_FILE")
|
|
MISSING_FILES=()
|
|
for file in "${REQUIRED_FILES[@]}"; do
|
|
if [[ ! -f "$file" ]]; then
|
|
MISSING_FILES+=("$file")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#MISSING_FILES[@]} -gt 0 ]]; then
|
|
echo "Error: The following required export files are missing:" >&2
|
|
for missing_file in "${MISSING_FILES[@]}"; do
|
|
echo " - $missing_file" >&2
|
|
done
|
|
echo "Please ensure you have run the Nagios export script first to create these files." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "All core dependencies seem to be in order. Launching Zabbix import."
|
|
# Run the embedded Python script
|
|
python3 - <<EOF_PYTHON
|
|
import os
|
|
import sys
|
|
import json
|
|
from pyzabbix import ZabbixAPI, ZabbixAPIException
|
|
import getpass
|
|
|
|
# Paths to the files created by the Nagios export script
|
|
# These are read from environment variables set by the bash script.
|
|
ZABBIX_HOSTGROUPS_FILE = os.environ.get('ZABBIX_HOSTGROUPS_FILE', 'zabbix_hostgroups.txt')
|
|
ZABBIX_HOSTS_FILE = os.environ.get('ZABBIX_HOSTS_FILE', 'zabbix_hosts.txt')
|
|
ZABBIX_COMMANDS_FILE = os.environ.get('ZABBIX_COMMANDS_FILE', 'zabbix_commands.txt')
|
|
ZABBIX_SERVICES_RAW_FILE = os.environ.get('ZABBIX_SERVICES_RAW_FILE', 'zabbix_services_raw.txt')
|
|
|
|
# --- Main script ---
|
|
def main():
|
|
print("\nPlease provide your Zabbix API connection details:")
|
|
zabbix_server = input("Zabbix Server URL (e.g., http://your_zabbix_server/api_jsonrpc.php): ").strip()
|
|
zabbix_user = input("Zabbix API Login Name: ").strip()
|
|
zabbix_password = getpass.getpass("Zabbix API Password: ").strip()
|
|
|
|
if not zabbix_server or not zabbix_user or not zabbix_password:
|
|
print("Error: All Zabbix connection details must be provided.", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
try:
|
|
zapi = ZabbixAPI(zabbix_server)
|
|
zapi.login(zabbix_user, zabbix_password)
|
|
print(f"Connected to Zabbix API at {zabbix_server} as user {zabbix_user}")
|
|
except ZabbixAPIException as e:
|
|
print(f"Error connecting to Zabbix API: {e}", file=sys.stderr)
|
|
print("Please check the provided server URL, login name, and password.", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# 1. Import Hostgroups
|
|
print("\n--- Importing Hostgroups ---")
|
|
created_hostgroups = {}
|
|
if not os.path.exists(ZABBIX_HOSTGROUPS_FILE):
|
|
print(f"Warning: Hostgroups file not found: {ZABBIX_HOSTGROUPS_FILE}. Skipping hostgroup import.")
|
|
else:
|
|
with open(ZABBIX_HOSTGROUPS_FILE, 'r') as f:
|
|
lines = f.readlines()
|
|
lines = [line for line in lines if not line.startswith("--- Hostgroups ---")]
|
|
for i in range(0, len(lines), 2):
|
|
name_alias_line = lines[i].strip()
|
|
|
|
if not name_alias_line.startswith("Name:"):
|
|
print(f"Warning: Skipping malformed hostgroup line: {name_alias_line}", file=sys.stderr)
|
|
continue
|
|
|
|
try:
|
|
name = name_alias_line.split("Name: ")[1].split(",")[0].strip()
|
|
alias = name_alias_line.split("Alias: ")[1].strip()
|
|
except IndexError:
|
|
print(f"Warning: Could not parse hostgroup name/alias from: {name_alias_line}", file=sys.stderr)
|
|
continue
|
|
|
|
print(f" Processing hostgroup: {name}")
|
|
try:
|
|
existing_groups = zapi.hostgroup.get(filter={'name': name}, output=['groupid'])
|
|
if existing_groups:
|
|
group_id = existing_groups[0]['groupid']
|
|
print(f" Hostgroup '{name}' already exists with ID: {group_id}")
|
|
created_hostgroups[name] = group_id
|
|
else:
|
|
new_group = zapi.hostgroup.create(name=name)
|
|
group_id = new_group['groupids'][0]
|
|
print(f" Created hostgroup '{name}' with ID: {group_id}")
|
|
created_hostgroups[name] = group_id
|
|
except ZabbixAPIException as e:
|
|
print(f" Error creating hostgroup '{name}': {e}", file=sys.stderr)
|
|
|
|
# 2. Import Hosts
|
|
print("\n--- Importing Hosts ---")
|
|
if not os.path.exists(ZABBIX_HOSTS_FILE):
|
|
print(f"Warning: Hosts file not found: {ZABBIX_HOSTS_FILE}. Skipping host import.")
|
|
else:
|
|
with open(ZABBIX_HOSTS_FILE, 'r') as f:
|
|
lines = f.readlines()
|
|
lines = [line for line in lines if not line.startswith("--- Hosts ---")]
|
|
|
|
host_data_buffer = []
|
|
for line in lines:
|
|
line = line.strip()
|
|
if line.startswith(" Host:"):
|
|
if host_data_buffer:
|
|
process_host_entry(zapi, host_data_buffer, created_hostgroups)
|
|
host_data_buffer = []
|
|
host_data_buffer.append(line)
|
|
elif host_data_buffer:
|
|
host_data_buffer.append(line)
|
|
|
|
if host_data_buffer:
|
|
process_host_entry(zapi, host_data_buffer, created_hostgroups)
|
|
|
|
# 3. Process Commands (for manual item creation/templating review)
|
|
print("\n--- Commands (for manual item creation/templating review) ---")
|
|
if not os.path.exists(ZABBIX_COMMANDS_FILE):
|
|
print(f"Warning: Commands file not found: {ZABBIX_COMMANDS_FILE}.")
|
|
else:
|
|
try:
|
|
with open(ZABBIX_COMMANDS_FILE, 'r') as f:
|
|
commands_json_str = ""
|
|
for line in f:
|
|
if not line.startswith("--- Commands (JSON Data) ---"):
|
|
commands_json_str += line
|
|
|
|
commands_data = json.loads(commands_json_str)
|
|
|
|
print(" Review the following Nagios commands for Zabbix Item conversion:")
|
|
for cmd_name, cmd_info in commands_data.items():
|
|
print(f" Command Name: {cmd_name}")
|
|
print(f" Command Line: {cmd_info.get('command_line', 'N/A')}")
|
|
print(f" Raw Attributes: {json.dumps(cmd_info.get('raw_attributes', {}), indent=6)}")
|
|
except FileNotFoundError:
|
|
print(f"Error: {ZABBIX_COMMANDS_FILE} not found.", file=sys.stderr)
|
|
except json.JSONDecodeError as e:
|
|
print(f"Error parsing JSON from {ZABBIX_COMMANDS_FILE}: {e}", file=sys.stderr)
|
|
print(f"Content that caused error (first 200 chars): {commands_json_str[:200]}", file=sys.stderr)
|
|
except Exception as e:
|
|
print(f"An unexpected error occurred while processing commands: {e}", file=sys.stderr)
|
|
|
|
# 4. Handle Services (as potential Zabbix Items/Templates) - For information only
|
|
print("\n--- Services (for manual item/trigger/template creation review) ---")
|
|
if not os.path.exists(ZABBIX_SERVICES_RAW_FILE):
|
|
print(f"Warning: Services raw file not found: {ZABBIX_SERVICES_RAW_FILE}.")
|
|
else:
|
|
with open(ZABBIX_SERVICES_RAW_FILE, 'r') as f:
|
|
print(" Review the following Nagios services for Zabbix Item/Trigger/Template conversion:")
|
|
service_block = []
|
|
for line in f:
|
|
line = line.strip()
|
|
if line == "Service_Block_Start":
|
|
service_block = []
|
|
elif line == "Service_Block_End":
|
|
if service_block:
|
|
try:
|
|
full_attrs_line = next((s for s in service_block if s.startswith("All attributes:")), None)
|
|
if full_attrs_line:
|
|
json_str = full_attrs_line.split("All attributes: ")[1]
|
|
service_info = json.loads(json_str)
|
|
print(f" Service Name: {service_info.get('service_description', 'N/A')}")
|
|
print(f" Host Name(s): {service_info.get('host_name', 'N/A')}")
|
|
print(f" Check Command: {service_info.get('check_command', 'N/A')}")
|
|
else:
|
|
print(f" Could not parse service block for full attributes: {service_block}")
|
|
except json.JSONDecodeError as e:
|
|
print(f" Error parsing service JSON: {e} in block: {service_block}", file=sys.stderr)
|
|
service_block = []
|
|
else:
|
|
service_block.append(line)
|
|
|
|
|
|
print("\nZabbix import script finished. Please review logs for any errors or warnings.")
|
|
print("Manual mapping will still be required for complex Nagios commands and services.")
|
|
|
|
def process_host_entry(zapi, host_lines, created_hostgroups):
|
|
"""Processes a buffered host entry and attempts to create it in Zabbix."""
|
|
host_name = ""
|
|
alias = ""
|
|
address = ""
|
|
nagios_hostgroups = []
|
|
|
|
for line in host_lines:
|
|
if line.startswith(" Host:"):
|
|
parts = line.split("|")
|
|
host_name = parts[0].split("Host:")[1].strip()
|
|
alias = parts[1].split("Name:")[1].strip()
|
|
elif line.startswith(" Interfaces:"):
|
|
try:
|
|
interfaces_str = line.split("Interfaces:")[1].strip()
|
|
interfaces_list = json.loads(interfaces_str)
|
|
if interfaces_list:
|
|
address = interfaces_list[0].get('ip', '')
|
|
except json.JSONDecodeError as e:
|
|
print(f"Warning: Could not parse interfaces for {host_name}: {e} - {line}", file=sys.stderr)
|
|
elif line.startswith(" Groups:"):
|
|
groups_str = line.split("Groups:")[1].strip()
|
|
nagios_hostgroups = [g.strip().strip("'") for g in groups_str.strip('[]').split(',') if g.strip()]
|
|
|
|
if not host_name:
|
|
print(f"Warning: Skipping host due to missing name in block: {host_lines}", file=sys.stderr)
|
|
return
|
|
|
|
print(f" Processing host: {host_name} (IP: {address})")
|
|
|
|
zabbix_groups_payload = []
|
|
for hg_name in nagios_hostgroups:
|
|
if hg_name in created_hostgroups:
|
|
zabbix_groups_payload.append({'groupid': created_hostgroups[hg_name]})
|
|
else:
|
|
try:
|
|
existing_groups = zapi.hostgroup.get(filter={'name': hg_name}, output=['groupid'])
|
|
if existing_groups:
|
|
group_id = existing_groups[0]['groupid']
|
|
created_hostgroups[hg_name] = group_id
|
|
zabbix_groups_payload.append({'groupid': group_id})
|
|
print(f" Found existing group '{hg_name}' for host '{host_name}'.")
|
|
else:
|
|
new_group = zapi.hostgroup.create(name=hg_name)
|
|
group_id = new_group['groupids'][0]
|
|
created_hostgroups[hg_name] = group_id
|
|
zabbix_groups_payload.append({'groupid': group_id})
|
|
print(f" Created missing hostgroup '{hg_name}' for host '{host_name}'.")
|
|
except ZabbixAPIException as e:
|
|
print(f" Error ensuring hostgroup '{hg_name}' for host '{host_name}': {e}", file=sys.stderr)
|
|
continue
|
|
|
|
zabbix_interfaces_payload = []
|
|
if address:
|
|
zabbix_interfaces_payload.append({
|
|
"type": 1,
|
|
"main": 1,
|
|
"useip": 1,
|
|
"ip": address,
|
|
"dns": "",
|
|
"port": "10050"
|
|
})
|
|
else:
|
|
print(f" Warning: Host '{host_name}' has no address. Skipping interface creation.", file=sys.stderr)
|
|
|
|
existing_hosts = zapi.host.get(filter={'host': host_name}, output=['hostid'])
|
|
if existing_hosts:
|
|
host_id = existing_hosts[0]['hostid']
|
|
print(f" Host '{host_name}' already exists with ID: {host_id}. Skipping creation.")
|
|
try:
|
|
zapi.host.update(hostid=host_id, groups=zabbix_groups_payload, interfaces=zabbix_interfaces_payload)
|
|
print(f" Updated host '{host_name}'.")
|
|
except ZabbixAPIException as e:
|
|
print(f" Error updating host '{host_name}': {e}", file=sys.stderr)
|
|
else:
|
|
if not zabbix_interfaces_payload:
|
|
print(f" Skipping creation of host '{host_name}' as no valid interfaces could be determined.", file=sys.stderr)
|
|
return
|
|
|
|
try:
|
|
new_host = zapi.host.create(
|
|
host=host_name,
|
|
name=alias if alias else host_name,
|
|
interfaces=zabbix_interfaces_payload,
|
|
groups=zabbix_groups_payload
|
|
)
|
|
host_id = new_host['hostids'][0]
|
|
print(f" Created host '{host_name}' with ID: {host_id}")
|
|
except ZabbixAPIException as e:
|
|
print(f" Error creating host '{host_name}': {e}", file=sys.stderr)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
EOF_PYTHON
|
|
|
|
echo ""
|
|
echo "--- Zabbix Import Process Complete ---"
|
|
echo "Please review the output above for any errors or warnings."
|
|
echo "Remember to manually configure Zabbix Items, Triggers, and Templates"
|
|
echo "based on the exported Nagios Commands and Services." |