Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- # 2013.08.25, v2.1, Oleg Korchagin
- # http://www.linux.org.ru/forum/admin/9306990
- # скипт, проверяющий синхронизацию нод zabbix
- # шаблон здесь: http://pastebin.com/JKEpkLt6
- # установка:
- # 1) подключить клиент с slave node НЕПОСРЕДСТВЕННО к master node
- # 2) импортировать шаблон, назначить его на ноду из п.1
- # 3) установить данный скрипт на master node. crontab:
- # # раз в 5 минут собирать данные из БД master node. Обратите внимание на ключ --current_node master
- # */5 * * * * /usr/local/bin/check_zabbix_node_sync.pl --dbhost 10.x.x.x --current_node master --check_node_id 205 --check_node_name vml-slave-zabbix --zabbix_server 10.y.y.y --mode collect >> /var/log/zabbix/check_zabbix_node_205_collect.log 2>&1
- # # раз в час выполнять low level discovery. Да, число таклиц фиксированное и можно было бы забить в шаблон, но так удобнее.
- # 5 * * * * /usr/local/bin/check_zabbix_node_sync.pl --dbhost 10.x.x.x --current_node master --check_node_id 205 --check_node_name vml-slave-zabbix --zabbix_server 10.y.y.y --mode discover >> /var/log/zabbix/check_zabbix_node_205_discover.log 2>&1
- # , где
- # mode - collect | discover
- # current_node - master | slave.
- # zabbix_server - адрес _master_ node
- # check_node_id - node id для _slave_ node
- # check_node_name - имя _slave_ node в zabbix
- # dbhost, dbport, dbname, dbuser, dbpassword - параметры для подключения к БД zabbix
- # 4) установить скрипт на slave node. crontab:
- # */5 * * * * /usr/local/bin/check_zabbix_node_sync.pl --current_node slave --check_node_id 205 --check_node_name vml-slave-zabbix --zabbix_server 10.y.y.y --mode collect >> /var/log/zabbix/check_zabbix_node_205_collect.log 2>&1
- use strict;
- use DBI;
- use Data::Dumper;
- use Time::Local;
- use Getopt::Std;
- use Getopt::Long;
- my $version = '2.1';
- my $debug = 0; # печатать данные на экран вместо отправки в zabbix
- my $help=0;
- ################################################################################
- # переменные. можно редактировать здесь или указывать в командной строке
- # см. ниже usage и GetOptions
- ################################################################################
- # параметры подключения к БД.
- my $dbname='zabbix';
- my $dbuser='zabbix';
- my $dbpassword='password';
- my $dbhost;
- my $dbport=5432;
- my $current_node; # slave | master
- my $check_node_id; # slave node id
- my $zabbix_object; # имя slave node в zabbix
- my $mode = 'collect'; # discover|collect
- my $zabbix_server; # адрес master node
- ################################################################################
- # отправка данных в zabbix
- ################################################################################
- sub zabbix_directly_send($$){
- my ( $key, $value ) = @_;
- if ( $debug ) {
- system( "echo zabbix_sender -vvvv -z $zabbix_server -s \"$zabbix_object\" -k \"$key\" -o '$value'" );
- } else {
- system( "zabbix_sender -vvvv -z $zabbix_server -s \"$zabbix_object\" -k \"$key\" -o '$value'" );
- }
- }
- my @zabbix_queue;
- sub zabbix_add_to_queue($$$) {
- my ( $zabbix_object, $key, $value ) = @_;
- push @zabbix_queue, sprintf "%s\t%s\t%s", $zabbix_object, $key, $value;
- }
- sub zabbix_bulk_send() {
- my $ZS;
- if ( $debug ) { # всё выводим на экран
- print "zabbix_sender -vvvv -z \"$zabbix_server\" -s \"$zabbix_object\" -i -\n";
- open $ZS, "| cat";
- } else { # отправляем в zabbix
- open $ZS, "| zabbix_sender -vvvv -z \"$zabbix_server\" -s \"$zabbix_object\" -i -";
- }
- for my $line ( @zabbix_queue) {
- print $ZS $line . "\n";
- }
- close $ZS;
- }
- sub print_json_result($$) {
- my $data = $_[0];
- my $key = $_[1];
- my $result = sprintf "{\n";
- $result .= sprintf "\t\"data\":[\n\n";
- $result .= join (
- "\t,\n",
- map(
- { sprintf ( "\t{\n\t\t\"\{\#%s\}\":\"%s\"\n\t}\n", $key, $_) }
- @{ $data }
- )
- );
- $result .= sprintf "\n\t]\n"
- . sprintf "}\n";
- }
- ################################################################################
- # временные таблицы сервера zabbix. Информация в них хранится до тех пор, пока не будет передана на master node
- # для них проверяем самую старую строку
- my %tables_sync=(
- 'history_sync' => { time => 'clock', sort => 'id', },
- 'history_uint_sync' => { time => 'clock', sort => 'id', },
- 'history_str_sync' => { time => 'clock', sort => 'id', },
- );
- # постоянные таблицы
- # для них будем проверять самую новую строку
- my %tables=(
- 'alerts' => { time => 'clock', sort => 'alertid' },
- 'history_log' => { time => 'clock', sort => 'id' },
- 'history_text' => { time => 'clock', sort => 'id' },
- 'events' => { time => 'clock', sort => 'eventid' },
- 'acknowledges' => { time => 'clock', sort => 'acknowledgeid' },
- 'auditlog' => { time => 'clock', sort => 'auditid' },
- # 'auditlog_details' => { time => 'clock', sort => 'auditdetailid' },
- 'service_alarms' => { time => 'clock', sort => 'servicealarmid' },
- );
- # лучше было бы использовать POSIX::strptime, но его ещё установить нужно
- sub ut2str($) {
- my @tmp_time=(localtime $_[0])[5,4,3,2,1,0];
- $tmp_time[0]+=1900;
- $tmp_time[1]+=1;
- return sprintf("%.4d/%.2d/%.2d %.2d:%.2d:%.2d", @tmp_time);
- }
- # выдаёт время из самой старой строки в таблице
- # используется для оценки таблиц, отмеченных флагом ZBX_HISTORY_SYNC
- # параметры:
- # - DB handle
- # - имя таблицы
- # - имя поля, которое содержит время
- # - имя поля, по которому происходит сортировка
- sub get_first_row_timestamp($$$$){
- my ($dbh, $table, $field, $sort) = @_;
- # TODO: исправить
- my $result=time();
- # добавить ограничение по node id
- my $sth=$dbh->prepare("select $field from $table where nodeid=$check_node_id order by $sort limit 1;");
- $sth->execute();
- my $data = $sth->fetchrow_hashref();
- if ( $data ) {
- $result = $data->{$field};
- }
- return $result;
- printf "%s\n", Dumper($sth->fetchrow_hashref());
- };
- # число строк в таблице
- # параметры:
- # - DB handle
- # - имя таблицы
- sub get_row_count($$){
- my ( $dbh, $tablename ) = @_;
- my $result = 10**10;
- my $sth=$dbh->prepare("select count(*) from $tablename;");
- $sth->execute();
- my $data = $sth->fetchrow_hashref();
- if ( $data and exists $data->{'count'} ) { $result=$data->{'count'} };
- return $result;
- }
- # возвращает фильтр, который ограничит область запроса одной нодой
- # параметры:
- # - название поля, по которому происходит фильтрация
- # - идентификатор ноды
- sub node_filter($$) {
- my ( $column, $nodeid ) = @_;
- my $base = 10**14;
- return sprintf ("%s between %s and %s", $column, $nodeid * $base, ( $nodeid + 1 ) * $base - 1) ;
- }
- # выдаёт время самой новой строки в таблице
- # используется для таблиц, отмеченных флагом ZBX_HISTORY
- # нужно вручную сравнить полученные данные на двух непосредственно связанных нодах ( master node и её дочерняя нода )
- sub get_last_row_timestamp($$$$$){
- my ($dbh, $table, $field, $sort, $node) = @_;
- my $result=0;
- my $base = 10**14;
- # ищем последнюю строку, относящууюся к данной ноде
- #my $sth=$dbh->prepare("select $field from $table order by $sort desc limit 1;");
- my $sth=$dbh->prepare(
- "select max($sort) from $table where "
- . node_filter($sort, $node) . ";"
- );
- $sth->execute();
- my $data = $sth->fetchrow_hashref();
- # и из этой последней строки берём время
- if ( $data and exists ( $data->{'max'}) and $data->{'max'} ) {
- $sth = $dbh->prepare(
- "select $field from $table where $sort=" . $data->{'max'}
- );
- $sth->execute();
- $data = $sth->fetchrow_hashref();
- if ( $data ) {
- $result = $data->{$field};
- }
- }
- return $result;
- };
- # возвращает список нод ( кроме master node )
- # параметры:
- # - DB handle
- sub get_nodes($) {
- my $dbh = shift;
- my @nodes = ();
- my $sth=$dbh->prepare("select nodeid, masterid from nodes;");
- $sth->execute();
- while ( my $data = $sth->fetchrow_hashref() ) {
- if ( $data->{'masterid'} ) {
- push @nodes, $data->{'nodeid'};
- #printf "%s\n", Dumper( $data->{'nodeid'} );
- }
- };
- return \@nodes;
- }
- # проверяет таблицу, отмеченную флагом ZBX_HISTORY_SYNC.
- # параметры:
- # - DB handle
- # - информация о таблице, см. %tables_sync, пример: { 'time' => 'clock', sort => 'id'}
- sub check_zhs_table($$$) {
- my ( $dbh, $table, $name ) = @_;
- my $lasttime = get_first_row_timestamp($dbh, $name, $table->{'time'}, $table->{'sort'});
- my $now = time();
- zabbix_add_to_queue(
- $zabbix_object,
- sprintf( "nodesync.zh_s.oldest.[%s]", $name),
- $now - $lasttime,
- );
- #my $row_count = get_row_count($dbh, $name);
- #printf "%s: %i; %i\n", $name, $now - $lasttime, $row_count;
- };
- sub check_zh_table($$$$) {
- my ( $dbh, $tables, $name, $node ) = @_;
- my $lasttime = get_last_row_timestamp(
- $dbh,
- $name,
- $tables->{$name}{'time'},
- $tables->{$name}{'sort'},
- $node,
- );
- zabbix_add_to_queue(
- $zabbix_object,
- sprintf( "nodesync.zh.newest.%s.[%s]", $current_node , $name),
- $lasttime,
- );
- #printf "%-20s: %15i; %s\n", $name, $lasttime, ut2str( $lasttime );
- };
- sub usage() {
- printf "-h\t show help\n";
- printf "-n|--dbname <DB name>\n";
- printf "-u|--dbuser <DB user>\n";
- printf "-p|--dbpassword <DB password>\n";
- printf "--dbhost <DB host>\n";
- printf "--dbport <DB port>\n";
- printf "--mode <discover|collect>\n";
- printf "--current_node <master|slave> # mandatory\n";
- printf "--check_node_id <ID> # mandatory\n";
- printf "--check_node_name <host name in zabbix> # mandatory\n";
- }
- # TODO: в перспективе автоматизировать. Для каждого check_node_id получить у пользователя ( и запомнить в storable файле )
- # check_node_name и current_node
- Getopt::Long::Configure ('bundling');
- GetOptions (
- 'n|dbname=s' => \$dbname,
- 'u|dbuser=s' => \$dbuser,
- 'p|dbpassword=s' => \$dbpassword,
- 'dbhost=s' => \$dbhost,
- 'dbport=s' => \$dbport,
- 'current_node=s' => \$current_node, # master | slave
- 'check_node_id=s' => \$check_node_id,
- 'check_node_name=s' => \$zabbix_object,
- 'zabbix_server=s' => \$zabbix_server,
- 'mode=s' => \$mode,
- 'h' => \$help,
- );
- if ( $help ) {
- usage();
- exit 0;
- };
- if ( ! $current_node or ! $check_node_id or ! $zabbix_object ) {
- usage();
- exit 0;
- }
- sub collect() {
- #
- # подключаемся к БД
- #
- my $connect_string = $dbhost ? "dbi:Pg:dbname=$dbname;host=$dbhost;port=$dbport" : "dbi:Pg:dbname=$dbname";
- my $dbh;
- eval {
- $dbh = DBI->connect($connect_string,
- $dbuser, $dbpassword,
- {
- AutoCommit => 0,
- RaiseError => 0,
- }
- );
- };
- if ( ! $dbh ) {
- print "can't connect to DB\n";
- exit 1;
- };
- if ( $current_node eq 'slave' ) {
- #
- # проверяем все ZABBIX_HISTORY_SYNC для выбранной ноды
- #
- # проверяем ZBX_HISTORY_SINC таблицы.
- # Они говорят сами за себя, сравнивать их с другими нодами не нужно
- # все строки, что в них есть, ждут отправки на master node
- for my $name ( keys %tables_sync ) {
- check_zhs_table($dbh, $tables_sync{$name}, $name);
- }
- }
- #
- # проверяем все ZABBIX_HISTORY для выбранной ноды
- #
- # проверяем ZBX_HISTORY таблицы. Из них берём информацию по отдельным нодам,
- # сравниваем данные ноды с данными её непосредственного master node
- for my $name ( sort keys %tables ) {
- check_zh_table($dbh, \%tables, $name, $check_node_id);
- }
- $dbh->disconnect();
- zabbix_bulk_send();
- };
- sub discover() {
- # ZBX_HISTORY_SYNC
- my @zbx_history_sync_tables = keys( %tables_sync );
- zabbix_directly_send( "nodesync.zh_s.discover", print_json_result(\@zbx_history_sync_tables, "ENTITY"));
- # ZBX_HISTORY
- my @zbx_history_tables = keys( %tables );
- zabbix_directly_send( "nodesync.zh.discover", print_json_result(\@zbx_history_tables, "ENTITY"));
- for my $name ( sort keys %tables ) {
- #check_zh_table($dbh, \%tables, $name, $check_node_id);
- }
- };
- if ( $mode eq 'collect' ) {
- collect();
- } elsif ( ( $mode eq 'discover') and ( $current_node eq 'master' ) ) {
- discover();
- }
- exit 0;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement