diff --git a/packaging/centreon-plugin-Applications-Rubrik-Restapi/deb.json b/packaging/centreon-plugin-Applications-Rubrik-Restapi/deb.json index 9757fe112..113c4a8ad 100644 --- a/packaging/centreon-plugin-Applications-Rubrik-Restapi/deb.json +++ b/packaging/centreon-plugin-Applications-Rubrik-Restapi/deb.json @@ -1,4 +1,7 @@ { "dependencies": [ + "libdatetime-perl", + "libdigest-md5-perl", + "libjson-perl" ] } diff --git a/packaging/centreon-plugin-Applications-Rubrik-Restapi/rpm.json b/packaging/centreon-plugin-Applications-Rubrik-Restapi/rpm.json index 9757fe112..962a3832e 100644 --- a/packaging/centreon-plugin-Applications-Rubrik-Restapi/rpm.json +++ b/packaging/centreon-plugin-Applications-Rubrik-Restapi/rpm.json @@ -1,4 +1,7 @@ { "dependencies": [ + "perl(DateTime)", + "perl(Digest::MD5)", + "perl(JSON::XS)" ] } diff --git a/src/apps/backup/rubrik/restapi/mode/jobs.pm b/src/apps/backup/rubrik/restapi/mode/jobs.pm index 24ea815ec..69ab58974 100644 --- a/src/apps/backup/rubrik/restapi/mode/jobs.pm +++ b/src/apps/backup/rubrik/restapi/mode/jobs.pm @@ -221,7 +221,8 @@ sub new { 'filter-location-name:s' => { name => 'filter_location_name' }, 'filter-object-type:s' => { name => 'filter_object_type' }, 'unit:s' => { name => 'unit', default => 's' }, - 'limit:s' => { name => 'limit' } + 'limit:s' => { name => 'limit' }, + 'check-retention' => { name => 'check_retention' } }); $self->{cache_exec} = centreon::plugins::statefile->new(%options); @@ -247,7 +248,11 @@ sub check_options { sub manage_selection { my ($self, %options) = @_; - my $jobs_exec = $options{custom}->get_jobs_monitoring(get_param => [ 'limit=' . $self->{option_results}->{limit} ]); + my $get_param = [ 'limit=' . $self->{option_results}->{limit} ]; + if (defined($self->{option_results}->{filter_job_type}) && $self->{option_results}->{filter_job_type} ne '') { + push @{$get_param}, 'job_type=' . $self->{option_results}->{filter_job_type}; + } + my $jobs_exec = $options{custom}->get_jobs_monitoring(get_param => $get_param); $self->{cache_exec}->read(statefile => 'rubrik_' . $self->{mode} . '_' . Digest::MD5::md5_hex( @@ -260,7 +265,8 @@ sub manage_selection { ); my $ctime = time(); my $last_exec_times = $self->{cache_exec}->get(name => 'jobs'); - $last_exec_times = {} if (!defined($last_exec_times)); + $last_exec_times = {} if (!defined($last_exec_times)); + my %jobs_detected = (); $self->{global} = { detected => 0 }; $self->{jobs} = {}; @@ -269,13 +275,13 @@ sub manage_selection { $job_exec->{objectId} !~ /$self->{option_results}->{filter_job_id}/); next if (defined($self->{option_results}->{filter_job_name}) && $self->{option_results}->{filter_job_name} ne '' && $job_exec->{objectName} !~ /$self->{option_results}->{filter_job_name}/); - next if (defined($self->{option_results}->{filter_job_type}) && $self->{option_results}->{filter_job_type} ne '' && - $job_exec->{jobType} !~ /$self->{option_results}->{filter_job_type}/i); next if (defined($self->{option_results}->{filter_object_type}) && $self->{option_results}->{filter_object_type} ne '' && $job_exec->{objectType} !~ /$self->{option_results}->{filter_object_type}/i); next if (defined($self->{option_results}->{filter_location_name}) && $self->{option_results}->{filter_location_name} ne '' && $job_exec->{locationName} !~ /$self->{option_results}->{filter_location_name}/); + $self->{global}->{detected}++; + $jobs_detected{$job_exec->{objectName}} = 1; $job_exec->{jobType} = lc($job_exec->{jobType}); if (!defined($self->{jobs}->{ $job_exec->{objectId} })) { @@ -302,7 +308,6 @@ sub manage_selection { $last_exec = $_; } - $self->{global}->{detected}++; # Failure, Scheduled, Success, SuccessfulWithWarnings, Active, Canceled $failed++ if ($_->{jobStatus} =~ /Failure/i); $total++; @@ -326,7 +331,9 @@ sub manage_selection { $last_exec_times->{ $job_exec->{objectId} } = { jobName => $job_exec->{objectName}, jobType => $job_exec->{jobType}, - epoch => $dt->epoch() + epoch => $dt->epoch(), + objectType => $job_exec->{objectType}, + locationName => $job_exec->{locationName} }; } @@ -355,6 +362,8 @@ sub manage_selection { $self->{jobs}->{$objectId} = { name => $last_exec_times->{$objectId}->{jobName}, jobType => $last_exec_times->{$objectId}->{jobType}, + objectType => $last_exec_times->{$objectId}->{objectType}, + locationName => $last_exec_times->{$objectId}->{locationName}, timers => { jobName => $last_exec_times->{$objectId}->{jobName}, jobType => $last_exec_times->{$objectId}->{jobType}, @@ -364,6 +373,15 @@ sub manage_selection { }; } + if ($self->{global}->{detected} == 0 && defined($self->{option_results}->{check_retention})) { + my $jobs_last_detected = $self->{cache_exec}->get(name => 'jobs'); + foreach my $job_id (keys %{$jobs_last_detected}) { + if (!defined($jobs_detected{$jobs_last_detected->{$job_id}->{jobName}})) { + $self->{global}->{detected}++; + } + } + } + $self->{cache_exec}->write(data => { jobs => $last_exec_times }); @@ -407,6 +425,10 @@ Select the time unit for last execution time thresholds. May be 's' for seconds, Define the number of entries to retrieve for the pagination (default: 500). +=item B<--check-retention> + +Use the retention file to check if a job have been detected once but does not appear in the API response. + =item B<--unknown-execution-status> Set unknown threshold for last job execution status. diff --git a/tests/apps/backup/rubrik/restapi/applications-rubrik-restapi.json b/tests/apps/backup/rubrik/restapi/applications-rubrik-restapi.json new file mode 100644 index 000000000..697042624 --- /dev/null +++ b/tests/apps/backup/rubrik/restapi/applications-rubrik-restapi.json @@ -0,0 +1,92 @@ +{ + "uuid": "c8fba1bd-af32-4acd-83a2-5b26a0152183", + "lastMigration": 32, + "name": "Rubrik2", + "endpointPrefix": "", + "latency": 0, + "port": 3004, + "hostname": "", + "folders": [], + "routes": [ + { + "uuid": "b9fdb329-671b-48d0-a906-d58e45a70527", + "type": "http", + "documentation": "", + "method": "get", + "endpoint": "", + "responses": [ + { + "uuid": "4aac7b2c-2947-4e6b-83a4-094da73ecc5a", + "body": "{\r\n \"jobMonitoringInfoList\": [\r\n {\r\n \"jobMonitoringState\": \"Success\",\r\n \"jobStatus\": \"Success\",\r\n \"jobType\": \"Backup\",\r\n \"objectId\": \"VolumeGroup:::123a456-123a-456b-789c-123456789\",\r\n \"objectType\": \"WindowsVolumeGroup\",\r\n \"objectName\": \"centreon.groupe.active volumes\",\r\n \"locationId\": \"Host:::123c456-a123-b456-c789-123a456\",\r\n \"locationName\": \"centreon.groupe.active\",\r\n \"slaDomainId\": \"1234a456-123a-456b-aaaa-12345\",\r\n \"slaDomainName\": \"CENTREON-DOMAIN\",\r\n \"startTime\": \"2024-07-18T20:00:01.382Z\",\r\n \"endTime\": \"2024-07-19T06:42:16.355Z\",\r\n \"lastSuccessfulJobTime\": \"2024-07-16T20:00:01.382Z\",\r\n \"nextJobTime\": \"2023-11-07T20:00:00.000Z\",\r\n \"isFirstFullSnapshot\": false,\r\n \"sourceClusterName\": \"LOCAL\",\r\n \"sourceClusterId\": \"aaaaaa-123a-456b-aaaa-12345\",\r\n \"retryCount\": 0,\r\n \"maximumAttemptsForJob\": 3,\r\n \"dataTransferred\": 571231961088,\r\n \"objectLogicalSize\": 193955119497216,\r\n \"eventSeriesId\": \"Zaaaaaa-123a-456b-123a-12345abcd\",\r\n \"duration\": 38534973,\r\n \"nodeId\": \"AAAABBBBCCCCDDD\",\r\n \"warningCount\": 0,\r\n \"lastUpdatedTime\": \"2024-07-19T06:42:16.721Z\",\r\n \"isLogTask\": false,\r\n \"isOnDemand\": false,\r\n \"retryStatus\": \"NotRetried\"\r\n },\r\n {\r\n \"jobMonitoringState\": \"Scheduled\",\r\n \"jobStatus\": \"Scheduled\",\r\n \"jobType\": \"Backup\",\r\n \"objectId\": \"VolumeGroup:::123a456-123a-456b-789c-123456789\",\r\n \"objectType\": \"WindowsVolumeGroup\",\r\n \"objectName\": \"centreon.groupe.active volumes\",\r\n \"locationId\": \"Host:::123c456-a123-b456-c789-123a456\",\r\n \"locationName\": \"centreon.groupe.active\",\r\n \"slaDomainId\": \"1234a456-123a-456b-aaaa-12345\",\r\n \"slaDomainName\": \"CENTREON-DOMAIN\",\r\n \"startTime\": \"2024-07-18T20:00:00.000Z\",\r\n \"lastSuccessfulJobTime\": \"2024-07-18T20:00:01.382Z\",\r\n \"isFirstFullSnapshot\": false,\r\n \"sourceClusterName\": \"LOCAL\",\r\n \"sourceClusterId\": \"aaaaaa-123a-456b-aaaa-12345\",\r\n \"retryCount\": 0,\r\n \"maximumAttemptsForJob\": 3,\r\n \"objectLogicalSize\": 193955119497216,\r\n \"eventSeriesId\": \"afba57d8-efb3-452e-892b-157acc6b6069\",\r\n \"nodeId\": \"AAAABBBBCCCCDDD\",\r\n \"warningCount\": 0,\r\n \"lastUpdatedTime\": \"2024-07-18T06:42:16.894Z\",\r\n \"isLogTask\": false,\r\n \"isOnDemand\": false,\r\n \"retryStatus\": \"NotRetried\"\r\n }\r\n ],\r\n \"jobType\": \"Backup\",\r\n \"shouldIncludeLogRelatedJob\": false,\r\n \"objectName\": \"CENTREON\",\r\n \"hasMore\": false\r\n}", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null + } + ], + "rootChildren": [ + { + "type": "route", + "uuid": "b9fdb329-671b-48d0-a906-d58e45a70527" + } + ], + "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": [] +} diff --git a/tests/apps/backup/rubrik/restapi/cache.robot b/tests/apps/backup/rubrik/restapi/cache.robot new file mode 100644 index 000000000..7816ebdc4 --- /dev/null +++ b/tests/apps/backup/rubrik/restapi/cache.robot @@ -0,0 +1,39 @@ +*** Settings *** +Documentation Check Rubrik REST API jobs cache file creation + +Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}applications-rubrik-restapi.json +${cmd} ${CENTREON_PLUGINS} +... --plugin=apps::backup::rubrik::restapi::plugin +... --hostname=${HOSTNAME} +... --api-username='username' +... --api-password='password' +... --proto='http' +... --port=${APIPORT} + + +*** Test Cases *** +cache ${tc}/1 + [Tags] apps backup rubrik restapi cache + + ${command} Catenate + ... ${cmd} + ... --mode=cache + + ${output} Run ${command} + ${output} Strip String ${output} + Should Be Equal As Strings + ... ${output} + ... ${expected_result} + ... \nWrong output result for command:\n${command}\n\nExpected:\n${expected_result}\nCommand output:\n${output}\n + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: Cache files created successfully + \ No newline at end of file diff --git a/tests/apps/backup/rubrik/restapi/jobs.robot b/tests/apps/backup/rubrik/restapi/jobs.robot new file mode 100644 index 000000000..e1052c8e1 --- /dev/null +++ b/tests/apps/backup/rubrik/restapi/jobs.robot @@ -0,0 +1,47 @@ +*** Settings *** +Documentation Check Rubrik REST API jobs + +Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}applications-rubrik-restapi.json +${cmd} ${CENTREON_PLUGINS} +... --plugin=apps::backup::rubrik::restapi::plugin +... --hostname=${HOSTNAME} +... --api-username='username' +... --api-password='password' +... --proto='http' +... --port=${APIPORT} + +*** Test Cases *** +jobs ${tc}/11 + [Tags] apps backup rubrik restapi jobs + + ${command} Catenate + ... ${cmd} + ... --mode=jobs + ... ${extraoptions} + + Log ${command} + + ${output} Run ${command} + + Should Match Regexp ${output} ${expected_result} + + Examples: tc extraoptions expected_result -- + ... 1 ${EMPTY} OK: job 'centreon.groupe.active volumes' \[type: backup\] number of failed executions: 0.00 % - last execution .* - last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*s;;;0; + ... 2 --unknown-execution-status='\\%\{status\} eq "Success"' UNKNOWN: job 'centreon.groupe.active volumes' \[type: backup\] last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*s;;;0; + ... 3 --warning-execution-status='\\%\{status\} eq "Success"' WARNING: job 'centreon.groupe.active volumes' \[type: backup\] last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*s;;;0; + ... 4 --critical-execution-status='\\%\{status\} eq "Success"' CRITICAL: job 'centreon.groupe.active volumes' \[type: backup\] last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*s;;;0; + ... 5 --warning-jobs-executions-detected=1 --critical-jobs-executions-detected=3 WARNING: Number of jobs executions detected: 2 \| 'jobs.executions.detected.count'=2;0:2;0:5;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;;;0; + ... 6 --warning-jobs-executions-detected=1 --critical-jobs-executions-detected=1 CRITICAL: Number of jobs executions detected: 2 \| 'jobs.executions.detected.count'=2;0:2;0:3;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;;;0; + ... 7 --warning-job-executions-failed-prct=1:1 --critical-job-executions-failed-prct=1 WARNING: job 'centreon.groupe.active volumes' \[type: backup\] number of failed executions: 0.00 % \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;1:1;0:1;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;;;0; + ... 8 --warning-job-executions-failed-prct=1 --critical-job-executions-failed-prct=1:1 CRITICAL: job 'centreon.groupe.active volumes' \[type: backup\] number of failed executions: 0.00 % \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;0:1;1:1;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;;;0; + ... 9 --warning-job-execution-last=315360000 --critical-job-execution-last=315360000 OK: job 'centreon.groupe.active volumes' \[type: backup\] number of failed executions: 0.00 % - last execution .* - last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;0:315360000;0:315360000;0; + ... 10 --warning-job-execution-last=1 --critical-job-execution-last=315360000 WARNING: job 'centreon.groupe.active volumes' \[type: backup\] number of failed executions: 0.00 % - last execution .* - last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;0:1;0:315360000;0; + ... 11 --warning-job-execution-last=315360000 --critical-job-execution-last=315360000 CRITICAL: job 'centreon.groupe.active volumes' \[type: backup\] number of failed executions: 0.00 % - last execution .* - last execution started: 2024-07-18T20:00:01.382Z status: Success \| 'jobs.executions.detected.count'=2;;;0; 'centreon.groupe.active volumes~backup#job.executions.failed.percentage'=0.00%;;;0;100 'centreon.groupe.active volumes~backup#job.execution.last.seconds'=.*;0:315360000;0:315360000;0; \ No newline at end of file