CTOR-1558: Enhance standby mode and extra parameters support (#5645)

This commit is contained in:
scresto 2025-07-02 14:58:39 +02:00 committed by GitHub
parent e18c959fc2
commit ed7cbedb25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 430 additions and 5 deletions

View File

@ -47,6 +47,13 @@ sub set_counters {
closure_custom_perfdata => sub { return 0; }, closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => \&catalog_status_threshold_ng closure_custom_threshold_check => \&catalog_status_threshold_ng
} }
},
{ label => 'standby-status', type => 2, set => {
key_values => [ { name => 'standby' } ],
output_template => "standby status : %s",
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
} }
]; ];
} }
@ -57,12 +64,32 @@ sub custom_prefix_output {
return 'Server ' . $options{instance_value}->{cluster_name} . ' '; return 'Server ' . $options{instance_value}->{cluster_name} . ' ';
} }
# List of parameteres added during the API call
our @code_parameters = (
{ 'code' => 'perfstandbyok', 'type' => 'bool' },
{ 'code' => 'activecode', 'type' => 'status' },
{ 'code' => 'drsecondarycode', 'type' => 'status' },
{ 'code' => 'haunhealthycode', 'type' => 'status' },
{ 'code' => 'performancestandbycode', 'type' => 'status' },
{ 'code' => 'removedcode', 'type' => 'status' },
# By default API will return error codes if sealed, uninit or standby
{ 'code' => 'standbyok', 'type' => 'bool', default => 'true' },
{ 'code' => 'sealedcode', 'type' => 'status', default => '200' },
{ 'code' => 'uninitcode', 'type' => 'status', default => '200' },
{ 'code' => 'standbycode', 'type' => 'status', default => '200' },
);
sub new { sub new {
my ($class, %options) = @_; my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class; bless $self, $class;
$options{options}->add_options(arguments => {}); my %arguments;
$arguments{$_->{'code'}.':s'} = { name => $_->{'code'}, default => $_->{'default'} // '', }
foreach (@code_parameters);
$options{options}->add_options(arguments => \%arguments );
return $self; return $self;
} }
@ -71,17 +98,49 @@ sub set_options {
my ($self, %options) = @_; my ($self, %options) = @_;
} }
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
foreach my $param (@code_parameters) {
my $value = lc $self->{option_results}->{$param->{'code'}};
next if $value eq '';
my $valid = 0;
if ($param->{'type'} eq 'status') {
$valid = $value =~ /^\d{1,3}$/;
} elsif ($param->{'type'} eq 'bool') {
$valid = $value eq 'true' || $value eq 'false';
$self->{option_results}->{$param->{code}} = lc $value;
}
unless ($valid) {
$self->{output}->add_option_msg(short_msg => "Invalid value for ".$param->{'code'}.".");
$self->{output}->option_exit();
}
}
}
sub manage_selection { sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
my $code_param = '?sealedcode=200&uninitcode=200'; # By default API will return error codes if sealed or uninit my @code_arr;
my $result = $options{custom}->request_api(url_path => 'health' . $code_param);
foreach my $param (@code_parameters) {
next if $self->{option_results}->{$param->{'code'}} eq '';
push @code_arr, $param->{'code'} .'='. $self->{option_results}->{$param->{'code'}};
}
my $result = $options{custom}->request_api(url_path => 'health' . (@code_arr ? '?'.join('&', @code_arr) : ''));
my $cluster_name = defined($result->{cluster_name}) ? $result->{cluster_name} : $self->{option_results}->{hostname}; my $cluster_name = defined($result->{cluster_name}) ? $result->{cluster_name} : $self->{option_results}->{hostname};
$self->{vault_cluster}->{$cluster_name} = { $self->{vault_cluster}->{$cluster_name} = {
cluster_name => $cluster_name, cluster_name => $cluster_name,
sealed => $result->{sealed} ? 'sealed' : 'unsealed', sealed => $result->{sealed} ? 'sealed' : 'unsealed',
init => $result->{initialized} ? 'initialized' : 'not initialized', init => $result->{initialized} ? 'initialized' : 'not initialized',
standby => $result->{standby} ? 'true' : 'false',
}; };
} }
@ -91,16 +150,22 @@ __END__
=head1 MODE =head1 MODE
Check Hashicorp Vault Health status. Check HashiCorp Vault Health status.
Example: Example:
perl centreon_plugins.pl --plugin=apps::hashicorp::vault::restapi::plugin --mode=health perl centreon_plugins.pl --plugin=apps::hashicorp::vault::restapi::plugin --mode=health
--hostname=10.0.0.1 --vault-token='s.aBCD123DEF456GHI789JKL012' --verbose --hostname=10.0.0.1 --vault-token='s.aBCD123DEF456GHI789JKL012' --verbose
More information on'https://www.vaultproject.io/api-docs/system/health'. More information on'https://developer.hashicorp.com/vault/api-docs/system/health'.
=over 8 =over 8
=item B<--standbyok --perfstandbyok --activecode --standbycode --drsecondarycode --haunhealthycode --performancestandbycode --removedcode --sealedcode --uninitcode>
Arguments to pass to the health API call, default are --sealedcode=200 and --uninitcode=200.
More information on'https://developer.hashicorp.com/vault/api-docs/system/health#parameters.'
=item B<--warning-seal-status> =item B<--warning-seal-status>
Set warning threshold for seal status (default: none). Set warning threshold for seal status (default: none).
@ -117,6 +182,14 @@ Set warning threshold for initialization status (default: none).
Set critical threshold for initialization status (default: '%{init} ne "initialized"'). Set critical threshold for initialization status (default: '%{init} ne "initialized"').
=item B<--warning-standby-status>
Set warning threshold for standby status (default: none).
=item B<--critical-standby-status>
Set critical threshold for standby status (default: none).
=back =back
=cut =cut

View File

@ -0,0 +1,312 @@
{
"uuid": "83005144-3d67-4049-be7e-e57a474c9ee2",
"lastMigration": 33,
"name": "Hshicorp",
"endpointPrefix": "",
"latency": 0,
"port": 3004,
"hostname": "",
"folders": [],
"routes": [
{
"uuid": "60154517-befe-43d0-a9cd-5f5d1afffde9",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "v1/sys/health",
"responses": [
{
"uuid": "a97e1d68-09ff-4940-89b0-982bb9f78e83",
"body": "{\n \"initialized\": true,\n \"sealed\": false,\n \"standby\": false,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-master\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "1",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "417f537a-6375-44ad-961f-cbe9f599b624",
"body": "{\n \"initialized\": false,\n \"sealed\": false,\n \"standby\": false,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-uninit\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "2",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "66a60ca3-f290-4f89-9ffe-e276994c0ae9",
"body": "{\n \"initialized\": true,\n \"sealed\": false,\n \"standby\": true,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-standby\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "3",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "f5cb8784-dc3f-4e4d-9eda-f5d0963febe0",
"body": "{\n \"initialized\": true,\n \"sealed\": true,\n \"standby\": false,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-sealed\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "4",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "cd88bf44-148c-45d0-95a0-d7a635030bb7",
"body": "{\n \"initialized\": false,\n \"sealed\": false,\n \"standby\": true,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-uninitstandby\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "5",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "0199facc-b9f6-4565-b73a-cddd52c37f75",
"body": "{\n \"initialized\": true,\n \"sealed\": false,\n \"standby\": true,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-standby-508\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 508,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "6",
"invert": false,
"operator": "equals"
},
{
"target": "query",
"modifier": "standbycode",
"value": "508",
"invert": false,
"operator": "equals"
},
{
"target": "query",
"modifier": "standbyok",
"value": "true",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "AND",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "8f8d93f7-d426-4cbc-b975-7e9d4e970bd8",
"body": "{\n \"initialized\": true,\n \"sealed\": false,\n \"standby\": false,\n \"performance_standby\": true,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-perfstandby-524,\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 524,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "7",
"invert": false,
"operator": "equals"
},
{
"target": "header",
"modifier": "performancestandbycode",
"value": "524",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
},
{
"uuid": "aca7de42-6586-4f3d-83ba-dc6eebdd014c",
"body": "{\n \"initialized\": true,\n \"sealed\": false,\n \"standby\": true,\n \"performance_standby\": false,\n \"replication_dr_mode\": \"disabled\",\n \"replication_performance_mode\": \"disabled\",\n \"server_time_utc\": 1720000000,\n \"version\": \"1.0.3\",\n \"cluster_name\": \"test-cluster-standby2\",\n \"cluster_id\": \"abab-0101-bcbd-12345abcde\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [
{
"target": "request_number",
"modifier": "",
"value": "8",
"invert": false,
"operator": "equals"
}
],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
}
],
"rootChildren": [
{
"type": "route",
"uuid": "60154517-befe-43d0-a9cd-5f5d1afffde9"
}
],
"proxyMode": false,
"proxyHost": "",
"proxyRemovePrefix": false,
"tlsOptions": {
"enabled": false,
"type": "CERT",
"pfxPath": "",
"certPath": "",
"keyPath": "",
"caPath": "",
"passphrase": ""
},
"cors": true,
"headers": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "Access-Control-Allow-Headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
}
],
"proxyReqHeaders": [
{
"key": "",
"value": ""
}
],
"proxyResHeaders": [
{
"key": "",
"value": ""
}
],
"data": [],
"callbacks": []
}

View File

@ -0,0 +1,40 @@
*** Settings ***
Documentation HashiCorp Vault REST API Health Check
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}hashicorp-health.mockoon.json
${HOSTNAME} 127.0.0.1
${APIPORT} 3000
${CMD} ${CENTREON_PLUGINS}
... --plugin=apps::hashicorp::vault::restapi::plugin
... --mode health
... --hostname=${HOSTNAME}
... --vault-token=xx-xxx
... --proto=http
... --port=${APIPORT}
*** Test Cases ***
List Edges ${tc}
[Tags] apps hashicorp vault restapi mockoon
${command} Catenate
... ${CMD}
... ${extra_options}
Ctn Run Command And Check Result As Strings ${command} ${expected_result}
Examples: tc extra_options expected_result --
... 1 ${EMPTY} OK: Server test-cluster-master seal status : unsealed, init status : initialized, standby status : false
... 2 --warning-init-status='\\%\{init\} ne "initialized"' --critical-init-status='' WARNING: Server test-cluster-uninit init status : not initialized
... 3 ${EMPTY} OK: Server test-cluster-standby seal status : unsealed, init status : initialized, standby status : true
... 4 --warning-seal-status='\\%\{init\} ne "sealed"' --critical-seal-status='' WARNING: Server test-cluster-sealed seal status : sealed
... 5 ${EMPTY} CRITICAL: Server test-cluster-uninitstandby init status : not initialized
... 6 --standbycode=508 UNKNOWN: 508 Loop Detected
... 7 --performancestandbycode=524 UNKNOWN: 524 unknown
... 8 --critical-standby-status='\\%\{standby\} ne "false"' CRITICAL: Server test-cluster-standby2 standby status : true