Zabbix: erste Version
This commit is contained in:
parent
5672dd82e1
commit
d00aa2ecc5
|
@ -0,0 +1,22 @@
|
|||
# Beispiel für feste IP-Adreß-Konfiguration:
|
||||
# Anpassen und als 00-eth0.network nach /etc/systemd/network verschieben
|
||||
# (s. "man systemd.network", "man systemd-resolved")
|
||||
#
|
||||
# NICHT VERGESSEN: entsprechende Einträge in /etc/hosts hinzufügen
|
||||
# <IPv4> <FQDN> <Hostname>
|
||||
# <IPv6> <FQDN> <Hostname>
|
||||
|
||||
[Match]
|
||||
Name=eth0
|
||||
|
||||
[Network]
|
||||
Description=1. Netzwerk-Port
|
||||
Address=192.168.1.2/24
|
||||
Address=fdb5:78b:64cc:0:f8c0::2/64
|
||||
Gateway=192.168.1.1
|
||||
Gateway=fdb5:78b:64cc:0:f8c0::1
|
||||
DNS=192.168.1.3
|
||||
DNS=fdb5:78b:64cc:0:f8c0::3
|
||||
NTP=192.168.1.4
|
||||
NTP=fdb5:78b:64cc:0:f8c0::4
|
||||
Domains=privacyidea.de
|
|
@ -0,0 +1,95 @@
|
|||
preinstall:
|
||||
# hardcoded users and groups
|
||||
$(inroot) useradd --system --comment="created from appliance building - zabbix user" --home-dir="/var/lib/zabbix/home" --shell="/sbin/nologin" --no-create-home --uid 600 --user-group zabbix
|
||||
# switch to hardened, build hardened toolchain, rebuild everything
|
||||
mkdir -p $(CHROOT)/etc/portage/profile
|
||||
echo "-hardened" >> $(CHROOT)/etc/portage/profile/use.mask
|
||||
$(inroot) $(EMERGE) $(USEPKG) --oneshot gcc
|
||||
$(inroot) $(EMERGE) $(USEPKG) --oneshot binutils virtual/libc
|
||||
-$(gcc_config)
|
||||
$(inroot) $(EMERGE) $(USEPKG) --emptytree @world
|
||||
$(inroot) bash -c 'yes YES | etc-update --automode -9'
|
||||
|
||||
# Unitas-Portage-Overlay einbinden
|
||||
$(inroot) $(EMERGE) -n $(USEPKG) app-portage/layman
|
||||
sed -i 's/check_official : Yes/check_official : No/' $(CHROOT)/etc/layman/layman.cfg
|
||||
wget -P $(CHROOT)/etc/layman/overlays http://dev.unitas-network.de/raw/Gentoo/Unitas.git/master/unitas-overlays.xml
|
||||
$(inroot) layman -l | grep -q unitas || $(inroot) layman -La unitas
|
||||
|
||||
postinstall: timesyncd.conf firstboot.start
|
||||
# Konfigurationen anpassen
|
||||
cp timesyncd.conf $(CHROOT)/etc/systemd/timesyncd.conf
|
||||
mkdir -p $(CHROOT)/etc/local.d
|
||||
cp firstboot.start $(CHROOT)/etc/local.d/firstboot.start
|
||||
touch $(CHROOT)/firstboot
|
||||
sed -i 's/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/' $(CHROOT)/etc/sudoers
|
||||
$(inroot) useradd -m -G users,wheel -s /bin/bash admin
|
||||
$(inroot) passwd -d admin; $(inroot) passwd -e admin
|
||||
$(inroot) systemctl enable screen@adm.service
|
||||
|
||||
# Beispiel feste IP-Adresse
|
||||
cp 00-eth0.network $(CHROOT)/00-eth0.network.example
|
||||
|
||||
# MariaDB-Konfiguration
|
||||
cp mariadb/my.cnf $(CHROOT)/etc/mysql/my.cnf
|
||||
cp mariadb/my.cnf.root $(CHROOT)/root/.my.cnf
|
||||
chmod 0600 $(CHROOT)/root/.my.cnf
|
||||
rm -rf $(CHROOT)/var/lib/mysql/*
|
||||
$(inroot) bash -c 'yes gentoo | emerge --config dev-db/mariadb'
|
||||
|
||||
# Apache-/PHP-Konfiguration
|
||||
sed -i 's:APACHE2_OPTS=\":APACHE2_OPTS=\"-D PHP :' $(CHROOT)/etc/conf.d/apache2
|
||||
find $(CHROOT)/etc/php/apache2-*/ -iname php.ini -print | xargs \sed -i \
|
||||
-e 's:.*date.timezone =.*:date.timezone = Europe/Berlin:' \
|
||||
-e 's:.*max_execution_time =.*:max_execution_time = 300:' \
|
||||
-e 's:.*max_input_time =.*:max_input_time = 300:' \
|
||||
-e 's:.*post_max_size =.*:post_max_size = 16M:' \
|
||||
-e 's:.*always_populate_raw_post_data =.*:always_populate_raw_post_data = -1:'
|
||||
$(inroot) systemctl enable apache2
|
||||
|
||||
# Add zabbix service definitions
|
||||
echo "zabbix-agent 10050/tcp Zabbix Agent" >> $(CHROOT)/etc/services
|
||||
echo "zabbix-agent 10050/udp Zabbix Agent" >> $(CHROOT)/etc/services
|
||||
echo "zabbix-trapper 10051/tcp Zabbix Trapper" >> $(CHROOT)/etc/services
|
||||
echo "zabbix-trapper 10051/udp Zabbix Trapper" >> $(CHROOT)/etc/services
|
||||
|
||||
# Install Zabbix webapp
|
||||
$(inroot)webapp-config -h localhost -d zabbix -I zabbix `ls $(CHROOT)/usr/share/webapps/zabbix`
|
||||
cp $(CHROOT)/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php.example $(CHROOT)/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php
|
||||
|
||||
# Zabbix Agent
|
||||
cp zabbix/userparameter_mysql.conf $(CHROOT)/var/lib/zabbix/userparameter_mysql.conf
|
||||
|
||||
# Zabbix Syslog (https://github.com/v-zhuravlev/zabbix-syslog)
|
||||
mkdir -p $(CHROOT)/etc/zabbix/scripts/lib
|
||||
cp zabbix/zabbix-syslog/zabbix_syslog_create_urls.pl $(CHROOT)/etc/zabbix/scripts/zabbix_syslog_create_urls.pl
|
||||
cp zabbix/zabbix-syslog/zabbix_syslog_lkp_host.pl $(CHROOT)/etc/zabbix/scripts/zabbix_syslog_lkp_host.pl
|
||||
cp zabbix/zabbix-syslog/zabbix_syslog.cfg $(CHROOT)/etc/zabbix/zabbix_syslog.cfg
|
||||
cp zabbix/zabbix-syslog/lib/ZabbixAPI.pm $(CHROOT)/etc/zabbix/scripts/lib/ZabbixAPI.pm
|
||||
cp zabbix/zabbix-syslog/70-zabbix_rsyslog.conf $(CHROOT)/etc/rsyslog.d/70-zabbix_rsyslog.conf
|
||||
$(inroot)chown -R zabbix:zabbix /etc/zabbix/scripts
|
||||
chmod +x $(CHROOT)/etc/zabbix/scripts/zabbix_syslog_create_urls.pl
|
||||
chmod +x $(CHROOT)/etc/zabbix/scripts/zabbix_syslog_lkp_host.pl
|
||||
|
||||
# FPing
|
||||
$(inroot)chmod u=rwsx,g=rx,o=rx /usr/sbin/fping
|
||||
$(inroot)chmod u=rwsx,g=rx,o=rx /usr/sbin/fping6
|
||||
|
||||
# SNMP
|
||||
cp snmp/snmpd.conf $(CHROOT)/etc/snmp/snmpd.conf
|
||||
cp snmp/snmptrapd.conf $(CHROOT)/etc/snmp/snmptrapd.conf
|
||||
cp snmp/snmptt.conf $(CHROOT)/etc/snmp/snmptt.conf
|
||||
sed -i \
|
||||
-e 's:net_snmp_perl_enable = 0:net_snmp_perl_enable = 1:' \
|
||||
-e 's:translate_integers = 1:translate_integers = 0:' \
|
||||
-e 's:#mibs_environment = ALL:mibs_environment = ALL:' \
|
||||
-e 's.#date_time_format =.date_time_format = %H:%M:%S %Y/%m/%d.' \
|
||||
-e 's:daemon_uid = snmptt:daemon_uid = zabbix:' \
|
||||
-e 's:log_system_enable = 0:log_system_enable = 1:' \
|
||||
-e 's:unknown_trap_log_enable = 0:unknown_trap_log_enable = 1:' \
|
||||
$(CHROOT)/etc/snmp/snmptt.ini
|
||||
mkdir -p $(CHROOT)/var/log/snmptt
|
||||
$(inroot)chmod 0775 /var/log/snmptt
|
||||
$(inroot)chown zabbix:zabbix /var/log/snmptt
|
||||
|
||||
clean:
|
|
@ -0,0 +1,9 @@
|
|||
Erstkonfiguration
|
||||
=================
|
||||
|
||||
- für variable Daten (MySQL/MariaDB, Konfiguration) muß eine mit ext4 formatierte Datenpartition mit dem Label "DATA" vorhanden sein. Diese wird nach /DATA gemountet.
|
||||
- feste IP-Adresse und /etc/hosts konfigurieren
|
||||
- evtl. Apache-Zertifikat neu erzeugen
|
||||
- unter VMware evtl. open-vm-tools aktivieren
|
||||
- Evt. /etc/mysql/my.cnf anpassen (~80% vom RAM): innodb_buffer_pool_size = 2G
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#!/bin/bash
|
||||
|
||||
# base settings
|
||||
set -e
|
||||
|
||||
[ -e /firstboot ] || exit 0
|
||||
|
||||
echo 'Setting defaults...'
|
||||
localectl --no-convert set-keymap de-latin1-nodeadkeys
|
||||
|
||||
echo 'Activate services...'
|
||||
timedatectl set-ntp true
|
||||
|
||||
# variables
|
||||
LABEL="DATA"
|
||||
DATABASE_PASS="Di1sgMySQLPwd."
|
||||
|
||||
# Data partition
|
||||
echo 'Mount data partition...'
|
||||
mkdir -p /$LABEL
|
||||
if [ ! -L "/dev/disk/by-label/$LABEL" ]; then
|
||||
echo 'ERROR: Data partition not found!'
|
||||
echo "Please create a data partition with ext4 filesystem and label \"$LABEL\":"
|
||||
echo "# cfdisk /dev/<disk> (use GPT label, create linux partition)"
|
||||
echo "# mkfs.ext4 -L $LABEL /dev/<partition>"
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -Fq "LABEL=$LABEL" /etc/fstab; then
|
||||
echo "LABEL=$LABEL /$LABEL ext4 noatime 0 1" >> /etc/fstab
|
||||
fi
|
||||
mount -a
|
||||
if ! mount | grep /$LABEL > /dev/null; then
|
||||
echo "ERROR: Could not mount data partition!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "/$LABEL/var/lib/mysql/zabbix" ]; then
|
||||
echo 'Initialize MariaDB...'
|
||||
systemctl stop mariadb
|
||||
mkdir -p /$LABEL/var/lib/mysql
|
||||
rm -rf /$LABEL/var/lib/mysql/*
|
||||
cp -a /var/lib/mysql/. /$LABEL/var/lib/mysql
|
||||
sed -i "s:^datadir.*:datadir = /$LABEL/var/lib/mysql:" /etc/mysql/my.cnf
|
||||
systemctl start mariadb
|
||||
sleep 5
|
||||
|
||||
echo 'Create Zabbix database...'
|
||||
mysql -u root -e "CREATE USER 'zabbix'@'localhost' IDENTIFIED BY '$DATABASE_PASS'"
|
||||
mysql -u root -e "CREATE DATABASE zabbix DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;"
|
||||
mysql -u root -e "GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'localhost' IDENTIFIED by '$DATABASE_PASS';"
|
||||
mysql -u root -e "FLUSH PRIVILEGES;"
|
||||
|
||||
echo 'Import Zabbix MySQL data'
|
||||
mysql -u root zabbix < /usr/share/zabbix/database/mysql/schema.sql
|
||||
mysql -u root zabbix < /usr/share/zabbix/database/mysql/images.sql
|
||||
mysql -u root zabbix < /usr/share/zabbix/database/mysql/data.sql
|
||||
else
|
||||
echo 'Start MariaDB...'
|
||||
sed -i "s:^datadir.*:datadir = /$LABEL/var/lib/mysql:" /etc/mysql/my.cnf
|
||||
systemctl start mariadb
|
||||
fi
|
||||
echo 'Enable database...'
|
||||
systemctl enable mariadb
|
||||
|
||||
echo 'Start Zabbix...'
|
||||
sed -i "s:# DBPassword=:DBPassword=${DATABASE_PASS}:" /etc/zabbix/zabbix_server.conf
|
||||
sed -i "s:\$DB\['PASSWORD'\].*:\$DB\['PASSWORD'\] = '${DATABASE_PASS}';:" /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php
|
||||
systemctl start zabbix-server
|
||||
systemctl enable zabbix-server
|
||||
systemctl start zabbix-agentd
|
||||
systemctl enable zabbix-agentd
|
||||
|
||||
rm /firstboot
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
CFLAGS="-O2 -pipe"
|
||||
CXXFLAGS="-O2 -pipe"
|
||||
USE="hardened justify pie ssp urandom xattr -fortran -jit -orc -pch -pic -prelink -profile -tcc"
|
||||
MAKEOPTS="-j5"
|
||||
PYTHON_TARGETS="python2_7 python3_6"
|
||||
PHP_TARGETS="php7-0 php7-1"
|
|
@ -0,0 +1,139 @@
|
|||
# /etc/mysql/my.cnf: The global mysql configuration file.
|
||||
# $Id$
|
||||
|
||||
# The following options will be passed to all MySQL clients
|
||||
[client]
|
||||
#password = your_password
|
||||
port = 3306
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
|
||||
[mysql]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
default-character-set=utf8
|
||||
|
||||
[mysqladmin]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
default-character-set=utf8
|
||||
|
||||
[mysqlcheck]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
default-character-set=utf8
|
||||
|
||||
[mysqldump]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
default-character-set=utf8
|
||||
|
||||
[mysqlimport]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
default-character-set=utf8
|
||||
|
||||
[mysqlshow]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
default-character-set=utf8
|
||||
|
||||
[myisamchk]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
|
||||
[myisampack]
|
||||
character-sets-dir=/usr/share/mysql/charsets
|
||||
|
||||
# add a section [mysqld-4.1] or [mysqld-5.0] for specific configurations
|
||||
[mysqld]
|
||||
character-set-server = utf8
|
||||
user = mysql
|
||||
port = 3306
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
pid-file = /var/run/mysqld/mysqld.pid
|
||||
log-error = /var/log/mysql/mysqld.err
|
||||
basedir = /usr
|
||||
datadir = /var/lib/mysql
|
||||
skip-external-locking
|
||||
key_buffer_size = 16M
|
||||
max_allowed_packet = 4M
|
||||
table_open_cache = 400
|
||||
sort_buffer_size = 512K
|
||||
net_buffer_length = 16K
|
||||
read_buffer_size = 256K
|
||||
read_rnd_buffer_size = 512K
|
||||
myisam_sort_buffer_size = 8M
|
||||
lc_messages_dir = /usr/share/mysql
|
||||
#Set this to your desired error message language
|
||||
lc_messages = en_US
|
||||
|
||||
# security:
|
||||
# using "localhost" in connects uses sockets by default
|
||||
# skip-networking
|
||||
bind-address = 127.0.0.1
|
||||
|
||||
##log-bin
|
||||
server-id = 1
|
||||
|
||||
# point the following paths to different dedicated disks
|
||||
tmpdir = /tmp/
|
||||
#log-update = /path-to-dedicated-directory/hostname
|
||||
|
||||
# you need the debug USE flag enabled to use the following directives,
|
||||
# if needed, uncomment them, start the server and issue
|
||||
# #tail -f /tmp/mysqld.sql /tmp/mysqld.trace
|
||||
# this will show you *exactly* what's happening in your server ;)
|
||||
|
||||
#log = /tmp/mysqld.sql
|
||||
#gdb
|
||||
#debug = d:t:i:o,/tmp/mysqld.trace
|
||||
#one-thread
|
||||
|
||||
# the rest of the innodb config follows:
|
||||
# don't eat too much memory, we're trying to be safe on 64Mb boxes
|
||||
# you might want to bump this up a bit on boxes with more RAM
|
||||
innodb_buffer_pool_size = 2G
|
||||
#
|
||||
# i'd like to use /var/lib/mysql/innodb, but that is seen as a database :-(
|
||||
# and upstream wants things to be under /var/lib/mysql/, so that's the route
|
||||
# we have to take for the moment
|
||||
#innodb_data_home_dir = /var/lib/mysql/
|
||||
#innodb_log_arch_dir = /var/lib/mysql/
|
||||
#innodb_log_group_home_dir = /var/lib/mysql/
|
||||
# you may wish to change this size to be more suitable for your system
|
||||
# the max is there to avoid run-away growth on your machine
|
||||
innodb_data_file_path = ibdata1:10M:autoextend
|
||||
# we keep this at around 25% of of innodb_buffer_pool_size
|
||||
# sensible values range from 1MB to (1/innodb_log_files_in_group*innodb_buffer_pool_size)
|
||||
innodb_log_file_size = 48M
|
||||
# this is the default, increase it if you have very large transactions going on
|
||||
innodb_log_buffer_size = 8M
|
||||
# this is the default and won't hurt you
|
||||
# you shouldn't need to tweak it
|
||||
innodb_log_files_in_group=2
|
||||
# see the innodb config docs, the other options are not always safe
|
||||
innodb_flush_log_at_trx_commit = 1
|
||||
innodb_lock_wait_timeout = 50
|
||||
innodb_file_per_table
|
||||
|
||||
# Uncomment this to get FEDERATED engine support
|
||||
#plugin-load=federated=ha_federated.so
|
||||
##loose-federated
|
||||
|
||||
[mysqldump]
|
||||
quick
|
||||
max_allowed_packet = 16M
|
||||
|
||||
[mysql]
|
||||
# uncomment the next directive if you are not familiar with SQL
|
||||
#safe-updates
|
||||
|
||||
[isamchk]
|
||||
key_buffer_size = 20M
|
||||
sort_buffer_size = 20M
|
||||
read_buffer = 2M
|
||||
write_buffer = 2M
|
||||
|
||||
[myisamchk]
|
||||
key_buffer_size = 20M
|
||||
sort_buffer_size = 20M
|
||||
read_buffer_size = 2M
|
||||
write_buffer_size = 2M
|
||||
|
||||
[mysqlhotcopy]
|
||||
interactive-timeout
|
||||
|
||||
[mariadb]
|
|
@ -0,0 +1,7 @@
|
|||
[mysqladmin]
|
||||
user = root
|
||||
password = gentoo
|
||||
|
||||
[mysql]
|
||||
user = root
|
||||
password = gentoo
|
|
@ -0,0 +1,8 @@
|
|||
# Grundsystem
|
||||
app-emulation/open-vm-tools ~amd64 ~x86
|
||||
sys-auth/pam_ssh_agent_auth ~amd64 ~x86
|
||||
|
||||
# Zabbix
|
||||
##dev-db/mariadb ~amd64 ~x86
|
||||
net-analyzer/zabbix ~amd64 ~x86
|
||||
net-analyzer/snmptt ~amd64 ~x86
|
|
@ -0,0 +1,2 @@
|
|||
# nur LTS-Versionen 3.0.x bauen
|
||||
>=net-analyzer/zabbix-3.1
|
|
@ -0,0 +1,25 @@
|
|||
app-admin/sudo -sendmail
|
||||
app-editors/nano ncurses
|
||||
app-emulation/open-vm-tools pic -modules
|
||||
app-misc/mc -slang
|
||||
dev-lang/python ssl threads xml
|
||||
dev-libs/libpcre cxx jit
|
||||
dev-libs/libpcre2 jit
|
||||
dev-util/pkgconfig internal-glib
|
||||
net-misc/openssh ssl
|
||||
net-misc/wget ssl
|
||||
sys-apps/hwids udev
|
||||
sys-apps/kmod tools
|
||||
sys-apps/net-tools hostname
|
||||
sys-apps/portage ipc
|
||||
sys-auth/pambase nullok sha512
|
||||
sys-devel/gcc cxx nptl
|
||||
sys-kernel/gentoo-sources symlink
|
||||
|
||||
# Zabbix
|
||||
app-admin/rsyslog dbi mysql snmp systemd
|
||||
app-eselect/eselect-php apache2
|
||||
dev-lang/php apache2 bcmath gd ldap mysql mysqli sockets sysvipc truetype xmlreader xmlwriter
|
||||
media-libs/gd jpeg png
|
||||
net-analyzer/zabbix curl frontend ldap libxml2 mysql openipmi proxy server snmp ssh xmpp
|
||||
net-analyzer/net-snmp perl
|
|
@ -0,0 +1 @@
|
|||
mibs +ALL
|
|
@ -0,0 +1,2 @@
|
|||
traphandle default /usr/sbin/snmptt
|
||||
disableAuthorization yes
|
|
@ -0,0 +1,2 @@
|
|||
EVENT general .* "General event" Normal
|
||||
FORMAT ZBXTRAP $aA $ar severity:$s $Fn$+*
|
|
@ -0,0 +1,12 @@
|
|||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# See timesyncd.conf(5) for details.
|
||||
|
||||
[Time]
|
||||
NTP=0.de.pool.ntp.org 1.de.pool.ntp.org 2.de.pool.ntp.org 3.de.pool.ntp.org
|
||||
FallbackNTP=0.gentoo.pool.ntp.org 1.gentoo.pool.ntp.org 2.gentoo.pool.ntp.org 3.gentoo.pool.ntp.org
|
|
@ -0,0 +1,21 @@
|
|||
app-admin/logrotate
|
||||
app-admin/sudo
|
||||
app-emulation/open-vm-tools
|
||||
app-misc/mc
|
||||
app-misc/screenservice
|
||||
net-analyzer/zabbix
|
||||
sys-auth/pam_ssh_agent_auth
|
||||
sys-power/acpid
|
||||
app-admin/rsyslog
|
||||
dev-db/mariadb
|
||||
dev-db/phpmyadmin
|
||||
dev-perl/Config-General
|
||||
dev-perl/JSON-XS
|
||||
dev-perl/libwww-perl
|
||||
dev-tcltk/expect
|
||||
net-analyzer/net-snmp
|
||||
net-analyzer/nmap
|
||||
net-analyzer/snmptt
|
||||
net-dns/bind-tools
|
||||
net-misc/netkit-telnetd
|
||||
sys-process/lsof
|
|
@ -0,0 +1,18 @@
|
|||
##HOSTNAME = $(APPLIANCE)
|
||||
##TIMEZONE = UTC
|
||||
DISK_SIZE = 8.0G
|
||||
##SWAP_SIZE = 30
|
||||
##SWAP_FILE = $(CHROOT)/.swap
|
||||
##ARCH = amd64-hardened
|
||||
##MAKEOPTS = -j10 -l10
|
||||
##PRUNE_CRITICAL = NO
|
||||
##CHANGE_PASSWORD = YES
|
||||
##HEADLESS = NO
|
||||
##SOFTWARE = 1
|
||||
##PKGLIST = 0
|
||||
##RSYNC_MIRROR = rsync://rsync15.de.gentoo.org/gentoo/
|
||||
##KERNEL_PKG = gentoo-sources
|
||||
KERNEL_CONFIG = appliances/$(APPLIANCE)/kernel.config
|
||||
ENABLE_SSHD = YES
|
||||
TIMEZONE=Europe/Berlin
|
||||
LOCALE=de_DE.utf8
|
|
@ -0,0 +1 @@
|
|||
UserParameter=mysql.status[*],echo "show global status where Variable_name='$1';" | HOME=/etc/ mysql -N | awk '{print $$2}'
|
|
@ -0,0 +1,19 @@
|
|||
# provides UDP syslog reception
|
||||
$ModLoad imudp
|
||||
$UDPServerRun 514
|
||||
|
||||
#enables omrpog module
|
||||
$ModLoad omprog
|
||||
|
||||
$template RFC3164fmt,"<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag%%msg%"
|
||||
$template network-fmt,"%TIMESTAMP:::date-rfc3339% [%fromhost-ip%] %pri-text% %syslogtag%%msg%\n"
|
||||
|
||||
#exclude unwanted messages(examples):
|
||||
:msg, contains, "Child connection from" stop
|
||||
:msg, contains, "exit after auth (ubnt): Disconnect received" stop
|
||||
:msg, contains, "password auth succeeded for 'ubnt' from" stop
|
||||
:msg, contains, "exit before auth: Exited normally" stop
|
||||
if $fromhost-ip != '127.0.0.1' then {
|
||||
action(type="omprog" binary="/etc/zabbix/scripts/zabbix_syslog_lkp_host.pl" template="network-fmt")
|
||||
stop
|
||||
}
|
|
@ -0,0 +1,587 @@
|
|||
package ZabbixAPI;
|
||||
use Data::Dumper;
|
||||
use LWP;
|
||||
use JSON::XS;
|
||||
use MIME::Base64 qw(encode_base64);
|
||||
|
||||
my @no_auth_methods = ('user.login','apiinfo.version');
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $args = shift;
|
||||
|
||||
my $api_url = $args->{api_url}
|
||||
|| 'http://localhost/zabbix/api_jsonrpc.php';
|
||||
my $username = $args->{username} || 'Admin';
|
||||
my $password = $args->{password} || 'zabbix';
|
||||
|
||||
my $self = bless {
|
||||
api_url => $api_url,
|
||||
username => $username,
|
||||
password => $password,
|
||||
ua => LWP::UserAgent->new(),
|
||||
auth => undef,
|
||||
id => 1,
|
||||
}, $class;
|
||||
|
||||
$self->{req} = HTTP::Request->new( POST => $self->{api_url} );
|
||||
$self->{req}->content_type('application/json-rpc');
|
||||
|
||||
return $self;
|
||||
}
|
||||
sub id {
|
||||
my $self = shift;
|
||||
return $self->{id}++;
|
||||
}
|
||||
|
||||
|
||||
sub prepare_auth {
|
||||
my $self = shift;
|
||||
my $method = shift;
|
||||
|
||||
if (grep /$method/,@no_auth_methods) {
|
||||
return undef;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $self->{auth};
|
||||
}
|
||||
};
|
||||
|
||||
sub do {
|
||||
|
||||
my $self = shift;
|
||||
my $method = shift;
|
||||
my $params = shift;
|
||||
|
||||
my $json = JSON::XS->new->utf8->encode(
|
||||
{
|
||||
jsonrpc => '2.0',
|
||||
method => $method,
|
||||
params => $params,
|
||||
id => $self->id,
|
||||
auth => $self->prepare_auth($method)
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
$self->{req}->content($json);
|
||||
|
||||
# Pass request to the user agent and get a response back
|
||||
my $res = $self->{ua}->request( $self->{req} );
|
||||
|
||||
# Check the outcome of the response
|
||||
if ( $res->is_success ) {
|
||||
|
||||
my $return = JSON::XS->new->utf8->decode( $res->content );
|
||||
die $return->{error}->{data}."\n" if $return->{error};
|
||||
return $return->{result};
|
||||
}
|
||||
else {
|
||||
die $res->status_line, "\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub do_raw {
|
||||
|
||||
my $self = shift;
|
||||
my $method = shift;
|
||||
my $params = shift;
|
||||
|
||||
my $json = JSON::XS->new->utf8->encode(
|
||||
{
|
||||
jsonrpc => '2.0',
|
||||
method => $method,
|
||||
params => JSON::XS->new->utf8->decode($params),
|
||||
id => $self->id,
|
||||
auth => $self->prepare_auth($method)
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
$self->{req}->content($json);
|
||||
|
||||
# Pass request to the user agent and get a response back
|
||||
my $res = $self->{ua}->request( $self->{req} );
|
||||
|
||||
# Check the outcome of the response
|
||||
if ( $res->is_success ) {
|
||||
my $return = JSON::XS->new->utf8->decode( $res->content );
|
||||
die $return->{error}->{data}."\n" if $return->{error};
|
||||
return $return->{result};
|
||||
}
|
||||
else {
|
||||
die $res->status_line, "\n";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
sub import_configuration_from_file {
|
||||
my $self = shift;
|
||||
my $file = shift;
|
||||
my $configuration;
|
||||
{
|
||||
local $/ = undef;
|
||||
open(my $fh,'<:encoding(UTF-8)', $file) or die "Error opening $file: $!";
|
||||
|
||||
$configuration = <$fh>;
|
||||
close $fh;
|
||||
}
|
||||
|
||||
my $json = <<'END_PARAMS';
|
||||
{
|
||||
"format": "xml",
|
||||
"rules": {
|
||||
"groups": {
|
||||
"createMissing": true
|
||||
},
|
||||
"hosts": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true
|
||||
},
|
||||
"templates": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true
|
||||
},
|
||||
"templateLinkage": {
|
||||
"createMissing": true
|
||||
},
|
||||
"templateScreens": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true,
|
||||
"deleteMissing": true
|
||||
},
|
||||
"applications": {
|
||||
"createMissing": true,
|
||||
"deleteMissing": true
|
||||
},
|
||||
"discoveryRules": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true,
|
||||
"deleteMissing": true
|
||||
},
|
||||
"items": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true,
|
||||
"deleteMissing": true
|
||||
},
|
||||
"triggers": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true,
|
||||
"deleteMissing": true
|
||||
},
|
||||
"graphs": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true,
|
||||
"deleteMissing": true
|
||||
},
|
||||
"screens": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true
|
||||
},
|
||||
"maps": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true
|
||||
},
|
||||
"images": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true
|
||||
},
|
||||
"valueMaps": {
|
||||
"createMissing": true,
|
||||
"updateExisting": true
|
||||
}
|
||||
|
||||
},
|
||||
"source": ""
|
||||
}
|
||||
END_PARAMS
|
||||
my $params = JSON::XS->new->utf8->decode($json);
|
||||
$params->{source}=$configuration;
|
||||
$self->do('configuration.import', $params);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
sub login {
|
||||
my $self = shift;
|
||||
my $params = {
|
||||
user => $self->{username},
|
||||
password => $self->{password}
|
||||
};
|
||||
my $content = $self->do("user.login",$params);
|
||||
$self->{auth}=$content;
|
||||
|
||||
}
|
||||
|
||||
sub logout {
|
||||
my $self = shift;
|
||||
$self->do( 'user.logout', {} );
|
||||
}
|
||||
|
||||
|
||||
sub create_or_update_mediatype {
|
||||
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $result;
|
||||
eval { #try to create JSON
|
||||
$result = $self->do('mediatype.create', $params);
|
||||
};
|
||||
if ($@) {
|
||||
if($@ =~ /already exists/) {
|
||||
warn "WARN: $params->{description} already exists. Updating instead..."."\n";
|
||||
#get mediatypeid
|
||||
$json = { output => ['mediatypeid'], filter =>{description=>[$params->{description}]}};
|
||||
my $id = $self->do('mediatype.get',$json);
|
||||
$params->{mediatypeid}= $id->[0]->{mediatypeid};
|
||||
#update instead of creating....
|
||||
$result = $self->do('mediatype.update', $params);
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
|
||||
die $@;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub create_or_update_user {
|
||||
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $result;
|
||||
eval { #try to create JSON
|
||||
$result = $self->do('user.create', $params);
|
||||
};
|
||||
if ($@) {
|
||||
if($@ =~ /already exists/) {
|
||||
warn "WARN: $params->{alias} already exists. Updating instead..."."\n";
|
||||
#get mediatypeid
|
||||
$json = { output => ['userid'], filter =>{alias=>[$params->{alias}]}};
|
||||
my $id = $self->do('user.get',$json);
|
||||
|
||||
$params->{userid}= $id->[0]->{userid};
|
||||
#update instead of creating....
|
||||
my $medias = $params->{user_medias}->[0];
|
||||
|
||||
delete $params->{user_medias}; # remove user_medias, not possible in 'user.update' call
|
||||
$result = $self->do('user.update', $params);
|
||||
|
||||
my $result_media = $self->do('user.updatemedia',{users => [ {userid=>$params->{userid}} ],
|
||||
medias => $medias
|
||||
});
|
||||
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
|
||||
die $@;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
sub create_or_update_action {
|
||||
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $result;
|
||||
eval { #try to create JSON
|
||||
$result = $self->do('action.create', $params);
|
||||
};
|
||||
if ($@) {
|
||||
if($@ =~ /already exists/) {
|
||||
warn "WARN: $params->{name} already exists. Updating instead..."."\n";
|
||||
#get mediatypeid
|
||||
$json = { output => ['actionid'], filter =>{name=>[$params->{name}]}};
|
||||
my $id = $self->do('action.get',$json);
|
||||
$params->{actionid}= $id->[0]->{actionid};
|
||||
#update instead of creating....
|
||||
delete $params->{eventsource}; #cannot be update, must be removed
|
||||
$result = $self->do('action.update', $params);
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
|
||||
die $@;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub create_or_update_drule {
|
||||
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $result;
|
||||
eval { #try to create JSON
|
||||
$result = $self->do('drule.create', $params);
|
||||
};
|
||||
if ($@) {
|
||||
if($@ =~ /already exists/) {
|
||||
warn "WARN: $params->{name} already exists. Updating instead..."."\n";
|
||||
$json = { output => ['druleid'], filter =>{name=>[$params->{name}]}};
|
||||
my $id = $self->do('drule.get',$json);
|
||||
$params->{druleid}= $id->[0]->{druleid};
|
||||
#update instead of creating....
|
||||
$result = $self->do('drule.update', $params);
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
|
||||
die $@;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub get_template_id {
|
||||
|
||||
my $self = shift;
|
||||
my $template_name = shift;
|
||||
|
||||
my $json = { output => ['host','templateid'], filter =>{host=>[$template_name]}};
|
||||
my $result = $self->do('template.get',$json);
|
||||
return $result->[0]->{templateid};
|
||||
|
||||
}
|
||||
|
||||
sub get_hostgroup_id {
|
||||
|
||||
my $self = shift;
|
||||
my $hgroup_name = shift;
|
||||
|
||||
my $json = { output => ['groupid'], filter =>{name=>[$hgroup_name]}};
|
||||
my $result = $self->do('hostgroup.get',$json);
|
||||
return $result->[0]->{groupid};
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub get_host_id {
|
||||
|
||||
my $self = shift;
|
||||
my $host_name = shift;
|
||||
|
||||
my $json = { output => ['hostid'], filter =>{host=>[$host_name]}};
|
||||
my $result = $self->do('host.get',$json);
|
||||
return $result->[0]->{hostid};
|
||||
|
||||
}
|
||||
|
||||
sub get_host_by_name {
|
||||
|
||||
my $self = shift;
|
||||
my $host_name = shift;
|
||||
|
||||
my $json = {
|
||||
output => ['hostid'],
|
||||
filter =>{host=>[$host_name]},
|
||||
selectGroups => ['groupid','name'],
|
||||
selectParentTemplates => ['templateid','name'],
|
||||
selectMacros => ['macro','value']
|
||||
};
|
||||
my $result = $self->do('host.get',$json);
|
||||
return $result->[0];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub create_or_merge_host {
|
||||
|
||||
my $self = shift;
|
||||
my $host_name = shift;
|
||||
my $params = shift;
|
||||
my $result;
|
||||
|
||||
my $hostid = $self->get_host_id($host_name);
|
||||
|
||||
if ($hostid) {
|
||||
print "WARN: Cannot create host $host_name ... going to merge instead\n";
|
||||
#print $hostid."\n";
|
||||
#update (merge mode currently)
|
||||
$params->{hostid}=$hostid;
|
||||
|
||||
my $host = $self->get_host_by_name($host_name);
|
||||
if ($params->{templates}) {
|
||||
#merge with already existed
|
||||
my @templates;
|
||||
foreach my $template (@{$params->{templates}}){
|
||||
push @templates,$template->{templateid};
|
||||
}
|
||||
foreach my $template (@{$host->{parentTemplates}}){
|
||||
push @templates,$template->{templateid};
|
||||
}
|
||||
my %seen = (); # see http://perldoc.perl.org/perlfaq4.html#How-can-I-remove-duplicate-elements-from-a-list-or-array%3f
|
||||
|
||||
@templates = grep { ! $seen{ $_ }++ } @templates;
|
||||
|
||||
my $i=0;
|
||||
delete $params->{templates};
|
||||
foreach my $templateid (@templates) {
|
||||
$params->{templates}->[$i]->{templateid} = $templateid;
|
||||
$i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($params->{groups}) {
|
||||
#merge with already existed
|
||||
my @groups;
|
||||
foreach my $group (@{$params->{groups}}){
|
||||
push @groups,$group->{groupid};
|
||||
}
|
||||
foreach my $group (@{$host->{groups}}){
|
||||
push @groups,$group->{groupid};
|
||||
}
|
||||
my %seen = (); # see http://perldoc.perl.org/perlfaq4.html#How-can-I-remove-duplicate-elements-from-a-list-or-array%3f
|
||||
|
||||
@groups = grep { ! $seen{ $_ }++ } @groups;
|
||||
|
||||
my $i=0;
|
||||
delete $params->{groups};
|
||||
foreach my $groupid (@groups) {
|
||||
$params->{groups}->[$i]->{groupid} = $groupid;
|
||||
$i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($params->{macros}) {
|
||||
#merge with already existed
|
||||
my @macros;
|
||||
foreach my $macro (@{$params->{macros}}){
|
||||
push @macros,
|
||||
{
|
||||
macro => $macro->{macro},
|
||||
value => $macro->{value}
|
||||
};
|
||||
}
|
||||
foreach my $macro (@{$host->{macros}}){
|
||||
push @macros,
|
||||
{
|
||||
macro => $macro->{macro},
|
||||
value => $macro->{value}
|
||||
};
|
||||
}
|
||||
my %seen = (); # see http://perldoc.perl.org/perlfaq4.html#How-can-I-remove-duplicate-elements-from-a-list-or-array%3f
|
||||
@macros = grep { ! $seen{ $_->{macro} }++ } @macros;
|
||||
|
||||
my $i=0;
|
||||
delete $params->{macros};
|
||||
|
||||
foreach my $macro (@macros) {
|
||||
$params->{macros}->[$i] = $macro;
|
||||
$i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($params->{interfaces}) {
|
||||
#merge with already existed
|
||||
#warn "WARN: host interfaces merge is not supported yet... skipping interfaces part\n";
|
||||
delete $params->{interfaces};
|
||||
}
|
||||
|
||||
#print Dumper $params;
|
||||
$result = $self->do('host.update', $params);
|
||||
|
||||
}
|
||||
else {
|
||||
#create
|
||||
$params->{host}=$host_name;
|
||||
#print Dumper $params;
|
||||
$result = $self->do('host.create', $params);
|
||||
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub import_image_from_file {
|
||||
my $self = shift;
|
||||
my $file = shift;
|
||||
my $imagename = shift || $file;
|
||||
my $imagetype = shift || 1; # 1 - icon , 2 - background
|
||||
my $image;
|
||||
my $result;
|
||||
my $json;
|
||||
{
|
||||
local $/ = undef;
|
||||
open(my $fh,, $file) or die "Error opening $file: $!";
|
||||
|
||||
$image = <$fh>;
|
||||
close $fh;
|
||||
}
|
||||
|
||||
my $params = {name => $imagename, imagetype => 1, image => encode_base64($image)};
|
||||
|
||||
eval {#try to import image
|
||||
$result = $self->do('image.create', $params);
|
||||
};
|
||||
if ($@) {
|
||||
if($@ =~ /already exists/) {
|
||||
warn "WARN: $params->{name} already exists. Updating instead..."."\n";
|
||||
#get imageid and update instead
|
||||
$json = { output => ['imageid'], filter =>{name=>[$params->{name}]}};
|
||||
my $id = $self->do('image.get',$json);
|
||||
$params->{imageid}= $id->[0]->{imageid};
|
||||
delete($params->{imagetype});
|
||||
#update instead of creating....
|
||||
$result = $self->do('image.update', $params);
|
||||
return $result;
|
||||
}
|
||||
else {
|
||||
|
||||
die $@;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1;
|
|
@ -0,0 +1,5 @@
|
|||
url = http://localhost/zabbix/api_jsonrpc.php
|
||||
user = Admin
|
||||
password = zabbix
|
||||
server = localhost
|
||||
debug = 0
|
|
@ -0,0 +1,207 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use 5.010;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib "$Bin/lib";
|
||||
use Data::Dumper;
|
||||
use Config::General;
|
||||
use ZabbixAPI;
|
||||
our $VERSION = 3.1;
|
||||
my $conf;
|
||||
$conf = eval {Config::General->new('/usr/local/etc/zabbix_syslog.cfg')};
|
||||
if ($@) {
|
||||
eval {$conf = Config::General->new('/etc/zabbix/zabbix_syslog.cfg')};
|
||||
if ($@) {die "Please check that config file is available as /usr/local/etc/zabbix_syslog.cfg or /etc/zabbix/zabbix_syslog.cfg\n";}
|
||||
}
|
||||
|
||||
my %Config = $conf->getall;
|
||||
|
||||
#Authenticate yourself
|
||||
my $url = $Config{'url'} || die "URL is missing in zabbix_syslog.cfg\n";
|
||||
my $user = $Config{'user'} || die "API user is missing in zabbix_syslog.cfg\n";
|
||||
my $password = $Config{'password'} || die "API user password is missing in zabbix_syslog.cfg\n";
|
||||
my $server = $Config{'server'} || die "server hostname is missing in zabbix_syslog.cfg\n";
|
||||
|
||||
my $debug = $Config{'debug'};
|
||||
my ( $authID, $response, $json );
|
||||
|
||||
|
||||
my $zbx = ZabbixAPI->new( { api_url => $url, username => $user, password => $password } );
|
||||
$zbx->login();
|
||||
|
||||
my $syslog_url_base = 'history.php?action=showvalues';
|
||||
|
||||
my @selements;
|
||||
|
||||
foreach my $map ( @{ map_get_extended() } ) {
|
||||
my $mapid=$map->{sysmapid};
|
||||
#put all map elements into array @selements (so you can update map later!)
|
||||
@selements = @{ $map->{selements} };
|
||||
|
||||
print "INFO: Checking map with mapid $map->{sysmapid}\n";
|
||||
foreach my $selement (@selements) {
|
||||
my $syslog_button_exists = 0;
|
||||
|
||||
if ( $debug > 0 ) {
|
||||
print 'Object ID: '
|
||||
. $selement->{selementid}
|
||||
. ' Type: '
|
||||
. $selement->{elementtype}."\n";
|
||||
}
|
||||
|
||||
# elementtype=0 hosts
|
||||
if ( $selement->{elementtype} == 0 ) {
|
||||
my $hostid;
|
||||
#Zabbix API 3.4+
|
||||
if (exists($selement->{elements}->[0]->{hostid})) {
|
||||
$hostid = $selement->{elements}->[0]->{hostid};
|
||||
}
|
||||
#Zabbix API before 3.4
|
||||
elsif (exists($selement->{elementid})) {
|
||||
$hostid = $selement->{elementid};
|
||||
}
|
||||
else {
|
||||
die "Cannot get hostid of selement $selement->{selementid}\n";
|
||||
}
|
||||
|
||||
my $itemid = get_syslogid_by_hostid($hostid);
|
||||
if ($itemid) {
|
||||
|
||||
#and add urls:
|
||||
|
||||
my $syslog_exists = 0;
|
||||
foreach my $syslog_url ( @{ $selement->{urls} } ) {
|
||||
$syslog_exists = 0;
|
||||
|
||||
if ( $syslog_url->{name} =~ 'Syslog' ) {
|
||||
|
||||
$syslog_exists = 1;
|
||||
$syslog_url->{'name'} = 'Syslog';
|
||||
|
||||
$syslog_url->{'url'} =
|
||||
$syslog_url_base
|
||||
. '&itemids['
|
||||
. $itemid . ']='
|
||||
. $itemid;
|
||||
}
|
||||
}
|
||||
if ( $syslog_exists == 0 ) {
|
||||
|
||||
#syslog item doesn't exist... add it
|
||||
push @{ $selement->{urls} },
|
||||
{
|
||||
'name' => 'Syslog',
|
||||
'url' => $syslog_url_base
|
||||
. '&itemids['
|
||||
. $itemid . ']='
|
||||
. $itemid
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
map_update($mapid,\@selements);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$zbx->logout();
|
||||
|
||||
#______SUBS
|
||||
sub get_syslogid_by_hostid {
|
||||
|
||||
|
||||
my $hostid = shift;
|
||||
|
||||
my $params = {
|
||||
output => ['itemid'],
|
||||
hostids => $hostid,
|
||||
filter => {'key_' => 'syslog' },
|
||||
limit => 1,
|
||||
};
|
||||
my $result = $zbx->do('item.get',$params);
|
||||
|
||||
|
||||
# Check if response was successful
|
||||
if ( !$result ) {
|
||||
$zbx->logout();
|
||||
die "item.get failed\n";
|
||||
}
|
||||
|
||||
#return itemid of syslog key (trapper type)
|
||||
return ${ $result }[0]->{itemid};
|
||||
}
|
||||
|
||||
|
||||
sub map_get {
|
||||
|
||||
#retrieve all maps
|
||||
my $params = {
|
||||
output => ['sysmapid']
|
||||
};
|
||||
my $result = $zbx->do('map.get',$params);
|
||||
|
||||
# Check if response was successful
|
||||
if ( !$result ) {
|
||||
$zbx->logout();
|
||||
die "map.get failed\n";
|
||||
}
|
||||
|
||||
if ( $debug > 1 ) { print Dumper $result; }
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub map_get_extended {
|
||||
my $params = {
|
||||
selectSelements => 'extend',
|
||||
#sysmapids => $map,
|
||||
};
|
||||
|
||||
my $result = $zbx->do('map.get',$params);
|
||||
|
||||
# Check if response was successful
|
||||
if ( !$result ) {
|
||||
$zbx->logout();
|
||||
die "map.get failed\n";
|
||||
}
|
||||
if ( $debug > 1 ) {
|
||||
|
||||
print Dumper $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub map_update {
|
||||
my $mapid = shift;
|
||||
my $selements_ref = shift;
|
||||
my $params = {
|
||||
selements => [@{$selements_ref}],
|
||||
sysmapid => $mapid,
|
||||
};
|
||||
my $result;
|
||||
eval {$result=$zbx->do('map.update',$params);};
|
||||
if($@){
|
||||
warn "Failed to update map with mapid $mapid, check for write permissions for this map\n";
|
||||
}
|
||||
else {
|
||||
if ( $debug > 0 ) {
|
||||
print "About to map.update this\n:";
|
||||
print Dumper $params;
|
||||
}
|
||||
|
||||
if ( $debug > 0 ) {
|
||||
print Dumper $result;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use 5.010;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib "$Bin/lib";
|
||||
use Data::Dumper;
|
||||
use Config::General;
|
||||
use ZabbixAPI;
|
||||
use English '-no_match_vars';
|
||||
use MIME::Base64 qw(encode_base64);
|
||||
use IO::Socket::INET;
|
||||
use Storable qw(lock_store lock_retrieve);
|
||||
our $VERSION = 3.1;
|
||||
|
||||
my $CACHE_TIMEOUT = 600;
|
||||
my $CACHE_DIR = '/tmp/zabbix_syslog_cache_n';
|
||||
die "No argumets required anymore since script version 3.0\n" if @ARGV > 0;
|
||||
my $conf;
|
||||
$conf = eval {Config::General->new('/usr/local/etc/zabbix_syslog.cfg')};
|
||||
if ($@) {
|
||||
eval {$conf = Config::General->new('/etc/zabbix/zabbix_syslog.cfg')};
|
||||
if ($@) {die "Please check that config file is available as /usr/local/etc/zabbix_syslog.cfg or /etc/zabbix/zabbix_syslog.cfg\n";}
|
||||
}
|
||||
my %Config = $conf->getall;
|
||||
|
||||
#Authenticate yourself
|
||||
my $url = $Config{'url'} || die "URL is missing in zabbix_syslog.cfg\n";
|
||||
my $user = $Config{'user'} || die "API user is missing in zabbix_syslog.cfg\n";
|
||||
my $password = $Config{'password'} || die "API user password is missing in zabbix_syslog.cfg\n";
|
||||
my $server = $Config{'server'} || die "server hostname is missing in zabbix_syslog.cfg\n";
|
||||
my $zbx;
|
||||
|
||||
my $debug = $Config{'debug'};
|
||||
my ( $authID, $response, $json );
|
||||
#IP regex patter part
|
||||
my $ipv4_octet = q/(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/;
|
||||
|
||||
#rsyslog omprog loop
|
||||
#http://www.rsyslog.com/doc/master/configuration/modules/omprog.html
|
||||
while (defined(my $message = <>)) {
|
||||
chomp($message);
|
||||
|
||||
#get ip from message
|
||||
my $ip;
|
||||
|
||||
if ( $message =~ / \[ ((?:$ipv4_octet[.]){3}${ipv4_octet}) \]/msx ) {
|
||||
$ip = $1;
|
||||
}
|
||||
else {
|
||||
warn "No IP in square brackets found in '$message', cannot continue\n";
|
||||
next;
|
||||
}
|
||||
|
||||
my $hostname = ${retrieve_from_store($ip)}->{'hostname'};
|
||||
|
||||
|
||||
if ( !defined $hostname ) {
|
||||
|
||||
my $result;
|
||||
|
||||
$zbx = ZabbixAPI->new( { api_url => $url, username => $user, password => $password } );
|
||||
$zbx->login();
|
||||
|
||||
|
||||
my @hosts_found;
|
||||
my $hostid;
|
||||
my @hostinterfaces;
|
||||
eval {@hostinterfaces=hostinterface_get($ip)};
|
||||
if($@){
|
||||
warn "Failed to retrieve any host interface with IP = $ip. Unable to bind message to item, skipping\n";
|
||||
next;
|
||||
}
|
||||
|
||||
foreach my $host (@hostinterfaces) {
|
||||
|
||||
$hostid = $host->{'hostid'};
|
||||
if ( grep { /$hostid/msx } @hosts_found ) {
|
||||
next;
|
||||
}#check if $hostid already is in array then skip(next)
|
||||
else { push @hosts_found, $hostid; }
|
||||
|
||||
#now get hostname
|
||||
if ( get_zbx_trapper_syslogid_by_hostid($hostid) ) {
|
||||
|
||||
my $result = host_get($hostid);
|
||||
|
||||
#return hostname if possible
|
||||
if ( $result->{'host'} ) {
|
||||
|
||||
if ( $result->{'proxy_hostid'} == 0 ) #check if host monitored directly or via proxy
|
||||
{
|
||||
#lease $server as is
|
||||
}
|
||||
else {
|
||||
#assume that rsyslogd and zabbix_proxy are on the same server
|
||||
$server = 'localhost';
|
||||
}
|
||||
$hostname = $result->{'host'};
|
||||
}
|
||||
last;
|
||||
}
|
||||
|
||||
}
|
||||
$zbx->logout();
|
||||
store_message( $ip, $hostname );
|
||||
}
|
||||
|
||||
zabbix_send( $server, $hostname, 'syslog', $message );
|
||||
}
|
||||
|
||||
|
||||
#______SUBS
|
||||
sub hostinterface_get {
|
||||
|
||||
my $ip = shift;
|
||||
my $params = {
|
||||
output => [ 'ip', 'hostid' ],
|
||||
filter => { ip => $ip, }
|
||||
};
|
||||
|
||||
my $result = $zbx->do('hostinterface.get',$params);
|
||||
|
||||
if ( $debug > 0 ) { print Dumper $result; }
|
||||
# Check if response was successful (not empty array in result)
|
||||
if ( !@{ $result } ) {
|
||||
$zbx->logout();
|
||||
die "hostinterface.get failed\n";
|
||||
}
|
||||
return @{ $result };
|
||||
|
||||
}
|
||||
|
||||
sub get_zbx_trapper_syslogid_by_hostid {
|
||||
|
||||
my $hostid = shift;
|
||||
my $params = {
|
||||
output => ['itemid'],
|
||||
hostids => $hostid,
|
||||
search => {
|
||||
'key_' => 'syslog',
|
||||
type => 2, #type => 2 is zabbix_trapper
|
||||
status => 0,
|
||||
},
|
||||
limit => 1,
|
||||
};
|
||||
my $result = $zbx->do('item.get',$params);
|
||||
|
||||
if ( $debug > 0 ) { print Dumper $result; }
|
||||
# Check if response was successful
|
||||
if ( !@{ $result } ) {
|
||||
warn "item.get failed\n";
|
||||
}
|
||||
#return itemid of syslog key (trapper type)
|
||||
return ${ $result }[0]->{itemid};
|
||||
}
|
||||
|
||||
sub host_get {
|
||||
my $hostid = shift;
|
||||
my $params = {
|
||||
hostids => [$hostid],
|
||||
output => [ 'host', 'proxy_hostid', 'status' ],
|
||||
filter => { status => 0, }, # only use hosts enabled
|
||||
limit => 1,
|
||||
};
|
||||
|
||||
|
||||
my $result = $zbx->do('host.get',$params);
|
||||
|
||||
if ( $debug > 0 ) { print Dumper $result; }
|
||||
|
||||
# Check if response was successful
|
||||
if ( !$result ) {
|
||||
$zbx->logout();
|
||||
die "host.get failed\n";
|
||||
}
|
||||
return ${ $result }[0]; #return result
|
||||
}
|
||||
|
||||
sub zabbix_send {
|
||||
my $zabbixserver = shift;
|
||||
my $hostname = shift;
|
||||
my $item = shift;
|
||||
my $data = shift;
|
||||
my $SOCK_TIMEOUT = 10;
|
||||
my $SOCK_RECV_LENGTH = 1024;
|
||||
|
||||
my $result;
|
||||
|
||||
my $request =
|
||||
sprintf
|
||||
"<req>\n<host>%s</host>\n<key>%s</key>\n<data>%s</data>\n</req>\n",
|
||||
encode_base64($hostname), encode_base64($item), encode_base64($data);
|
||||
|
||||
my $sock = IO::Socket::INET->new(
|
||||
PeerAddr => $zabbixserver,
|
||||
PeerPort => '10051',
|
||||
Proto => 'tcp',
|
||||
Timeout => $SOCK_TIMEOUT
|
||||
);
|
||||
|
||||
die "Could not create socket: $ERRNO\n" unless $sock;
|
||||
$sock->send($request);
|
||||
my @handles = IO::Select->new($sock)->can_read($SOCK_TIMEOUT);
|
||||
if ( $debug > 0 ) { print "host - $hostname, item - $item, data - $data\n"; }
|
||||
|
||||
if ( scalar(@handles) > 0 ) {
|
||||
$sock->recv( $result, $SOCK_RECV_LENGTH );
|
||||
if ( $debug > 0 ) {
|
||||
print "answer from zabbix server $zabbixserver: $result\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $debug > 0 ) { print "no answer from zabbix server\n"; }
|
||||
}
|
||||
$sock->close();
|
||||
return;
|
||||
}
|
||||
|
||||
#helpers
|
||||
sub store_message {
|
||||
my $ip = shift;
|
||||
my $hostname = shift;
|
||||
my $storage_file = $CACHE_DIR;
|
||||
my ( $stored, $to_store );
|
||||
|
||||
$to_store->{$ip} = {
|
||||
hostname => $hostname,
|
||||
created => time()
|
||||
};
|
||||
|
||||
|
||||
if ( -f $storage_file ) {
|
||||
$stored = lock_retrieve $storage_file;
|
||||
lock_store { %{$stored}, %{$to_store} }, $storage_file;
|
||||
}
|
||||
else {
|
||||
|
||||
#first time file creation, apply proper file permissions and store only single event
|
||||
lock_store $to_store, $storage_file;
|
||||
chmod 0666, $storage_file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub retrieve_from_store {
|
||||
my $ip = shift;
|
||||
my $storage_file = $CACHE_DIR;
|
||||
my $stored;
|
||||
my $message_to_retrieve;
|
||||
|
||||
if ( -f $storage_file ) {
|
||||
|
||||
$stored = lock_retrieve $storage_file;
|
||||
|
||||
#remove expired from cache
|
||||
if (defined($stored->{$ip})){
|
||||
if (time() - $stored->{$ip}->{created} > $CACHE_TIMEOUT){
|
||||
delete $stored->{$ip};
|
||||
lock_store $stored, $storage_file;
|
||||
}
|
||||
else {
|
||||
$message_to_retrieve = $stored->{$ip};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \$message_to_retrieve;
|
||||
|
||||
}
|
Reference in New Issue