From 92db819eae203c5c5f9cdfee502415373ac4d844 Mon Sep 17 00:00:00 2001 From: Quentin Garnier Date: Mon, 20 Oct 2014 17:24:58 +0200 Subject: [PATCH] Refs #7246 WIP --- .../vmware/src/centreon/esxd/cmdhealthhost.pm | 104 +++--- connectors/vmware/src/centreon/esxd/common.pm | 101 ++---- .../vmware/src/centreon/esxd/connector.pm | 299 ++++++++++++++++++ .../src/centreon/script/centreonesxd.pm | 277 +++++----------- 4 files changed, 452 insertions(+), 329 deletions(-) create mode 100644 connectors/vmware/src/centreon/esxd/connector.pm diff --git a/connectors/vmware/src/centreon/esxd/cmdhealthhost.pm b/connectors/vmware/src/centreon/esxd/cmdhealthhost.pm index 26a1cfc40..fcf0a2b7d 100644 --- a/connectors/vmware/src/centreon/esxd/cmdhealthhost.pm +++ b/connectors/vmware/src/centreon/esxd/cmdhealthhost.pm @@ -9,7 +9,6 @@ sub new { my $class = shift; my $self = {}; $self->{logger} = shift; - $self->{obj_esxd} = shift; $self->{commandName} = 'healthhost'; bless $self, $class; @@ -22,26 +21,38 @@ sub getCommandName { } sub checkArgs { - my $self = shift; - my ($host) = @_; + my ($self, %options) = @_; - if (!defined($host) || $host eq "") { - $self->{logger}->writeLogError("ARGS error: need hostname"); + if (!defined($options{arguments}->{esx_hostname}) || $options{arguments}->{esx_hostname} eq "") { + $options{manager}->{output}->output_add(severity => 'UNKNOWN', + short_msg => "Argument error: need esx hostname"); return 1; } return 0; } sub initArgs { - my $self = shift; - $self->{lhost} = $_[0]; - $self->{storage_status} = (defined($_[1]) && $_[1] == 1) ? 1 : 0; + my ($self, %options) = @_; + + foreach (keys %{$options{arguments}}) { + $self->{$_} = $options{arguments}->{$_}; + } + $self->{manager} = centreon::esxd::common::init_response(); + $self->{manager}->{output}->{plugin} = $options{arguments}->{identity}; + $self->{manager}->{perfdata}->threshold_validate(label => 'warning', value => 0); + $self->{manager}->{perfdata}->threshold_validate(label => 'critical', value => 0); +} + +sub set_connector { + my ($self, %options) = @_; + + $self->{obj_esxd} = $options{connector}; } sub run { my $self = shift; - my %filters = ('name' => $self->{lhost}); + my %filters = (name => $self->{esx_hostname}); my @properties = ('runtime.healthSystemRuntime.hardwareStatusInfo', 'runtime.healthSystemRuntime.systemHealthInfo.numericSensorInfo', 'runtime.connectionState'); my $result = centreon::esxd::common::get_entities_host($self->{obj_esxd}, 'HostSystem', \%filters, \@properties); @@ -49,20 +60,13 @@ sub run { return ; } - return if (centreon::esxd::common::host_state($self->{obj_esxd}, $self->{lhost}, + return if (centreon::esxd::common::host_state($self->{obj_esxd}, $self->{esx_hostname}, $$result[0]->{'runtime.connectionState'}->val) == 0); - my $status = 0; # OK - my $output_critical = ''; - my $output_critical_append = ''; - my $output_warning = ''; - my $output_warning_append = ''; - my $output = ''; - my $output_append = ''; - my $OKCount = 0; - my $CAlertCount = 0; - my $WAlertCount = 0; foreach my $entity_view (@$result) { + my $OKCount = 0; + my $CAlertCount = 0; + my $WAlertCount = 0; my $cpuStatusInfo = $entity_view->{'runtime.healthSystemRuntime.hardwareStatusInfo'}->{cpuStatusInfo}; my $memoryStatusInfo = $entity_view->{'runtime.healthSystemRuntime.hardwareStatusInfo'}->{memoryStatusInfo}; my $storageStatusInfo = $entity_view->{'runtime.healthSystemRuntime.hardwareStatusInfo'}->{storageStatusInfo}; @@ -72,14 +76,10 @@ sub run { if (defined($cpuStatusInfo)) { foreach (@$cpuStatusInfo) { if ($_->status->key =~ /^red$/i) { - centreon::esxd::common::output_add(\$output_critical, \$output_critical_append, ", ", - $_->name . ": " . $_->status->summary); - $status = centreon::esxd::common::errors_mask($status, 'CRITICAL'); + $self->{manager}->{output}->output_add(long_msg => $_->name . ": " . $_->status->summary); $CAlertCount++; } elsif ($_->status->key =~ /^yellow$/i) { - centreon::esxd::common::output_add(\$output_warning, \$output_warning_append, ", ", - $_->name . ": " . $_->status->summary); - $status = centreon::esxd::common::errors_mask($status, 'WARNING'); + $self->{manager}->{output}->output_add(long_msg => $_->name . ": " . $_->status->summary); $WAlertCount++; } else { $OKCount++; @@ -91,14 +91,10 @@ sub run { if (defined($memoryStatusInfo)) { foreach (@$memoryStatusInfo) { if ($_->status->key =~ /^red$/i) { - centreon::esxd::common::output_add(\$output_critical, \$output_critical_append, ", ", - $_->name . ": " . $_->status->summary); - $status = centreon::esxd::common::errors_mask($status, 'CRITICAL'); + $self->{manager}->{output}->output_add(long_msg => $_->name . ": " . $_->status->summary); $CAlertCount++; } elsif ($_->status->key =~ /^yellow$/i) { - centreon::esxd::common::output_add(\$output_warning, \$output_warning_append, ", ", - $_->name . ": " . $_->status->summary); - $status = centreon::esxd::common::errors_mask($status, 'WARNING'); + $self->{manager}->{output}->output_add(long_msg => $_->name . ": " . $_->status->summary); $WAlertCount++; } else { $OKCount++; @@ -110,14 +106,10 @@ sub run { if ($self->{storage_status} == 1 && defined($storageStatusInfo)) { foreach (@$storageStatusInfo) { if ($_->status->key =~ /^red$/i) { - centreon::esxd::common::output_add(\$output_critical, \$output_critical_append, ", ", - $_->name . ": " . $_->status->summary); - $status = centreon::esxd::common::errors_mask($status, 'CRITICAL'); + $self->{manager}->{output}->output_add(long_msg => $_->name . ": " . $_->status->summary); $CAlertCount++; } elsif ($_->status->key =~ /^yellow$/i) { - centreon::esxd::common::output_add(\$output_warning, \$output_warning_append, ", ", - $_->name . ": " . $_->status->summary); - $status = centreon::esxd::common::errors_mask($status, 'WARNING'); + $self->{manager}->{output}->output_add(long_msg => $_->name . ": " . $_->status->summary); $WAlertCount++; } else { $OKCount++; @@ -129,34 +121,32 @@ sub run { if (defined($numericSensorInfo)) { foreach (@$numericSensorInfo) { if ($_->healthState->key =~ /^red$/i) { - centreon::esxd::common::output_add(\$output_critical, \$output_critical_append, ", ", - $_->sensorType . " sensor " . $_->name . ": ".$_->healthState->summary); - $status = centreon::esxd::common::errors_mask($status, 'CRITICAL'); + $self->{manager}->{output}->output_add(long_msg => $_->sensorType . " sensor " . $_->name . ": ".$_->healthState->summary); $CAlertCount++; } elsif ($_->healthState->key =~ /^yellow$/i) { - centreon::esxd::common::output_add(\$output_warning, \$output_warning_append, ", ", - $_->sensorType . " sensor " . $_->name . ": ".$_->healthState->summary); - $status = centreon::esxd::common::errors_mask($status, 'WARNING'); + $self->{manager}->{output}->output_add(long_msg => $_->sensorType . " sensor " . $_->name . ": ".$_->healthState->summary); $WAlertCount++; } else { $OKCount++; } } } + + my $exit = $self->{manager}->{perfdata}->threshold_check(value => $WAlertCount, + threshold => [ { label => 'warning', exit_litteral => 'warning' } ]); + if (!$self->{manager}->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{manager}->{output}->output_add(severity => $exit, + short_msg => sprintf("%s health issue(s) found", $WAlertCount)); + } + $exit = $self->{manager}->{perfdata}->threshold_check(value => $CAlertCount, threshold => [ { label => 'critical', 'exit_litteral' => 'critical' } ]); + if (!$self->{manager}->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{manager}->{output}->output_add(severity => $exit, + short_msg => sprintf("%s health issue(s) found", $CAlertCount)); + } + + $self->{manager}->{output}->output_add(severity => 'OK', + short_msg => sprintf("All %s health checks are green", $OKCount)); } - - if ($output_critical ne "") { - $output .= $output_append . "CRITICAL - $CAlertCount health issue(s) found: $output_critical"; - $output_append = ". "; - } - if ($output_warning ne "") { - $output .= $output_append . "WARNING - $WAlertCount health issue(s) found: $output_warning"; - } - if ($status == 0) { - $output = "All $OKCount health checks are green"; - } - - $self->{obj_esxd}->print_response(centreon::esxd::common::get_status($status) . "|$output\n"); } 1; diff --git a/connectors/vmware/src/centreon/esxd/common.pm b/connectors/vmware/src/centreon/esxd/common.pm index 147cb3f3d..9036dda32 100644 --- a/connectors/vmware/src/centreon/esxd/common.pm +++ b/connectors/vmware/src/centreon/esxd/common.pm @@ -14,10 +14,6 @@ use centreon::plugins::perfdata; my $manager_display = {}; -my %ERRORS = ( "OK" => 0, "WARNING" => 1, "CRITICAL" => 2, "UNKNOWN" => 3, "PENDING" => 4); -my %MYERRORS = (0 => "OK", 1 => "WARNING", 3 => "CRITICAL", 7 => "UNKNOWN"); -my %MYERRORS_MASK = ("CRITICAL" => 3, "WARNING" => 1, "UNKNOWN" => 7, "OK" => 0); - sub init_response { $manager_display->{options} = centreon::plugins::options->new(); $manager_display->{output} = centreon::plugins::output->new(options => $manager_display->{options}); @@ -30,64 +26,37 @@ sub response { my (%options) = @_; my $stdout; - { + if (!defined($options{stdout})) { local *STDOUT; $manager_display->{output}->{option_results}->{output_json} = 1; open STDOUT, '>', \$stdout; - $manager_display->{output}->display(force_long_output => 1); + $manager_display->{output}->display(force_long_output => 1, nolabel => 1); + } else { + $stdout = $options{stdout}; } - print "====stdout === $stdout===\n"; - zmq_sendmsg($options{endpoint}, $options{identity}, ZMQ_SNDMORE); - zmq_sendmsg($options{endpoint}, "RESPSERVER " . $stdout); -} - -sub errors_mask { - my ($status, $state) = @_; - - $status |= $MYERRORS_MASK{$state}; - return $status; -} - -sub get_status { - my ($state) = @_; - - return $ERRORS{$MYERRORS{$state}}; -} - -sub response_client2 { - my ($obj_esxd, $id, $msg) = @_; - - # Avoid croak kill. Can be happened (not often) - eval { - ${$obj_esxd->{sockets}->{$id}->{obj}}->send($msg); - }; - $obj_esxd->{read_select}->remove(${$obj_esxd->{sockets}->{$id}->{obj}}); - close ${$obj_esxd->{sockets}->{$id}->{obj}}; - delete $obj_esxd->{sockets}->{$id}; -} - -sub response_client1 { - my ($obj_esxd, $rh, $current_fileno, $msg) = @_; - - # Avoid croak kill. Can be happened (not often) - eval { - $rh->send($msg); - }; - $obj_esxd->{read_select}->remove($rh); - close $rh; - delete $obj_esxd->{sockets}->{$current_fileno}; + if (defined($options{reinit})) { + my $context = zmq_init(); + $options{endpoint} = zmq_socket($context, ZMQ_DEALER); + zmq_connect($options{endpoint}, $options{reinit}); + } + if (defined($options{identity})) { + zmq_sendmsg($options{endpoint}, $options{identity}, ZMQ_SNDMORE); + } + zmq_sendmsg($options{endpoint}, $options{token} . " " . $stdout); } sub vmware_error { my ($obj_esxd, $lerror) = @_; + $manager_display->{output}->output_add(long_msg => $lerror); $obj_esxd->{logger}->writeLogError("'" . $obj_esxd->{whoaim} . "' $lerror"); - $lerror =~ s/\n/ /g; if ($lerror =~ /NoPermissionFault/i) { - $obj_esxd->print_response("-2|Error: Not enough permissions\n"); + $manager_display->{output}->output_add(severity => 'UNKNOWN', + short_msg => 'VMWare error: not enought permissions'); } else { - $obj_esxd->print_response("-1|Error: " . $lerror . "\n"); + $manager_display->{output}->output_add(severity => 'UNKNOWN', + short_msg => 'VMWare error (verbose mode for more details)'); } return undef; } @@ -104,7 +73,7 @@ sub connect_vsphere { password => $password); alarm(0); }; - if($@) { + if ($@) { $logger->writeLogError("'$whoaim' No response from VirtualCenter server") if($@ =~ /TIMEOUT/); $logger->writeLogError("'$whoaim' You need to upgrade HTTP::Message!") if($@ =~ /HTTP::Message/); $logger->writeLogError("'$whoaim' Login to VirtualCenter server failed: $@"); @@ -120,12 +89,6 @@ sub connect_vsphere { return 0; } -sub output_add($$$$) { - my ($output_str, $output_append, $delim, $str) = (shift, shift, shift, shift); - $$output_str .= $$output_append . $str; - $$output_append = $delim; -} - sub simplify_number { my ($number, $cnt) = @_; $cnt = 2 if (!defined($cnt)); @@ -252,7 +215,8 @@ sub generic_performance_values_historic { my $perfdata = $obj_esxd->{perfmanager_view}->QueryPerf(querySpec => \@perf_query_spec); if (!$$perfdata[0] || !defined($$perfdata[0]->value)) { - $obj_esxd->print_response("-3|Error: Cannot get value for counters. Maybe you have call a wrong instance.\n"); + $manager_display->{output}->output_add(severity => 'UNKNOWN', + short_msg => 'Cannot get value for counters. Maybe you have call a wrong instance'); return undef; } foreach my $val (@$perfdata) { @@ -261,7 +225,8 @@ sub generic_performance_values_historic { $results{$_->id->counterId . ":" . (defined($_->id->instance) ? $_->id->instance : "")} = undef; next; } elsif (!defined($_->value)) { - $obj_esxd->print_response("-3|Error: Cannot get value for counters. Maybe there is time sync problem (check the esxd server and the target also).\n"); + $manager_display->{output}->output_add(severity => 'UNKNOWN', + short_msg => 'Cannot get value for counters. Maybe there is time sync problem (check the esxd server and the target also)'); return undef; } @@ -330,8 +295,8 @@ sub get_entities_host { } if (!@$entity_views) { my $status = 0; - $status = errors_mask($status, 'UNKNOWN'); - $obj_esxd->print_response(get_status($status) . "|Object $view_type does not exist.\n"); + $manager_display->{output}->output_add(severity => 'UNKNOWN', + short_msg => "Object $view_type does not exist"); return undef; } #eval { @@ -400,15 +365,15 @@ sub vm_state { if ($connection_state !~ /^connected$/i) { my $output = "VM '" . $vm . "' not connected. Current Connection State: '$connection_state'."; - my $status = errors_mask(0, $obj_esxd->{centreonesxd_config}->{vm_state_error}); - $obj_esxd->print_response(get_status($status) . "|$output\n"); + $manager_display->{output}->output_add(severity => $obj_esxd->{centreonesxd_config}->{vm_state_error}, + short_msg => $output); return 0; } - if (!defined($nocheck_ps) && $power_state !~ /^poweredOn$/i) { + if (!defined($nocheck_ps) && $power_state !~ /^poweredOn$/i) { my $output = "VM '" . $vm . "' not running. Current Power State: '$power_state'."; - my $status = errors_mask(0, $obj_esxd->{centreonesxd_config}->{vm_state_error}); - $obj_esxd->print_response(get_status($status) . "|$output\n"); + $manager_display->{output}->output_add(severity => $obj_esxd->{centreonesxd_config}->{vm_state_error}, + short_msg => $output); return 0; } @@ -420,8 +385,8 @@ sub host_state { if ($connection_state !~ /^connected$/i) { my $output = "Host '" . $host . "' not connected. Current Connection State: '$connection_state'."; - my $status = errors_mask(0, $obj_esxd->{centreonesxd_config}->{host_state_error}); - $obj_esxd->print_response(get_status($status) . "|$output\n"); + $manager_display->{output}->output_add(severity => $obj_esxd->{centreonesxd_config}->{host_state_error}, + short_msg => $output); return 0; } @@ -443,7 +408,7 @@ sub stats_info { } elsif ($$args[0] ne '' and $num_connection >= $$args[0]) { $status = errors_mask($status, 'WARNING'); } - response_client1($obj_esxd, $rh, $current_fileno, get_status($status) . "|$output\n"); + #response_client1($obj_esxd, $rh, $current_fileno, get_status($status) . "|$output\n"); } 1; diff --git a/connectors/vmware/src/centreon/esxd/connector.pm b/connectors/vmware/src/centreon/esxd/connector.pm new file mode 100644 index 000000000..3b8fb79a6 --- /dev/null +++ b/connectors/vmware/src/centreon/esxd/connector.pm @@ -0,0 +1,299 @@ +#!/usr/bin/perl -w + +package centreon::esxd::connector; + +use strict; +use VMware::VIRuntime; +use VMware::VILib; +use JSON; +use ZMQ::LibZMQ3; +use ZMQ::Constants qw(:all); +use File::Basename; +use POSIX ":sys_wait_h"; +use centreon::script; +use centreon::esxd::common; + +my %handlers = (TERM => {}, HUP => {}, CHLD => {}); +my ($connector, $backend); + +sub new { + my ($class, %options) = @_; + $connector = {}; + bless $connector, $class; + + $connector->{child_proc} = {}; + $connector->{return_child} = {}; + $connector->{vsphere_connected} = 0; + $connector->{last_time_vsphere} = undef; + $connector->{keeper_session_time} = undef; + $connector->{last_time_check} = undef; + $connector->{perfmanager_view} = undef; + $connector->{perfcounter_cache} = {}; + $connector->{perfcounter_cache_reverse} = {}; + $connector->{perfcounter_refreshrate} = 20; + $connector->{perfcounter_speriod} = -1; + $connector->{stop} = 0; + $connector->{childs_vpshere_pid} = {}; + $connector->{session1} = undef; + + $connector->{modules_registry} = $options{modules_registry}; + $connector->{logger} = $options{logger}; + $connector->{whoaim} = $options{name}; + $connector->{module_date_parse_loaded} = $options{module_date_parse_loaded}; + $connector->{config_child_timeout} = $options{config}->{timeout}; + $connector->{config_stop_child_timeout} = $options{config}->{timeout_kill}; + $connector->{config_vsphere_session_heartbeat} = $options{config}->{refresh_keeper_session}; + $connector->{config_vsphere_connect_timeout} = $options{config}->{timeout_vsphere}; + $connector->{config_vsphere_url} = $options{config}->{vsphere_server}->{$options{name}}->{url}; + $connector->{config_vsphere_user} = $options{config}->{vsphere_server}->{$options{name}}->{username}; + $connector->{config_vsphere_pass} = $options{config}->{vsphere_server}->{$options{name}}->{password}; + + return $connector; +} + +sub set_signal_handlers { + my $self = shift; + + $SIG{TERM} = \&class_handle_TERM; + $handlers{TERM}->{$self} = sub { $self->handle_TERM() }; + $SIG{HUP} = \&class_handle_HUP; + $handlers{HUP}->{$self} = sub { $self->handle_HUP() }; + $SIG{CHLD} = \&class_handle_CHLD; + $handlers{CHLD}->{$self} = sub { $self->handle_CHLD() }; +} + +sub class_handle_TERM { + foreach (keys %{$handlers{TERM}}) { + &{$handlers{TERM}->{$_}}(); + } +} + +sub class_handle_HUP { + foreach (keys %{$handlers{HUP}}) { + &{$handlers{HUP}->{$_}}(); + } +} + +sub class_handle_CHLD { + foreach (keys %{$handlers{CHLD}}) { + &{$handlers{CHLD}->{$_}}(); + } +} + +sub handle_TERM { + my $self = shift; + $self->{logger}->writeLogInfo("$$ Receiving order to stop..."); + $self->{stop} = 1; +} + +sub handle_HUP { + my $self = shift; + $self->{logger}->writeLogInfo("$$ Receiving order to reload..."); + # TODO +} + +sub handle_CHLD { + my $self = shift; + my $child_pid; + + while (($child_pid = waitpid(-1, &WNOHANG)) > 0) { + $self->{return_child}{$child_pid} = {status => 1, rtime => time()}; + } + $SIG{CHLD} = \&class_handle_CHLD; +} + +sub response_router { + my ($self, %options) = @_; + + my $manager = centreon::esxd::common::init_response(); + $manager->{output}->output_add(severity => $options{severity}, + short_msg => $options{msg}); + $manager->{output}->{plugin} = $options{identity}; + centreon::esxd::common::response(token => 'RESPSERVER2', endpoint => $backend); +} + +sub verify_child { + my $self = shift; + my $progress = 0; + + # Verify process + foreach (keys %{$self->{child_proc}}) { + # Check ctime + if (time() - $self->{child_proc}->{$_}->{ctime} > $self->{config_child_timeout}) { + $self->response_router(severity => 'UNKNOWN', msg => 'Timeout process', + identity => $_); + kill('INT', $self->{child_proc}->{$_}->{pid}); + delete $self->{child_proc}->{$_}; + } else { + $progress++; + } + } + + # Clean old hash CHILD (security) + foreach (keys %{$self->{return_child}}) { + if (time() - $self->{return_child}->{$_}->{rtime} > 600) { + $self->{logger}->writeLogInfo("Clean Old return_child list = " . $_); + delete $self->{return_child}->{$_}; + } + } + + return $progress; +} + +sub reqclient { + my ($self, %options) = @_; + + my $result; + eval { + $result = JSON->new->utf8->decode($options{data}); + }; + if ($@) { + $self->{logger}->writeLogError("Cannot decode JSON: $@ (options{data}"); + return ; + } + + if ($self->{vsphere_connected}) { + $self->{logger}->writeLogInfo("vpshere '" . $self->{whoaim} . "' handler asking: $options{data}"); + + $self->{child_proc}->{$result->{identity}} = { ctime => time() }; + $self->{child_proc}->{$result->{identity}}->{pid} = fork; + if (!$self->{child_proc}->{$result->{identity}}->{pid}) { + $self->{modules_registry}->{$result->{command}}->set_connector(connector => $self); + $self->{modules_registry}->{$result->{command}}->initArgs(arguments => $result); + $self->{modules_registry}->{$result->{command}}->run(); + + centreon::esxd::common::response(token => 'RESPSERVER2', endpoint => $backend, reinit => 'ipc://routing.ipc'); + exit(0); + } + } else { + $self->response_router(severity => 'UNKNOWN', msg => 'Container connection problem', + identity => $result->{identity}); + } +} + +sub vsphere_event { + while (1) { + # Process all parts of the message + my $message = zmq_recvmsg($backend); + my $data = zmq_msg_data($message); + + if ($data =~ /^REQCLIENT\s+(.*)$/msi) { + $connector->reqclient(data => $1); + } + + my $more = zmq_getsockopt($backend, ZMQ_RCVMORE); + last unless $more; + } +} + +sub run { + my ($connector) = shift; + my $timeout_process = 0; + + my $context = zmq_init(); + + $backend = zmq_socket($context, ZMQ_DEALER); + zmq_setsockopt($backend, ZMQ_IDENTITY, "server-" . $connector->{whoaim}); + zmq_connect($backend, 'ipc://routing.ipc'); + + # Initialize poll set + my @poll = ( + { + socket => $backend, + events => ZMQ_POLLIN, + callback => \&vsphere_event, + }, + ); + + while (1) { + my $progress = $connector->verify_child(); + + ##### + # Manage ending + ##### + if ($connector->{stop} && $timeout_process > $connector->{config_stop_child_timeout}) { + $connector->{logger}->writeLogError("'" . $connector->{whoaim} . "' Kill child not gently."); + foreach (keys %{$connector->{child_proc}}) { + kill('INT', $connector->{child_proc}->{$_}->{pid}); + } + $progress = 0; + } + if ($connector->{stop} && !$progress) { + if ($connector->{vsphere_connected}) { + eval { + $connector->{session1}->logout(); + }; + } + exit (0); + } + + ### + # Manage vpshere connection + ### + if (defined($connector->{last_time_vsphere}) && defined($connector->{last_time_check}) + && $connector->{last_time_vsphere} < $connector->{last_time_check}) { + $connector->{logger}->writeLogError("'" . $connector->{whoaim} . "' Disconnect"); + $connector->{vsphere_connected} = 0; + eval { + $connector->{session1}->logout(); + }; + } + + if ($connector->{vsphere_connected} == 0) { + if (!centreon::esxd::common::connect_vsphere($connector->{logger}, + $connector->{whoaim}, + $connector->{config_vsphere_connect_timeout}, + \$connector->{session1}, + $connector->{config_vsphere_url}, + $connector->{config_vsphere_user}, + $connector->{config_vsphere_pass})) { + $connector->{logger}->writeLogInfo("'" . $connector->{whoaim} . "' Vsphere connection ok"); + $connector->{logger}->writeLogInfo("'" . $connector->{whoaim} . "' Create perf counters cache in progress"); + if (!centreon::esxd::common::cache_perf_counters($connector)) { + $connector->{last_time_vsphere} = time(); + $connector->{keeper_session_time} = time(); + $connector->{vsphere_connected} = 1; + $connector->{logger}->writeLogInfo("'" . $connector->{whoaim} . "' Create perf counters cache done"); + } + } + } + + ### + # Manage session time + ### + if (defined($connector->{keeper_session_time}) && + (time() - $connector->{keeper_session_time}) > ($connector->{config_vsphere_session_heartbeat} * 60)) { + my $stime; + + eval { + $stime = $connector->{session1}->get_service_instance()->CurrentTime(); + $connector->{keeper_session_time} = time(); + }; + if ($@) { + $connector->{logger}->writeLogError("$@"); + $connector->{logger}->writeLogError("'" . $connector->{whoaim} . "' Ask a new connection"); + # Ask a new connection + $connector->{last_time_check} = time(); + } else { + $connector->{logger}->writeLogInfo("'" . $connector->{whoaim} . "' Get current time = " . Data::Dumper::Dumper($stime)); + } + } + + my $data_element; + my @rh_set; + if ($connector->{vsphere_connected} == 0) { + sleep(5); + } + if ($connector->{stop} != 0) { + sleep(1); + $timeout_process++; + next; + } + + zmq_poll(\@poll, 5000); + } +} + +1; + +__END__ \ No newline at end of file diff --git a/connectors/vmware/src/centreon/script/centreonesxd.pm b/connectors/vmware/src/centreon/script/centreonesxd.pm index eecf6cea6..e78488bde 100644 --- a/connectors/vmware/src/centreon/script/centreonesxd.pm +++ b/connectors/vmware/src/centreon/script/centreonesxd.pm @@ -1,19 +1,22 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl package centreon::script::centreonesxd; use strict; +use warnings; use VMware::VIRuntime; use VMware::VILib; use ZMQ::LibZMQ3; use ZMQ::Constants qw(:all); use File::Basename; use POSIX ":sys_wait_h"; +use JSON; use Data::Dumper; use centreon::script; use centreon::esxd::common; +use centreon::esxd::connector; -my ($centreonesxd, $frontend, $backend); +my ($centreonesxd, $frontend); BEGIN { $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; @@ -22,8 +25,9 @@ BEGIN { use base qw(centreon::script); use vars qw(%centreonesxd_config); -my $VERSION = "1.5.6"; +my $VERSION = "1.6.0"; my %handlers = (TERM => {}, HUP => {}, CHLD => {}); + my @load_modules = ('centreon::esxd::cmdcountvmhost', 'centreon::esxd::cmdcpuhost', 'centreon::esxd::cmdcpuvm', @@ -87,21 +91,9 @@ sub new { } ); - $self->{child_proc} = {}; $self->{return_child} = {}; - $self->{vsphere_connected} = 0; - $self->{last_time_vsphere} = undef; - $self->{keeper_session_time} = undef; - $self->{last_time_check} = undef; - $self->{perfmanager_view} = undef; - $self->{perfcounter_cache} = {}; - $self->{perfcounter_cache_reverse} = {}; - $self->{perfcounter_refreshrate} = 20; - $self->{perfcounter_speriod} = -1; $self->{stop} = 0; - $self->{counter_request_id} = 0; $self->{childs_vpshere_pid} = {}; - $self->{session1} = undef; $self->{counter} = 0; $self->{whoaim} = undef; # to know which vsphere to connect $self->{module_date_parse_loaded} = 0; @@ -219,19 +211,13 @@ sub handle_CHLD { $SIG{CHLD} = \&class_handle_CHLD; } -sub print_response { - my $self = shift; - - print $self->{global_id} . "|" . $_[0]; -} - sub load_module { my $self = shift; for (@_) { (my $file = "$_.pm") =~ s{::}{/}g; require $file; - my $obj = $_->new($self->{logger}, $self); + my $obj = $_->new($self->{logger}); $self->{modules_registry}->{$obj->getCommandName()} = $obj; } } @@ -263,35 +249,64 @@ sub verify_child_vsphere { $count++; } } - + return $count; } -sub verify_child { - my $self = shift; - my $progress = 0; - - # Verify process - foreach (keys %{$self->{child_proc}}) { - # Check ctime - if (time() - $self->{child_proc}->{$_}->{ctime} > $self->{centreonesxd_config}->{timeout}) { - print "===timeout papa===\n"; - #print $handle_writer_pipe "$_|-1|Timeout Process.\n"; - kill('INT', $self->{child_proc}->{$_}->{pid}); - delete $self->{child_proc}->{$_}; - } else { - $progress++; - } +sub request { + my ($self, %options) = @_; + + # Decode json + my $result; + eval { + $result = JSON->new->utf8->decode($options{data}); + }; + if ($@) { + $options{manager}->{output}->output_add(severity => 'UNKNOWN', + short_msg => "Cannot decode json result: $@"); + centreon::esxd::common::response(token => 'RESPSERVER', endpoint => $frontend, identity => $options{identity}); + return ; } - # Clean old hash CHILD (security) - foreach (keys %{$self->{return_child}}) { - if (time() - $self->{return_child}->{$_}->{rtime} > 600) { - $self->{logger}->writeLogInfo("Clean Old return_child list = " . $_); - delete $self->{return_child}->{$_}; - } + if (!defined($self->{modules_registry}->{$result->{command}})) { + $options{manager}->{output}->output_add(severity => 'UNKNOWN', + short_msg => "Unknown method name '$result->{command}'"); + centreon::esxd::common::response(token => 'RESPSERVER', endpoint => $frontend, identity => $options{identity}); + return ; + } + if ($self->{modules_registry}->{$result->{command}}->checkArgs(manager => $options{manager}, + arguments => $result)) { + centreon::esxd::common::response(token => 'RESPSERVER', endpoint => $frontend, identity => $options{identity}); + return ; + } + if (!defined($self->{centreonesxd_config}->{vsphere_server}->{$result->{container}})) { + $options{manager}->{output}->output_add(severity => 'UNKNOWN', + short_msg => "Unknown container name '$result->{container}'"); + centreon::esxd::common::response(token => 'RESPSERVER', endpoint => $frontend, identity => $options{identity}); + return ; } - return $progress; + zmq_sendmsg($frontend, "server-" . $result->{container}, ZMQ_SNDMORE); + zmq_sendmsg($frontend, 'REQCLIENT ' . $options{data}); +} + +sub repserver { + my ($self, %options) = @_; + + # Decode json + my $result; + eval { + $result = JSON->new->utf8->decode($options{data}); + }; + if ($@) { + $self->{logger}->writeLogError("Cannot decode JSON: $@ (options{data}"); + return ; + } + + $result->{plugin}->{name} =~ /^client-(.*)$/; + my $identity = 'client-' . pack('H*', $1); + + centreon::esxd::common::response(token => 'RESPSERVER', endpoint => $frontend, + identity => $identity, stdout => $options{data}); } sub router_event { @@ -304,183 +319,37 @@ sub router_event { my $data = zmq_msg_data($message); my $manager = centreon::esxd::common::init_response(); - if ($centreonesxd->{stop} != 0) { # We quit so we say we're leaving ;) $manager->{output}->output_add(severity => 'UNKNOWN', short_msg => 'Daemon is restarting...'); - centreon::esxd::common::response(endpoint => $frontend, identity => $identity); - } elsif ($data =~ /^REQCLIENT\s+(.*)$/) { - - - - zmq_sendmsg($frontend, "server-" . $1, ZMQ_SNDMORE); - zmq_sendmsg($frontend, $data); - - my $manager = centreon::esxd::common::init_response(); - $manager->{output}->output_add(severity => 'OK', - short_msg => 'ma reponse enfin'); - centreon::esxd::common::response(endpoint => $frontend, identity => $identity); + centreon::esxd::common::response(token => 'RESPSERVER', endpoint => $frontend, identity => $identity); + } elsif ($data =~ /^REQCLIENT\s+(.*)$/msi) { + $centreonesxd->request(identity => $identity, data => $1, manager => $manager); + } elsif ($data =~ /^RESPSERVER2\s+(.*)$/msi) { + $centreonesxd->repserver(data => $1, manager => $manager); } - + my $more = zmq_getsockopt($frontend, ZMQ_RCVMORE); last unless $more; } } -sub vsphere_event { - while (1) { - # Process all parts of the message - my $message = zmq_recvmsg($backend); - print "=== " . Data::Dumper::Dumper(zmq_msg_data($message)) . " ===\n"; - - zmq_sendmsg($backend, 'bien tutu'); - - print "=PLAPLA=\n"; - my $data = zmq_msg_data($message); - if (defined($message)) { - if ($centreonesxd->{vsphere_connected}) { - $centreonesxd->{logger}->writeLogInfo("vpshere '" . $centreonesxd->{whoaim} . "' handler asking: $message"); - - $centreonesxd->{child_proc}->{pid} = fork; - if (!$centreonesxd->{child_proc}->{pid}) { - # Child - $centreonesxd->{logger}->{log_mode} = 1 if ($centreonesxd->{logger}->{log_mode} == 0); - my ($id, $name, @args) = split /\Q$centreonesxd->{separatorin}\E/, $message; - $centreonesxd->{global_id} = $id; - $centreonesxd->{modules_registry}->{$name}->initArgs(@args); - $centreonesxd->{modules_registry}->{$name}->run(); - exit(0); - } - } else { - #print $handle_writer_pipe "$id|-1|Vsphere connection error.\n"; - } - } - - my $more = zmq_getsockopt($backend, ZMQ_RCVMORE); - #zmq_sendmsg($backend, $message, $more ? ZMQ_SNDMORE : 0); - last unless $more; - } -} - -sub vsphere_handler { - $centreonesxd = shift; - my $timeout_process; - - my $context = zmq_init(); - - $backend = zmq_socket($context, ZMQ_DEALER); - zmq_setsockopt($backend, ZMQ_IDENTITY, "server-" . $centreonesxd->{whoaim}); - zmq_connect($backend, 'ipc://routing.ipc'); - #zmq_sendmsg($backend, 'ready'); - - # Initialize poll set - my @poll = ( - { - socket => $backend, - events => ZMQ_POLLIN, - callback => \&vsphere_event, - }, - ); - - while (1) { - my $progress = $centreonesxd->verify_child(); - - ##### - # Manage ending - ##### - if ($centreonesxd->{stop} && $timeout_process > $centreonesxd->{centreonesxd_config}->{timeout_kill}) { - $centreonesxd->{logger}->writeLogError("'" . $centreonesxd->{whoaim} . "' Kill child not gently."); - foreach (keys %{$centreonesxd->{child_proc}}) { - kill('INT', $centreonesxd->{child_proc}->{$_}->{pid}); - } - $progress = 0; - } - if ($centreonesxd->{stop} && !$progress) { - if ($centreonesxd->{vsphere_connected}) { - eval { - $centreonesxd->{session1}->logout(); - }; - } - exit (0); - } - - ### - # Manage vpshere connection - ### - if (defined($centreonesxd->{last_time_vsphere}) && defined($centreonesxd->{last_time_check}) - && $centreonesxd->{last_time_vsphere} < $centreonesxd->{last_time_check}) { - $centreonesxd->{logger}->writeLogError("'" . $centreonesxd->{whoaim} . "' Disconnect"); - $centreonesxd->{vsphere_connected} = 0; - eval { - $centreonesxd->{session1}->logout(); - }; - } - if ($centreonesxd->{vsphere_connected} == 0) { - if (!centreon::esxd::common::connect_vsphere($centreonesxd->{logger}, - $centreonesxd->{whoaim}, - $centreonesxd->{centreonesxd_config}->{timeout_vsphere}, - \$centreonesxd->{session1}, - $centreonesxd->{centreonesxd_config}->{vsphere_server}->{$centreonesxd->{whoaim}}->{url}, - $centreonesxd->{centreonesxd_config}->{vsphere_server}->{$centreonesxd->{whoaim}}->{username}, - $centreonesxd->{centreonesxd_config}->{vsphere_server}->{$centreonesxd->{whoaim}}->{password})) { - $centreonesxd->{logger}->writeLogInfo("'" . $centreonesxd->{whoaim} . "' Vsphere connection ok"); - $centreonesxd->{logger}->writeLogInfo("'" . $centreonesxd->{whoaim} . "' Create perf counters cache in progress"); - if (!centreon::esxd::common::cache_perf_counters($centreonesxd)) { - $centreonesxd->{last_time_vsphere} = time(); - $centreonesxd->{keeper_session_time} = time(); - $centreonesxd->{vsphere_connected} = 1; - $centreonesxd->{logger}->writeLogInfo("'" . $centreonesxd->{whoaim} . "' Create perf counters cache done"); - } - } - } - - ### - # Manage session time - ### - if (defined($centreonesxd->{keeper_session_time}) && - (time() - $centreonesxd->{keeper_session_time}) > ($centreonesxd->{centreonesxd_config}->{refresh_keeper_session} * 60)) { - my $stime; - - eval { - $stime = $centreonesxd->{session1}->get_service_instance()->CurrentTime(); - $centreonesxd->{keeper_session_time} = time(); - }; - if ($@) { - $centreonesxd->{logger}->writeLogError("$@"); - $centreonesxd->{logger}->writeLogError("'" . $centreonesxd->{whoaim} . "' Ask a new connection"); - # Ask a new connection - $centreonesxd->{last_time_check} = time(); - } else { - $centreonesxd->{logger}->writeLogInfo("'" . $centreonesxd->{whoaim} . "' Get current time = " . Data::Dumper::Dumper($stime)); - } - } - - my $data_element; - my @rh_set; - if ($centreonesxd->{vsphere_connected} == 0) { - sleep(5); - } - if ($centreonesxd->{stop} != 0) { - sleep(1); - next; - } - - print "====chaton===\n"; - zmq_poll(\@poll, 5000); - } -} - sub create_vsphere_child { my ($self, %options) = @_; + $self->{whoaim} = $options{vsphere_name}; $self->{centreonesxd_config}->{vsphere_server}->{$self->{whoaim}}->{running} = 0; $self->{logger}->writeLogInfo("Create vsphere sub-process for '" . $options{vsphere_name} . "'"); - $self->{whoaim} = $options{vsphere_name}; my $child_vpshere_pid = fork(); if ($child_vpshere_pid == 0) { - $self->vsphere_handler(); + my $connector = centreon::esxd::connector->new(name => $self->{whoaim}, + modules_registry => $self->{modules_registry}, + module_date_parse_loaded => $self->{module_date_parse_loaded}, + config => $self->{centreonesxd_config}, + logger => $self->{logger}); + $connector->run(); exit(0); } $self->{childs_vpshere_pid}->{$child_vpshere_pid} = $self->{whoaim};