From 98d73c43e96f26013ed61dbbba26f9da633b4c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Deckert?= Date: Sun, 15 Oct 2023 11:06:01 +0200 Subject: [PATCH] First commit to own repository --- Makefile | 145 +++++ appliance/02firstboot.start | 221 +++++++ appliance/MySQL-Backup.sh | 32 + appliance/backup.service | 8 + appliance/backup.timer | 12 + appliance/cert-renew.service | 8 + appliance/cert-renew.sh | 52 ++ appliance/cert-renew.timer | 12 + mariadb/my.cnf.root | 11 + package.accept_keywords | 2 + package.mask | 2 + package.use | 12 + snmp/snmpd.conf | 2 + snmp/snmptrapd.conf | 2 + snmp/snmptt.conf | 2 + va-zabbix.cfg | 2 + world | 20 + zabbix/userparameter_mysql.conf | 1 + zabbix/zabbix-syslog/70-zabbix_rsyslog.conf | 19 + zabbix/zabbix-syslog/Template_syslog.xml | 128 ++++ zabbix/zabbix-syslog/lib/ZabbixAPI.pm | 587 ++++++++++++++++++ zabbix/zabbix-syslog/zabbix_syslog.cfg | 5 + .../zabbix_syslog_create_urls.pl | 207 ++++++ .../zabbix-syslog/zabbix_syslog_lkp_host.pl | 274 ++++++++ 24 files changed, 1766 insertions(+) create mode 100644 Makefile create mode 100755 appliance/02firstboot.start create mode 100755 appliance/MySQL-Backup.sh create mode 100644 appliance/backup.service create mode 100644 appliance/backup.timer create mode 100644 appliance/cert-renew.service create mode 100755 appliance/cert-renew.sh create mode 100644 appliance/cert-renew.timer create mode 100644 mariadb/my.cnf.root create mode 100644 package.accept_keywords create mode 100644 package.mask create mode 100644 package.use create mode 100644 snmp/snmpd.conf create mode 100644 snmp/snmptrapd.conf create mode 100644 snmp/snmptt.conf create mode 100644 va-zabbix.cfg create mode 100644 world create mode 100644 zabbix/userparameter_mysql.conf create mode 100644 zabbix/zabbix-syslog/70-zabbix_rsyslog.conf create mode 100644 zabbix/zabbix-syslog/Template_syslog.xml create mode 100644 zabbix/zabbix-syslog/lib/ZabbixAPI.pm create mode 100644 zabbix/zabbix-syslog/zabbix_syslog.cfg create mode 100644 zabbix/zabbix-syslog/zabbix_syslog_create_urls.pl create mode 100644 zabbix/zabbix-syslog/zabbix_syslog_lkp_host.pl diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a224433 --- /dev/null +++ b/Makefile @@ -0,0 +1,145 @@ +02firstboot = $(CHROOT)/usr/local/bin/02firstboot.start +cert-renew.sh = $(CHROOT)/etc/ssl/cert-renew.sh +zabbix-userparameter = $(CHROOT)/var/lib/zabbix/userparameter_mysql.conf + +systemd-units: appliance/MySQL-Backup.sh appliance/backup.service appliance/backup.timer appliance/cert-renew.service appliance/cert-renew.timer + mkdir -p $(CHROOT)/usr/local/bin + cp appliance/MySQL-Backup.sh $(CHROOT)/usr/local/bin/ + cp appliance/backup.service appliance/backup.timer appliance/cert-renew.service appliance/cert-renew.timer $(CHROOT)/etc/systemd/system/ + +$(02firstboot): appliance/02firstboot.start + mkdir -p $(CHROOT)/usr/local/bin + cp $< $@ + touch $(CHROOT)/02firstboot + +$(cert-renew.sh): appliance/cert-renew.sh + mkdir -p $(CHROOT)/etc/ssl + cp $< $@ + +$(CHROOT)/var/lib/mysql: mariadb/my.cnf.root + # MariaDB-Konfiguration ($$, weil make ein $ entfernt) + sed -i "s/^character-set-server.*$$/character-set-server = utf8mb4/" $(CHROOT)/etc/mysql/mariadb.d/50-distro-server.cnf + sed -iE 's/^\(log-bin\)/#\1/' $(CHROOT)/etc/mysql/mariadb.d/50-distro-server.cnf + echo >> $(CHROOT)/etc/mysql/mariadb.d/50-distro-server.cnf + echo "# innodb tuning" >> $(CHROOT)/etc/mysql/mariadb.d/50-distro-server.cnf + echo "innodb_buffer_pool_size = 2G" >> $(CHROOT)/etc/mysql/mariadb.d/50-distro-server.cnf + echo "innodb_strict_mode = OFF" >> $(CHROOT)/etc/mysql/mariadb.d/50-distro-server.cnf + cp mariadb/my.cnf.root $(CHROOT)/root/.my.cnf + chmod 0600 $(CHROOT)/root/.my.cnf + rm -rf $(CHROOT)/var/lib/mysql/* + RUN bash -c 'yes gentoo | emerge --config dev-db/mariadb' + +apache-php: + 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:.*pcre.jit=.*:pcre.jit=0:' \ + -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:' + +zabbix-services: + 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 + +zabbix-webapp: + RUN 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 + # enable any language + sed -i "s:'display' => false]:'display' => true]:" $(CHROOT)/var/www/localhost/htdocs/zabbix/include/locales.inc.php + # im Zabbix-Ebuild wird fowners und fperms vor webapp_src_install aufgerufen und deswegen wieder überschrieben + RUN chown -R zabbix:zabbix \ + /etc/zabbix \ + /var/lib/zabbix \ + /var/lib/zabbix/home \ + /var/lib/zabbix/scripts \ + /var/lib/zabbix/alertscripts \ + /var/lib/zabbix/externalscripts \ + /var/log/zabbix + chmod 0750 \ + $(CHROOT)/etc/zabbix \ + $(CHROOT)/var/lib/zabbix \ + $(CHROOT)/var/lib/zabbix/home \ + $(CHROOT)/var/lib/zabbix/scripts \ + $(CHROOT)/var/lib/zabbix/alertscripts \ + $(CHROOT)/var/lib/zabbix/externalscripts \ + $(CHROOT)/var/log/zabbix + +$(zabbix-userparameter): zabbix/userparameter_mysql.conf + mkdir -p $(CHROOT)/var/lib/zabbix + cp $< $@ + +zabbix-syslog: + # 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/Template_syslog.xml $(CHROOT)/etc/zabbix/scripts/Template_syslog.xml + 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 + RUN 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 + +zabbix-config: + sed -i \ + -e 's:# PidFile=/tmp/zabbix_agent2.pid:PidFile=/run/zabbix/zabbix_agent2.pid:' \ + -e 's:# LogFile=/tmp/zabbix_agent2.log:LogFile=/var/log/zabbix/zabbix_agent2.log:' \ + $(CHROOT)/etc/zabbix/zabbix_agent2.conf + sed -i \ + -e 's:LogFile=/tmp/zabbix_proxy.log:LogFile=/var/log/zabbix/zabbix_proxy.log:' \ + -e 's:# PidFile=/tmp/zabbix_proxy.pid:PidFile=/run/zabbix/zabbix_proxy.pid:' \ + $(CHROOT)/etc/zabbix/zabbix_proxy.conf + sed -i \ + -e 's:LogFile=/tmp/zabbix_server.log:LogFile=/var/log/zabbix/zabbix_server.log:' \ + -e 's:# PidFile=/tmp/zabbix_server.pid:PidFile=/run/zabbix/zabbix_server.pid:' \ + -e 's:# StartPollers=5:StartPollers=15:' \ + -e 's:# StartIPMIPollers=0:StartIPMIPollers=5:' \ + -e 's:# StartPollersUnreachable=1:StartPollersUnreachable=15:' \ + -e 's:# StartPingers=1:StartPingers=25:' \ + -e 's:# StartDiscoverers=1:StartDiscoverers=5:' \ + -e 's:# JavaGateway=:JavaGateway=127.0.0.1:' \ + -e 's:# VMwareCacheSize=8M:VMwareCacheSize=16M:' \ + -e 's:# VMwareTimeout=10:VMwareTimeout=30:' \ + -e 's:# SNMPTrapperFile=/tmp/zabbix_traps.tmp:SNMPTrapperFile=/var/log/snmptt/snmptt.log:' \ + -e 's:# CacheSize=8M:CacheSize=32M:' \ + -e 's:# HistoryIndexCacheSize=4M:HistoryIndexCacheSize=8M:' \ + -e 's:Timeout=4:Timeout=10:' \ + -e 's:^# AlertScriptsPath=.*:AlertScriptsPath=/var/lib/zabbix/alertscripts:' \ + -e 's:^# ExternalScripts=.*:ExternalScripts=/var/lib/zabbix/externalscripts:' \ + -e 's:# ProxyConfigFrequency=3600:ProxyConfigFrequency=360:' \ + -e 's:# ProxyDataFrequency=1:ProxyDataFrequency=60:' \ + $(CHROOT)/etc/zabbix/zabbix_server.conf + +fping-perm: + chmod u=rwsx,g=rx,o=rx $(CHROOT)/usr/sbin/fping + chmod u=rwsx,g=rx,o=rx $(CHROOT)/usr/sbin/fping6 + +snmp-conf: + cp -f snmp/snmpd.conf $(CHROOT)/etc/snmp/snmpd.conf + cp -f snmp/snmptrapd.conf $(CHROOT)/etc/snmp/snmptrapd.conf + cp -f snmp/snmptt.conf $(CHROOT)/etc/snmp/snmptt.conf + sed -i \ + -e 's:^mode = .*:mode = standalone:' \ + -e 's:^net_snmp_perl_enable = .*:net_snmp_perl_enable = 1:' \ + -e 's:^translate_log_trap_oid = .*:translate_log_trap_oid = 2:' \ + -e 's:^translate_integers = .*:translate_integers = 0:' \ + -e 's:^#mibs_environment = .*:mibs_environment = ALL:' \ + -e 's.^#date_time_format =.date_time_format = %H:%M:%S %Y/%m/%d.' \ + -e 's:^daemon_uid = .*:daemon_uid = zabbix:' \ + -e 's:^log_system_enable = .*:log_system_enable = 1:' \ + -e 's:^unknown_trap_log_enable = .*:unknown_trap_log_enable = 1:' \ + -e 's:^syslog_level = .*:syslog_level = err:' \ + -e 's:^syslog_system_level = .*:syslog_system_level = err:' \ + $(CHROOT)/etc/snmp/snmptt.ini + mkdir -p $(CHROOT)/var/log/snmptt + chmod 0775 $(CHROOT)/var/log/snmptt + RUN chown zabbix:zabbix /var/log/snmptt + +preinstall: + +postinstall: systemd-units $(02firstboot) $(cert-renew.sh) $(CHROOT)/var/lib/mysql apache-php zabbix-services zabbix-webapp $(zabbix-userparameter) zabbix-syslog zabbix-config fping-perm snmp-conf diff --git a/appliance/02firstboot.start b/appliance/02firstboot.start new file mode 100755 index 0000000..82ca7e7 --- /dev/null +++ b/appliance/02firstboot.start @@ -0,0 +1,221 @@ +#!/bin/bash + +# variables +LABEL="DATA" +DATABASE_PASS=$(head -c 300 /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 16) +TLD="example.com" +HOST="zabbix" +ORGNAME="Zabbix example" + +# start +set -e + +[ -e /01firstboot ] && exit 0 +[ -e /02firstboot ] || exit 0 + +# Select type +if [ -f "/$LABEL/etc/zabbix/zabbix_server.conf" ]; then + zabbixtype="server" +elif [ -f "/$LABEL/etc/zabbix/zabbix_proxy.conf" ]; then + zabbixtype="proxy" +else + echo + echo "Should the new appliance be configured as a server or a proxy?" + while read -n1 -r -p "choose [s]erver|[p]roxy: "; do + case $REPLY in + s|S) zabbixtype="server" + break + ;; + p|P) zabbixtype="proxy" + break + ;; + *) echo " (Invalid option, choose again...)" + ;; + esac + done + echo +fi + +# Zabbix configuration +if [ "$zabbixtype" == "server" ]; then + if [ ! -L /etc/zabbix/zabbix_server.conf ]; then + if [ ! -f "/$LABEL/etc/zabbix/zabbix_server.conf" ]; then + echo 'Create Zabbix Server config...' + mkdir -p /$LABEL/etc/zabbix + cp /etc/zabbix/zabbix_server.conf /$LABEL/etc/zabbix/zabbix_server.conf + mv /etc/zabbix/zabbix_server.conf /$LABEL/etc/zabbix/zabbix_server.conf.orig + chown -R zabbix:zabbix /$LABEL/etc/zabbix + ln -s /$LABEL/etc/zabbix/zabbix_server.conf /etc/zabbix/zabbix_server.conf + else + echo 'Linking Zabbix Server config...' + cp /$LABEL/etc/zabbix/zabbix_server.conf /$LABEL/etc/zabbix/zabbix_server.conf.alt + rm -f /$LABEL/etc/zabbix/zabbix_server.conf.orig + mv /etc/zabbix/zabbix_server.conf /$LABEL/etc/zabbix/zabbix_server.conf.orig + chown -R zabbix:zabbix /$LABEL/etc/zabbix + ln -s /$LABEL/etc/zabbix/zabbix_server.conf /etc/zabbix/zabbix_server.conf + fi + fi +else + if [ ! -L /etc/zabbix/zabbix_proxy.conf ]; then + if [ ! -f "/$LABEL/etc/zabbix/zabbix_proxy.conf" ]; then + echo 'Create Zabbix Proxy config...' + mkdir -p /$LABEL/etc/zabbix + chown zabbix:zabbix /$LABEL/etc/zabbix + cp /etc/zabbix/zabbix_proxy.conf /$LABEL/etc/zabbix/zabbix_proxy.conf + mv /etc/zabbix/zabbix_proxy.conf /$LABEL/etc/zabbix/zabbix_proxy.conf.orig + sed -i "s:^DBName=.*:DBName=zabbix:" /$LABEL/etc/zabbix/zabbix_proxy.conf + chown -R zabbix:zabbix /$LABEL/etc/zabbix + ln -s /$LABEL/etc/zabbix/zabbix_proxy.conf /etc/zabbix/zabbix_proxy.conf + else + echo 'Linking Zabbix Proxy config...' + cp /$LABEL/etc/zabbix/zabbix_proxy.conf /$LABEL/etc/zabbix/zabbix_proxy.conf.alt + rm -f /$LABEL/etc/zabbix/zabbix_proxy.conf.orig + mv /etc/zabbix/zabbix_proxy.conf /$LABEL/etc/zabbix/zabbix_proxy.conf.orig + chown -R zabbix:zabbix /$LABEL/etc/zabbix + ln -s /$LABEL/etc/zabbix/zabbix_proxy.conf /etc/zabbix/zabbix_proxy.conf + fi + fi +fi + +if [ "$zabbixtype" == "server" ]; then + if [ ! -L /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php ]; then + if [ ! -f "/$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php" ]; then + echo 'Create Zabbix Frontend config...' + mkdir -p /$LABEL/var/www/localhost/htdocs/zabbix/conf + cp /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php + mv /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php.orig + ln -s /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php + else + echo 'Linking Zabbix Frontend config...' + cp /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php.alt + rm -f /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php.orig + mv /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php.orig + ln -s /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php /var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php + fi + fi + if [ ! -L /var/lib/net-snmp ]; then + echo 'Linking SNMP data directory...' + if [ ! -d "/$LABEL/var/lib/net-snmp" ]; then + mkdir -p /$LABEL/var/lib/net-snmp + cp -a /var/lib/net-snmp/. /$LABEL/var/lib/net-snmp + fi + rm -rf /var/lib/net-snmp.orig + mv /var/lib/net-snmp /var/lib/net-snmp.orig + ln -s /$LABEL/var/lib/net-snmp /var/lib/net-snmp + fi +fi + +# Zabbix home directory +if [ ! -L /var/lib/zabbix ]; then + echo 'Linking Zabbix home directory...' + if [ ! -d "/$LABEL/var/lib/zabbix" ]; then + mkdir -p /$LABEL/var/lib/zabbix + chown zabbix:zabbix /$LABEL/var/lib/zabbix + cp -a /var/lib/zabbix/. /$LABEL/var/lib/zabbix + fi + rm -rf /var/lib/zabbix.orig + mv /var/lib/zabbix /var/lib/zabbix.orig + ln -s /$LABEL/var/lib/zabbix /var/lib/zabbix +fi + + +# Database +if [ ! -L /var/lib/mysql ]; then + systemctl stop mariadb + if [ ! -d "/$LABEL/var/lib/mysql/zabbix" ]; then + echo 'Initialize MariaDB...' + mkdir -p "/$LABEL/var/lib" + rm -rf "/$LABEL/var/lib/mysql" + rm -rf "/$LABEL/var/lib/mysql.orig" + cp -a "/var/lib/mysql" "/$LABEL/var/lib/mysql" + mv "/var/lib/mysql" "/$LABEL/var/lib/mysql.orig" + ln -s "/$LABEL/var/lib/mysql" "/var/lib/mysql" + 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 + if [ "$zabbixtype" == "server" ]; then + mysql -u root zabbix < /usr/share/zabbix/database/mysql/images.sql + mysql -u root zabbix < /usr/share/zabbix/database/mysql/data.sql + fi + else + echo 'Start MariaDB...' + rm -rf "/$LABEL/var/lib/mysql.orig" + mv "/var/lib/mysql" "/$LABEL/var/lib/mysql.orig" + ln -s "/$LABEL/var/lib/mysql" "/var/lib/mysql" + systemctl start mariadb + sleep 5 + mysql -u root -e "GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'localhost' IDENTIFIED by '$DATABASE_PASS';" + fi +else + echo 'Set new database password...' + systemctl restart mariadb + sleep 5 + mysql -u root -e "GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'localhost' IDENTIFIED by '$DATABASE_PASS';" +fi +# update config with new database password +if [ "$zabbixtype" == "server" ]; then + sed -i "s:.*DBPassword=.*:DBPassword=${DATABASE_PASS}:" /$LABEL/etc/zabbix/zabbix_server.conf + sed -i "s:\$DB\['PASSWORD'\].*:\$DB\['PASSWORD'\] = '${DATABASE_PASS}';:" /$LABEL/var/www/localhost/htdocs/zabbix/conf/zabbix.conf.php +else + sed -i "s:.*DBPassword=.*:DBPassword=${DATABASE_PASS}:" /$LABEL/etc/zabbix/zabbix_proxy.conf +fi + +# Certificate +if [ "$zabbixtype" == "server" ]; then + if [ -x "/$LABEL/etc/ssl/cert-renew.sh" ]; then + # angepaßtes Zertifikat vorhanden (kein example) + if [ ! -L /etc/ssl/cert-renew.sh ]; then + rm -f "/$LABEL/etc/ssl/cert-renew.sh.orig" + mv "/etc/ssl/cert-renew.sh" "/$LABEL/etc/ssl/cert-renew.sh.orig" + else + rm -f "/etc/ssl/cert-renew.sh" + fi + ln -s "/$LABEL/etc/ssl/cert-renew.sh" "/etc/ssl/cert-renew.sh" + else + echo 'Create example certificate...' + mkdir -p "/$LABEL/CERTS/KEYS/" + mkdir -p "/$LABEL/CERTS/$HOST.$TLD" + echo "FQDN = $HOST.$TLD" > "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" + echo "ORGNAME = $ORGNAME" >> "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" + echo "ALTNAMES = DNS:$HOST.$TLD , DNS:$TLD" >> "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" + echo -e "\n[ req ]\ndefault_bits = 4096\ndefault_md = sha256\nprompt = no\nencrypt_key = no\ndistinguished_name = dn\nreq_extensions = req_ext\ndefault_keyfile = ../KEYS/\$FQDN-key.pem\n" >> "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" + echo -e "\n[ dn ]\nC = DE\nO = \$ORGNAME\nCN = \$FQDN\n" >> "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" + echo -e "\n[ req_ext ]\nsubjectAltName = \$ALTNAMES" >> "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" + openssl req -x509 -new -config "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD.cnf" -out "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD-cert.pem" -keyout "/$LABEL/CERTS/KEYS/$HOST.$TLD-key.pem" + cp "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD-cert.pem" "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD-fullchain.pem" + touch "/$LABEL/CERTS/$HOST.$TLD/$HOST.$TLD-chain.pem" + fi + + rm -rf /etc/ssl/apache2 + mkdir -p /etc/ssl + ln -sf "/$LABEL/etc/ssl/apache2" "/etc/ssl/apache2" + + /etc/ssl/cert-renew.sh +fi + +systemctl enable mariadb +systemctl enable zabbix-agent2 +if [ "$zabbixtype" == "server" ]; then + systemctl enable zabbix-server + systemctl enable apache2 +else + systemctl enable zabbix-proxy +fi + +systemctl restart zabbix-agent2 +if [ "$zabbixtype" == "server" ]; then + systemctl restart zabbix-server + systemctl restart apache2 +else + systemctl restart zabbix-proxy +fi + +rm /02firstboot diff --git a/appliance/MySQL-Backup.sh b/appliance/MySQL-Backup.sh new file mode 100755 index 0000000..19ccfc9 --- /dev/null +++ b/appliance/MySQL-Backup.sh @@ -0,0 +1,32 @@ +#!/bin/bash +PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" + +DIR="/DATA/Backup/MySQL" + +if [ -z $1 ]; then + echo "database name missing! use --all for all db's" + exit 1; +elif [ $1 = '--all' ]; then + echo "full backup" + for i in `mysqlshow --defaults-file=/root/.my.cnf | awk '{print $2}' | grep -v Databases`; do + if [ "$i" != "information_schema" ] && [ "$i" != "performance_schema" ]; then + if test -f ${DIR}/${i}.sql; then + echo "Move ${DIR}/${i}.sql to ${DIR}/${i}.sql.1" + mv ${DIR}/${i}.sql ${DIR}/${i}.sql.1 + fi + echo "dump ${i} to ${DIR}/${i}.sgl" + mysqldump --defaults-file=/root/.my.cnf --single-transaction --events --opt -QF -r${DIR}/${i}.sql $i + chmod 600 ${DIR}/${i}.sql + fi + done; +elif [ -n $1 ]; then + echo "Starting backup of $1" + if test -f $DIR/$1.sql; then + echo "Move $DIR/$1.sql to $DIR/$1.sql.1" + mv ${DIR}/${1}.sql ${DIR}/${1}.sql.1 + fi + mysqldump --defaults-file=/root/.my.cnf --single-transaction --opt -QF -r${DIR}/${1}.sql $1 + chmod 600 ${DIR}/${1}.sql +fi +echo "Done" +exit 0; diff --git a/appliance/backup.service b/appliance/backup.service new file mode 100644 index 0000000..13ca921 --- /dev/null +++ b/appliance/backup.service @@ -0,0 +1,8 @@ +[Unit] +Description=execute backup tasks +RefuseManualStart=no +RefuseManualStop=yes + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/MySQL-Backup.sh --all diff --git a/appliance/backup.timer b/appliance/backup.timer new file mode 100644 index 0000000..ec59929 --- /dev/null +++ b/appliance/backup.timer @@ -0,0 +1,12 @@ +[Unit] +Description=execute backup tasks +RefuseManualStart=no +RefuseManualStop=no + +[Timer] +Persistent=false +OnCalendar=Sun *-*-* 02:19:00 +Unit=backup.service + +[Install] +WantedBy=default.target diff --git a/appliance/cert-renew.service b/appliance/cert-renew.service new file mode 100644 index 0000000..59ec86d --- /dev/null +++ b/appliance/cert-renew.service @@ -0,0 +1,8 @@ +[Unit] +Description=renew certificates from git store +RefuseManualStart=no +RefuseManualStop=yes + +[Service] +Type=oneshot +ExecStart=/etc/ssl/cert-renew.sh diff --git a/appliance/cert-renew.sh b/appliance/cert-renew.sh new file mode 100755 index 0000000..07747a4 --- /dev/null +++ b/appliance/cert-renew.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +HOST="zabbix" +TLD="example.com" +FQDN="$HOST.$TLD" +LABEL="DATA" + +CERT_DIR=/$LABEL/CERTS +CERT_APACHE=/$LABEL/etc/ssl/apache2 +GETREPO="" +GETUSER="" +GETPASS="" + +function getCurrentVersion() { +# Get hash from latest revision + git log --format=format:%H -1 +} + +cd $CERT_DIR + +if [ -z "$GETREPO" ]; then + GIT_REVISION=0 + GIT_NEW_REVISION=1 + cd $FQDN +elif [ ! -d "$FQDN" ]; then + GIT_REVISION=0 + git clone "https://$GETUSER:$GETPASS@$GETREPO" + cd $FQDN + GIT_NEW_REVISION=$(getCurrentVersion) +else + cd $FQDN + GIT_REVISION=$(getCurrentVersion) + git commit -m "CRON: auto commit" + git fetch + git merge origin/master -m "Auto Merge" + GIT_NEW_REVISION=$(getCurrentVersion) +fi + +echo "old: $GIT_REVISION" +echo "new: $GIT_NEW_REVISION" + +if [ $GIT_REVISION != $GIT_NEW_REVISION ] +then + echo "Update Apache certificate..." + mkdir -p $CERT_APACHE + cp $CERT_DIR/$FQDN/$FQDN-fullchain.pem $CERT_APACHE/server.crt + cp $CERT_DIR/KEYS/$FQDN-key.pem $CERT_APACHE/server.key + echo "Restarting Apache..." + systemctl is-active --quiet apache2 && systemctl restart apache2 +fi + +exit 0 diff --git a/appliance/cert-renew.timer b/appliance/cert-renew.timer new file mode 100644 index 0000000..fa2ee54 --- /dev/null +++ b/appliance/cert-renew.timer @@ -0,0 +1,12 @@ +[Unit] +Description=renew certificates from git store +RefuseManualStart=no +RefuseManualStop=no + +[Timer] +Persistent=false +OnCalendar=Sun *-*-* 04:03:00 +Unit=cert-renew.service + +[Install] +WantedBy=default.target diff --git a/mariadb/my.cnf.root b/mariadb/my.cnf.root new file mode 100644 index 0000000..b5ac578 --- /dev/null +++ b/mariadb/my.cnf.root @@ -0,0 +1,11 @@ +[mysqladmin] +user = root +password = gentoo + +[mysql] +user = root +password = gentoo + +[client] +user = root +password = gentoo diff --git a/package.accept_keywords b/package.accept_keywords new file mode 100644 index 0000000..ca7f274 --- /dev/null +++ b/package.accept_keywords @@ -0,0 +1,2 @@ +# Zabbix +net-analyzer/snmptt diff --git a/package.mask b/package.mask new file mode 100644 index 0000000..bb0343a --- /dev/null +++ b/package.mask @@ -0,0 +1,2 @@ +# nur LTS-Versionen 6.0.x bauen +>=net-analyzer/zabbix-6.1 diff --git a/package.use b/package.use new file mode 100644 index 0000000..d82b983 --- /dev/null +++ b/package.use @@ -0,0 +1,12 @@ +# Zabbix +app-admin/rsyslog dbi mysql openssl snmp systemd +app-eselect/eselect-php apache2 +app-text/poppler -introspection -jpeg -jpeg2k +dev-java/openjdk-bin headless-awt +dev-lang/php apache2 bcmath curl gd ldap mysql mysqli odbc sockets sysvipc truetype xmlreader xmlwriter +media-libs/gd jpeg png +net-analyzer/zabbix -agent agent2 curl frontend java ldap libxml2 mysql odbc openipmi -postgres proxy server snmp ssh xmpp +net-analyzer/zabbix-headers -agent agent2 curl frontend java ldap libxml2 mysql odbc openipmi -postgres proxy server snmp ssh xmpp +net-analyzer/net-snmp perl +net-analyzer/fping suid +net-print/cups-filters -foomatic -postscript diff --git a/snmp/snmpd.conf b/snmp/snmpd.conf new file mode 100644 index 0000000..4c2263b --- /dev/null +++ b/snmp/snmpd.conf @@ -0,0 +1,2 @@ +#mibs +SOME-OTHER-SPIFFY-MIB +mibs +ALL diff --git a/snmp/snmptrapd.conf b/snmp/snmptrapd.conf new file mode 100644 index 0000000..c91bbcd --- /dev/null +++ b/snmp/snmptrapd.conf @@ -0,0 +1,2 @@ +traphandle default /usr/sbin/snmptt +disableAuthorization yes diff --git a/snmp/snmptt.conf b/snmp/snmptt.conf new file mode 100644 index 0000000..c06e586 --- /dev/null +++ b/snmp/snmptt.conf @@ -0,0 +1,2 @@ +EVENT general .* "General event" Normal +FORMAT ZBXTRAP $aA $ar severity:$s $Fn$+* diff --git a/va-zabbix.cfg b/va-zabbix.cfg new file mode 100644 index 0000000..f4f8641 --- /dev/null +++ b/va-zabbix.cfg @@ -0,0 +1,2 @@ +REPO_NAMES += unitas-zabbix +REPO_URI_unitas-zabbix = https://git.unitas-network.de/Gentoo/unitas-zabbix.git diff --git a/world b/world new file mode 100644 index 0000000..99c51f8 --- /dev/null +++ b/world @@ -0,0 +1,20 @@ +app-admin/rsyslog +dev-db/mariadb +dev-db/phpmyadmin +dev-java/openjdk-bin:11 +dev-perl/Config-General +dev-perl/JSON-RPC +dev-perl/JSON-XS +dev-perl/libwww-perl +dev-tcltk/expect +net-analyzer/snmp-lldp +net-analyzer/net-snmp +net-analyzer/nmap +net-analyzer/snmptt +net-analyzer/traceroute +net-dns/bind-tools +net-im/sendxmpp +net-misc/netkit-telnetd +sys-apps/ipmitool +sys-libs/openipmi +sys-process/lsof diff --git a/zabbix/userparameter_mysql.conf b/zabbix/userparameter_mysql.conf new file mode 100644 index 0000000..099ed1c --- /dev/null +++ b/zabbix/userparameter_mysql.conf @@ -0,0 +1 @@ +UserParameter=mysql.status[*],echo "show global status where Variable_name='$1';" | HOME=/etc/ mysql -N | awk '{print $$2}' \ No newline at end of file diff --git a/zabbix/zabbix-syslog/70-zabbix_rsyslog.conf b/zabbix/zabbix-syslog/70-zabbix_rsyslog.conf new file mode 100644 index 0000000..08afc2c --- /dev/null +++ b/zabbix/zabbix-syslog/70-zabbix_rsyslog.conf @@ -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 +} diff --git a/zabbix/zabbix-syslog/Template_syslog.xml b/zabbix/zabbix-syslog/Template_syslog.xml new file mode 100644 index 0000000..00c76fd --- /dev/null +++ b/zabbix/zabbix-syslog/Template_syslog.xml @@ -0,0 +1,128 @@ + + + 2.0 + 2015-03-13T14:27:56Z + + + Templates + + + + + + + + ({Template_Syslog:syslog.str(.alert)}=1)and({Template_Syslog:syslog.nodata(900)}=0) + [SYSLOG] Alert message received + + 0 + 4 + + 0 + + + + ({Template_Syslog:syslog.str(.crit)}=1)and({Template_Syslog:syslog.nodata(900)}=0) + [SYSLOG] Critical message received + + 0 + 3 + + 0 + + + + ({Template_Syslog:syslog.str(.emerg)}=1)and({Template_Syslog:syslog.nodata(900)}=0) + [SYSLOG] Emergency message received + + 0 + 5 + + 0 + + + + ({Template_Syslog:syslog.str(.err)}=1)and({Template_Syslog:syslog.nodata(900)}=0) + [SYSLOG] Error received + + 0 + 2 + + 0 + + + + ({Template_Syslog:syslog.str(.warning)}=1)and({Template_Syslog:syslog.nodata(900)}=0) + [SYSLOG] Warning received + + 0 + 1 + + 0 + + + + diff --git a/zabbix/zabbix-syslog/lib/ZabbixAPI.pm b/zabbix/zabbix-syslog/lib/ZabbixAPI.pm new file mode 100644 index 0000000..2c41751 --- /dev/null +++ b/zabbix/zabbix-syslog/lib/ZabbixAPI.pm @@ -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; \ No newline at end of file diff --git a/zabbix/zabbix-syslog/zabbix_syslog.cfg b/zabbix/zabbix-syslog/zabbix_syslog.cfg new file mode 100644 index 0000000..39d6a4f --- /dev/null +++ b/zabbix/zabbix-syslog/zabbix_syslog.cfg @@ -0,0 +1,5 @@ +url = http://localhost/zabbix/api_jsonrpc.php +user = Admin +password = zabbix +server = localhost +debug = 0 \ No newline at end of file diff --git a/zabbix/zabbix-syslog/zabbix_syslog_create_urls.pl b/zabbix/zabbix-syslog/zabbix_syslog_create_urls.pl new file mode 100644 index 0000000..00826f8 --- /dev/null +++ b/zabbix/zabbix-syslog/zabbix_syslog_create_urls.pl @@ -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 = 4.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 $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; +} \ No newline at end of file diff --git a/zabbix/zabbix-syslog/zabbix_syslog_lkp_host.pl b/zabbix/zabbix-syslog/zabbix_syslog_lkp_host.pl new file mode 100644 index 0000000..d5f89bf --- /dev/null +++ b/zabbix/zabbix-syslog/zabbix_syslog_lkp_host.pl @@ -0,0 +1,274 @@ +#!/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 = 4.0; + +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 + "\n%s\n%s\n%s\n\n", + encode_base64($hostname), encode_base64($item), encode_base64($data); + my $packet = "ZBXD\1" . pack('V', length($request)) . "\0\0\0\0" . $request; + + 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($packet); + + 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; + +} \ No newline at end of file