new(plugin): eclipse mosquitto mqtt (#5059)

This commit is contained in:
sdepassio 2024-06-13 13:37:16 +02:00 committed by GitHub
parent fc601ab39e
commit 0294d1d560
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 1333 additions and 14 deletions

View File

@ -27,7 +27,7 @@ def test_plugin(plugin_name):
print(f"{plugin_name} folders_list : {folders_list}")
if len(folders_list) == 0:
return 0 # no tests present at the moment, but we still have tested the plugin can be installed.
robot_results = subprocess.run("robot -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(folders_list),
robot_results = subprocess.run("robot --exclude notauto -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(folders_list),
shell=True, check=False)
return robot_results.returncode

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"libnet-mqtt-simple-perl"
]
}

View File

@ -0,0 +1,10 @@
{
"pkg_name": "centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt",
"pkg_summary": "Centreon Plugin to monitor Eclipse Mosquitto throught MQTT",
"plugin_name": "centreon_eclipse_mosquitto_mqtt.pl",
"files": [
"centreon/plugins/script_mqtt.pm",
"centreon/plugins/mqtt.pm",
"apps/eclipse/mosquitto/mqtt/"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"perl(Net::MQTT::Simple)"
]
}

View File

@ -0,0 +1,90 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::eclipse::mosquitto::mqtt::mode::clients;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'global', type => 0 }
];
$self->{maps_counters}->{global} = [];
for my $label (('connected', 'maximum', 'active', 'inactive')) {
push @{$self->{maps_counters}->{global}},
{ label => 'clients-' . $label,
nlabel => 'clients.' . $label . '.count',
set => {
key_values => [{ name => $label }],
output_template => ucfirst($label) . ' clients: %d',
perfdatas => [
{ label => $label . '_clients', template => '%d',
min => 0 }
]
}
};
}
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
my %results = $options{mqtt}->queries(
base_topic => '$SYS/broker/clients/',
topics => ['connected', 'maximum', 'active', 'inactive']
);
for my $topic (keys %results) {
$self->{global}->{$topic} = $results{$topic};
}
}
1;
__END__
=head1 MODE
Check clients statistics.
=over 8
=item B<--warning-*> B<--critical-*>
Thresholds.
Can be: 'clients-connected', 'clients-maximum', 'clients-active', 'clients-inactive'.
=back
=cut

View File

@ -0,0 +1,89 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::eclipse::mosquitto::mqtt::mode::messages;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'global', type => 0 }
];
$self->{maps_counters}->{global} = [];
for my $label (('stored', 'received', 'sent')) {
push @{$self->{maps_counters}->{global}},
{ label => 'messages-' . $label,
nlabel => 'messages.' . $label . '.count',
set => {
key_values => [{ name => $label }],
output_template => ucfirst($label) . ' messages: %d',
perfdatas => [
{ label => $label . '_messages', template => '%d',
min => 0 }
]
}
};
}
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
my %results = $options{mqtt}->queries(
base_topic => '$SYS/broker/messages/',
topics => ['stored', 'received', 'sent']
);
for my $topic (keys %results) {
$self->{global}->{$topic} = $results{$topic};
}
}
1;
__END__
=head1 MODE
Check messages statistics.
=over 8
=item B<--warning-*> B<--critical-*>
Thresholds.
Can be: 'messages-stored', 'messages-received', 'messages-sent'.
=back
=cut

View File

@ -0,0 +1,205 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::eclipse::mosquitto::mqtt::mode::numericvalue;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::misc;
use Time::HiRes qw(time);
use POSIX qw(floor);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {
'topic:s' => { name => 'topic' },
'warning:s' => { name => 'warning' },
'critical:s' => { name => 'critical' },
'extracted-pattern:s' => { name => 'extracted_pattern' },
'format:s' => { name => 'format' },
'format-custom:s' => { name => 'format_custom' },
'perfdata-unit:s' => { name => 'perfdata_unit' },
'perfdata-name:s' => { name => 'perfdata_name', default => 'value' },
'perfdata-min:s' => { name => 'perfdata_min' },
'perfdata-max:s' => { name => 'perfdata_max' },
});
return $self;
}
sub custom_generic_output {
my ($self, %options) = @_;
my $format = $self->{instance_mode}{option_results}->{perfdata_name} . ' is: %s';
if (defined($self->{instance_mode}{option_results}->{format})) {
$format = $self->{instance_mode}{option_results}->{format};
}
my $value = $self->{result_values}->{numericvalue};
if (!centreon::plugins::misc::is_empty($self->{instance_mode}{option_results}->{format_custom})) {
$value = eval "$value $self->{instance_mode}{option_results}->{format_custom}";
}
return sprintf($format, $value);
}
sub custom_generic_perfdata {
my ($self, %options) = @_;
$self->{output}->perfdata_add(
label => $options{option_results}->{perfdata_name},
unit => $options{option_results}->{perfdata_unit},
value => $self->{result_values}->{numericvalue},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}),
min => $options{option_results}->{perfdata_min},
max => $options{option_results}->{perfdata_max}
);
}
sub custom_generic_threshold {
my ($self, %options) = @_;
return $self->{perfdata}->threshold_check(
value => $self->{result_values}->{numericvalue},
threshold => [
{ label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' },
{ label => 'unknown-' . $self->{thlabel}, exit_litteral => 'unknown' }
]
);
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'global', type => 0 }
];
$self->{maps_counters}->{global} = [
{ label => 'generic',
set => {
key_values => [{ name => 'numericvalue' }],
closure_custom_output => $self->can('custom_generic_output'),
closure_custom_perfdata => $self->can('custom_generic_perfdata'),
closure_custom_threshold_check => $self->can('custom_generic_threshold')
}
}
];
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
if (centreon::plugins::misc::is_empty($options{option_results}->{topic})) {
$self->{output}->add_option_msg(short_msg => 'Missing parameter --topic.');
$self->{output}->option_exit();
}
}
sub manage_selection {
my ($self, %options) = @_;
my $value = $options{mqtt}->query(
topic => $self->{option_results}->{topic}
);
if (!centreon::plugins::misc::is_empty($self->{option_results}->{extracted_pattern})) {
if ($value =~ /$self->{option_results}->{extracted_pattern}/ && defined($1)) {
$value = $1;
}
}
if ($value !~ /^-?\d+(?:\.\d+)?$/) {
$self->{output}->output_add(
severity => 'UNKNOWN',
short_msg => 'topic value is not numeric (' . $value . ')'
);
return;
}
if (!defined($value)) {
$self->{output}->add_option_msg(short_msg => "Cannot find information");
$self->{output}->option_exit();
}
$self->{global} = { numericvalue => $value };
}
1;
__END__
=head1 MODE
Check an Eclipse Mosquitto MQTT topic numeric value.
=over 8
=item B<--topic>
Topic value to check.
=item B<--warning>
Warning threshold.
=item B<--critical>
Critical threshold.
=item B<--extracted-pattern>
Define a pattern to extract a number from the returned string.
=item B<--format>
Output format (default: 'current value is %s')
=item B<--format-custom>
Apply a custom change on the value
(example to multiply the value: --format-custom='* 8').
=item B<--perfdata-unit>
Perfdata unit in perfdata output (default: '')
=item B<--perfdata-name>
Perfdata name in perfdata output (default: 'value')
=item B<--perfdata-min>
Minimum value to add in perfdata output (default: '')
=item B<--perfdata-max>
Maximum value to add in perfdata output (default: '')
=back
=cut

View File

@ -0,0 +1,180 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::eclipse::mosquitto::mqtt::mode::stringvalue;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::misc;
use Time::HiRes qw(time);
use POSIX qw(floor);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {
'topic:s' => { name => 'topic' },
'format-custom' => { name => 'format_custom' },
'warning-regexp:s' => { name => 'warning_regexp' },
'critical-regexp:s' => { name => 'critical_regexp' },
'unknown-regexp:s' => { name => 'unknown_regexp' },
'regexp-insensitive' => { name => 'use_iregexp' },
'format-ok:s' => { name => 'format_ok', default => 'value: %{value}' },
'format-warning:s' => { name => 'format_warning', default => 'value: %{value}' },
'format-critical:s' => { name => 'format_critical', default => 'value: %{value}' },
'format-unknown:s' => { name => 'format_unknown', default => 'value: %{value}' },
});
return $self;
}
sub custom_stringvalue_output {
my ($self, %options) = @_;
my $value = $self->{result_values}->{stringvalue};
if (!centreon::plugins::misc::is_empty($self->{instance_mode}->{option_results}->{'format_' . $self->{severity}})) {
my $format_value = $self->{instance_mode}->{option_results}->{'format_' . $self->{severity}};
$format_value =~ s/%\{value\}/$value/g;
$format_value =~ s/%\{(.*?)\}/$format_value->{$1}/g;
$value = $format_value;
}
return $value;
}
sub custom_stringvalue_threshold {
my ($self, %options) = @_;
my $severity = 'ok';
foreach my $check_severity (('critical', 'warning', 'unknown')) {
next if (centreon::plugins::misc::is_empty($self->{option_results}->{$check_severity . '_regexp'}));
my $regexp = $self->{option_results}->{$check_severity . '_regexp'};
if (defined($self->{option_results}->{use_iregexp}) && $options{value} =~ /$regexp/i) {
$severity = $check_severity;
} elsif (!defined($self->{option_results}->{use_iregexp}) && $options{value} =~ /$regexp/) {
$severity = $check_severity;
}
}
$self->{severity} = $severity;
return $severity;
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'global', type => 0 }
];
$self->{maps_counters}->{global} = [
{ label => 'generic',
set => {
key_values => [{ name => 'stringvalue' }],
closure_custom_output => $self->can('custom_stringvalue_output'),
closure_custom_threshold_check => \&custom_stringvalue_threshold
}
}
];
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
if (centreon::plugins::misc::is_empty($options{option_results}->{topic})) {
$self->{output}->add_option_msg(short_msg => 'Missing parameter --topic.');
$self->{output}->option_exit();
}
}
sub manage_selection {
my ($self, %options) = @_;
my $value = $options{mqtt}->query(
topic => $self->{option_results}->{topic}
);
if (!centreon::plugins::misc::is_empty($self->{option_results}->{format_custom})) {
if ($value =~ /$self->{option_results}->{format_custom}/ && defined($1)) {
$value = $1;
}
}
if (!defined($value)) {
$self->{output}->add_option_msg(short_msg => "Cannot find information");
$self->{output}->option_exit();
}
$self->{global} = { stringvalue => $value };
}
1;
__END__
=head1 MODE
Check an Eclipse Mosquitto MQTT topic value against regular expression.
=over 8
=item B<--topic>
Topic value to check.
=item B<--format-custom>
Apply a custom change on the value.
=item B<--warning-regexp>
Return Warning if the topic value match the regexp.
=item B<--critical-regexp>
Return Critical if the topic value match the regexp.
=item B<--regexp-insensitive>
Allows to use case-insensitive regexp.
=item B<--format-*>
Output format according to the threshold.
Can be:
'ok' (default: 'value: %{value}'),
'warning' (default: 'value: %{value}'),
'critical' (default: 'value: %{value}'),
'unknown' (default: 'value: %{value}').
=item B<--format-custom>
Apply a custom change on the value.
=back
=cut

View File

@ -0,0 +1,153 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::eclipse::mosquitto::mqtt::mode::uptime;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::misc;
use Time::HiRes qw(time);
use POSIX qw(floor);
my $unitdiv = { s => 1, w => 604800, d => 86400, h => 3600, m => 60 };
my $unitdiv_long = { s => 'seconds', w => 'weeks', d => 'days', h => 'hours', m => 'minutes' };
sub custom_uptime_output {
my ($self, %options) = @_;
return sprintf(
'uptime is: %s',
centreon::plugins::misc::change_seconds(value => $self->{result_values}->{uptime}, start => 'd')
);
}
sub custom_uptime_perfdata {
my ($self, %options) = @_;
$self->{output}->perfdata_add(
label => 'uptime', unit => $self->{instance_mode}->{option_results}->{unit},
nlabel => 'system.uptime.' . $unitdiv_long->{ $self->{instance_mode}->{option_results}->{unit} },
value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }),
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}),
min => 0
);
}
sub custom_uptime_threshold {
my ($self, %options) = @_;
return $self->{perfdata}->threshold_check(
value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }),
threshold => [
{ label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' },
{ label => 'unknown-' . $self->{thlabel}, exit_litteral => 'unknown' }
]
);
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'global', type => 0 }
];
$self->{maps_counters}->{global} = [
{ label => 'uptime',
set => {
key_values => [{ name => 'uptime' }],
closure_custom_output => $self->can('custom_uptime_output'),
closure_custom_perfdata => $self->can('custom_uptime_perfdata'),
closure_custom_threshold_check => $self->can('custom_uptime_threshold')
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {
'unit:s' => { name => 'unit', default => 's' }
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
if ($self->{option_results}->{unit} eq '' || !defined($unitdiv->{$self->{option_results}->{unit}})) {
$self->{option_results}->{unit} = 's';
}
}
sub manage_selection {
my ($self, %options) = @_;
my $topic = '$SYS/broker/uptime';
my $uptime = $options{mqtt}->query(
topic => $topic
);
if ($uptime =~ /^(\d+) seconds$/) {
$uptime = $1;
}
if (centreon::plugins::misc::is_empty($uptime)) {
$self->{output}->add_option_msg(short_msg => "Cannot find uptime information");
$self->{output}->option_exit();
}
$self->{global} = { uptime => $uptime };
}
1;
__END__
=head1 MODE
Check system uptime.
=over 8
=item B<--warning-uptime>
Warning threshold.
=item B<--critical-uptime>
Critical threshold.
=item B<--unit>
Select the time unit for thresholds. May be 's' for seconds, 'm' for minutes, 'h' for hours, 'd' for days, 'w' for weeks. Default is seconds.
=back
=cut

View File

@ -0,0 +1,52 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::eclipse::mosquitto::mqtt::plugin;
use strict;
use warnings;
use base qw(centreon::plugins::script_mqtt);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$self->{modes} = {
'uptime' => 'apps::eclipse::mosquitto::mqtt::mode::uptime',
'clients' => 'apps::eclipse::mosquitto::mqtt::mode::clients',
'messages' => 'apps::eclipse::mosquitto::mqtt::mode::messages',
'numeric-value' => 'apps::eclipse::mosquitto::mqtt::mode::numericvalue',
'string-value' => 'apps::eclipse::mosquitto::mqtt::mode::stringvalue'
};
return $self;
}
1;
__END__
=head1 PLUGIN DESCRIPTION
Check Eclipse Mosquitto using MQTT.
=cut

View File

@ -0,0 +1,210 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package centreon::plugins::mqtt;
use strict;
use warnings;
use Time::HiRes;
use Net::MQTT::Simple;
use Net::MQTT::Simple::SSL;
sub new {
my ($class, %options) = @_;
my $self = {};
bless $self, $class;
if (!defined($options{noptions}) || $options{noptions} != 1) {
$options{options}->add_options(arguments => {
'hostname|host:s' => { name => 'host' },
'mqtt-port:s' => { name => 'mqtt_port', default => 8883 },
'mqtt-ssl:s' => { name => 'mqtt_ssl', default => 1 },
'mqtt-ca-certificate:s' => { name => 'mqtt_ca_certificate' },
'mqtt-ssl-certificate:s' => { name => 'mqtt_ssl_certificate' },
'mqtt-ssl-key:s' => { name => 'mqtt_ssl_key' },
'mqtt-username:s' => { name => 'mqtt_username' },
'mqtt-password:s' => { name => 'mqtt_password' },
'mqtt-allow-insecure' => { name => 'mqtt_allow_insecure', default => 0 },
'mqtt-timeout:s' => { name => 'mqtt_timeout', default => 5 }
});
$options{options}->add_help(package => __PACKAGE__, sections => 'MQTT GLOBAL OPTIONS');
}
$self->{output} = $options{output};
$self->{connection_set} = 0;
return $self;
}
sub check_options {
my ($self, %options) = @_;
if (!defined($options{option_results}->{host})) {
$self->{output}->add_option_msg(short_msg => 'Missing parameter --hostname.');
$self->{output}->option_exit();
}
$self->{mqtt_host} = $options{option_results}->{host};
$self->{mqtt_port} = defined($options{option_results}->{mqtt_port}) && $options{option_results}->{mqtt_port} =~ /(\d+)/ ? $1 : 8883;
$self->{mqtt_ssl} = $options{option_results}->{mqtt_ssl};
$self->{mqtt_ca_certificate} = $options{option_results}->{mqtt_ca_certificate};
$self->{mqtt_ssl_certificate} = $options{option_results}->{mqtt_ssl_certificate};
$self->{mqtt_ssl_key} = $options{option_results}->{mqtt_ssl_key};
$self->{mqtt_username} = $options{option_results}->{mqtt_username};
$self->{mqtt_password} = $options{option_results}->{mqtt_password};
$self->{mqtt_allow_unsecure} = $options{option_results}->{mqtt_allow_unsecure};
$self->{mqtt_timeout} = $options{option_results}->{mqtt_timeout};
}
# Prepare the MQTT connection
sub set_mqtt_options {
my ($self, %options) = @_;
if ($self->{connection_set} == 1) {
return;
}
if (!centreon::plugins::misc::is_empty($self->{mqtt_allow_insecure}) && $self->{mqtt_allow_insecure} == 1) {
$ENV{MQTT_SIMPLE_ALLOW_INSECURE_LOGIN} = 1;
}
if (!centreon::plugins::misc::is_empty($self->{mqtt_ssl}) && $self->{mqtt_ssl} == 1) {
$self->{mqtt} = Net::MQTT::Simple::SSL->new($self->{mqtt_host}, {
LocalPort => $self->{mqtt_port},
SSL_ca_file => $self->{mqtt_ca_certificate},
SSL_cert_file => $self->{mqtt_ssl_certificate},
SSL_key_file => $self->{mqtt_ssl_key}
});
} else {
$self->{mqtt} = Net::MQTT::Simple->new($self->{mqtt_host} . ':' . $self->{mqtt_port});
}
$self->{mqtt}->login($self->{mqtt_username}, $self->{mqtt_password}) if (defined($self->{mqtt_username}) && defined($self->{mqtt_password}));
$self->{connection_set} = 1;
}
# Query a single topic
# Returns the message
# If no message is received, the script will exit with a message indicating that no message was received in the topic
sub query {
my ($self, %options) = @_;
$self->set_mqtt_options(%options);
my %mqtt_received;
my $starttime = Time::HiRes::time();
my $endtime = $starttime + $self->{mqtt_timeout};
$self->{mqtt}->subscribe($options{topic}, sub {
my ($topic, $message) = @_;
$mqtt_received{$topic} = $message;
});
my $messages_received = 0;
while ($messages_received == 0 and Time::HiRes::time() < $endtime) {
$self->{mqtt}->tick(5);
$messages_received = scalar keys %mqtt_received;
}
eval {
$self->{mqtt}->unsubscribe($options{topic});
};
if (%mqtt_received) {
return %mqtt_received{$options{topic}};
} else {
$self->{output}->add_option_msg(short_msg => 'No message in topic: ' . $options{topic});
$self->{output}->option_exit();
}
}
# Query multiple topics
# Returns a hash with the topics as keys and the messages as values
sub queries {
my ($self, %options) = @_;
$self->set_mqtt_options(%options);
my %mqtt_received;
foreach my $topic (@{$options{topics}}) {
my $topic_for_query = defined($options{base_topic}) ? $options{base_topic} . $topic : $topic;
my $result = $self->query(topic => $topic_for_query);
$mqtt_received{$topic} = $result;
}
return %mqtt_received;
}
1;
__END__
=head1 NAME
MQTT global
=head1 SYNOPSIS
MQTT class
=head1 MQTT OPTIONS
=over 8
=item B<--hostname>
Name or address of the host to monitor (mandatory).
=item B<--mqtt-port>
Port used by MQTT (default: 8883).
=item B<--mqtt-ssl>
Use SSL for MQTT connection (default: 1).
=item B<--mqtt-ca-certificate>
CA certificate file.
=item B<--mqtt-ssl-certificate>
Client SSL certificate file.
=item B<--mqtt-ssl-key>
Client SSL key file.
=item B<--mqtt-username>
MQTT username.
=item B<--mqtt-password>
MQTT password.
=item B<--mqtt-allow-insecure>
Allow unsecure login (default: 0).
=item B<--mqtt-timeout>
MQTT timeout (default: 5).
=back
=head1 DESCRIPTION
B<mqtt>.
=cut

View File

@ -0,0 +1,242 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package centreon::plugins::script_mqtt;
use strict;
use warnings;
use centreon::plugins::mqtt;
use centreon::plugins::misc;
sub new {
my ($class, %options) = @_;
my $self = {};
bless $self, $class;
$self->{options} = $options{options};
$self->{output} = $options{output};
$self->{options}->add_options(
arguments => {
'mode:s' => { name => 'mode_name' },
'dyn-mode:s' => { name => 'dynmode_name' },
'list-mode' => { name => 'list_mode' },
'mode-version:s' => { name => 'mode_version' },
'no-sanity-options' => { name => 'no_sanity_options' },
'pass-manager:s' => { name => 'pass_manager' },
}
);
$self->{version} = '1.0';
%{$self->{modes}} = ();
$self->{default} = undef;
$self->{options}->parse_options();
$self->{option_results} = $self->{options}->get_options();
foreach (keys %{$self->{option_results}}) {
$self->{$_} = $self->{option_results}->{$_};
}
$self->{options}->clean();
$self->{options}->add_help(package => $options{package}, sections => 'PLUGIN DESCRIPTION');
$self->{options}->add_help(package => __PACKAGE__, sections => 'GLOBAL OPTIONS');
$self->{output}->mode(name => $self->{mode_name});
return $self;
}
sub init {
my ($self, %options) = @_;
# add meta mode
$self->{modes}->{multi} = 'centreon::plugins::multi';
if (defined($options{help}) && !defined($self->{mode_name}) && !defined($self->{dynmode_name})) {
$self->{options}->display_help();
$self->{output}->option_exit();
}
if (defined($options{version}) && !defined($self->{mode_name}) && !defined($self->{dynmode_name})) {
$self->version();
}
if (defined($self->{list_mode})) {
$self->list_mode();
}
$self->{options}->set_sanity() if (!defined($self->{no_sanity_options}));
# Output HELP
$self->{options}->add_help(package => 'centreon::plugins::output', sections => 'OUTPUT OPTIONS');
$self->load_password_mgr();
# MQTT
$self->{mqtt} = centreon::plugins::mqtt->new(options => $self->{options}, output => $self->{output});
# Load mode
if (defined($self->{mode_name}) && $self->{mode_name} ne '') {
$self->is_mode(mode => $self->{mode_name});
centreon::plugins::misc::mymodule_load(output => $self->{output}, module => $self->{modes}{$self->{mode_name}},
error_msg => "Cannot load module --mode.");
$self->{mode} = $self->{modes}{$self->{mode_name}}->new(options => $self->{options}, output => $self->{output}, mode => $self->{mode_name});
} elsif (defined($self->{dynmode_name}) && $self->{dynmode_name} ne '') {
(undef, $self->{dynmode_name}) = centreon::plugins::misc::mymodule_load(output => $self->{output}, module => $self->{dynmode_name},
error_msg => "Cannot load module --dyn-mode.");
$self->{mode} = $self->{dynmode_name}->new(options => $self->{options}, output => $self->{output}, mode => $self->{dynmode_name});
} else {
$self->{output}->add_option_msg(short_msg => "Need to specify '--mode' or '--dyn-mode' option.");
$self->{output}->option_exit();
}
if (defined($options{help})) {
if (defined($self->{mode_name}) && $self->{mode_name} ne '') {
$self->{options}->add_help(package => $self->{modes}{$self->{mode_name}}, sections => 'MODE');
} else {
$self->{options}->add_help(package => $self->{dynmode_name}, sections => 'MODE');
}
$self->{options}->display_help();
$self->{output}->option_exit();
}
if (defined($options{version})) {
$self->{mode}->version();
$self->{output}->option_exit(nolabel => 1);
}
if (centreon::plugins::misc::minimal_version($self->{mode}->{version}, $self->{mode_version}) == 0) {
$self->{output}->add_option_msg(short_msg => "Not good version for plugin mode. Excepted at least: " . $self->{mode_version} . ". Get: " . $self->{mode}->{version});
$self->{output}->option_exit();
}
$self->{options}->parse_options();
$self->{option_results} = $self->{options}->get_options();
$self->{pass_mgr}->manage_options(option_results => $self->{option_results}) if (defined($self->{pass_mgr}));
$self->{mqtt}->check_options(option_results => $self->{option_results});
$self->{mode}->check_options(
option_results => $self->{option_results},
default => $self->{default},
modes => $self->{modes} # for meta mode multi
);
}
sub load_password_mgr {
my ($self, %options) = @_;
return if (!defined($self->{option_results}->{pass_manager}) || $self->{option_results}->{pass_manager} eq '');
(undef, my $pass_mgr_name) = centreon::plugins::misc::mymodule_load(
output => $self->{output}, module => "centreon::plugins::passwordmgr::" . $self->{option_results}->{pass_manager},
error_msg => "Cannot load module 'centreon::plugins::passwordmgr::" . $self->{option_results}->{pass_manager} . "'"
);
$self->{pass_mgr} = $pass_mgr_name->new(options => $self->{options}, output => $self->{output});
}
sub run {
my $self = shift;
if ($self->{output}->is_disco_format()) {
$self->{mode}->disco_format();
$self->{output}->display_disco_format();
$self->{output}->exit(exit_litteral => 'ok');
}
$self->{mqtt}->set_mqtt_options();
if ($self->{output}->is_disco_show()) {
$self->{mode}->disco_show(snmp => $self->{snmp});
$self->{output}->display_disco_show();
$self->{output}->exit(exit_litteral => 'ok');
} else {
$self->{mode}->run(mqtt => $self->{mqtt});
}
}
sub is_mode {
my ($self, %options) = @_;
# $options->{mode} = mode
if (!defined($self->{modes}{$options{mode}})) {
$self->{output}->add_option_msg(short_msg => "mode '" . $options{mode} . "' doesn't exist (use --list-mode option to show available modes).");
$self->{output}->option_exit();
}
}
sub version {
my $self = shift;
$self->{output}->add_option_msg(short_msg => "Plugin Version: " . $self->{version});
$self->{output}->option_exit(nolabel => 1);
}
sub list_mode {
my $self = shift;
$self->{options}->display_help();
$self->{output}->add_option_msg(long_msg => 'Modes Meta:');
$self->{output}->add_option_msg(long_msg => ' multi');
$self->{output}->add_option_msg(long_msg => '');
$self->{output}->add_option_msg(long_msg => 'Modes Available:');
foreach (sort keys %{$self->{modes}}) {
next if ($_ eq 'multi');
$self->{output}->add_option_msg(long_msg => ' ' . $_);
}
$self->{output}->option_exit(nolabel => 1);
}
1;
__END__
=head1 NAME
-
=head1 SYNOPSIS
-
=head1 GLOBAL OPTIONS
=over 8
=item B<--mode>
Define the mode in which you want the plugin to be executed (see --list-mode).
=item B<--dyn-mode>
Specify a mode with the module's path (advanced).
=item B<--list-mode>
List all available modes.
=item B<--mode-version>
Check minimal version of mode. If not, unknown error.
=item B<--version>
Return the version of the plugin.
=item B<--pass-manager>
Define the password manager you want to use.
Supported managers are: environment, file, keepass, hashicorpvault and teampass.
=back
=head1 DESCRIPTION
B<>.
=cut

View File

@ -4,6 +4,7 @@
--critical-bytesallocatedpercentage
--display-transform-dst
--display-transform-src
--dyn-mode
--exclude-fs
--filter-fs
--filter-vdom
@ -11,6 +12,8 @@
--force-counters64
--force-oid
--map-speed-dsl
--mqtt
--mqtt-ssl
--nagvis-perfdata
--oid-display
--oid-extra-display
@ -38,10 +41,13 @@ in-ucast
interface-dsl-name
IpAddr
Iwsva
keepass
ldap
license-instances-usage-prct
Loggly
MBean
Mosquitto
MQTT
NagVis
Netscaler
OID
@ -61,6 +67,7 @@ SNMP
space-usage-prct
SSH
SureBackup
teampass
timeframe
topic-messages-inflighted
total-oper-down

View File

@ -0,0 +1,74 @@
*** Settings ***
Documentation Eclipse Mosquitto MQTT plugin tests
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}..${/}resources/import.resource
Test Timeout 120s
Keyword Tags notauto
*** Variables ***
${HOSTNAME} mosquitto_openssl
${MQTT_PORT} 8883
${MQTT_CA_CERTIFICATE} /home/code/tests/robot/apps/eclipse/mosquitto/mqtt/certs/ca.crt
${MQTT_SSL_CERTIFICATE} /home/code/tests/robot/apps/eclipse/mosquitto/mqtt/certs/client.crt
${MQTT_SSL_KEY} /home/code/tests/robot/apps/eclipse/mosquitto/mqtt/certs/client.key
${CMD} ${CENTREON_PLUGINS} --plugin=apps::eclipse::mosquitto::mqtt::plugin --hostname=${HOSTNAME} --mqtt-port=${MQTT_PORT} --mqtt-ca-certificate=${MQTT_CA_CERTIFICATE} --mqtt-ssl-certificate=${MQTT_SSL_CERTIFICATE} --mqtt-ssl-key=${MQTT_SSL_KEY}
*** Test Cases ***
Mosquitto MQTT uptime
[Documentation] Check Mosquitto MQTT uptime
[Tags] eclipse mosquitto mqtt
${command} Catenate
... ${CMD}
... --mode=uptime
... --help
${output} Run ${command}
${output} Strip String ${output}
Mosquitto MQTT clients
[Documentation] Check Mosquitto MQTT uptime
[Tags] eclipse mosquitto mqtt
${command} Catenate
... ${CMD}
... --mode=clients
... --help
${output} Run ${command}
${output} Strip String ${output}
Mosquitto MQTT messages
[Documentation] Check Mosquitto MQTT uptime
[Tags] eclipse mosquitto mqtt
${command} Catenate
... ${CMD}
... --mode=messages
... --help
${output} Run ${command}
${output} Strip String ${output}
Mosquitto MQTT numeric-value
[Documentation] Check Mosquitto MQTT uptime
[Tags] eclipse mosquitto mqtt
${command} Catenate
... ${CMD}
... --mode=numeric-value
... --help
${output} Run ${command}
${output} Strip String ${output}
Mosquitto MQTT string-value
[Documentation] Check Mosquitto MQTT uptime
[Tags] eclipse mosquitto mqtt
${command} Catenate
... ${CMD}
... --mode=string-value
... --help
${output} Run ${command}
${output} Strip String ${output}

View File

@ -11,14 +11,14 @@ Test Timeout 120s
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}collection-centreon-web.mockoon.json
${CMD} ${CENTREON_PLUGINS} --plugin apps::protocols::http::plugin --mode collection
... --constant='hostname=127.0.0.1' --constant='protocol=http' --constant='port=3000'
... --constant='username=admin' --constant='password=myPassword'
${CMD} ${CENTREON_PLUGINS} --plugin apps::protocols::http::plugin --mode collection
... --constant='hostname=127.0.0.1' --constant='protocol=http' --constant='port=3000'
... --constant='username=admin' --constant='password=myPassword'
*** Test Cases ***
Check if ${test_desc} on Centreon
[Tags] Centreon Collections HTTP
[Tags] centreon collections http
${output} Run
... ${CMD} --config=${CURDIR}/${collection}
${output} Strip String ${output}
@ -31,4 +31,3 @@ Check if ${test_desc} on Centreon
... authentication succeeds collection-centreon-web-check-auth.collection.json OK: Authentication resulted in 200 HTTP code
... hosts are down collection-centreon-web-check-down-hosts.collection.json OK: All hosts are UP | 'hostsRequest.down.count'=0;0;;0;1
... commands are broken collection-centreon-web-check-broken-commands.collection.json WARNING:${SPACE} - Service FakeHostThatIsDown/Svc-BadCommand output is '(Execute command failed)' | 'commands.broken.count'=1;0;;0;

View File

@ -1,14 +1,15 @@
*** Settings ***
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}vault-authentication-hashicorp.json
${MOCKOON_JSON} ${CURDIR}${/}vault-authentication-hashicorp.json
${CMD} ${CENTREON_PLUGINS} --plugin apps::protocols::snmp::plugin --hostname=127.0.0.1
${CMD} ${CENTREON_PLUGINS} --plugin apps::protocols::snmp::plugin --hostname=127.0.0.1
*** Test Cases ***
@ -44,4 +45,4 @@ check hashicorp vault manager${Name}
Examples: Name path-param result --
... default path --auth-path='' --auth-settings="password=secrethashicorpPassword" OK: current value is: Linux centreon-devbox 5.10.0-28-amd64 #1 SMP Debian 5.10.209-2 (2024-01-31) x86_64
... wrong path --auth-path='specific-url' --auth-settings="password=secrethashicorpPassword" OK: current value is: Linux centreon-devbox 5.10.0-28-amd64 #1 SMP Debian 5.10.209-2 (2024-01-31) x86_64
... wrong password --auth-path='' --auth-settings="password=WrongPassword" UNKNOWN: 401 Unauthorized
... wrong password --auth-path='' --auth-settings="password=WrongPassword" UNKNOWN: 401 Unauthorized

View File

@ -35,4 +35,3 @@ Avigilon camera Memory ${tc}/3
... 1 ${EMPTY} ${EMPTY} OK: total system memory available: 464.85 KB | 'memory.available'=476004B;;;0;
... 2 5000 ${EMPTY} WARNING: total system memory available: 464.85 KB | 'memory.available'=476004B;0:5000;;0;
... 3 ${EMPTY} 5000 CRITICAL: total system memory available: 464.85 KB | 'memory.available'=476004B;;0:5000;0;

View File

@ -39,4 +39,3 @@ Avigilon camera Temperature ${tc}/5
... 3 ${EMPTY} 20 ${EMPTY} ${EMPTY} CRITICAL: temperature: 23.00 C | 'sensor.temperature.celsius'=23C;;0:20;0;
... 4 ${EMPTY} ${EMPTY} \\%\{status\} =~ /ok/ ${EMPTY} WARNING: sensor 1 [type:mainSensor] status: ok | 'sensor.temperature.celsius'=23C;;;0;
... 5 ${EMPTY} ${EMPTY} ${EMPTY} \\%\{status\} =~ /ok/ CRITICAL: sensor 1 [type:mainSensor] status: ok | 'sensor.temperature.celsius'=23C;;;0;

View File

@ -7,7 +7,8 @@ Test Timeout 120s
*** Variables ***
${CMD} ${CENTREON_PLUGINS} --plugin=network::citrix::netscaler::snmp::plugin
${CMD} ${CENTREON_PLUGINS} --plugin=network::citrix::netscaler::snmp::plugin
*** Test Cases ***
check psu components ${tc}/2
@ -32,5 +33,3 @@ check psu components ${tc}/2
Examples: tc alternative_status_mapping community expected_result --
... 1 true psu-citrix-v13 OK: All 4 components are ok [4/4 psus]. | 'count_psu'=4;;;;
... 2 ${EMPTY} psu-citrix-v13 UNKNOWN: Power supply '1' status is 'not supported' - Power supply '2' status is 'not supported' - Power supply '3' status is 'not supported' - Power supply '4' status is 'not supported' | 'count_psu'=4;;;;