initial commit of file from CVS for smeserver-zabbix-server on Sat Sep 7 21:19:08 AEST 2024
This commit is contained in:
parent
43379e295c
commit
88f19a11b6
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.rpm
|
||||
*.log
|
||||
*spec-20*
|
||||
*.tar.gz
|
21
Makefile
Normal file
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
# Makefile for source rpm: smeserver-zabbix-server
|
||||
# $Id: Makefile,v 1.1 2020/12/04 18:33:23 brianr Exp $
|
||||
NAME := smeserver-zabbix-server
|
||||
SPECFILE = $(firstword $(wildcard *.spec))
|
||||
|
||||
define find-makefile-common
|
||||
for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done
|
||||
endef
|
||||
|
||||
MAKEFILE_COMMON := $(shell $(find-makefile-common))
|
||||
|
||||
ifeq ($(MAKEFILE_COMMON),)
|
||||
# attept a checkout
|
||||
define checkout-makefile-common
|
||||
test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2
|
||||
endef
|
||||
|
||||
MAKEFILE_COMMON := $(shell $(checkout-makefile-common))
|
||||
endif
|
||||
|
||||
include $(MAKEFILE_COMMON)
|
16
README.md
16
README.md
@ -1,3 +1,15 @@
|
||||
# smeserver-zabbix-server
|
||||
# <img src="https://www.koozali.org/images/koozali/Logo/Png/Koozali_logo_2016.png" width="25%" vertical="auto" style="vertical-align:bottom"> smeserver-zabbix-server
|
||||
|
||||
SMEServer Koozali developed git repo for smeserver-zabbix-server smecontribs
|
||||
SMEServer Koozali developed git repo for smeserver-zabbix-server smecontribs
|
||||
|
||||
## Wiki
|
||||
<br />https://wiki.koozali.org/
|
||||
|
||||
## Bugzilla
|
||||
Show list of outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?component=smeserver-zabbix-server&product=SME%20Contribs&query_format=advanced&limit=0&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=CONFIRMED)
|
||||
|
||||
## Description
|
||||
|
||||
<br />*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.*
|
||||
*Once it has been checked, then this comment will be deleted*
|
||||
<br />
|
||||
|
1
contriborbase
Normal file
1
contriborbase
Normal file
@ -0,0 +1 @@
|
||||
contribs10
|
75
createlinks
Normal file
75
createlinks
Normal file
@ -0,0 +1,75 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use esmith::Build::CreateLinks qw(:all);
|
||||
|
||||
my $event = 'zabbix-server-update';
|
||||
|
||||
# Templates to expand
|
||||
templates2events("/etc/httpd/conf/httpd.conf", $event);
|
||||
templates2events("/etc/zabbix/zabbix_server.conf", qw(zabbix-server-update bootstrap-console-save));
|
||||
templates2events("/etc/zabbix/zabbix.conf.php", qw(zabbix-server-update bootstrap-console-save));
|
||||
|
||||
|
||||
# new path with zabbix 4.4.6
|
||||
templates2events("/etc/zabbix/web/zabbix.conf.php", qw(zabbix-server-update bootstrap-console-save));
|
||||
templates2events("/etc/sudoers", $event);
|
||||
templates2events("/var/lib/zabbix/bin/sendxmpp", $event);
|
||||
templates2events("/var/lib/zabbix/.sendxmpprc", $event);
|
||||
templates2events("/etc/e-smith/sql/init105/80zabbix-server", qw(zabbix-server-update bootstrap-console-save));
|
||||
templates2events("/etc/rc.d/init.d/masq", $event);
|
||||
|
||||
# Services to restart
|
||||
#safe_symlink("restart", "root/etc/e-smith/events/$event/services2adjust/mysql.init");
|
||||
safe_symlink("sigusr1", "root/etc/e-smith/events/$event/services2adjust/httpd-e-smith");
|
||||
safe_symlink("restart", "root/etc/e-smith/events/$event/services2adjust/zabbix-server");
|
||||
safe_symlink("adjust", "root/etc/e-smith/events/$event/services2adjust/masq");
|
||||
safe_symlink("/etc/e-smith/events/actions/zabbix-server","root/etc/e-smith/events/$event/50zabbix-server");
|
||||
|
||||
# PHP header and footer
|
||||
safe_symlink("/etc/e-smith/templates-default/template-begin-php", "root/etc/e-smith/templates/etc/zabbix/zabbix.conf.php/template-begin");
|
||||
safe_symlink("/etc/e-smith/templates-default/template-end-php", "root/etc/e-smith/templates/etc/zabbix/zabbix.conf.php/template-end");
|
||||
|
||||
# Bash header
|
||||
safe_symlink("/etc/e-smith/templates-default/template-begin-shell", "root/etc/e-smith/templates/var/lib/zabbix/bin/sendxmpp/template-begin");
|
||||
|
||||
# Start and stop links - sysV
|
||||
#service_link_enhanced("zabbix-server", "S99", "7");
|
||||
#service_link_enhanced("zabbix-server", "K10", "6");
|
||||
#service_link_enhanced("zabbix-server", "K10", "0");
|
||||
|
||||
#Systemd start stop
|
||||
# rpm update action (invoked by yum on install and update
|
||||
$contrib = "smeserver-zabbix-server";
|
||||
safe_symlink("/etc/e-smith/events/$contrib-update", "root/etc/e-smith/events/$contrib-z50-update");
|
||||
event_actions("$contrib-update", qw(
|
||||
systemd-default 88
|
||||
systemd-reload 89
|
||||
zabbix-server 92
|
||||
));
|
||||
|
||||
event_templates("$contrib-update", qw(
|
||||
/etc/httpd/conf/httpd.conf
|
||||
/etc/crontab
|
||||
/etc/rc.d/init.d/masq
|
||||
/etc/sudoers
|
||||
/etc/e-smith/sql/init105/80zabbix-server
|
||||
/etc/zabbix/zabbix.conf.php
|
||||
/etc/zabbix/web/zabbix.conf.php
|
||||
/var/lib/zabbix/bin/sendxmpp
|
||||
/etc/zabbix/zabbix_server.conf
|
||||
/usr/share/zabbix/.user.ini
|
||||
/etc/systemd/system-preset/49-koozali.preset
|
||||
/etc/opt/remi/php74/php-fpm.d/www.conf
|
||||
/etc/backup-data.d/smeserver-zabbix-server.include
|
||||
|
||||
));
|
||||
|
||||
event_services("$contrib-update", qw(
|
||||
httpd-e-smith sigusr1
|
||||
php74-php-fpm reload
|
||||
masq adjust
|
||||
));
|
||||
|
||||
#zabbix server 92 will stop zabbix, restart mariadb105-mysql.init and start zabbix
|
||||
#that is why those services are not listed in event_service. order matter.
|
||||
#also this is at the end to be sure that mariadb105 is installed and running
|
@ -0,0 +1 @@
|
||||
zabbixdb
|
@ -0,0 +1 @@
|
||||
zabbixuser
|
@ -0,0 +1 @@
|
||||
zabbix
|
@ -0,0 +1 @@
|
||||
secret
|
@ -0,0 +1 @@
|
||||
localhost
|
@ -0,0 +1 @@
|
||||
enabled
|
@ -0,0 +1 @@
|
||||
0
|
@ -0,0 +1 @@
|
||||
10051
|
@ -0,0 +1 @@
|
||||
local
|
@ -0,0 +1 @@
|
||||
private
|
@ -0,0 +1 @@
|
||||
enabled
|
@ -0,0 +1 @@
|
||||
service
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
my $rec = $DB->get('zabbix-server')
|
||||
|| $DB->new_record('zabbix-server', {type => 'service'});
|
||||
my $pw = $rec->prop('DbPassword');
|
||||
if (not $pw or length($pw) < 57)
|
||||
{
|
||||
use MIME::Base64 qw(encode_base64);
|
||||
|
||||
$pw = "not set due to error";
|
||||
if ( open( RANDOM, "/dev/urandom" ) )
|
||||
{
|
||||
my $buf;
|
||||
# 57 bytes is a full line of Base64 coding, and contains
|
||||
# 456 bits of randomness - given a perfectly random /dev/random
|
||||
if ( read( RANDOM, $buf, 57 ) != 57 )
|
||||
{
|
||||
warn("Short read from /dev/random: $!");
|
||||
}
|
||||
else
|
||||
{
|
||||
$pw = encode_base64($buf);
|
||||
chomp $pw;
|
||||
}
|
||||
close RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
warn "Could not open /dev/urandom: $!";
|
||||
}
|
||||
$rec->set_prop('DbPassword', $pw);
|
||||
}
|
||||
|
||||
my $AdminPass = $rec->prop('AdminPassword') ||
|
||||
$rec->set_prop('AdminPassword', `/usr/bin/openssl rand -base64 15 | /usr/bin/tr -c -d '[:graph:]'`);
|
||||
|
||||
|
||||
}
|
||||
|
3
root/etc/e-smith/events/actions/smeserver-zabbix-server
Normal file
3
root/etc/e-smith/events/actions/smeserver-zabbix-server
Normal file
@ -0,0 +1,3 @@
|
||||
systemctl daemon-reload
|
||||
systemsctl preset-all
|
||||
systemsctl restart zabbix-server
|
7
root/etc/e-smith/events/actions/zabbix-server
Normal file
7
root/etc/e-smith/events/actions/zabbix-server
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
# restart mysql.init
|
||||
/usr/bin/systemctl stop zabbix-server 1>/dev/null
|
||||
/usr/bin/systemctl restart mariadb105-mysql.init 1>/dev/null
|
||||
/usr/bin/systemctl start zabbix-server 1>/dev/null
|
||||
exit 0
|
||||
|
@ -0,0 +1 @@
|
||||
PERMS=0750
|
@ -0,0 +1,3 @@
|
||||
TEMPLATE_PATH="/etc/zabbix/zabbix.conf.php"
|
||||
OUTPUT_FILENAME="/etc/zabbix/web/zabbix.conf.php"
|
||||
|
@ -0,0 +1,3 @@
|
||||
PERMS=0600
|
||||
UID="zabbix"
|
||||
GID="zabbix"
|
@ -0,0 +1,4 @@
|
||||
PERMS=0750
|
||||
UID="root"
|
||||
GID="zabbix"
|
||||
|
@ -0,0 +1,21 @@
|
||||
#Only non rpm owned files are backupe there
|
||||
{
|
||||
use RPM2;
|
||||
my $rpm_db = RPM2->open_rpm_db();
|
||||
|
||||
my @dirs = qw(
|
||||
/etc/zabbix
|
||||
/etc/zabbix/zabbix_agentd.conf.d/
|
||||
/var/lib/zabbix/bin/
|
||||
);
|
||||
|
||||
foreach my $some_dir (@dirs) {
|
||||
next unless ( -e $some_dir );
|
||||
opendir(my $dh, $some_dir) || die "Can't open $some_dir: $!";
|
||||
while ( (my $file = readdir $dh) ) {
|
||||
next if $file =~ /^\.{1,2}$/;
|
||||
$OUT .= "$some_dir/$file\n" unless $rpm_db->find_by_file("$some_dir/$file");
|
||||
}
|
||||
closedir $dh;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
{
|
||||
my $db = ${'zabbix-server'}{'DbName'} || 'zabbixdb';
|
||||
my $user = ${'zabbix-server'}{'DbUser'} || 'zabbixuser';
|
||||
my $pass = ${'zabbix-server'}{'DbPassword'} || 'secret';
|
||||
|
||||
my $schema = `rpm -qd zabbix-server-mysql | grep create`;
|
||||
chomp $schema;
|
||||
my $curcharset= ( -d "/var/lib/mysql/$db" ) ? `echo 'show variables like "character_set_database";'|mysql $db|grep character_set_database|sed -r 's/^character_set_database\\s*([a-zA-Z0-9_-]+)/\\1/'` : "utf8";
|
||||
chomp $curcharset;
|
||||
my $adminpass= ${'zabbix-server'}{'AdminPassword'} || 'zabbix';
|
||||
$hashpass=`/usr/bin/htpasswd -bnBC 10 '' $adminpass | tr -d ':'`;
|
||||
$hashpass =~ tr/\r\n//d;
|
||||
$version = `/bin/ls -d /usr/share/doc/zabbix-web*|grep -Eo '[0-9.]+\$'|cut -d. -f1 || echo 4 `;
|
||||
$modpass=($version > 4)? "update users set passwd='$hashpass' where alias='Admin';": "#$version";
|
||||
$OUT .= <<"END";
|
||||
#! /bin/sh
|
||||
if [ -d /var/opt/rh/rh-mariadb105/lib/mysql/$db ]; then
|
||||
# check if utf8
|
||||
if [[ "$curcharset" != "utf8" ]] ;then
|
||||
echo "ALTER DATABASE $db CHARACTER SET utf8 COLLATE utf8_bin;" |/usr/bin/mysql105
|
||||
echo 'ALTER TABLE `$db`.`problem_tag` DROP INDEX `problem_tag_1`, ADD INDEX `problem_tag_1` (`eventid`, `tag` (100), `value`(100));' |/usr/bin/mysql105
|
||||
mysql --batch --skip-column-names --execute 'select concat("alter table ",TABLE_SCHEMA,".",TABLE_NAME," CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;") from information_schema.TABLES where TABLE_SCHEMA="$db"' | /usr/bin/mysql105
|
||||
fi
|
||||
for P in \$(rpm -qd zabbix-server-mysql | grep dbpatch | grep mysql); do
|
||||
/usr/bin/mysql105 $db < \$P
|
||||
done
|
||||
else
|
||||
echo "CREATE DATABASE $db CHARACTER SET utf8 COLLATE utf8_bin;" | /usr/bin/mysql105
|
||||
/usr/bin/gunzip < $schema | /usr/bin/mysql105 $db
|
||||
|
||||
fi
|
||||
|
||||
/usr/bin/mysql105 <<EOF
|
||||
USE $db;
|
||||
update users set passwd=md5('$adminpass') where alias='Admin' and passwd=md5('zabbix');
|
||||
$modpass
|
||||
EOF
|
||||
|
||||
|
||||
/usr/bin/mysql105 <<EOF
|
||||
USE mysql;
|
||||
|
||||
grant all on $db.* to '${'zabbix-server'}{DbUser}'\@'localhost' identified by '${'zabbix-server'}{DbPassword}';
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
USE ${'zabbix-server'}{DbName};
|
||||
|
||||
INSERT IGNORE INTO media_type (
|
||||
mediatypeid,
|
||||
type, description,
|
||||
smtp_server,
|
||||
smtp_helo,
|
||||
smtp_email,
|
||||
exec_path,
|
||||
gsm_modem,
|
||||
username,
|
||||
passwd)
|
||||
VALUES(
|
||||
4,
|
||||
1,
|
||||
'xmpp',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'sendxmpp',
|
||||
'',
|
||||
'',
|
||||
'');
|
||||
|
||||
EOF
|
||||
END
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
if (
|
||||
((${'zabbix-server'}{'status'} || 'disabled') eq 'enabled') &&
|
||||
((${'zabbix-server'}{'WebAccess'} || 'local') ne 'disabled')){
|
||||
|
||||
my $access = (${'zabbix-server'}{'WebAccess'} || 'local') eq 'public' ?
|
||||
'all granted':"ip $localAccess $externalSSLAccess";
|
||||
|
||||
my $tz = ${'TimeZone'} || 'Europe/Paris';
|
||||
|
||||
$OUT .=<<"HERE";
|
||||
#-------------------------------------------#
|
||||
# Zabbix monitoring system php web frontend #
|
||||
#-------------------------------------------#
|
||||
|
||||
Alias /zabbix /usr/share/zabbix
|
||||
|
||||
<Directory "/usr/share/zabbix">
|
||||
SSLRequireSSL on
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
#AddType application/x-httpd-php .php
|
||||
<FilesMatch .php>
|
||||
SetHandler "proxy:unix:/var/run/php-fpm/php74-zabbix-server.sock|fcgi://localhost"
|
||||
</FilesMatch>
|
||||
Require $access
|
||||
</Directory>
|
||||
|
||||
<Directory "/usr/share/zabbix/include">
|
||||
Require all denied
|
||||
<files *.php>
|
||||
Require all denied
|
||||
</files>
|
||||
</Directory>
|
||||
|
||||
<Directory "/usr/share/zabbix/include/classes">
|
||||
Require all denied
|
||||
<files *.php>
|
||||
Require all denied
|
||||
</files>
|
||||
</Directory>
|
||||
|
||||
HERE
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
|
||||
if ($port ne ${modSSL}{'TCPPort'}){
|
||||
$OUT = ' RewriteRule ^/zabbix(/.*|$) https://%{HTTP_HOST}/zabbix$1 [L,R]';
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
{
|
||||
if ($PHP_VERSION eq '74'){
|
||||
if ((${'zabbix-server'}{status} || 'disabled') eq 'enabled'){
|
||||
my $id = 'zabbix-server';
|
||||
my $openbasedir = '/usr/share/zabbix:/var/cache/zabbix/:/var/run/php-fpm/:/var/lib/php/zabbix/' .
|
||||
':/var/lock/zabbix/:/etc/zabbix/:/usr/share/php/:/usr/share/pear/:/opt/remi/php74/root/usr/share/pear/' .
|
||||
':/opt/remi/php74/root/usr/share/php/';
|
||||
$disablefunctions = 'system, show_source, symlink, exec, dl, shell_exec, passthru, phpinfo, ' .
|
||||
'escapeshellarg, escapeshellcmd';
|
||||
|
||||
$socket = ( -d "/var/lib/mysql/zabbixdb") ? "/var/lib/mysql/mysql.sock" : "/var/lib/mysql/mariadb105.sock";
|
||||
|
||||
$OUT .=<<_EOF;
|
||||
|
||||
[php$PHP_VERSION-$id]
|
||||
user = www
|
||||
group = www
|
||||
listen.owner = root
|
||||
listen.group = www
|
||||
listen.mode = 0660
|
||||
listen = /var/run/php-fpm/php$PHP_VERSION-$id.sock
|
||||
pm = dynamic
|
||||
pm.max_children = 15
|
||||
pm.start_servers = 3
|
||||
pm.min_spare_servers = 3
|
||||
pm.max_spare_servers = 4
|
||||
pm.max_requests = 1000
|
||||
request_terminate_timeout = 30
|
||||
php_admin_value[session.save_path] = /var/lib/php/zabbix/session
|
||||
php_admin_value[opcache.file_cache] = /var/lib/php/zabbix/opcache
|
||||
php_admin_value[upload_tmp_dir] = /var/lib/php/zabbix/tmp
|
||||
php_admin_value[error_log] = /var/log/php/zabbix/error.log
|
||||
slowlog = /var/log/php/zabbix/slow.log
|
||||
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f php@{ $DomainName }
|
||||
php_admin_flag[display_errors] = off
|
||||
php_admin_flag[log_errors] = on
|
||||
php_admin_value[error_log] = syslog
|
||||
php_admin_value[memory_limit] = 256M
|
||||
php_admin_value[max_execution_time] = 600
|
||||
php_admin_value[max_input_time] = 600
|
||||
php_admin_value[post_max_size] = 32M
|
||||
php_admin_value[upload_max_filesize] = 16M
|
||||
php_admin_value[disable_functions] = $disablefunctions
|
||||
php_admin_value[open_basedir] = $openbasedir
|
||||
php_admin_flag[allow_url_fopen] = on
|
||||
php_admin_flag[file_upload] = off
|
||||
php_admin_flag[session.cookie_httponly] = on
|
||||
php_admin_flag[allow_url_include] = off
|
||||
php_admin_value[session.save_handler] = files
|
||||
php_admin_value[always_populate_raw_post_data] = -1
|
||||
php_value[mysqli.default_socket] = $socket
|
||||
php_value[mysql.default_socket] = $socket
|
||||
|
||||
_EOF
|
||||
}
|
||||
else{
|
||||
$OUT .= '; Zabbix Server is disabled';
|
||||
}
|
||||
}
|
||||
}
|
1
root/etc/e-smith/templates/etc/sudoers/00zabbixAlias
Normal file
1
root/etc/e-smith/templates/etc/sudoers/00zabbixAlias
Normal file
@ -0,0 +1 @@
|
||||
Cmnd_Alias ZABBIX = /usr/sbin/fping,/usr/sbin/fping6
|
1
root/etc/e-smith/templates/etc/sudoers/30zabbix
Normal file
1
root/etc/e-smith/templates/etc/sudoers/30zabbix
Normal file
@ -0,0 +1 @@
|
||||
zabbix ALL=(root) NOPASSWD: ZABBIX
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
** ZABBIX
|
||||
** Copyright (C) 2000-2005 SIA Zabbix
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software
|
||||
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**/
|
||||
|
@ -0,0 +1,20 @@
|
||||
global $DB;
|
||||
|
||||
$DB["TYPE"] = "MYSQL";
|
||||
$DB["SERVER"] = "localhost";
|
||||
$DB["PORT"] = "0";
|
||||
|
||||
{
|
||||
|
||||
my $dbname = ${'zabbix-server'}{'DbName'} || 'zabbix';
|
||||
my $dbuser = ${'zabbix-server'}{'DbUser'} || 'zabbix';
|
||||
my $dbpass = ${'zabbix-server'}{'DbPassword'} || 'secret';
|
||||
|
||||
$OUT .=<<"HERE";
|
||||
|
||||
\$DB["DATABASE"] = "$dbname";
|
||||
\$DB["USER"] = "$dbuser";
|
||||
\$DB["PASSWORD"] = "$dbpass";
|
||||
HERE
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
my $port = ${'zabbix-server'}{'TCPPort'} || '10051';
|
||||
|
||||
$OUT .=<<"HERE";
|
||||
|
||||
\$ZBX_SERVER = "localhost";
|
||||
\$ZBX_SERVER_PORT = "$port";
|
||||
HERE
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
|
@ -0,0 +1,4 @@
|
||||
# This is config file for ZABBIX server process
|
||||
# To get more information about ZABBIX,
|
||||
# go http://www.zabbix.com
|
||||
|
@ -0,0 +1,11 @@
|
||||
############ GENERAL PARAMETERS #################
|
||||
|
||||
#NodeID dropped since Zabbix 2.40
|
||||
{
|
||||
# This defines unique NodeID in distributed setup,
|
||||
# Default value 0 (standalone server)
|
||||
# This parameter must be between 0 and 999
|
||||
#my $nodeID = ${'zabbix-server'}{'NodeID'} || '0';
|
||||
#$OUT .= "NodeID=$nodeID\n";
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
# Number of pre-forked instances of pollers
|
||||
# Default value is 5
|
||||
# This parameter must be between 0 and 255
|
||||
StartPollers=5
|
||||
|
||||
# Number of pre-forked instances of IPMI pollers
|
||||
# Default value is 0
|
||||
# This parameter must be between 0 and 255
|
||||
#StartIPMIPollers=0
|
||||
|
||||
# Number of pre-forked instances of pollers for unreachable hosts
|
||||
# Default value is 1
|
||||
# This parameter must be between 0 and 255
|
||||
#StartPollersUnreachable=1
|
||||
|
||||
# Number of pre-forked instances of trappers
|
||||
# Default value is 5
|
||||
# This parameter must be between 0 and 255
|
||||
StartTrappers=5
|
||||
|
||||
# Number of pre-forked instances of ICMP pingers
|
||||
# Default value is 1
|
||||
# This parameter must be between 0 and 255
|
||||
StartPingers=1
|
||||
|
||||
# Number of pre-forked instances of discoverers
|
||||
# Default value is 1
|
||||
# This parameter must be between 0 and 255
|
||||
StartDiscoverers=1
|
||||
|
||||
# Number of pre-forked instances of HTTP pollers
|
||||
# Default value is 1
|
||||
# This parameter must be between 0 and 255
|
||||
#StartHTTPPollers=1
|
||||
|
@ -0,0 +1,16 @@
|
||||
# Listen port for trapper. Default port number is 10051. This parameter
|
||||
# must be between 1024 and 32767
|
||||
{
|
||||
my $port = ${'zabbix-server'}{'TCPPort'} || '10051';
|
||||
$OUT .= "ListenPort=$port\n";
|
||||
}
|
||||
|
||||
# Source IP address for outgouing connections
|
||||
#SourceIP=
|
||||
|
||||
# Listen interface for trapper. Trapper will listen all network interfaces
|
||||
# if this parameter is missing.
|
||||
|
||||
#ListenIP=127.0.0.1
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
# How often ZABBIX will perform housekeeping procedure
|
||||
# (in hours)
|
||||
# Default value is 1 hour
|
||||
# Housekeeping is removing unnecessary information from
|
||||
# tables history, alert, and alarms
|
||||
# This parameter must be between 1 and 24
|
||||
|
||||
#HousekeepingFrequency=1
|
||||
|
||||
# Uncomment this line to disable housekeeping procedure
|
||||
#DisableHousekeeping=1
|
||||
|
||||
# Frequency of ICMP pings (item keys 'icmpping' and 'icmppingsec'). Defauls is 60 seconds.
|
||||
#PingerFrequency=60
|
||||
|
@ -0,0 +1,9 @@
|
||||
# Specifies debug level
|
||||
# 0 - debug is not created
|
||||
# 1 - critical information
|
||||
# 2 - error information
|
||||
# 3 - warnings (default)
|
||||
# 4 - for debugging (produces lots of information)
|
||||
|
||||
DebugLevel=3
|
||||
|
@ -0,0 +1,13 @@
|
||||
# Name of PID file
|
||||
|
||||
PidFile=/run/zabbix/zabbix_server.pid
|
||||
|
||||
# Name of log file
|
||||
# If not set, syslog is used
|
||||
|
||||
LogFile=/var/log/zabbix/zabbix_server.log
|
||||
|
||||
# Maximum size of log file in MB. Set to 0 to disable automatic log rotation.
|
||||
LogFileSize=10
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
# Location for custom alert scripts
|
||||
AlertScriptsPath=/var/lib/zabbix/bin
|
||||
|
||||
# Location of external scripts
|
||||
ExternalScripts=/var/lib/zabbix/bin
|
||||
|
||||
# Location of fping. Default is /usr/sbin/fping
|
||||
# Make sure that fping binary has root permissions and SUID flag set
|
||||
FpingLocation=/var/lib/zabbix/bin/fping
|
||||
|
||||
# Location of fping6. Default is /usr/sbin/fping6
|
||||
# Make sure that fping binary has root permissions and SUID flag set
|
||||
Fping6Location=/var/lib/zabbix/bin/fping6
|
||||
|
||||
# Temporary directory. Default is /tmp
|
||||
TmpDir=/var/lib/zabbix/tmp
|
||||
|
@ -0,0 +1,36 @@
|
||||
# Database host name
|
||||
# Default is localhost
|
||||
|
||||
DBHost=localhost
|
||||
|
||||
# Database name
|
||||
# SQLite3 note: path to database file must be provided. DBUser and DBPassword are ignored.
|
||||
{
|
||||
my $dbname = ${'zabbix-server'}{'DbName'} || 'zabbix';
|
||||
my $dbuser = ${'zabbix-server'}{'DbUser'} || 'zabbix';
|
||||
my $dbpass = ${'zabbix-server'}{'DbPassword'} || 'secret';
|
||||
|
||||
$OUT .=<<"HERE";
|
||||
|
||||
DBName=$dbname
|
||||
|
||||
# Database user
|
||||
|
||||
DBUser=$dbuser
|
||||
|
||||
# Database password
|
||||
# Comment this line if no password used
|
||||
|
||||
DBPassword=$dbpass
|
||||
HERE
|
||||
|
||||
}
|
||||
|
||||
# Connect to MySQL using Unix socket?
|
||||
|
||||
#DBSocket=/var/lib/mysql/mysql.sock
|
||||
DBSocket=/var/lib/mysql/{$OUT = ( -d "/var/lib/mysql/zabbixdb") ? "mysql" : "mariadb105"}.sock
|
||||
|
||||
# Enable database cache module
|
||||
StartDBSyncers=1
|
||||
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
my $tz = ${'TimeZone'} || 'Europe/Paris';
|
||||
$OUT =<<"HERE";
|
||||
max_execution_time=600
|
||||
max_input_time=600
|
||||
memory_limit=256M
|
||||
date.timezone=$tz
|
||||
post_max_size=32M
|
||||
always_populate_raw_post_data=-1
|
||||
HERE
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
# Jabber Account for zabbix alerts
|
||||
{${'zabbix-server'}{'JabberAccount'}}@{${'zabbix-server'}{'JabberServer'}} {${'zabbix-server'}{'JabberPassword'}}
|
||||
|
@ -0,0 +1,6 @@
|
||||
|
||||
echo "$3" | \
|
||||
sendxmpp -r zabbix -f /var/lib/zabbix/.sendxmpprc \
|
||||
{(${'zabbix-server'}{'JabberTLS'} || 'enabled') eq 'disabled' ? '':'-t \\';}
|
||||
-s "$2" "$1"
|
||||
|
@ -0,0 +1,3 @@
|
||||
[Install]
|
||||
WantedBy=sme-server.target
|
||||
|
6
root/usr/share/zabbix/.user.ini
Normal file
6
root/usr/share/zabbix/.user.ini
Normal file
@ -0,0 +1,6 @@
|
||||
max_execution_time=600
|
||||
max_input_time=600
|
||||
memory_limit=256M
|
||||
date.timezone=$tz
|
||||
post_max_size=32M
|
||||
always_populate_raw_post_data=-1
|
139
root/var/lib/zabbix/bin/cert_expire.pl
Normal file
139
root/var/lib/zabbix/bin/cert_expire.pl
Normal file
@ -0,0 +1,139 @@
|
||||
#!/usr/bin/perl -w
|
||||
# Check peer certificate validity for Zabbix
|
||||
# Require perl module : IO::Socket, Net::SSLeay, Date::Parse
|
||||
# Require unix programs : openssl, echo, sendmail
|
||||
#
|
||||
# Based on sslexpire from Emmanuel Lacour <elacour@home-dn.net>
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This file is distributed in the hope that it will be
|
||||
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this file; see the file COPYING. If not, write to the Free
|
||||
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
#
|
||||
|
||||
|
||||
use strict;
|
||||
use IO::Socket;
|
||||
use Net::SSLeay;
|
||||
use Getopt::Long;
|
||||
use Date::Parse;
|
||||
|
||||
Net::SSLeay::SSLeay_add_ssl_algorithms();
|
||||
Net::SSLeay::randomize();
|
||||
|
||||
# Default values
|
||||
my $opensslpath = "/usr/bin/openssl";
|
||||
my $host = '127.0.0.1';
|
||||
my $port = '443';
|
||||
|
||||
my %opts;
|
||||
GetOptions (\%opts,
|
||||
'host|h=s',
|
||||
'port|p=s',
|
||||
'help',
|
||||
);
|
||||
|
||||
if ($opts{'host'}) {
|
||||
$host = $opts{'host'};
|
||||
}
|
||||
if ($opts{'port'}){
|
||||
$port = $opts{'port'};
|
||||
}
|
||||
|
||||
if ($opts{'help'}) {
|
||||
&usage;
|
||||
}
|
||||
|
||||
# Print program usage
|
||||
sub usage {
|
||||
print "Usage: sslexpire [OPTION]...
|
||||
-h, --host=HOST check this host
|
||||
-p, --port=TCPPORT check this port on the previous host
|
||||
--help print this help, then exit
|
||||
";
|
||||
exit;
|
||||
}
|
||||
|
||||
# This will return the expiration date
|
||||
sub getExpire {
|
||||
|
||||
my ($l_host,$l_port) = @_;
|
||||
my ($l_expdate,$l_comment);
|
||||
|
||||
# Connect to $l_host:$l_port
|
||||
my $socket = IO::Socket::INET->new(
|
||||
Proto => "tcp",
|
||||
PeerAddr => $l_host,
|
||||
PeerPort => $l_port
|
||||
);
|
||||
# If we connected successfully
|
||||
if ($socket) {
|
||||
# Intiate ssl
|
||||
my $l_ctx = Net::SSLeay::CTX_new();
|
||||
my $l_ssl = Net::SSLeay::new($l_ctx);
|
||||
|
||||
Net::SSLeay::set_fd($l_ssl, fileno($socket));
|
||||
my $res = Net::SSLeay::connect($l_ssl);
|
||||
|
||||
# Get peer certificate
|
||||
my $l_x509 = Net::SSLeay::get_peer_certificate($l_ssl);
|
||||
if ($l_x509) {
|
||||
my $l_string = Net::SSLeay::PEM_get_string_X509($l_x509);
|
||||
# Get the expiration date, using openssl
|
||||
$l_expdate = `echo "$l_string" | $opensslpath x509 -enddate -noout 2>&1`;
|
||||
$l_expdate =~ s/.*=//;
|
||||
chomp($l_expdate);
|
||||
}
|
||||
else {
|
||||
$l_expdate = 1;
|
||||
}
|
||||
|
||||
# Close and cleanup
|
||||
Net::SSLeay::free($l_ssl);
|
||||
Net::SSLeay::CTX_free($l_ctx);
|
||||
close $socket;
|
||||
}
|
||||
else {
|
||||
$l_expdate = 1;
|
||||
}
|
||||
return $l_expdate;
|
||||
}
|
||||
|
||||
|
||||
# Print remaining days before expiration
|
||||
sub report {
|
||||
# Convert date into epoch using date command
|
||||
my ($l_expdate) = @_;
|
||||
|
||||
if ($l_expdate ne "1") {
|
||||
# The current date
|
||||
my $l_today = time;
|
||||
my $l_epochdate = str2time($l_expdate);
|
||||
|
||||
# Calculate diff between expiration date and today
|
||||
my $l_diff = ($l_epochdate - $l_today)/(3600*24);
|
||||
|
||||
# Report if needed
|
||||
printf "%.0f\n", $l_diff;
|
||||
}
|
||||
else {
|
||||
print "Unable to read certificate!\n";
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
# Get expiration date
|
||||
my $expdate = getExpire($host,$port);
|
||||
|
||||
# Report
|
||||
report("$expdate");
|
109
root/var/lib/zabbix/bin/check_cert.pl
Normal file
109
root/var/lib/zabbix/bin/check_cert.pl
Normal file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
check_ssl_certificate.pl
|
||||
--url,-u URL
|
||||
--sni,-s HOSTNAME SNI servername (SSL vhost) that will be requested during SSL handshake.
|
||||
This tells the server which certificate to return.
|
||||
Default to the host passed with --url
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use IO::Socket::SSL;
|
||||
use LWP::UserAgent;
|
||||
use URI::URL;
|
||||
use DateTime::Format::ISO8601;
|
||||
use Getopt::Long qw/:config auto_help/;
|
||||
use Pod::Usage;
|
||||
use JSON qw(to_json);
|
||||
|
||||
use constant TIMEOUT => 10;
|
||||
|
||||
my ($url, $sni, $status, @san);
|
||||
|
||||
sub ssl_opts {
|
||||
my ($sni, $expiration_date_ref, $status_ref, $san_ref) = @_;
|
||||
return (
|
||||
'verify_hostname' => 0,
|
||||
'SSL_ca_file' => '/etc/pki/tls/certs/ca-bundle.crt',
|
||||
'SSL_hostname' => $sni,
|
||||
'SSL_verifycn_name' => $sni,
|
||||
'SSL_verify_scheme' => 'http',
|
||||
'SSL_verify_callback' => sub {
|
||||
my (undef, $ctx_store) = @_;
|
||||
# Get the error message from openssl verification
|
||||
$$status_ref = Net::SSLeay::X509_verify_cert_error_string(Net::SSLeay::X509_STORE_CTX_get_error($ctx_store));
|
||||
# Get the raw cert, to extract the expiration
|
||||
my $cert = Net::SSLeay::X509_STORE_CTX_get_current_cert($ctx_store);
|
||||
$$expiration_date_ref = Net::SSLeay::P_ASN1_TIME_get_isotime(Net::SSLeay::X509_get_notAfter($cert));
|
||||
# Get Alt names so we can check later if the hostname match
|
||||
@$san_ref = Net::SSLeay::X509_get_subjectAltNames($cert);
|
||||
# Keep only odd elements. Even ones contains subject types which we're not interested in
|
||||
@$san_ref = @$san_ref[grep $_ % 2, 0..scalar(@$san_ref)];
|
||||
# Always return success
|
||||
return 1;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
sub https_get {
|
||||
my ($url, $sni, $expiration_date_ref, $status_ref, $san_ref) = @_;
|
||||
|
||||
my $ua = LWP::UserAgent->new();
|
||||
$ua->timeout(TIMEOUT);
|
||||
$ua->ssl_opts( ssl_opts($sni, $expiration_date_ref, $status_ref, $san_ref) );
|
||||
my $request = HTTP::Request->new('GET', $url);
|
||||
$request->header(Host => $sni);
|
||||
my $response = $ua->simple_request($request);
|
||||
return $response;
|
||||
}
|
||||
|
||||
sub wildcard_match {
|
||||
my ($cn, $host) = @_;
|
||||
my $match = 0;
|
||||
return 0 if $cn !~ m/^\*\.(.*)$/;
|
||||
my $cn_dom = $1;
|
||||
my $host_dom = ($sni =~ m/^[^\.]+\.(.*)$/)[0];
|
||||
return ($cn_dom eq $host_dom);
|
||||
}
|
||||
|
||||
GetOptions ("url|u=s" => \$url,
|
||||
"sni|s=s" => \$sni) or pod2usage(1);
|
||||
if (@ARGV) {
|
||||
print "This script takes no arguments...\n";
|
||||
pod2usage(1);
|
||||
}
|
||||
pod2usage(1) if (!$url);
|
||||
|
||||
my $expiration_date;
|
||||
my $uri = URI->new($url);
|
||||
die "Only https urls are supported\n" unless $uri->scheme eq 'https';
|
||||
$sni ||= $uri->host;
|
||||
my $response = https_get($url, $sni, \$expiration_date, \$status, \@san);
|
||||
|
||||
my $out = {
|
||||
code => $response->code,
|
||||
status => $response->message,
|
||||
days_left => undef,
|
||||
cert_cn => undef,
|
||||
issuer => undef
|
||||
};
|
||||
|
||||
if ($response->code != 500) { # Even a 404 is good enough, as far as cert validation goes...
|
||||
my $now = DateTime->now;
|
||||
$expiration_date = DateTime::Format::ISO8601->parse_datetime( $expiration_date );
|
||||
|
||||
$out->{issuer} = $response->headers->{'client-ssl-cert-issuer'};
|
||||
$out->{cert_cn} = ($response->headers->{'client-ssl-cert-subject'} =~ m/CN=(.*)$/)[0];
|
||||
$status = "no common name" if !$out->{cert_cn};
|
||||
$out->{status} = ($status eq 'ok' and !grep { $sni eq $_ } @san and !wildcard_match($out->{cert_cn},$sni)) ?
|
||||
$out->{status} = "hostname mismatch ($sni doesn't match any of " . join(" ", @san) . ")" :
|
||||
$status;
|
||||
$out->{days_left} = ($expiration_date < $now) ? -1 * $expiration_date->delta_days($now)->delta_days :
|
||||
$expiration_date->delta_days($now)->delta_days
|
||||
}
|
||||
|
||||
print to_json($out, { pretty => 1 });
|
2
root/var/lib/zabbix/bin/fping
Normal file
2
root/var/lib/zabbix/bin/fping
Normal file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec /usr/bin/sudo /usr/sbin/fping "$@"
|
2
root/var/lib/zabbix/bin/fping6
Normal file
2
root/var/lib/zabbix/bin/fping6
Normal file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec /usr/bin/sudo /usr/sbin/fping6 "$@"
|
939
root/var/lib/zabbix/bin/zbxtg.py
Normal file
939
root/var/lib/zabbix/bin/zbxtg.py
Normal file
@ -0,0 +1,939 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
import stat
|
||||
import hashlib
|
||||
import subprocess
|
||||
#import sqlite3
|
||||
from os.path import dirname
|
||||
import zbxtg_settings
|
||||
|
||||
|
||||
class Cache:
|
||||
def __init__(self, database):
|
||||
self.database = database
|
||||
|
||||
def create_db(self, database):
|
||||
pass
|
||||
|
||||
|
||||
class TelegramAPI:
|
||||
tg_url_bot_general = "https://api.telegram.org/bot"
|
||||
|
||||
def http_get(self, url):
|
||||
answer = requests.get(url, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def __init__(self, key):
|
||||
self.debug = False
|
||||
self.key = key
|
||||
self.proxies = {}
|
||||
self.type = "private" # 'private' for private chats or 'group' for group chats
|
||||
self.markdown = False
|
||||
self.html = False
|
||||
self.disable_web_page_preview = False
|
||||
self.disable_notification = False
|
||||
self.reply_to_message_id = 0
|
||||
self.tmp_dir = None
|
||||
self.tmp_uids = None
|
||||
self.location = {"latitude": None, "longitude": None}
|
||||
self.update_offset = 0
|
||||
self.image_buttons = False
|
||||
self.result = None
|
||||
self.ok = None
|
||||
self.error = None
|
||||
self.get_updates_from_file = False
|
||||
|
||||
def get_me(self):
|
||||
url = self.tg_url_bot_general + self.key + "/getMe"
|
||||
me = self.http_get(url)
|
||||
return me
|
||||
|
||||
def get_updates(self):
|
||||
url = self.tg_url_bot_general + self.key + "/getUpdates"
|
||||
params = {"offset": self.update_offset}
|
||||
if self.debug:
|
||||
print_message(url)
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
if self.get_updates_from_file:
|
||||
print_message("Getting updated from file getUpdates.txt")
|
||||
self.result = json.loads("".join(file_read("getUpdates.txt")))
|
||||
if self.debug:
|
||||
print_message("Content of /getUpdates:")
|
||||
print_message(json.dumps(self.result))
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def send_message(self, to, message):
|
||||
url = self.tg_url_bot_general + self.key + "/sendMessage"
|
||||
message = "\n".join(message)
|
||||
params = {"chat_id": to, "text": message, "disable_web_page_preview": self.disable_web_page_preview,
|
||||
"disable_notification": self.disable_notification}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
if self.markdown or self.html:
|
||||
parse_mode = "HTML"
|
||||
if self.markdown:
|
||||
parse_mode = "Markdown"
|
||||
params["parse_mode"] = parse_mode
|
||||
if self.debug:
|
||||
print_message("Trying to /sendMessage:")
|
||||
print_message(url)
|
||||
print_message("post params: " + str(params))
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
if answer.status_code == 414:
|
||||
self.result = {"ok": False, "description": "414 URI Too Long"}
|
||||
else:
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def update_message(self, to, message_id, message):
|
||||
url = self.tg_url_bot_general + self.key + "/editMessageText"
|
||||
message = "\n".join(message)
|
||||
params = {"chat_id": to, "message_id": message_id, "text": message,
|
||||
"disable_web_page_preview": self.disable_web_page_preview,
|
||||
"disable_notification": self.disable_notification}
|
||||
if self.markdown or self.html:
|
||||
parse_mode = "HTML"
|
||||
if self.markdown:
|
||||
parse_mode = "Markdown"
|
||||
params["parse_mode"] = parse_mode
|
||||
if self.debug:
|
||||
print_message("Trying to /editMessageText:")
|
||||
print_message(url)
|
||||
print_message("post params: " + str(params))
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def send_photo(self, to, message, path):
|
||||
url = self.tg_url_bot_general + self.key + "/sendPhoto"
|
||||
message = "\n".join(message)
|
||||
if self.image_buttons:
|
||||
reply_markup = json.dumps({"inline_keyboard": [[
|
||||
{"text": "R", "callback_data": "graph_refresh"},
|
||||
{"text": "1h", "callback_data": "graph_period_3600"},
|
||||
{"text": "3h", "callback_data": "graph_period_10800"},
|
||||
{"text": "6h", "callback_data": "graph_period_21600"},
|
||||
{"text": "12h", "callback_data": "graph_period_43200"},
|
||||
{"text": "24h", "callback_data": "graph_period_86400"},
|
||||
], ]})
|
||||
else:
|
||||
reply_markup = json.dumps({})
|
||||
params = {"chat_id": to, "caption": message, "disable_notification": self.disable_notification,
|
||||
"reply_markup": reply_markup}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
files = {"photo": open(path, 'rb')}
|
||||
if self.debug:
|
||||
print_message("Trying to /sendPhoto:")
|
||||
print_message(url)
|
||||
print_message(params)
|
||||
print_message("files: " + str(files))
|
||||
answer = requests.post(url, params=params, files=files, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def send_txt(self, to, text, text_name=None):
|
||||
path = self.tmp_dir + "/" + "zbxtg_txt_"
|
||||
url = self.tg_url_bot_general + self.key + "/sendDocument"
|
||||
text = "\n".join(text)
|
||||
if not text_name:
|
||||
path += "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
|
||||
else:
|
||||
path += text_name
|
||||
path += ".txt"
|
||||
file_write(path, text)
|
||||
params = {"chat_id": to, "caption": path.split("/")[-1], "disable_notification": self.disable_notification}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
files = {"document": open(path, 'rb')}
|
||||
if self.debug:
|
||||
print_message("Trying to /sendDocument:")
|
||||
print_message(url)
|
||||
print_message(params)
|
||||
print_message("files: " + str(files))
|
||||
answer = requests.post(url, params=params, files=files, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def get_uid(self, name):
|
||||
uid = 0
|
||||
if self.debug:
|
||||
print_message("Getting uid from /getUpdates...")
|
||||
updates = self.get_updates()
|
||||
for m in updates["result"]:
|
||||
if "message" in m:
|
||||
chat = m["message"]["chat"]
|
||||
elif "edited_message" in m:
|
||||
chat = m["edited_message"]["chat"]
|
||||
else:
|
||||
continue
|
||||
if chat["type"] == self.type == "private":
|
||||
if "username" in chat:
|
||||
if chat["username"] == name:
|
||||
uid = chat["id"]
|
||||
if (chat["type"] == "group" or chat["type"] == "supergroup") and self.type == "group":
|
||||
if "title" in chat:
|
||||
if sys.version_info[0] < 3:
|
||||
if chat["title"] == name.decode("utf-8"):
|
||||
uid = chat["id"]
|
||||
else:
|
||||
if chat["title"] == name:
|
||||
uid = chat["id"]
|
||||
return uid
|
||||
|
||||
def error_need_to_contact(self, to):
|
||||
if self.type == "private":
|
||||
print_message("User '{0}' needs to send some text bot in private".format(to))
|
||||
if self.type == "group":
|
||||
print_message("You need start a conversation with your bot first in '{0}' group chat, type '/start@{1}'"
|
||||
.format(to, self.get_me()["result"]["username"]))
|
||||
|
||||
def update_cache_uid(self, name, uid, message="Add new string to cache file"):
|
||||
cache_string = "{0};{1};{2}\n".format(name, self.type, str(uid).rstrip())
|
||||
# FIXME
|
||||
if self.debug:
|
||||
print_message("{0}: {1}".format(message, cache_string))
|
||||
with open(self.tmp_uids, "a") as cache_file_uids:
|
||||
cache_file_uids.write(cache_string)
|
||||
return True
|
||||
|
||||
def get_uid_from_cache(self, name):
|
||||
if self.debug:
|
||||
print_message("Trying to read cached uid for {0}, {1}, from {2}".format(name, self.type, self.tmp_uids))
|
||||
uid = 0
|
||||
if os.path.isfile(self.tmp_uids):
|
||||
with open(self.tmp_uids, 'r') as cache_file_uids:
|
||||
cache_uids_old = cache_file_uids.readlines()
|
||||
for u in cache_uids_old:
|
||||
u_splitted = u.split(";")
|
||||
if name == u_splitted[0] and self.type == u_splitted[1]:
|
||||
uid = u_splitted[2]
|
||||
return uid
|
||||
|
||||
def send_location(self, to, coordinates):
|
||||
url = self.tg_url_bot_general + self.key + "/sendLocation"
|
||||
params = {"chat_id": to, "disable_notification": self.disable_notification,
|
||||
"latitude": coordinates["latitude"], "longitude": coordinates["longitude"]}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
if self.debug:
|
||||
print_message("Trying to /sendLocation:")
|
||||
print_message(url)
|
||||
print_message("post params: " + str(params))
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def answer_callback_query(self, callback_query_id, text=None):
|
||||
url = self.tg_url_bot_general + self.key + "/answerCallbackQuery"
|
||||
if not text:
|
||||
params = {"callback_query_id": callback_query_id}
|
||||
else:
|
||||
params = {"callback_query_id": callback_query_id, "text": text}
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def ok_update(self):
|
||||
self.ok = self.result["ok"]
|
||||
if self.ok:
|
||||
self.error = None
|
||||
else:
|
||||
self.error = self.result["description"]
|
||||
print_message(self.error)
|
||||
return True
|
||||
|
||||
|
||||
def markdown_fix(message, offset, emoji=False):
|
||||
offset = int(offset)
|
||||
if emoji: # https://github.com/ableev/Zabbix-in-Telegram/issues/152
|
||||
offset -= 2
|
||||
message = "\n".join(message)
|
||||
message = message[:offset] + message[offset+1:]
|
||||
message = message.split("\n")
|
||||
return message
|
||||
|
||||
|
||||
class ZabbixWeb:
|
||||
def __init__(self, server, username, password):
|
||||
self.debug = False
|
||||
self.server = server
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.proxies = {}
|
||||
self.verify = True
|
||||
self.cookie = None
|
||||
self.basic_auth_user = None
|
||||
self.basic_auth_pass = None
|
||||
self.tmp_dir = None
|
||||
|
||||
def login(self):
|
||||
if not self.verify:
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
data_api = {"name": self.username, "password": self.password, "enter": "Sign in"}
|
||||
answer = requests.post(self.server + "/", data=data_api, proxies=self.proxies, verify=self.verify,
|
||||
auth=requests.auth.HTTPBasicAuth(self.basic_auth_user, self.basic_auth_pass))
|
||||
cookie = answer.cookies
|
||||
if len(answer.history) > 1 and answer.history[0].status_code == 302:
|
||||
print_message("probably the server in your config file has not full URL (for example "
|
||||
"'{0}' instead of '{1}')".format(self.server, self.server + "/zabbix"))
|
||||
if not cookie:
|
||||
print_message("authorization has failed, url: {0}".format(self.server + "/"))
|
||||
cookie = None
|
||||
|
||||
self.cookie = cookie
|
||||
|
||||
def graph_get(self, itemid, period, title, width, height, version=3):
|
||||
file_img = self.tmp_dir + "/{0}.png".format("".join(itemid))
|
||||
|
||||
title = requests.utils.quote(title)
|
||||
|
||||
colors = {
|
||||
0: "00CC00",
|
||||
1: "CC0000",
|
||||
2: "0000CC",
|
||||
3: "CCCC00",
|
||||
4: "00CCCC",
|
||||
5: "CC00CC",
|
||||
}
|
||||
|
||||
drawtype = 5
|
||||
if len(itemid) > 1:
|
||||
drawtype = 2
|
||||
|
||||
zbx_img_url_itemids = []
|
||||
for i in range(0, len(itemid)):
|
||||
itemid_url = "&items[{0}][itemid]={1}&items[{0}][sortorder]={0}&" \
|
||||
"items[{0}][drawtype]={3}&items[{0}][color]={2}".format(i, itemid[i], colors[i], drawtype)
|
||||
zbx_img_url_itemids.append(itemid_url)
|
||||
|
||||
zbx_img_url = self.server + "/chart3.php?"
|
||||
if version < 4:
|
||||
zbx_img_url += "period={0}".format(period)
|
||||
else:
|
||||
zbx_img_url += "from=now-{0}&to=now".format(period)
|
||||
zbx_img_url += "&name={0}&width={1}&height={2}&graphtype=0&legend=1".format(title, width, height)
|
||||
zbx_img_url += "".join(zbx_img_url_itemids)
|
||||
|
||||
if self.debug:
|
||||
print_message(zbx_img_url)
|
||||
answer = requests.get(zbx_img_url, cookies=self.cookie, proxies=self.proxies, verify=self.verify,
|
||||
auth=requests.auth.HTTPBasicAuth(self.basic_auth_user, self.basic_auth_pass))
|
||||
status_code = answer.status_code
|
||||
if status_code == 404:
|
||||
print_message("can't get image from '{0}'".format(zbx_img_url))
|
||||
return False
|
||||
res_img = answer.content
|
||||
file_bwrite(file_img, res_img)
|
||||
return file_img
|
||||
|
||||
def api_test(self):
|
||||
headers = {'Content-type': 'application/json'}
|
||||
api_data = json.dumps({"jsonrpc": "2.0", "method": "user.login", "params":
|
||||
{"user": self.username, "password": self.password}, "id": 1})
|
||||
api_url = self.server + "/api_jsonrpc.php"
|
||||
api = requests.post(api_url, data=api_data, proxies=self.proxies, headers=headers)
|
||||
return api.text
|
||||
|
||||
|
||||
def print_message(message):
|
||||
message = str(message) + "\n"
|
||||
filename = sys.argv[0].split("/")[-1]
|
||||
sys.stderr.write(filename + ": " + message)
|
||||
|
||||
|
||||
def list_cut(elements, symbols_limit):
|
||||
symbols_count = symbols_count_now = 0
|
||||
elements_new = []
|
||||
element_last_list = []
|
||||
for e in elements:
|
||||
symbols_count_now = symbols_count + len(e)
|
||||
if symbols_count_now > symbols_limit:
|
||||
limit_idx = symbols_limit - symbols_count
|
||||
e_list = list(e)
|
||||
for idx, ee in enumerate(e_list):
|
||||
if idx < limit_idx:
|
||||
element_last_list.append(ee)
|
||||
else:
|
||||
break
|
||||
break
|
||||
else:
|
||||
symbols_count = symbols_count_now + 1
|
||||
elements_new.append(e)
|
||||
if symbols_count_now < symbols_limit:
|
||||
return elements, False
|
||||
else:
|
||||
element_last = "".join(element_last_list)
|
||||
elements_new.append(element_last)
|
||||
return elements_new, True
|
||||
|
||||
|
||||
class Maps:
|
||||
# https://developers.google.com/maps/documentation/geocoding/intro
|
||||
def __init__(self):
|
||||
self.key = None
|
||||
self.proxies = {}
|
||||
|
||||
def get_coordinates_by_address(self, address):
|
||||
coordinates = {"latitude": 0, "longitude": 0}
|
||||
url_api = "https://maps.googleapis.com/maps/api/geocode/json?key={0}&address={1}".format(self.key, address)
|
||||
url = url_api
|
||||
answer = requests.get(url, proxies=self.proxies)
|
||||
result = answer.json()
|
||||
try:
|
||||
coordinates_dict = result["results"][0]["geometry"]["location"]
|
||||
except:
|
||||
if "error_message" in result:
|
||||
print_message("[" + result["status"] + "]: " + result["error_message"])
|
||||
return coordinates
|
||||
coordinates = {"latitude": coordinates_dict["lat"], "longitude": coordinates_dict["lng"]}
|
||||
return coordinates
|
||||
|
||||
|
||||
def file_write(filename, text):
|
||||
with open(filename, "w") as fd:
|
||||
fd.write(str(text))
|
||||
return True
|
||||
|
||||
|
||||
def file_bwrite(filename, data):
|
||||
with open(filename, "wb") as fd:
|
||||
fd.write(data)
|
||||
return True
|
||||
|
||||
|
||||
def file_read(filename):
|
||||
with open(filename, "r") as fd:
|
||||
text = fd.readlines()
|
||||
return text
|
||||
|
||||
|
||||
def file_append(filename, text):
|
||||
with open(filename, "a") as fd:
|
||||
fd.write(str(text))
|
||||
return True
|
||||
|
||||
|
||||
def external_image_get(url, tmp_dir, timeout=6):
|
||||
image_hash = hashlib.md5()
|
||||
image_hash.update(url.encode())
|
||||
file_img = tmp_dir + "/external_{0}.png".format(image_hash.hexdigest())
|
||||
try:
|
||||
answer = requests.get(url, timeout=timeout, allow_redirects=True)
|
||||
except requests.exceptions.ReadTimeout as ex:
|
||||
print_message("Can't get external image from '{0}': timeout".format(url))
|
||||
return False
|
||||
status_code = answer.status_code
|
||||
if status_code == 404:
|
||||
print_message("Can't get external image from '{0}': HTTP 404 error".format(url))
|
||||
return False
|
||||
answer_image = answer.content
|
||||
file_bwrite(file_img, answer_image)
|
||||
return file_img
|
||||
|
||||
|
||||
def age2sec(age_str):
|
||||
age_sec = 0
|
||||
age_regex = "([0-9]+d)?\s?([0-9]+h)?\s?([0-9]+m)?"
|
||||
age_pattern = re.compile(age_regex)
|
||||
intervals = age_pattern.match(age_str).groups()
|
||||
for i in intervals:
|
||||
if i:
|
||||
metric = i[-1]
|
||||
if metric == "d":
|
||||
age_sec += int(i[0:-1])*86400
|
||||
if metric == "h":
|
||||
age_sec += int(i[0:-1])*3600
|
||||
if metric == "m":
|
||||
age_sec += int(i[0:-1])*60
|
||||
return age_sec
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
tmp_dir = zbxtg_settings.zbx_tg_tmp_dir
|
||||
if tmp_dir == "/tmp/" + zbxtg_settings.zbx_tg_prefix:
|
||||
print_message("WARNING: it is strongly recommended to change `zbx_tg_tmp_dir` variable in config!!!")
|
||||
print_message("https://github.com/ableev/Zabbix-in-Telegram/wiki/Change-zbx_tg_tmp_dir-in-settings")
|
||||
|
||||
tmp_cookie = tmp_dir + "/cookie.py.txt"
|
||||
tmp_uids = tmp_dir + "/uids.txt"
|
||||
tmp_need_update = False # do we need to update cache file with uids or not
|
||||
|
||||
rnd = random.randint(0, 999)
|
||||
ts = time.time()
|
||||
hash_ts = str(ts) + "." + str(rnd)
|
||||
|
||||
log_file = "/dev/null"
|
||||
|
||||
args = sys.argv
|
||||
|
||||
settings = {
|
||||
"zbxtg_itemid": "0", # itemid for graph
|
||||
"zbxtg_title": None, # title for graph
|
||||
"zbxtg_image_period": None,
|
||||
"zbxtg_image_age": "3600",
|
||||
"zbxtg_image_width": "900",
|
||||
"zbxtg_image_height": "200",
|
||||
"tg_method_image": False, # if True - default send images, False - send text
|
||||
"tg_chat": False, # send message to chat or in private
|
||||
"tg_group": False, # send message to chat or in private
|
||||
"is_debug": False,
|
||||
"is_channel": False,
|
||||
"disable_web_page_preview": False,
|
||||
"location": None, # address
|
||||
"lat": 0, # latitude
|
||||
"lon": 0, # longitude
|
||||
"is_single_message": False,
|
||||
"markdown": False,
|
||||
"html": False,
|
||||
"signature": None,
|
||||
"signature_disable": False,
|
||||
"graph_buttons": False,
|
||||
"extimg": None,
|
||||
"to": None,
|
||||
"to_group": None,
|
||||
"forked": False,
|
||||
}
|
||||
|
||||
url_github = "https://github.com/ableev/Zabbix-in-Telegram"
|
||||
url_wiki_base = "https://github.com/ableev/Zabbix-in-Telegram/wiki"
|
||||
url_tg_group = "https://t.me/ZbxTg"
|
||||
url_tg_channel = "https://t.me/Zabbix_in_Telegram"
|
||||
|
||||
settings_description = {
|
||||
"itemid": {"name": "zbxtg_itemid", "type": "list",
|
||||
"help": "script will attach a graph with that itemid (could be multiple)", "url": "Graphs"},
|
||||
"title": {"name": "zbxtg_title", "type": "str", "help": "title for attached graph", "url": "Graphs"},
|
||||
"graphs_period": {"name": "zbxtg_image_period", "type": "int", "help": "graph period", "url": "Graphs"},
|
||||
"graphs_age": {"name": "zbxtg_image_age", "type": "str", "help": "graph period as age", "url": "Graphs"},
|
||||
"graphs_width": {"name": "zbxtg_image_width", "type": "int", "help": "graph width", "url": "Graphs"},
|
||||
"graphs_height": {"name": "zbxtg_image_height", "type": "int", "help": "graph height", "url": "Graphs"},
|
||||
"graphs": {"name": "tg_method_image", "type": "bool", "help": "enables graph sending", "url": "Graphs"},
|
||||
"chat": {"name": "tg_chat", "type": "bool", "help": "deprecated, don't use it, see 'group'",
|
||||
"url": "How-to-send-message-to-the-group-chat"},
|
||||
"group": {"name": "tg_group", "type": "bool", "help": "sends message to a group",
|
||||
"url": "How-to-send-message-to-the-group-chat"},
|
||||
"debug": {"name": "is_debug", "type": "bool", "help": "enables 'debug'",
|
||||
"url": "How-to-test-script-in-command-line"},
|
||||
"channel": {"name": "is_channel", "type": "bool", "help": "sends message to a channel",
|
||||
"url": "Channel-support"},
|
||||
"disable_web_page_preview": {"name": "disable_web_page_preview", "type": "bool",
|
||||
"help": "disable web page preview", "url": "Disable-web-page-preview"},
|
||||
"location": {"name": "location", "type": "str", "help": "address of location", "url": "Location"},
|
||||
"lat": {"name": "lat", "type": "str", "help": "specify latitude (and lon too!)", "url": "Location"},
|
||||
"lon": {"name": "lon", "type": "str", "help": "specify longitude (and lat too!)", "url": "Location"},
|
||||
"single_message": {"name": "is_single_message", "type": "bool", "help": "do not split message and graph",
|
||||
"url": "Why-am-I-getting-two-messages-instead-of-one"},
|
||||
"markdown": {"name": "markdown", "type": "bool", "help": "markdown support", "url": "Markdown-and-HTML"},
|
||||
"html": {"name": "html", "type": "bool", "help": "markdown support", "url": "Markdown-and-HTML"},
|
||||
"signature": {"name": "signature", "type": "str",
|
||||
"help": "bot's signature", "url": "Bot-signature"},
|
||||
"signature_disable": {"name": "signature_disable", "type": "bool",
|
||||
"help": "enables/disables bot's signature", "url": "Bot-signature"},
|
||||
"graph_buttons": {"name": "graph_buttons", "type": "bool",
|
||||
"help": "activates buttons under graph, could be using in ZbxTgDaemon",
|
||||
"url": "Interactive-bot"},
|
||||
"external_image": {"name": "extimg", "type": "str",
|
||||
"help": "should be url; attaches external image from different source",
|
||||
"url": "External-image-as-graph"},
|
||||
"to": {"name": "to", "type": "str", "help": "rewrite zabbix username, use that instead of arguments",
|
||||
"url": "Custom-to-and-to_group"},
|
||||
"to_group": {"name": "to_group", "type": "str",
|
||||
"help": "rewrite zabbix username, use that instead of arguments", "url": "Custom-to-and-to_group"},
|
||||
"forked": {"name": "forked", "type": "bool", "help": "internal variable, do not use it. Ever.", "url": ""},
|
||||
}
|
||||
|
||||
if len(args) < 4:
|
||||
do_not_exit = False
|
||||
if "--features" in args:
|
||||
print(("List of available settings, see {0}/Settings\n---".format(url_wiki_base)))
|
||||
for sett, proprt in list(settings_description.items()):
|
||||
print(("{0}: {1}\ndoc: {2}/{3}\n--".format(sett, proprt["help"], url_wiki_base, proprt["url"])))
|
||||
|
||||
elif "--show-settings" in args:
|
||||
do_not_exit = True
|
||||
print_message("Settings: " + str(json.dumps(settings, indent=2)))
|
||||
|
||||
else:
|
||||
print(("Hi. You should provide at least three arguments.\n"
|
||||
"zbxtg.py [TO] [SUBJECT] [BODY]\n\n"
|
||||
"1. Read main page and/or wiki: {0} + {1}\n"
|
||||
"2. Public Telegram group (discussion): {2}\n"
|
||||
"3. Public Telegram channel: {3}\n"
|
||||
"4. Try dev branch for test purposes (new features, etc): {0}/tree/dev"
|
||||
.format(url_github, url_wiki_base, url_tg_group, url_tg_channel)))
|
||||
if not do_not_exit:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
zbx_to = args[1]
|
||||
zbx_subject = args[2]
|
||||
zbx_body = args[3]
|
||||
|
||||
tg = TelegramAPI(key=zbxtg_settings.tg_key)
|
||||
|
||||
tg.tmp_dir = tmp_dir
|
||||
tg.tmp_uids = tmp_uids
|
||||
|
||||
if zbxtg_settings.proxy_to_tg:
|
||||
proxy_to_tg = zbxtg_settings.proxy_to_tg
|
||||
if not proxy_to_tg.find("http") and not proxy_to_tg.find("socks"):
|
||||
proxy_to_tg = "https://" + proxy_to_tg
|
||||
tg.proxies = {
|
||||
"https": "{0}".format(proxy_to_tg),
|
||||
}
|
||||
|
||||
zbx = ZabbixWeb(server=zbxtg_settings.zbx_server, username=zbxtg_settings.zbx_api_user,
|
||||
password=zbxtg_settings.zbx_api_pass)
|
||||
|
||||
zbx.tmp_dir = tmp_dir
|
||||
|
||||
# workaround for Zabbix 4.x
|
||||
zbx_version = 3
|
||||
|
||||
try:
|
||||
zbx_version = zbxtg_settings.zbx_server_version
|
||||
except:
|
||||
pass
|
||||
|
||||
if zbxtg_settings.proxy_to_zbx:
|
||||
zbx.proxies = {
|
||||
"http": "http://{0}/".format(zbxtg_settings.proxy_to_zbx),
|
||||
"https": "https://{0}/".format(zbxtg_settings.proxy_to_zbx)
|
||||
}
|
||||
|
||||
# https://github.com/ableev/Zabbix-in-Telegram/issues/55
|
||||
try:
|
||||
if zbxtg_settings.zbx_basic_auth:
|
||||
zbx.basic_auth_user = zbxtg_settings.zbx_basic_auth_user
|
||||
zbx.basic_auth_pass = zbxtg_settings.zbx_basic_auth_pass
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
zbx_api_verify = zbxtg_settings.zbx_api_verify
|
||||
zbx.verify = zbx_api_verify
|
||||
except:
|
||||
pass
|
||||
|
||||
map = Maps()
|
||||
# api key to resolve address to coordinates via google api
|
||||
try:
|
||||
if zbxtg_settings.google_maps_api_key:
|
||||
map.key = zbxtg_settings.google_maps_api_key
|
||||
if zbxtg_settings.proxy_to_tg:
|
||||
map.proxies = {
|
||||
"http": "http://{0}/".format(zbxtg_settings.proxy_to_tg),
|
||||
"https": "https://{0}/".format(zbxtg_settings.proxy_to_tg)
|
||||
}
|
||||
except:
|
||||
pass
|
||||
|
||||
zbxtg_body = (zbx_subject + "\n" + zbx_body).splitlines()
|
||||
zbxtg_body_text = []
|
||||
|
||||
for line in zbxtg_body:
|
||||
if line.find(zbxtg_settings.zbx_tg_prefix) > -1:
|
||||
setting = re.split("[\s:=]+", line, maxsplit=1)
|
||||
key = setting[0].replace(zbxtg_settings.zbx_tg_prefix + ";", "")
|
||||
if key not in settings_description:
|
||||
if "--debug" in args:
|
||||
print_message("[ERROR] There is no '{0}' method, use --features to get help".format(key))
|
||||
continue
|
||||
if settings_description[key]["type"] == "list":
|
||||
value = setting[1].split(",")
|
||||
elif len(setting) > 1 and len(setting[1]) > 0:
|
||||
value = setting[1]
|
||||
elif settings_description[key]["type"] == "bool":
|
||||
value = True
|
||||
else:
|
||||
value = settings[settings_description[key]["name"]]
|
||||
if key in settings_description:
|
||||
settings[settings_description[key]["name"]] = value
|
||||
else:
|
||||
zbxtg_body_text.append(line)
|
||||
|
||||
tg_method_image = bool(settings["tg_method_image"])
|
||||
tg_chat = bool(settings["tg_chat"])
|
||||
tg_group = bool(settings["tg_group"])
|
||||
is_debug = bool(settings["is_debug"])
|
||||
is_channel = bool(settings["is_channel"])
|
||||
disable_web_page_preview = bool(settings["disable_web_page_preview"])
|
||||
is_single_message = bool(settings["is_single_message"])
|
||||
|
||||
# experimental way to send message to the group https://github.com/ableev/Zabbix-in-Telegram/issues/15
|
||||
if args[0].split("/")[-1] == "zbxtg_group.py" or "--group" in args or tg_chat or tg_group:
|
||||
tg_chat = True
|
||||
tg_group = True
|
||||
tg.type = "group"
|
||||
|
||||
if "--debug" in args or is_debug:
|
||||
is_debug = True
|
||||
tg.debug = True
|
||||
zbx.debug = True
|
||||
print_message(tg.get_me())
|
||||
print_message("Cache file with uids: " + tg.tmp_uids)
|
||||
log_file = tmp_dir + ".debug." + hash_ts + ".log"
|
||||
#print_message(log_file)
|
||||
|
||||
if "--markdown" in args or settings["markdown"]:
|
||||
tg.markdown = True
|
||||
|
||||
if "--html" in args or settings["html"]:
|
||||
tg.html = True
|
||||
|
||||
if "--channel" in args or is_channel:
|
||||
tg.type = "channel"
|
||||
|
||||
if "--disable_web_page_preview" in args or disable_web_page_preview:
|
||||
if is_debug:
|
||||
print_message("'disable_web_page_preview' option has been enabled")
|
||||
tg.disable_web_page_preview = True
|
||||
|
||||
if "--graph_buttons" in args or settings["graph_buttons"]:
|
||||
tg.image_buttons = True
|
||||
|
||||
if "--forked" in args:
|
||||
settings["forked"] = True
|
||||
|
||||
if "--tg-key" in args:
|
||||
tg.key = args[args.index("--tg-key") + 1]
|
||||
|
||||
location_coordinates = {"latitude": None, "longitude": None}
|
||||
if settings["lat"] > 0 and settings["lat"] > 0:
|
||||
location_coordinates = {"latitude": settings["lat"], "longitude": settings["lon"]}
|
||||
tg.location = location_coordinates
|
||||
else:
|
||||
if settings["location"]:
|
||||
location_coordinates = map.get_coordinates_by_address(settings["location"])
|
||||
if location_coordinates:
|
||||
settings["lat"] = location_coordinates["latitude"]
|
||||
settings["lon"] = location_coordinates["longitude"]
|
||||
tg.location = location_coordinates
|
||||
|
||||
if not os.path.isdir(tmp_dir):
|
||||
if is_debug:
|
||||
print_message("Tmp dir doesn't exist, creating new one...")
|
||||
try:
|
||||
os.makedirs(tmp_dir)
|
||||
open(tg.tmp_uids, "a").close()
|
||||
os.chmod(tmp_dir, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
|
||||
os.chmod(tg.tmp_uids, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
|
||||
except:
|
||||
tmp_dir = "/tmp"
|
||||
if is_debug:
|
||||
print_message("Using {0} as a temporary dir".format(tmp_dir))
|
||||
|
||||
done_all_work_in_the_fork = False
|
||||
# issue75
|
||||
|
||||
to_types = ["to", "to_group", "to_channel"]
|
||||
to_types_to_telegram = {"to": "private", "to_group": "group", "to_channel": "channel"}
|
||||
multiple_to = {}
|
||||
for i in to_types:
|
||||
multiple_to[i]=[]
|
||||
|
||||
for t in to_types:
|
||||
try:
|
||||
if settings[t] and not settings["forked"]:
|
||||
# zbx_to = settings["to"]
|
||||
multiple_to[t] = re.split(",", settings[t])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# example:
|
||||
# {'to_channel': [], 'to': ['usr1', 'usr2', 'usr3'], 'to_group': []}
|
||||
|
||||
if (sum([len(v) for k, v in list(multiple_to.items())])) == 1:
|
||||
# if we have only one recipient, we don't need fork to send message, just re-write "to" vaiable
|
||||
tmp_max = 0
|
||||
for t in to_types:
|
||||
if len(multiple_to[t]) > tmp_max:
|
||||
tmp_max = len(multiple_to[t])
|
||||
tg.type = to_types_to_telegram[t]
|
||||
zbx_to = multiple_to[t][0]
|
||||
else:
|
||||
for t in to_types:
|
||||
for i in multiple_to[t]:
|
||||
args_new = list(args)
|
||||
args_new[1] = i
|
||||
if t == "to_group":
|
||||
args_new.append("--group")
|
||||
args_new.append("--forked")
|
||||
args_new.insert(0, sys.executable)
|
||||
if is_debug:
|
||||
print_message("Fork for custom recipient ({1}), new args: {0}".format(args_new,
|
||||
to_types_to_telegram[t]))
|
||||
subprocess.call(args_new)
|
||||
done_all_work_in_the_fork = True
|
||||
|
||||
if done_all_work_in_the_fork:
|
||||
sys.exit(0)
|
||||
|
||||
uid = None
|
||||
|
||||
if tg.type == "channel":
|
||||
uid = zbx_to
|
||||
if tg.type == "private":
|
||||
zbx_to = zbx_to.replace("@", "")
|
||||
|
||||
if zbx_to.isdigit():
|
||||
uid = zbx_to
|
||||
|
||||
if not uid:
|
||||
uid = tg.get_uid_from_cache(zbx_to)
|
||||
|
||||
if not uid:
|
||||
uid = tg.get_uid(zbx_to)
|
||||
if uid:
|
||||
tmp_need_update = True
|
||||
if not uid:
|
||||
tg.error_need_to_contact(zbx_to)
|
||||
sys.exit(1)
|
||||
|
||||
if tmp_need_update:
|
||||
tg.update_cache_uid(zbx_to, str(uid).rstrip())
|
||||
|
||||
if is_debug:
|
||||
print_message("Telegram uid of {0} '{1}': {2}".format(tg.type, zbx_to, uid))
|
||||
|
||||
# add signature, turned off by default, you can turn it on in config
|
||||
try:
|
||||
if "--signature" in args or settings["signature"] or zbxtg_settings.zbx_tg_signature\
|
||||
and not "--signature_disable" in args and not settings["signature_disable"]:
|
||||
if "--signature" in args:
|
||||
settings["signature"] = args[args.index("--signature") + 1]
|
||||
if not settings["signature"]:
|
||||
settings["signature"] = zbxtg_settings.zbx_server
|
||||
zbxtg_body_text.append("--")
|
||||
zbxtg_body_text.append(settings["signature"])
|
||||
except:
|
||||
pass
|
||||
|
||||
# replace text with emojis
|
||||
internal_using_emoji = False # I hate that, but... https://github.com/ableev/Zabbix-in-Telegram/issues/152
|
||||
if hasattr(zbxtg_settings, "emoji_map"):
|
||||
zbxtg_body_text_emoji_support = []
|
||||
for l in zbxtg_body_text:
|
||||
l_new = l
|
||||
for k, v in list(zbxtg_settings.emoji_map.items()):
|
||||
l_new = l_new.replace("{{" + k + "}}", v)
|
||||
zbxtg_body_text_emoji_support.append(l_new)
|
||||
if len("".join(zbxtg_body_text)) - len("".join(zbxtg_body_text_emoji_support)):
|
||||
internal_using_emoji = True
|
||||
zbxtg_body_text = zbxtg_body_text_emoji_support
|
||||
|
||||
if not is_single_message:
|
||||
tg.send_message(uid, zbxtg_body_text)
|
||||
if not tg.ok:
|
||||
# first case – if group has been migrated to a supergroup, we need to update chat_id of that group
|
||||
if tg.error.find("migrated") > -1 and tg.error.find("supergroup") > -1:
|
||||
migrate_to_chat_id = tg.result["parameters"]["migrate_to_chat_id"]
|
||||
tg.update_cache_uid(zbx_to, migrate_to_chat_id, message="Group chat is migrated to supergroup, "
|
||||
"updating cache file")
|
||||
uid = migrate_to_chat_id
|
||||
tg.send_message(uid, zbxtg_body_text)
|
||||
|
||||
# another case if markdown is enabled and we got parse error, try to remove "bad" symbols from message
|
||||
if tg.markdown and tg.error.find("Can't find end of the entity starting at byte offset") > -1:
|
||||
markdown_warning = "Original message has been fixed due to {0}. " \
|
||||
"Please, fix the markdown, it's slowing down messages sending."\
|
||||
.format(url_wiki_base + "/" + settings_description["markdown"]["url"])
|
||||
markdown_fix_attempts = 0
|
||||
while not tg.ok and markdown_fix_attempts != 3:
|
||||
offset = re.search("Can't find end of the entity starting at byte offset ([0-9]+)", tg.error).group(1)
|
||||
zbxtg_body_text = markdown_fix(zbxtg_body_text, offset, emoji=internal_using_emoji) + \
|
||||
["\n"] + [markdown_warning]
|
||||
tg.disable_web_page_preview = True
|
||||
tg.send_message(uid, zbxtg_body_text)
|
||||
markdown_fix_attempts += 1
|
||||
if tg.ok:
|
||||
print_message(markdown_warning)
|
||||
|
||||
if is_debug:
|
||||
print((tg.result))
|
||||
|
||||
if settings["zbxtg_image_age"]:
|
||||
age_sec = age2sec(settings["zbxtg_image_age"])
|
||||
if age_sec > 0 and age_sec > 3600:
|
||||
settings["zbxtg_image_period"] = age_sec
|
||||
|
||||
message_id = 0
|
||||
if tg_method_image:
|
||||
zbx.login()
|
||||
if not zbx.cookie:
|
||||
text_warn = "Login to Zabbix web UI has failed (web url, user or password are incorrect), "\
|
||||
"unable to send graphs check manually"
|
||||
tg.send_message(uid, [text_warn])
|
||||
print_message(text_warn)
|
||||
else:
|
||||
if not settings["extimg"]:
|
||||
zbxtg_file_img = zbx.graph_get(settings["zbxtg_itemid"], settings["zbxtg_image_period"],
|
||||
settings["zbxtg_title"], settings["zbxtg_image_width"],
|
||||
settings["zbxtg_image_height"], version=zbx_version)
|
||||
else:
|
||||
zbxtg_file_img = external_image_get(settings["extimg"], tmp_dir=zbx.tmp_dir)
|
||||
zbxtg_body_text, is_modified = list_cut(zbxtg_body_text, 200)
|
||||
if tg.ok:
|
||||
message_id = tg.result["result"]["message_id"]
|
||||
tg.reply_to_message_id = message_id
|
||||
if not zbxtg_file_img:
|
||||
text_warn = "Can't get graph image, check script manually, see logs, or disable graphs"
|
||||
tg.send_message(uid, [text_warn])
|
||||
print_message(text_warn)
|
||||
else:
|
||||
if not is_single_message:
|
||||
zbxtg_body_text = ""
|
||||
else:
|
||||
if is_modified:
|
||||
text_warn = "probably you will see MEDIA_CAPTION_TOO_LONG error, "\
|
||||
"the message has been cut to 200 symbols, "\
|
||||
"https://github.com/ableev/Zabbix-in-Telegram/issues/9"\
|
||||
"#issuecomment-166895044"
|
||||
print_message(text_warn)
|
||||
if not is_single_message:
|
||||
tg.disable_notification = True
|
||||
tg.send_photo(uid, zbxtg_body_text, zbxtg_file_img)
|
||||
if tg.ok:
|
||||
settings["zbxtg_body_text"] = zbxtg_body_text
|
||||
os.remove(zbxtg_file_img)
|
||||
else:
|
||||
if tg.error.find("PHOTO_INVALID_DIMENSIONS") > -1:
|
||||
if not tg.disable_web_page_preview:
|
||||
tg.disable_web_page_preview = True
|
||||
text_warn = "Zabbix user couldn't get graph (probably has no rights to get data from host), " \
|
||||
"check script manually, see {0}".format(url_wiki_base + "/" +
|
||||
settings_description["graphs"]["url"])
|
||||
tg.send_message(uid, [text_warn])
|
||||
print_message(text_warn)
|
||||
if tg.location and location_coordinates["latitude"] and location_coordinates["longitude"]:
|
||||
tg.reply_to_message_id = message_id
|
||||
tg.disable_notification = True
|
||||
tg.send_location(to=uid, coordinates=location_coordinates)
|
||||
|
||||
if "--show-settings" in args:
|
||||
print_message("Settings: " + str(json.dumps(settings, indent=2)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
939
root/var/lib/zabbix/bin/zbxtg_group.py
Normal file
939
root/var/lib/zabbix/bin/zbxtg_group.py
Normal file
@ -0,0 +1,939 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
import stat
|
||||
import hashlib
|
||||
import subprocess
|
||||
#import sqlite3
|
||||
from os.path import dirname
|
||||
import zbxtg_settings
|
||||
|
||||
|
||||
class Cache:
|
||||
def __init__(self, database):
|
||||
self.database = database
|
||||
|
||||
def create_db(self, database):
|
||||
pass
|
||||
|
||||
|
||||
class TelegramAPI:
|
||||
tg_url_bot_general = "https://api.telegram.org/bot"
|
||||
|
||||
def http_get(self, url):
|
||||
answer = requests.get(url, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def __init__(self, key):
|
||||
self.debug = False
|
||||
self.key = key
|
||||
self.proxies = {}
|
||||
self.type = "private" # 'private' for private chats or 'group' for group chats
|
||||
self.markdown = False
|
||||
self.html = False
|
||||
self.disable_web_page_preview = False
|
||||
self.disable_notification = False
|
||||
self.reply_to_message_id = 0
|
||||
self.tmp_dir = None
|
||||
self.tmp_uids = None
|
||||
self.location = {"latitude": None, "longitude": None}
|
||||
self.update_offset = 0
|
||||
self.image_buttons = False
|
||||
self.result = None
|
||||
self.ok = None
|
||||
self.error = None
|
||||
self.get_updates_from_file = False
|
||||
|
||||
def get_me(self):
|
||||
url = self.tg_url_bot_general + self.key + "/getMe"
|
||||
me = self.http_get(url)
|
||||
return me
|
||||
|
||||
def get_updates(self):
|
||||
url = self.tg_url_bot_general + self.key + "/getUpdates"
|
||||
params = {"offset": self.update_offset}
|
||||
if self.debug:
|
||||
print_message(url)
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
if self.get_updates_from_file:
|
||||
print_message("Getting updated from file getUpdates.txt")
|
||||
self.result = json.loads("".join(file_read("getUpdates.txt")))
|
||||
if self.debug:
|
||||
print_message("Content of /getUpdates:")
|
||||
print_message(json.dumps(self.result))
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def send_message(self, to, message):
|
||||
url = self.tg_url_bot_general + self.key + "/sendMessage"
|
||||
message = "\n".join(message)
|
||||
params = {"chat_id": to, "text": message, "disable_web_page_preview": self.disable_web_page_preview,
|
||||
"disable_notification": self.disable_notification}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
if self.markdown or self.html:
|
||||
parse_mode = "HTML"
|
||||
if self.markdown:
|
||||
parse_mode = "Markdown"
|
||||
params["parse_mode"] = parse_mode
|
||||
if self.debug:
|
||||
print_message("Trying to /sendMessage:")
|
||||
print_message(url)
|
||||
print_message("post params: " + str(params))
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
if answer.status_code == 414:
|
||||
self.result = {"ok": False, "description": "414 URI Too Long"}
|
||||
else:
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def update_message(self, to, message_id, message):
|
||||
url = self.tg_url_bot_general + self.key + "/editMessageText"
|
||||
message = "\n".join(message)
|
||||
params = {"chat_id": to, "message_id": message_id, "text": message,
|
||||
"disable_web_page_preview": self.disable_web_page_preview,
|
||||
"disable_notification": self.disable_notification}
|
||||
if self.markdown or self.html:
|
||||
parse_mode = "HTML"
|
||||
if self.markdown:
|
||||
parse_mode = "Markdown"
|
||||
params["parse_mode"] = parse_mode
|
||||
if self.debug:
|
||||
print_message("Trying to /editMessageText:")
|
||||
print_message(url)
|
||||
print_message("post params: " + str(params))
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def send_photo(self, to, message, path):
|
||||
url = self.tg_url_bot_general + self.key + "/sendPhoto"
|
||||
message = "\n".join(message)
|
||||
if self.image_buttons:
|
||||
reply_markup = json.dumps({"inline_keyboard": [[
|
||||
{"text": "R", "callback_data": "graph_refresh"},
|
||||
{"text": "1h", "callback_data": "graph_period_3600"},
|
||||
{"text": "3h", "callback_data": "graph_period_10800"},
|
||||
{"text": "6h", "callback_data": "graph_period_21600"},
|
||||
{"text": "12h", "callback_data": "graph_period_43200"},
|
||||
{"text": "24h", "callback_data": "graph_period_86400"},
|
||||
], ]})
|
||||
else:
|
||||
reply_markup = json.dumps({})
|
||||
params = {"chat_id": to, "caption": message, "disable_notification": self.disable_notification,
|
||||
"reply_markup": reply_markup}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
files = {"photo": open(path, 'rb')}
|
||||
if self.debug:
|
||||
print_message("Trying to /sendPhoto:")
|
||||
print_message(url)
|
||||
print_message(params)
|
||||
print_message("files: " + str(files))
|
||||
answer = requests.post(url, params=params, files=files, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def send_txt(self, to, text, text_name=None):
|
||||
path = self.tmp_dir + "/" + "zbxtg_txt_"
|
||||
url = self.tg_url_bot_general + self.key + "/sendDocument"
|
||||
text = "\n".join(text)
|
||||
if not text_name:
|
||||
path += "".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
|
||||
else:
|
||||
path += text_name
|
||||
path += ".txt"
|
||||
file_write(path, text)
|
||||
params = {"chat_id": to, "caption": path.split("/")[-1], "disable_notification": self.disable_notification}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
files = {"document": open(path, 'rb')}
|
||||
if self.debug:
|
||||
print_message("Trying to /sendDocument:")
|
||||
print_message(url)
|
||||
print_message(params)
|
||||
print_message("files: " + str(files))
|
||||
answer = requests.post(url, params=params, files=files, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def get_uid(self, name):
|
||||
uid = 0
|
||||
if self.debug:
|
||||
print_message("Getting uid from /getUpdates...")
|
||||
updates = self.get_updates()
|
||||
for m in updates["result"]:
|
||||
if "message" in m:
|
||||
chat = m["message"]["chat"]
|
||||
elif "edited_message" in m:
|
||||
chat = m["edited_message"]["chat"]
|
||||
else:
|
||||
continue
|
||||
if chat["type"] == self.type == "private":
|
||||
if "username" in chat:
|
||||
if chat["username"] == name:
|
||||
uid = chat["id"]
|
||||
if (chat["type"] == "group" or chat["type"] == "supergroup") and self.type == "group":
|
||||
if "title" in chat:
|
||||
if sys.version_info[0] < 3:
|
||||
if chat["title"] == name.decode("utf-8"):
|
||||
uid = chat["id"]
|
||||
else:
|
||||
if chat["title"] == name:
|
||||
uid = chat["id"]
|
||||
return uid
|
||||
|
||||
def error_need_to_contact(self, to):
|
||||
if self.type == "private":
|
||||
print_message("User '{0}' needs to send some text bot in private".format(to))
|
||||
if self.type == "group":
|
||||
print_message("You need start a conversation with your bot first in '{0}' group chat, type '/start@{1}'"
|
||||
.format(to, self.get_me()["result"]["username"]))
|
||||
|
||||
def update_cache_uid(self, name, uid, message="Add new string to cache file"):
|
||||
cache_string = "{0};{1};{2}\n".format(name, self.type, str(uid).rstrip())
|
||||
# FIXME
|
||||
if self.debug:
|
||||
print_message("{0}: {1}".format(message, cache_string))
|
||||
with open(self.tmp_uids, "a") as cache_file_uids:
|
||||
cache_file_uids.write(cache_string)
|
||||
return True
|
||||
|
||||
def get_uid_from_cache(self, name):
|
||||
if self.debug:
|
||||
print_message("Trying to read cached uid for {0}, {1}, from {2}".format(name, self.type, self.tmp_uids))
|
||||
uid = 0
|
||||
if os.path.isfile(self.tmp_uids):
|
||||
with open(self.tmp_uids, 'r') as cache_file_uids:
|
||||
cache_uids_old = cache_file_uids.readlines()
|
||||
for u in cache_uids_old:
|
||||
u_splitted = u.split(";")
|
||||
if name == u_splitted[0] and self.type == u_splitted[1]:
|
||||
uid = u_splitted[2]
|
||||
return uid
|
||||
|
||||
def send_location(self, to, coordinates):
|
||||
url = self.tg_url_bot_general + self.key + "/sendLocation"
|
||||
params = {"chat_id": to, "disable_notification": self.disable_notification,
|
||||
"latitude": coordinates["latitude"], "longitude": coordinates["longitude"]}
|
||||
if self.reply_to_message_id:
|
||||
params["reply_to_message_id"] = self.reply_to_message_id
|
||||
if self.debug:
|
||||
print_message("Trying to /sendLocation:")
|
||||
print_message(url)
|
||||
print_message("post params: " + str(params))
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def answer_callback_query(self, callback_query_id, text=None):
|
||||
url = self.tg_url_bot_general + self.key + "/answerCallbackQuery"
|
||||
if not text:
|
||||
params = {"callback_query_id": callback_query_id}
|
||||
else:
|
||||
params = {"callback_query_id": callback_query_id, "text": text}
|
||||
answer = requests.post(url, params=params, proxies=self.proxies)
|
||||
self.result = answer.json()
|
||||
self.ok_update()
|
||||
return self.result
|
||||
|
||||
def ok_update(self):
|
||||
self.ok = self.result["ok"]
|
||||
if self.ok:
|
||||
self.error = None
|
||||
else:
|
||||
self.error = self.result["description"]
|
||||
print_message(self.error)
|
||||
return True
|
||||
|
||||
|
||||
def markdown_fix(message, offset, emoji=False):
|
||||
offset = int(offset)
|
||||
if emoji: # https://github.com/ableev/Zabbix-in-Telegram/issues/152
|
||||
offset -= 2
|
||||
message = "\n".join(message)
|
||||
message = message[:offset] + message[offset+1:]
|
||||
message = message.split("\n")
|
||||
return message
|
||||
|
||||
|
||||
class ZabbixWeb:
|
||||
def __init__(self, server, username, password):
|
||||
self.debug = False
|
||||
self.server = server
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.proxies = {}
|
||||
self.verify = True
|
||||
self.cookie = None
|
||||
self.basic_auth_user = None
|
||||
self.basic_auth_pass = None
|
||||
self.tmp_dir = None
|
||||
|
||||
def login(self):
|
||||
if not self.verify:
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
data_api = {"name": self.username, "password": self.password, "enter": "Sign in"}
|
||||
answer = requests.post(self.server + "/", data=data_api, proxies=self.proxies, verify=self.verify,
|
||||
auth=requests.auth.HTTPBasicAuth(self.basic_auth_user, self.basic_auth_pass))
|
||||
cookie = answer.cookies
|
||||
if len(answer.history) > 1 and answer.history[0].status_code == 302:
|
||||
print_message("probably the server in your config file has not full URL (for example "
|
||||
"'{0}' instead of '{1}')".format(self.server, self.server + "/zabbix"))
|
||||
if not cookie:
|
||||
print_message("authorization has failed, url: {0}".format(self.server + "/"))
|
||||
cookie = None
|
||||
|
||||
self.cookie = cookie
|
||||
|
||||
def graph_get(self, itemid, period, title, width, height, version=3):
|
||||
file_img = self.tmp_dir + "/{0}.png".format("".join(itemid))
|
||||
|
||||
title = requests.utils.quote(title)
|
||||
|
||||
colors = {
|
||||
0: "00CC00",
|
||||
1: "CC0000",
|
||||
2: "0000CC",
|
||||
3: "CCCC00",
|
||||
4: "00CCCC",
|
||||
5: "CC00CC",
|
||||
}
|
||||
|
||||
drawtype = 5
|
||||
if len(itemid) > 1:
|
||||
drawtype = 2
|
||||
|
||||
zbx_img_url_itemids = []
|
||||
for i in range(0, len(itemid)):
|
||||
itemid_url = "&items[{0}][itemid]={1}&items[{0}][sortorder]={0}&" \
|
||||
"items[{0}][drawtype]={3}&items[{0}][color]={2}".format(i, itemid[i], colors[i], drawtype)
|
||||
zbx_img_url_itemids.append(itemid_url)
|
||||
|
||||
zbx_img_url = self.server + "/chart3.php?"
|
||||
if version < 4:
|
||||
zbx_img_url += "period={0}".format(period)
|
||||
else:
|
||||
zbx_img_url += "from=now-{0}&to=now".format(period)
|
||||
zbx_img_url += "&name={0}&width={1}&height={2}&graphtype=0&legend=1".format(title, width, height)
|
||||
zbx_img_url += "".join(zbx_img_url_itemids)
|
||||
|
||||
if self.debug:
|
||||
print_message(zbx_img_url)
|
||||
answer = requests.get(zbx_img_url, cookies=self.cookie, proxies=self.proxies, verify=self.verify,
|
||||
auth=requests.auth.HTTPBasicAuth(self.basic_auth_user, self.basic_auth_pass))
|
||||
status_code = answer.status_code
|
||||
if status_code == 404:
|
||||
print_message("can't get image from '{0}'".format(zbx_img_url))
|
||||
return False
|
||||
res_img = answer.content
|
||||
file_bwrite(file_img, res_img)
|
||||
return file_img
|
||||
|
||||
def api_test(self):
|
||||
headers = {'Content-type': 'application/json'}
|
||||
api_data = json.dumps({"jsonrpc": "2.0", "method": "user.login", "params":
|
||||
{"user": self.username, "password": self.password}, "id": 1})
|
||||
api_url = self.server + "/api_jsonrpc.php"
|
||||
api = requests.post(api_url, data=api_data, proxies=self.proxies, headers=headers)
|
||||
return api.text
|
||||
|
||||
|
||||
def print_message(message):
|
||||
message = str(message) + "\n"
|
||||
filename = sys.argv[0].split("/")[-1]
|
||||
sys.stderr.write(filename + ": " + message)
|
||||
|
||||
|
||||
def list_cut(elements, symbols_limit):
|
||||
symbols_count = symbols_count_now = 0
|
||||
elements_new = []
|
||||
element_last_list = []
|
||||
for e in elements:
|
||||
symbols_count_now = symbols_count + len(e)
|
||||
if symbols_count_now > symbols_limit:
|
||||
limit_idx = symbols_limit - symbols_count
|
||||
e_list = list(e)
|
||||
for idx, ee in enumerate(e_list):
|
||||
if idx < limit_idx:
|
||||
element_last_list.append(ee)
|
||||
else:
|
||||
break
|
||||
break
|
||||
else:
|
||||
symbols_count = symbols_count_now + 1
|
||||
elements_new.append(e)
|
||||
if symbols_count_now < symbols_limit:
|
||||
return elements, False
|
||||
else:
|
||||
element_last = "".join(element_last_list)
|
||||
elements_new.append(element_last)
|
||||
return elements_new, True
|
||||
|
||||
|
||||
class Maps:
|
||||
# https://developers.google.com/maps/documentation/geocoding/intro
|
||||
def __init__(self):
|
||||
self.key = None
|
||||
self.proxies = {}
|
||||
|
||||
def get_coordinates_by_address(self, address):
|
||||
coordinates = {"latitude": 0, "longitude": 0}
|
||||
url_api = "https://maps.googleapis.com/maps/api/geocode/json?key={0}&address={1}".format(self.key, address)
|
||||
url = url_api
|
||||
answer = requests.get(url, proxies=self.proxies)
|
||||
result = answer.json()
|
||||
try:
|
||||
coordinates_dict = result["results"][0]["geometry"]["location"]
|
||||
except:
|
||||
if "error_message" in result:
|
||||
print_message("[" + result["status"] + "]: " + result["error_message"])
|
||||
return coordinates
|
||||
coordinates = {"latitude": coordinates_dict["lat"], "longitude": coordinates_dict["lng"]}
|
||||
return coordinates
|
||||
|
||||
|
||||
def file_write(filename, text):
|
||||
with open(filename, "w") as fd:
|
||||
fd.write(str(text))
|
||||
return True
|
||||
|
||||
|
||||
def file_bwrite(filename, data):
|
||||
with open(filename, "wb") as fd:
|
||||
fd.write(data)
|
||||
return True
|
||||
|
||||
|
||||
def file_read(filename):
|
||||
with open(filename, "r") as fd:
|
||||
text = fd.readlines()
|
||||
return text
|
||||
|
||||
|
||||
def file_append(filename, text):
|
||||
with open(filename, "a") as fd:
|
||||
fd.write(str(text))
|
||||
return True
|
||||
|
||||
|
||||
def external_image_get(url, tmp_dir, timeout=6):
|
||||
image_hash = hashlib.md5()
|
||||
image_hash.update(url.encode())
|
||||
file_img = tmp_dir + "/external_{0}.png".format(image_hash.hexdigest())
|
||||
try:
|
||||
answer = requests.get(url, timeout=timeout, allow_redirects=True)
|
||||
except requests.exceptions.ReadTimeout as ex:
|
||||
print_message("Can't get external image from '{0}': timeout".format(url))
|
||||
return False
|
||||
status_code = answer.status_code
|
||||
if status_code == 404:
|
||||
print_message("Can't get external image from '{0}': HTTP 404 error".format(url))
|
||||
return False
|
||||
answer_image = answer.content
|
||||
file_bwrite(file_img, answer_image)
|
||||
return file_img
|
||||
|
||||
|
||||
def age2sec(age_str):
|
||||
age_sec = 0
|
||||
age_regex = "([0-9]+d)?\s?([0-9]+h)?\s?([0-9]+m)?"
|
||||
age_pattern = re.compile(age_regex)
|
||||
intervals = age_pattern.match(age_str).groups()
|
||||
for i in intervals:
|
||||
if i:
|
||||
metric = i[-1]
|
||||
if metric == "d":
|
||||
age_sec += int(i[0:-1])*86400
|
||||
if metric == "h":
|
||||
age_sec += int(i[0:-1])*3600
|
||||
if metric == "m":
|
||||
age_sec += int(i[0:-1])*60
|
||||
return age_sec
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
tmp_dir = zbxtg_settings.zbx_tg_tmp_dir
|
||||
if tmp_dir == "/tmp/" + zbxtg_settings.zbx_tg_prefix:
|
||||
print_message("WARNING: it is strongly recommended to change `zbx_tg_tmp_dir` variable in config!!!")
|
||||
print_message("https://github.com/ableev/Zabbix-in-Telegram/wiki/Change-zbx_tg_tmp_dir-in-settings")
|
||||
|
||||
tmp_cookie = tmp_dir + "/cookie.py.txt"
|
||||
tmp_uids = tmp_dir + "/uids.txt"
|
||||
tmp_need_update = False # do we need to update cache file with uids or not
|
||||
|
||||
rnd = random.randint(0, 999)
|
||||
ts = time.time()
|
||||
hash_ts = str(ts) + "." + str(rnd)
|
||||
|
||||
log_file = "/dev/null"
|
||||
|
||||
args = sys.argv
|
||||
|
||||
settings = {
|
||||
"zbxtg_itemid": "0", # itemid for graph
|
||||
"zbxtg_title": None, # title for graph
|
||||
"zbxtg_image_period": None,
|
||||
"zbxtg_image_age": "3600",
|
||||
"zbxtg_image_width": "900",
|
||||
"zbxtg_image_height": "200",
|
||||
"tg_method_image": False, # if True - default send images, False - send text
|
||||
"tg_chat": False, # send message to chat or in private
|
||||
"tg_group": False, # send message to chat or in private
|
||||
"is_debug": False,
|
||||
"is_channel": False,
|
||||
"disable_web_page_preview": False,
|
||||
"location": None, # address
|
||||
"lat": 0, # latitude
|
||||
"lon": 0, # longitude
|
||||
"is_single_message": False,
|
||||
"markdown": False,
|
||||
"html": False,
|
||||
"signature": None,
|
||||
"signature_disable": False,
|
||||
"graph_buttons": False,
|
||||
"extimg": None,
|
||||
"to": None,
|
||||
"to_group": None,
|
||||
"forked": False,
|
||||
}
|
||||
|
||||
url_github = "https://github.com/ableev/Zabbix-in-Telegram"
|
||||
url_wiki_base = "https://github.com/ableev/Zabbix-in-Telegram/wiki"
|
||||
url_tg_group = "https://t.me/ZbxTg"
|
||||
url_tg_channel = "https://t.me/Zabbix_in_Telegram"
|
||||
|
||||
settings_description = {
|
||||
"itemid": {"name": "zbxtg_itemid", "type": "list",
|
||||
"help": "script will attach a graph with that itemid (could be multiple)", "url": "Graphs"},
|
||||
"title": {"name": "zbxtg_title", "type": "str", "help": "title for attached graph", "url": "Graphs"},
|
||||
"graphs_period": {"name": "zbxtg_image_period", "type": "int", "help": "graph period", "url": "Graphs"},
|
||||
"graphs_age": {"name": "zbxtg_image_age", "type": "str", "help": "graph period as age", "url": "Graphs"},
|
||||
"graphs_width": {"name": "zbxtg_image_width", "type": "int", "help": "graph width", "url": "Graphs"},
|
||||
"graphs_height": {"name": "zbxtg_image_height", "type": "int", "help": "graph height", "url": "Graphs"},
|
||||
"graphs": {"name": "tg_method_image", "type": "bool", "help": "enables graph sending", "url": "Graphs"},
|
||||
"chat": {"name": "tg_chat", "type": "bool", "help": "deprecated, don't use it, see 'group'",
|
||||
"url": "How-to-send-message-to-the-group-chat"},
|
||||
"group": {"name": "tg_group", "type": "bool", "help": "sends message to a group",
|
||||
"url": "How-to-send-message-to-the-group-chat"},
|
||||
"debug": {"name": "is_debug", "type": "bool", "help": "enables 'debug'",
|
||||
"url": "How-to-test-script-in-command-line"},
|
||||
"channel": {"name": "is_channel", "type": "bool", "help": "sends message to a channel",
|
||||
"url": "Channel-support"},
|
||||
"disable_web_page_preview": {"name": "disable_web_page_preview", "type": "bool",
|
||||
"help": "disable web page preview", "url": "Disable-web-page-preview"},
|
||||
"location": {"name": "location", "type": "str", "help": "address of location", "url": "Location"},
|
||||
"lat": {"name": "lat", "type": "str", "help": "specify latitude (and lon too!)", "url": "Location"},
|
||||
"lon": {"name": "lon", "type": "str", "help": "specify longitude (and lat too!)", "url": "Location"},
|
||||
"single_message": {"name": "is_single_message", "type": "bool", "help": "do not split message and graph",
|
||||
"url": "Why-am-I-getting-two-messages-instead-of-one"},
|
||||
"markdown": {"name": "markdown", "type": "bool", "help": "markdown support", "url": "Markdown-and-HTML"},
|
||||
"html": {"name": "html", "type": "bool", "help": "markdown support", "url": "Markdown-and-HTML"},
|
||||
"signature": {"name": "signature", "type": "str",
|
||||
"help": "bot's signature", "url": "Bot-signature"},
|
||||
"signature_disable": {"name": "signature_disable", "type": "bool",
|
||||
"help": "enables/disables bot's signature", "url": "Bot-signature"},
|
||||
"graph_buttons": {"name": "graph_buttons", "type": "bool",
|
||||
"help": "activates buttons under graph, could be using in ZbxTgDaemon",
|
||||
"url": "Interactive-bot"},
|
||||
"external_image": {"name": "extimg", "type": "str",
|
||||
"help": "should be url; attaches external image from different source",
|
||||
"url": "External-image-as-graph"},
|
||||
"to": {"name": "to", "type": "str", "help": "rewrite zabbix username, use that instead of arguments",
|
||||
"url": "Custom-to-and-to_group"},
|
||||
"to_group": {"name": "to_group", "type": "str",
|
||||
"help": "rewrite zabbix username, use that instead of arguments", "url": "Custom-to-and-to_group"},
|
||||
"forked": {"name": "forked", "type": "bool", "help": "internal variable, do not use it. Ever.", "url": ""},
|
||||
}
|
||||
|
||||
if len(args) < 4:
|
||||
do_not_exit = False
|
||||
if "--features" in args:
|
||||
print(("List of available settings, see {0}/Settings\n---".format(url_wiki_base)))
|
||||
for sett, proprt in list(settings_description.items()):
|
||||
print(("{0}: {1}\ndoc: {2}/{3}\n--".format(sett, proprt["help"], url_wiki_base, proprt["url"])))
|
||||
|
||||
elif "--show-settings" in args:
|
||||
do_not_exit = True
|
||||
print_message("Settings: " + str(json.dumps(settings, indent=2)))
|
||||
|
||||
else:
|
||||
print(("Hi. You should provide at least three arguments.\n"
|
||||
"zbxtg.py [TO] [SUBJECT] [BODY]\n\n"
|
||||
"1. Read main page and/or wiki: {0} + {1}\n"
|
||||
"2. Public Telegram group (discussion): {2}\n"
|
||||
"3. Public Telegram channel: {3}\n"
|
||||
"4. Try dev branch for test purposes (new features, etc): {0}/tree/dev"
|
||||
.format(url_github, url_wiki_base, url_tg_group, url_tg_channel)))
|
||||
if not do_not_exit:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
zbx_to = args[1]
|
||||
zbx_subject = args[2]
|
||||
zbx_body = args[3]
|
||||
|
||||
tg = TelegramAPI(key=zbxtg_settings.tg_key)
|
||||
|
||||
tg.tmp_dir = tmp_dir
|
||||
tg.tmp_uids = tmp_uids
|
||||
|
||||
if zbxtg_settings.proxy_to_tg:
|
||||
proxy_to_tg = zbxtg_settings.proxy_to_tg
|
||||
if not proxy_to_tg.find("http") and not proxy_to_tg.find("socks"):
|
||||
proxy_to_tg = "https://" + proxy_to_tg
|
||||
tg.proxies = {
|
||||
"https": "{0}".format(proxy_to_tg),
|
||||
}
|
||||
|
||||
zbx = ZabbixWeb(server=zbxtg_settings.zbx_server, username=zbxtg_settings.zbx_api_user,
|
||||
password=zbxtg_settings.zbx_api_pass)
|
||||
|
||||
zbx.tmp_dir = tmp_dir
|
||||
|
||||
# workaround for Zabbix 4.x
|
||||
zbx_version = 3
|
||||
|
||||
try:
|
||||
zbx_version = zbxtg_settings.zbx_server_version
|
||||
except:
|
||||
pass
|
||||
|
||||
if zbxtg_settings.proxy_to_zbx:
|
||||
zbx.proxies = {
|
||||
"http": "http://{0}/".format(zbxtg_settings.proxy_to_zbx),
|
||||
"https": "https://{0}/".format(zbxtg_settings.proxy_to_zbx)
|
||||
}
|
||||
|
||||
# https://github.com/ableev/Zabbix-in-Telegram/issues/55
|
||||
try:
|
||||
if zbxtg_settings.zbx_basic_auth:
|
||||
zbx.basic_auth_user = zbxtg_settings.zbx_basic_auth_user
|
||||
zbx.basic_auth_pass = zbxtg_settings.zbx_basic_auth_pass
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
zbx_api_verify = zbxtg_settings.zbx_api_verify
|
||||
zbx.verify = zbx_api_verify
|
||||
except:
|
||||
pass
|
||||
|
||||
map = Maps()
|
||||
# api key to resolve address to coordinates via google api
|
||||
try:
|
||||
if zbxtg_settings.google_maps_api_key:
|
||||
map.key = zbxtg_settings.google_maps_api_key
|
||||
if zbxtg_settings.proxy_to_tg:
|
||||
map.proxies = {
|
||||
"http": "http://{0}/".format(zbxtg_settings.proxy_to_tg),
|
||||
"https": "https://{0}/".format(zbxtg_settings.proxy_to_tg)
|
||||
}
|
||||
except:
|
||||
pass
|
||||
|
||||
zbxtg_body = (zbx_subject + "\n" + zbx_body).splitlines()
|
||||
zbxtg_body_text = []
|
||||
|
||||
for line in zbxtg_body:
|
||||
if line.find(zbxtg_settings.zbx_tg_prefix) > -1:
|
||||
setting = re.split("[\s:=]+", line, maxsplit=1)
|
||||
key = setting[0].replace(zbxtg_settings.zbx_tg_prefix + ";", "")
|
||||
if key not in settings_description:
|
||||
if "--debug" in args:
|
||||
print_message("[ERROR] There is no '{0}' method, use --features to get help".format(key))
|
||||
continue
|
||||
if settings_description[key]["type"] == "list":
|
||||
value = setting[1].split(",")
|
||||
elif len(setting) > 1 and len(setting[1]) > 0:
|
||||
value = setting[1]
|
||||
elif settings_description[key]["type"] == "bool":
|
||||
value = True
|
||||
else:
|
||||
value = settings[settings_description[key]["name"]]
|
||||
if key in settings_description:
|
||||
settings[settings_description[key]["name"]] = value
|
||||
else:
|
||||
zbxtg_body_text.append(line)
|
||||
|
||||
tg_method_image = bool(settings["tg_method_image"])
|
||||
tg_chat = bool(settings["tg_chat"])
|
||||
tg_group = bool(settings["tg_group"])
|
||||
is_debug = bool(settings["is_debug"])
|
||||
is_channel = bool(settings["is_channel"])
|
||||
disable_web_page_preview = bool(settings["disable_web_page_preview"])
|
||||
is_single_message = bool(settings["is_single_message"])
|
||||
|
||||
# experimental way to send message to the group https://github.com/ableev/Zabbix-in-Telegram/issues/15
|
||||
if args[0].split("/")[-1] == "zbxtg_group.py" or "--group" in args or tg_chat or tg_group:
|
||||
tg_chat = True
|
||||
tg_group = True
|
||||
tg.type = "group"
|
||||
|
||||
if "--debug" in args or is_debug:
|
||||
is_debug = True
|
||||
tg.debug = True
|
||||
zbx.debug = True
|
||||
print_message(tg.get_me())
|
||||
print_message("Cache file with uids: " + tg.tmp_uids)
|
||||
log_file = tmp_dir + ".debug." + hash_ts + ".log"
|
||||
#print_message(log_file)
|
||||
|
||||
if "--markdown" in args or settings["markdown"]:
|
||||
tg.markdown = True
|
||||
|
||||
if "--html" in args or settings["html"]:
|
||||
tg.html = True
|
||||
|
||||
if "--channel" in args or is_channel:
|
||||
tg.type = "channel"
|
||||
|
||||
if "--disable_web_page_preview" in args or disable_web_page_preview:
|
||||
if is_debug:
|
||||
print_message("'disable_web_page_preview' option has been enabled")
|
||||
tg.disable_web_page_preview = True
|
||||
|
||||
if "--graph_buttons" in args or settings["graph_buttons"]:
|
||||
tg.image_buttons = True
|
||||
|
||||
if "--forked" in args:
|
||||
settings["forked"] = True
|
||||
|
||||
if "--tg-key" in args:
|
||||
tg.key = args[args.index("--tg-key") + 1]
|
||||
|
||||
location_coordinates = {"latitude": None, "longitude": None}
|
||||
if settings["lat"] > 0 and settings["lat"] > 0:
|
||||
location_coordinates = {"latitude": settings["lat"], "longitude": settings["lon"]}
|
||||
tg.location = location_coordinates
|
||||
else:
|
||||
if settings["location"]:
|
||||
location_coordinates = map.get_coordinates_by_address(settings["location"])
|
||||
if location_coordinates:
|
||||
settings["lat"] = location_coordinates["latitude"]
|
||||
settings["lon"] = location_coordinates["longitude"]
|
||||
tg.location = location_coordinates
|
||||
|
||||
if not os.path.isdir(tmp_dir):
|
||||
if is_debug:
|
||||
print_message("Tmp dir doesn't exist, creating new one...")
|
||||
try:
|
||||
os.makedirs(tmp_dir)
|
||||
open(tg.tmp_uids, "a").close()
|
||||
os.chmod(tmp_dir, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
|
||||
os.chmod(tg.tmp_uids, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
|
||||
except:
|
||||
tmp_dir = "/tmp"
|
||||
if is_debug:
|
||||
print_message("Using {0} as a temporary dir".format(tmp_dir))
|
||||
|
||||
done_all_work_in_the_fork = False
|
||||
# issue75
|
||||
|
||||
to_types = ["to", "to_group", "to_channel"]
|
||||
to_types_to_telegram = {"to": "private", "to_group": "group", "to_channel": "channel"}
|
||||
multiple_to = {}
|
||||
for i in to_types:
|
||||
multiple_to[i]=[]
|
||||
|
||||
for t in to_types:
|
||||
try:
|
||||
if settings[t] and not settings["forked"]:
|
||||
# zbx_to = settings["to"]
|
||||
multiple_to[t] = re.split(",", settings[t])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# example:
|
||||
# {'to_channel': [], 'to': ['usr1', 'usr2', 'usr3'], 'to_group': []}
|
||||
|
||||
if (sum([len(v) for k, v in list(multiple_to.items())])) == 1:
|
||||
# if we have only one recipient, we don't need fork to send message, just re-write "to" vaiable
|
||||
tmp_max = 0
|
||||
for t in to_types:
|
||||
if len(multiple_to[t]) > tmp_max:
|
||||
tmp_max = len(multiple_to[t])
|
||||
tg.type = to_types_to_telegram[t]
|
||||
zbx_to = multiple_to[t][0]
|
||||
else:
|
||||
for t in to_types:
|
||||
for i in multiple_to[t]:
|
||||
args_new = list(args)
|
||||
args_new[1] = i
|
||||
if t == "to_group":
|
||||
args_new.append("--group")
|
||||
args_new.append("--forked")
|
||||
args_new.insert(0, sys.executable)
|
||||
if is_debug:
|
||||
print_message("Fork for custom recipient ({1}), new args: {0}".format(args_new,
|
||||
to_types_to_telegram[t]))
|
||||
subprocess.call(args_new)
|
||||
done_all_work_in_the_fork = True
|
||||
|
||||
if done_all_work_in_the_fork:
|
||||
sys.exit(0)
|
||||
|
||||
uid = None
|
||||
|
||||
if tg.type == "channel":
|
||||
uid = zbx_to
|
||||
if tg.type == "private":
|
||||
zbx_to = zbx_to.replace("@", "")
|
||||
|
||||
if zbx_to.isdigit():
|
||||
uid = zbx_to
|
||||
|
||||
if not uid:
|
||||
uid = tg.get_uid_from_cache(zbx_to)
|
||||
|
||||
if not uid:
|
||||
uid = tg.get_uid(zbx_to)
|
||||
if uid:
|
||||
tmp_need_update = True
|
||||
if not uid:
|
||||
tg.error_need_to_contact(zbx_to)
|
||||
sys.exit(1)
|
||||
|
||||
if tmp_need_update:
|
||||
tg.update_cache_uid(zbx_to, str(uid).rstrip())
|
||||
|
||||
if is_debug:
|
||||
print_message("Telegram uid of {0} '{1}': {2}".format(tg.type, zbx_to, uid))
|
||||
|
||||
# add signature, turned off by default, you can turn it on in config
|
||||
try:
|
||||
if "--signature" in args or settings["signature"] or zbxtg_settings.zbx_tg_signature\
|
||||
and not "--signature_disable" in args and not settings["signature_disable"]:
|
||||
if "--signature" in args:
|
||||
settings["signature"] = args[args.index("--signature") + 1]
|
||||
if not settings["signature"]:
|
||||
settings["signature"] = zbxtg_settings.zbx_server
|
||||
zbxtg_body_text.append("--")
|
||||
zbxtg_body_text.append(settings["signature"])
|
||||
except:
|
||||
pass
|
||||
|
||||
# replace text with emojis
|
||||
internal_using_emoji = False # I hate that, but... https://github.com/ableev/Zabbix-in-Telegram/issues/152
|
||||
if hasattr(zbxtg_settings, "emoji_map"):
|
||||
zbxtg_body_text_emoji_support = []
|
||||
for l in zbxtg_body_text:
|
||||
l_new = l
|
||||
for k, v in list(zbxtg_settings.emoji_map.items()):
|
||||
l_new = l_new.replace("{{" + k + "}}", v)
|
||||
zbxtg_body_text_emoji_support.append(l_new)
|
||||
if len("".join(zbxtg_body_text)) - len("".join(zbxtg_body_text_emoji_support)):
|
||||
internal_using_emoji = True
|
||||
zbxtg_body_text = zbxtg_body_text_emoji_support
|
||||
|
||||
if not is_single_message:
|
||||
tg.send_message(uid, zbxtg_body_text)
|
||||
if not tg.ok:
|
||||
# first case – if group has been migrated to a supergroup, we need to update chat_id of that group
|
||||
if tg.error.find("migrated") > -1 and tg.error.find("supergroup") > -1:
|
||||
migrate_to_chat_id = tg.result["parameters"]["migrate_to_chat_id"]
|
||||
tg.update_cache_uid(zbx_to, migrate_to_chat_id, message="Group chat is migrated to supergroup, "
|
||||
"updating cache file")
|
||||
uid = migrate_to_chat_id
|
||||
tg.send_message(uid, zbxtg_body_text)
|
||||
|
||||
# another case if markdown is enabled and we got parse error, try to remove "bad" symbols from message
|
||||
if tg.markdown and tg.error.find("Can't find end of the entity starting at byte offset") > -1:
|
||||
markdown_warning = "Original message has been fixed due to {0}. " \
|
||||
"Please, fix the markdown, it's slowing down messages sending."\
|
||||
.format(url_wiki_base + "/" + settings_description["markdown"]["url"])
|
||||
markdown_fix_attempts = 0
|
||||
while not tg.ok and markdown_fix_attempts != 3:
|
||||
offset = re.search("Can't find end of the entity starting at byte offset ([0-9]+)", tg.error).group(1)
|
||||
zbxtg_body_text = markdown_fix(zbxtg_body_text, offset, emoji=internal_using_emoji) + \
|
||||
["\n"] + [markdown_warning]
|
||||
tg.disable_web_page_preview = True
|
||||
tg.send_message(uid, zbxtg_body_text)
|
||||
markdown_fix_attempts += 1
|
||||
if tg.ok:
|
||||
print_message(markdown_warning)
|
||||
|
||||
if is_debug:
|
||||
print((tg.result))
|
||||
|
||||
if settings["zbxtg_image_age"]:
|
||||
age_sec = age2sec(settings["zbxtg_image_age"])
|
||||
if age_sec > 0 and age_sec > 3600:
|
||||
settings["zbxtg_image_period"] = age_sec
|
||||
|
||||
message_id = 0
|
||||
if tg_method_image:
|
||||
zbx.login()
|
||||
if not zbx.cookie:
|
||||
text_warn = "Login to Zabbix web UI has failed (web url, user or password are incorrect), "\
|
||||
"unable to send graphs check manually"
|
||||
tg.send_message(uid, [text_warn])
|
||||
print_message(text_warn)
|
||||
else:
|
||||
if not settings["extimg"]:
|
||||
zbxtg_file_img = zbx.graph_get(settings["zbxtg_itemid"], settings["zbxtg_image_period"],
|
||||
settings["zbxtg_title"], settings["zbxtg_image_width"],
|
||||
settings["zbxtg_image_height"], version=zbx_version)
|
||||
else:
|
||||
zbxtg_file_img = external_image_get(settings["extimg"], tmp_dir=zbx.tmp_dir)
|
||||
zbxtg_body_text, is_modified = list_cut(zbxtg_body_text, 200)
|
||||
if tg.ok:
|
||||
message_id = tg.result["result"]["message_id"]
|
||||
tg.reply_to_message_id = message_id
|
||||
if not zbxtg_file_img:
|
||||
text_warn = "Can't get graph image, check script manually, see logs, or disable graphs"
|
||||
tg.send_message(uid, [text_warn])
|
||||
print_message(text_warn)
|
||||
else:
|
||||
if not is_single_message:
|
||||
zbxtg_body_text = ""
|
||||
else:
|
||||
if is_modified:
|
||||
text_warn = "probably you will see MEDIA_CAPTION_TOO_LONG error, "\
|
||||
"the message has been cut to 200 symbols, "\
|
||||
"https://github.com/ableev/Zabbix-in-Telegram/issues/9"\
|
||||
"#issuecomment-166895044"
|
||||
print_message(text_warn)
|
||||
if not is_single_message:
|
||||
tg.disable_notification = True
|
||||
tg.send_photo(uid, zbxtg_body_text, zbxtg_file_img)
|
||||
if tg.ok:
|
||||
settings["zbxtg_body_text"] = zbxtg_body_text
|
||||
os.remove(zbxtg_file_img)
|
||||
else:
|
||||
if tg.error.find("PHOTO_INVALID_DIMENSIONS") > -1:
|
||||
if not tg.disable_web_page_preview:
|
||||
tg.disable_web_page_preview = True
|
||||
text_warn = "Zabbix user couldn't get graph (probably has no rights to get data from host), " \
|
||||
"check script manually, see {0}".format(url_wiki_base + "/" +
|
||||
settings_description["graphs"]["url"])
|
||||
tg.send_message(uid, [text_warn])
|
||||
print_message(text_warn)
|
||||
if tg.location and location_coordinates["latitude"] and location_coordinates["longitude"]:
|
||||
tg.reply_to_message_id = message_id
|
||||
tg.disable_notification = True
|
||||
tg.send_location(to=uid, coordinates=location_coordinates)
|
||||
|
||||
if "--show-settings" in args:
|
||||
print_message("Settings: " + str(json.dumps(settings, indent=2)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
68
root/var/lib/zabbix/bin/zbxtg_settings.example.py
Normal file
68
root/var/lib/zabbix/bin/zbxtg_settings.example.py
Normal file
@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
tg_key = "XYZ" # telegram bot api key
|
||||
|
||||
zbx_tg_prefix = "zbxtg" # variable for separating text from script info
|
||||
zbx_tg_tmp_dir = "/var/tmp/" + zbx_tg_prefix # directory for saving caches, uids, cookies, etc.
|
||||
zbx_tg_signature = False
|
||||
|
||||
zbx_tg_update_messages = True
|
||||
zbx_tg_matches = {
|
||||
"problem": "PROBLEM: ",
|
||||
"ok": "OK: "
|
||||
}
|
||||
|
||||
zbx_server = "http://127.0.0.1/zabbix/" # zabbix server full url
|
||||
zbx_api_user = "api"
|
||||
zbx_api_pass = "api"
|
||||
zbx_api_verify = True # True - do not ignore self signed certificates, False - ignore
|
||||
|
||||
#zbx_server_version = 2 # for Zabbix 2.x version
|
||||
zbx_server_version = 3 # for Zabbix 3.x version, by default, not everyone updated to 4.x yet
|
||||
#zbx_server_version = 4 # for Zabbix 4.x version, default will be changed in the future with this
|
||||
|
||||
zbx_basic_auth = False
|
||||
zbx_basic_auth_user = "zabbix"
|
||||
zbx_basic_auth_pass = "zabbix"
|
||||
|
||||
proxy_to_zbx = None
|
||||
proxy_to_tg = None
|
||||
|
||||
# proxy_to_zbx = "http://proxy.local:3128"
|
||||
# proxy_to_tg = "https://proxy.local:3128"
|
||||
|
||||
# proxy_to_tg = "socks5://user1:password2@hostname:port" # socks5 with username and password
|
||||
# proxy_to_tg = "socks5://hostname:port" # socks5 without username and password
|
||||
# proxy_to_tg = "socks5h://hostname:port" # hostname resolution on SOCKS proxy.
|
||||
# This helps when internet provider alter DNS queries.
|
||||
# Found here: https://stackoverflow.com/a/43266186/957508
|
||||
|
||||
google_maps_api_key = None # get your key, see https://developers.google.com/maps/documentation/geocoding/intro
|
||||
|
||||
zbx_tg_daemon_enabled = False
|
||||
zbx_tg_daemon_enabled_ids = [6931850, ]
|
||||
zbx_tg_daemon_enabled_users = ["ableev", ]
|
||||
zbx_tg_daemon_enabled_chats = ["Zabbix in Telegram Script", ]
|
||||
|
||||
zbx_db_host = "localhost"
|
||||
zbx_db_database = "zabbix"
|
||||
zbx_db_user = "zbxtg"
|
||||
zbx_db_password = "zbxtg"
|
||||
|
||||
|
||||
emoji_map = {
|
||||
"Disaster": "🔥",
|
||||
"High": "🛑",
|
||||
"Average": "❗",
|
||||
"Warning": "⚠️",
|
||||
"Information": "ℹ️",
|
||||
"Not classified": "🔘",
|
||||
"OK": "✅",
|
||||
"PROBLEM": "❗",
|
||||
"info": "ℹ️",
|
||||
"WARNING": "⚠️",
|
||||
"DISASTER": "❌",
|
||||
"bomb": "💣",
|
||||
"fire": "🔥",
|
||||
"hankey": "💩",
|
||||
}
|
241
smeserver-zabbix-server.spec
Normal file
241
smeserver-zabbix-server.spec
Normal file
@ -0,0 +1,241 @@
|
||||
# $Id: smeserver-zabbix-server.spec,v 1.20 2022/12/11 07:12:36 jpp Exp $
|
||||
# Authority: vip-ire
|
||||
# Name: Daniel Berteaud
|
||||
|
||||
%define name smeserver-zabbix-server
|
||||
%define version 0.1
|
||||
%define release 32
|
||||
Summary: sme server integration of zabbix server and web front-end
|
||||
Name: %{name}
|
||||
Version: %{version}
|
||||
Release: %{release}%{?dist}
|
||||
License: GNU GPL version 2
|
||||
URL: http://www.zabbix.com/
|
||||
Group: SMEserver/addon
|
||||
Source: %{name}-%{version}.tar.xz
|
||||
|
||||
|
||||
BuildArchitectures: noarch
|
||||
BuildRequires: e-smith-devtools
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
Requires: e-smith-release >= 10.0
|
||||
Requires: e-smith-apache >= 2.6.0-19
|
||||
Requires: smeserver-php >= 3.0.0-43
|
||||
Requires: fping
|
||||
Requires: zabbix-server-mysql >= 4.4.6
|
||||
Requires: zabbix-web-mysql >= 4.4.6
|
||||
Requires: zabbix-web >= 4.4.6
|
||||
Requires: sendxmpp
|
||||
Requires: smeserver-remoteuseraccess
|
||||
Requires: smeserver-mariadb105
|
||||
# for telegram bot
|
||||
Requires: python2-pysocks python-requests python2-requests-oauthlib
|
||||
Obsoletes: zabbix-server
|
||||
Conflicts: smeserver-zabbix-proxy
|
||||
AutoReqProv: no
|
||||
|
||||
%description
|
||||
smserver integration of zabbix server and web front-end.
|
||||
Zabbix is an entreprise-class open source distributed monitoring
|
||||
solution
|
||||
|
||||
%package z50
|
||||
%define provscl 5.0.30-1.el7
|
||||
#5.0.30-1
|
||||
Summary: SME Server integration of zabbix server 5.0 and web front-end using Remi SCLO
|
||||
Group: Applications/Internet
|
||||
#common
|
||||
BuildArchitectures: noarch
|
||||
BuildRequires: e-smith-devtools
|
||||
Requires: e-smith-release >= 10.0
|
||||
Requires: e-smith-apache >= 2.6.0-19
|
||||
Requires: smeserver-php >= 3.0.0-43
|
||||
Requires: fping
|
||||
Requires: zabbix-server-mysql >= 5.0.0
|
||||
#Requires: zabbix-web-mysql-scl >= 5.0.0
|
||||
#Requires: zabbix-web >= 5.0.0
|
||||
Requires: sendxmpp
|
||||
Requires: smeserver-remoteuseraccess
|
||||
Requires: smeserver-mariadb105
|
||||
# specific
|
||||
#Provides: rh-php72-php-fpm rh-php72-php-mbstring rh-php72 rh-php72-php-mysqlnd rh-php72-php-gd rh-php72-php-xml rh-php72-php-ldap rh-php72-php-bcmath
|
||||
Provides: zabbix-web-database-scl-php74 = %{provscl}
|
||||
Provides: zabbix-web-deps-scl = %{provscl}
|
||||
Provides: zabbix-web-deps-scl-php73 = %{provscl}
|
||||
Requires: zabbix-web = %{provscl}
|
||||
Requires: php74-php-mysqlnd php74 php74-php-gd php74-php-bcmath php74-php-mbstring php74-php-xml php74-php-ldap php74-php-fpm php74-php-mysqlnd
|
||||
|
||||
%description z50
|
||||
SME Server integration of zabbix server 5.0 and web front-end using Remi SCLO.
|
||||
Zabbix is an entreprise-class open source distributed monitoring
|
||||
solution
|
||||
|
||||
%changelog
|
||||
* Sat Sep 07 2024 cvs2git.sh aka Brian Read <brianr@koozali.org> 0.1-32.sme
|
||||
- Roll up patches and move to git repo [SME: 12338]
|
||||
|
||||
* Sat Sep 07 2024 BogusDateBot
|
||||
- Eliminated rpmbuild "bogus date" warnings due to inconsistent weekday,
|
||||
by assuming the date is correct and changing the weekday.
|
||||
|
||||
* Sat Dec 10 2022 Jean-Philippe Pialasse <tests@pialasse.com> 0.1-31.sme
|
||||
- original package build for Zabbix 5.0 using Remi SCLO [SME: 11748]
|
||||
support for LTS 5.0 EOL May 31, 2025
|
||||
needs mariadb105.
|
||||
manual migration from mariadb55 to mariadb105 needed for existing installs
|
||||
|
||||
* Mon Aug 01 2022 Jean-Philippe Pialasse <tests@pialasse.com> 0.1-30.sme
|
||||
- update to httpd 2.4 access syntax [SME: 12068]
|
||||
thanks to Vasarhelyi Zsolt
|
||||
- add to core backup [SME: 12031]
|
||||
non rpm owned files in /etc/zabbix, /etc/zabbix/zabbix_agentd.conf.d/
|
||||
and /var/lib/zabbix/bin/
|
||||
|
||||
* Tue Nov 09 2021 Jean-Philippe Pialasse <tests@pialasse.com> 0.1-29.sme
|
||||
- set random password to Admin i fuser exists and password is zabbix [SME: 11749]
|
||||
|
||||
* Mon Nov 08 2021 Jean-Philippe Pialasse <tests@pialasse.com> 0.1-28.sme
|
||||
- add check cert scripts and telegram [SME: 10802]
|
||||
no template provided to use with
|
||||
|
||||
* Sun Nov 07 2021 Jean-Philippe Pialasse <tests@pialasse.com> 0.1-27.sme
|
||||
- fix init sql, typo and reload deamon [SME: 11232]
|
||||
|
||||
* Sun Nov 07 2021 Jean-Philippe Pialasse <tests@pialasse.com> 0.1-26.sme
|
||||
- fix session and log issue [SME: 11232]
|
||||
fix mysql-init not launched
|
||||
|
||||
* Mon Nov 01 2021 BogusDateBot
|
||||
- Eliminated rpmbuild "bogus date" warnings due to inconsistent weekday,
|
||||
by assuming the date is correct and changing the weekday.
|
||||
Tue Mar 02 2009 --> Tue Feb 24 2009 or Mon Mar 02 2009 or Tue Mar 03 2009 or ....
|
||||
Wed Feb 07 2016 --> Wed Feb 03 2016 or Sun Feb 07 2016 or Wed Feb 10 2016 or ....
|
||||
|
||||
* Mon Nov 01 2021 Brian Read <brianr@bjsystems.co.uk> 0.1-25.sme
|
||||
- Switch-to-specific-php-fpm [SME: 11232]
|
||||
|
||||
* Mon Nov 01 2021 Brian Read <brianr@bjsystems.co.uk> 0.1-24.sme
|
||||
- Remove post and postun command in spec file [SME: 11232]
|
||||
|
||||
* Thu Dec 10 2020 Brian Read <brianr@bjsystems.co.uk> 0.1-23.sme
|
||||
- Add in post instructions to spec for SQL db creation [SME: 11232]
|
||||
|
||||
* Tue Dec 08 2020 Brian Read <brianr@bjsystems.co.uk> 0.1-22.sme
|
||||
- Add expand zabbix-server.conf and .user.ini to creatlinks update event [SME:11232]
|
||||
|
||||
* Tue Dec 08 2020 Brian Read <brianr@bjsystems.co.uk> 0.1-21.sme
|
||||
- Template-user-dot-ini-and-override-service-file-change-pid-in-conf-file [SME: 11232]
|
||||
|
||||
* Mon Dec 07 2020 Brian Read <brianr@bjsystems.co.uk> 0.1-20.sme
|
||||
- Import to SME10 tree [SME: 11232]
|
||||
- Update createlinks for systemd
|
||||
- Update httpd.conf for php-fpw
|
||||
- Add .user.ini for php-admin-flags that where in httpd.conf
|
||||
|
||||
* Sun May 10 2020 Jean-Philipe Pialasse <tests@pialasse.com> 0.1-19.sme
|
||||
- adapt for zabbix 4.4.6 [SME: 10944]
|
||||
|
||||
* Thu Sep 05 2019 Jean-Philipe Pialasse <tests@pialasse.com> 0.1-17.sme
|
||||
- remove deprecated option preventing from starting service [SME: 10458]
|
||||
|
||||
* Wed Mar 29 2017 Jean-Philipe Pialasse <tests@pialasse.com> 0.1-16.sme
|
||||
- fix sql init not finding default sql dump to import [SME: 9569]
|
||||
- NodeID support droped as per zabbix 2.4.0 and higher
|
||||
- requires smeserver-php-scl as Zabbix-server 3.2.4 requires php 5.4 or higher
|
||||
|
||||
* Mon Jun 13 2016 Jean-Philipe Pialasse <tests@pialasse.com> 0.1-15.sme
|
||||
- finitial import [SME: 9569]
|
||||
- fix php requirement
|
||||
- fix add path to new db
|
||||
|
||||
* Sun Feb 07 2016 stephane de Labrusse <stephdl@de-labrusse.fr> 0.1-14.sme
|
||||
Wed Feb 07 2016 --> Wed Feb 03 2016 or Sun Feb 07 2016 or Wed Feb 10 2016 or ....
|
||||
- New roll for sme9
|
||||
|
||||
* Mon Apr 29 2013 Daniel B. <daniel@firewall-services.com> 0.1-13
|
||||
- Increase PHP mem limit to 128M
|
||||
|
||||
* Mon Mar 8 2010 Daniel B. <daniel@firewall-services.com> 0.1-12
|
||||
- Use global TimeZone
|
||||
|
||||
* Wed Dec 2 2009 Daniel B. <daniel@firewall-services.com> 0.1-11
|
||||
- Support several mysql DB patches
|
||||
|
||||
* Tue Mar 03 2009 Daniel B. <daniel@firewall-services.com> 0.1-10
|
||||
- Add smeserver-remoteuseraccess as a dependencie (sudoers template problem)
|
||||
|
||||
* Mon Mar 02 2009 Daniel B. <daniel@firewall-services.com> 0.1-9
|
||||
- specify path to .sendxmpprc file in the script sendxmpp
|
||||
|
||||
* Mon Mar 02 2009 Daniel B. <daniel@firewall-services.com> 0.1-8
|
||||
- move .sendxmpprc template to the correct directory
|
||||
|
||||
* Mon Mar 02 2009 Daniel B. <daniel@firewall-services.com> 0.1-7
|
||||
- Move jabber account informations to xmpprc
|
||||
|
||||
* Mon Mar 02 2009 Daniel B. <daniel@firewall-services.com> 0.1-6
|
||||
- Adjust service masq during zabbix-server-update event
|
||||
- Enable DB cache module with StartDBSyncers directive
|
||||
|
||||
* Sun Mar 01 2009 Daniel B. <daniel@firewall-services.com> 0.1-5
|
||||
- Fix permissions on /var/lib/zabbix/tmp
|
||||
|
||||
* Tue Feb 17 2009 Daniel B. <daniel@firewall-services.com> 0.1-4
|
||||
- rename event zabbix-update to zabbix-server-update
|
||||
|
||||
* Wed Feb 11 2009 Daniel B. <daniel@firewall-services.com> 0.1-3
|
||||
- disable web access (usefull for distributed monitoring)
|
||||
- Use stronger password for mysql database
|
||||
- Use /var/lib/zabbix/bin as default location for scripts
|
||||
- Use /var/lib/zabbix/tmp for temp dir
|
||||
|
||||
* Fri Feb 06 2009 Daniel B. <daniel@firewall-services.com> 0.1-2
|
||||
- Link template-begin-shell to template-begin for sendxmpp script
|
||||
|
||||
* Fri Feb 06 2009 Daniel B. <daniel@firewall-services.com> 0.1-1
|
||||
- templatize sendxmpp as zabbix user doesn't have access to SME db
|
||||
- Add JabberTLS option in the db
|
||||
|
||||
* Mon Feb 02 2009 Daniel B. <daniel@firewall-services.com> 0.1-0
|
||||
- initial release
|
||||
|
||||
%prep
|
||||
%setup
|
||||
|
||||
%build
|
||||
perl ./createlinks
|
||||
%{__mkdir_p} root/var/lib/zabbix/tmp
|
||||
#%{__mkdir_p} root/var/log/zabbix - conflict with zabbix-server-mysql
|
||||
%{__mkdir_p} root/var/log/php/zabbix
|
||||
%{__mkdir_p} root/var/lib/php/zabbix/{tmp,wsdlcache,opcache,session}
|
||||
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
(cd root ; find . -depth -print | cpio -dump $RPM_BUILD_ROOT)
|
||||
rm -f %{name}-%{version}-filelist
|
||||
/sbin/e-smith/genfilelist $RPM_BUILD_ROOT \
|
||||
--file /var/lib/zabbix/bin/fping 'attr(0750,root,zabbix)' \
|
||||
--file /var/lib/zabbix/bin/fping6 'attr(0750,root,zabbix)' \
|
||||
--dir /var/lib/zabbix/tmp 'attr(0750,zabbix,zabbix)' \
|
||||
--dir /var/log/php/zabbix 'attr(0770,www,www)' \
|
||||
--dir /var/lib/php/zabbix 'attr(0755,root,www)' \
|
||||
--dir /var/lib/php/zabbix/tmp 'attr(0770,root,www)' \
|
||||
--dir /var/lib/php/zabbix/opcache 'attr(0770,root,www)' \
|
||||
--dir /var/lib/php/zabbix/session 'attr(0770,root,www)' \
|
||||
|grep -v '.pyc'|grep -v '.pyo' \
|
||||
> %{name}-%{version}-filelist
|
||||
|
||||
%files -f %{name}-%{version}-filelist
|
||||
%defattr(-,root,root)
|
||||
|
||||
%files z50 -f %{name}-%{version}-filelist
|
||||
%defattr(-,root,root)
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%post
|
||||
|
||||
%postun
|
||||
|
Loading…
Reference in New Issue
Block a user