#BY Weigun http://blog.chinaunix.net/u2/70443/
use warnings;
use strict;
use 5.010;
use lib 'D:/test-area/desgin/Module';
use PublicLib;
use YAML qw(Dump LoadFile);
use Config::IniFiles;
use Data::Dumper;
#use AnyEvent;
#use Coro;
use POE;
use POE::Filter::Reference;
use POE::Component::Server::TCP;
#use POE::Component::Client::SMTP;
use Mail::Sender;
use RRDTool::OO;
use Log::Log;
use DBI;
#use AnyEvent;
$|++;
my $lib = PublicLib->new();
my $cfg_file = 'server config.ini';
my $cfg = $lib->load_config($cfg_file);
#say Dumper $cfg;
my %client_table;
my @alarm_id;
my $timer = 60*5;
POE::Component::Server::TCP->new(
Alias => $cfg->{General}->{server_name} ||= "server",
Address => "localhost",
Port => $cfg->{General}->{port} ||= 12345,
ClientFilter => ["POE::Filter::Reference", "YAML"],
#ClientFilter => "POE::Filter::Reference",
ClientConnected => \&ClientConnected,
ClientInput => \&ClientInput,
ClientDisconnected => \&ClientDisconnected,
InlineStates =>{
time_to_check => \&time_to_check,
client_time_out => \&client_time_out,
send_warning_email => \&send_warning_email,
update_rrd_file => \&update_rrd_file,
create_graph => \&create_graph,
write_db => \&write_db,
# write_log => \&write_log,
}
);
$poe_kernel->run();
sub ClientConnected
{
#一上线就发送检查信息
my ($kernel,$heap) = @_[KERNEL,HEAP];
say 'ClientConnected';
say "id is:",$heap->{client}->ID;
say 'ip:',$heap->{remote_ip};
write_log('Log',"[$heap->{remote_ip}]Connected");
my $client_id = $heap->{client}->ID;
for my $client_node (keys %$cfg)
{
if (exists $cfg->{$client_node}->{host} and $cfg->{$client_node}->{host} eq $heap->{remote_ip})
{
$client_table{$client_id}{client} = $heap->{client};
$client_table{$client_id}{host} = $heap->{remote_ip};
$client_table{$client_id}{alias} = $cfg->{$client_node}->{alias};
$client_table{$client_id}{check_item} = $cfg->{$client_node}->{check_item};
$client_table{$client_id}{rrd_file} = $cfg->{$client_node}->{RRDfile};
$client_table{$client_id}{status} = 0;#1=>down,0=>up
my %check_items =map{$_,1} split / /,$cfg->{$client_node}->{check_item};
$heap->{client}->put(\%check_items); #TODO
# send_msg(\%check_items);
$client_table{$client_id}{last_check_time} = time; #record time
# say 'check_items are follow:';
write_log('Log',"[$heap->{remote_ip}]check for ".$client_table{$client_id}{check_item});
# say Dumper \%check_items;
}
}
my $task_id = $kernel->delay_set('time_to_check',$timer,$client_id);#定时执行
#may be has problem here
push @alarm_id,$kernel->alarm_set('client_time_out',time()+$cfg->{General}->{timeout},$client_id,$task_id );
}
sub ClientInput
{
my ($kernel,$heap,$yaml) = @_[KERNEL,HEAP,ARG0];
$kernel->alarm_remove(shift @alarm_id);
# print Dump $yaml;
my $client_alias = delete $yaml->{alias};
unless (defined $client_alias)
{
write_log('Fatal',"Client Alias is undef");
}
say 'client alias is:',$client_alias;
for my $item (sort keys %$yaml)
{
next unless exists $cfg->{$client_alias}->{$item};
say "$item check?";
my ($operator,$threshold_value) = ($cfg->{$client_alias}->{$item})=~/^([<>=]+)(\d+)|unlimit$/;
my %operator_table =(
'>=' => sub{$_[0] >= $_[1];},
'<=' => sub{$_[0] <= $_[1];},
unlimit => sub{0},
);
my $is_failed = $operator_table{$operator}->($yaml->{$item},$threshold_value);
if ($is_failed)
{
say "$item over:",$yaml->{$item};
write_log('Log',"[$heap->{remote_ip}]$item overload:$yaml->{$item}");
set_client_down_flag($heap->{client}->ID);
if (exists $cfg->{$client_alias}->{repair})
{
for (split / /,$cfg->{ $client_alias }->{repair})
{
next unless $_ eq $item;
my %check_item = map{$_ => 1} qw($_ repair);
$heap->{client}->put(\%check_item);
write_log('Log',"[$heap->{remote_ip}]system try to repair");
}
}
$kernel->yield('send_warning_email',$item,$yaml->{$item});
write_log('Log',"[$heap->{remote_ip}]warning mail send:$item");#不应该在这里写日志
#TODO:设置报警原因,填写邮件模板,发邮件,DC
}
else
{
say "$item normal:",$yaml->{$item};
#TODO:设计数据结构,为写数据库准备。DC
}
}
$kernel->yield('update_rrd_file',$client_alias,$yaml);
#$kernel->yield('write_db',$client_alias,$yaml);
}
sub time_to_check
{
my ($kernel,$heap,$client_id) = @_[KERNEL,HEAP,ARG0];
say 'time_to_check';
# $client_table{$client_id}{client}->put($client_table{$client_id}{check_item});
if (exists $client_table{$client_id})
{
say "id is:$client_id";
my %check_items =map{$_,1} split / /,$client_table{$client_id}{check_item};
$client_table{$client_id}{client}->put(\%check_items) if exists $client_table{$client_id}{client}; #error here
write_log('Log',"[$client_table{$client_id}{host}]check for ".$client_table{$client_id}{check_item});
$client_table{$client_id}{last_check_time} = time;
my $task_id = $kernel->delay_set('time_to_check',$timer,$client_id);#定时执行
$client_table{$client_id}{task_id} = $task_id;
push @alarm_id,$kernel->alarm_set('client_time_out',time()+$cfg->{General}->{timeout},$client_id,$task_id);
}
}
sub client_time_out
{
my ($kernel,$heap,$client_id,$task_id) = @_[KERNEL,HEAP,ARG0,ARG1];
say 'client_time_out';
$kernel->alarm_remove($task_id);
if (exists $client_table{$client_id})
{
set_client_down_flag($client_id);
write_log('Log',"[$client_table{$client_id}{host}]client time out");
}
$kernel->yield('send_warning_email','ClientTimeOut','down');
write_log('Log',"[$client_table{$client_id}{host}]warning mail send:ClientTimeOut"); #不应该在这里写日志
#TODO:set warning etc
}
sub update_rrd_file
{
my ($kernel,$heap,$client_alias,$yaml) = @_[KERNEL,HEAP,ARG0,ARG1];
say "update rrd datafile";
my $rrd = RRDTool::OO->new(file => $cfg->{$client_alias}->{RRDfile} ) || return;
#尝试所有数据绘在同一张图上
#构造一个hash
my %value_structure = map{$_,$yaml->{$_}} get_ds($rrd); #这里要加判断
eval{
$rrd->update(
time => time()+60*5,
values => \%value_structure,
);
};
if ($@)
{
write_log('Log',"[$client_alias]rrd update failed");
return;
}
write_log('Log',"[$client_alias]rrd update success");
}
sub send_warning_email
{
my ($kernel,$heap,$item,$value) = @_[KERNEL,HEAP,ARG0,ARG1];
say "send mail ok";
my @to = split / /,$cfg->{MailServer}->{to};
my $subject = '监控项目'.$item.'异常';
my $msg = '当前值:'.$value;
print "$subject;$msg\n";
# my $sender = new Mail::Sender();
# my @protocols = $sender->QueryAuthProtocols(); #查询服务器支持的认证方式
# say "QueryAuthProtocols:@protocols";
# if ($sender->MailMsg({
# smtp => $cfg->{MailServer}->{smtp},
# from => $cfg->{MailServer}->{from},
# to => \@to,
# subject => $subject, #主题
# msg => $msg, #内容
# auth => 'LOGIN', #smtp的验证方式
# authid =>$cfg->{MailServer}->{user}, #user
# authpwd => $cfg->{MailServer}->{passwd}, #pwd
# }) < 0) {
# warn "$Mail::Sender::Error\n";
# }
# else
# {
# print "send mail OK.\n";
# }
# POE::Component::Client::SMTP->send(
# # Email related parameters
# From => $cfg->{MailServer}->{from} || 'Admin',
# To => \@to,
# Body => \$email_body, # here's where your message is stored use Email::MIME
# Server => $cfg->{MailServer}->{smtp},
# # POE related parameters
# Alias => 'smtp',
# SMTP_Success => 'send_success',
# SMTP_Failure => 'send_failure',
# );
}
sub write_db
{
my ($kernel,$heap,$client_alias,$yaml) = @_[KERNEL,HEAP,ARG0,ARG1];
}
sub write_log
{
# my ($kernel,$heap,$type,$msg) = @_[KERNEL,HEAP,ARG0,ARG1];
my ($type,$msg) = @_;
my $logger = Log::Log->new(file => $cfg->{General}->{log},size => $cfg->{General}->{log_size});
my %method =(
Log => sub{$logger->Log(shift);},
Fatal => sub{$logger->Fatal(shift);}
);
$method{$type}->($msg);
return 1;
}
sub ClientDisconnected
{
my ($kernel,$heap) = @_[KERNEL,HEAP];
$kernel->alarm_remove(shift @alarm_id); #warn!!
$kernel->alarm_remove($client_table{$heap->{client}->ID}->{task_id});
say "ClientDisconnected:delete client ok";
write_log('Log',"[$heap->{remote_ip}]Disconnected");
delete $client_table{$heap->{client}->ID};
delete $heap->{client};
}
sub set_client_down_flag
{
#超时或者over时执行
my $client_id =shift;
$client_table{$client_id}{status} = 1 ;#1=>down,0=>up
my $host = $client_table{$client_id}{host};
my $alias = $client_table{$client_id}{alias};
}
sub get_ds
{
return keys %{ shift->info()->{ds}};
}
|