centreon-plugins
centreon-plugins copied to clipboard
fix(http/collection): infinite loop and json encoding
Description
That patch fixes 2 issues and add 2 capabilities:
- fix infinite loop when the attribute
parse
is not defined - fix following error: UNKNOWN: hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this) at /usr/lib/centreon/plugins/centreon_protocol_http.pl line 348.
- add the capability to use attribute
full_url
- add the capability to use attribute
functions
Type of change
- [X] Patch fixing an issue (non-breaking change)
- [X] New functionality (non-breaking change)
- [ ] Breaking change (patch or feature) that might cause side effects breaking part of the Software
Target serie
- [X] 22.04.x
- [X] 22.10.x
- [X] 23.04.x
- [X] 23.10.x
- [X] 24.04.x (master)
How this pull request can be tested ?
The first issue can be tested with following file:
{
"mapping": {},
"http": {
"requests": [
{
"name": "google",
"hostname": "www.google.fr",
"proto": "https",
"port": "443",
"endpoint": "/",
"method": "GET",
"insecure": 1,
"timeout": 30,
"backend": "curl",
"rtype": "txt"
}
]
},
"selection": [
{
"name": "google",
"critical": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"exit": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"formatting": {
"printf_msg":"google failed: %s",
"printf_var":[
"%(builtin.httpCode.google)"
],
"display_ok": true
}
}
],
"formatting":{
"custom_message_global": "login site ok",
"separator": "-"
}
}
The second issue can be tested with the following file if your JSON::XS
version is lower than 4.0:
{
"mapping": {},
"http": {
"requests": [
{
"name": "google",
"hostname": "www.google.fr",
"proto": "https",
"port": "443",
"endpoint": "/",
"method": "GET",
"insecure": 1,
"timeout": 30,
"backend": "curl",
"rtype": "txt"
}
]
},
"selection": [
{
"name": "google",
"critical": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"exit": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"formatting": {
"printf_msg":"authentication failed: %s",
"printf_var":[
"%(builtin.httpCode.google)"
],
"display_ok": true
}
}
],
"formatting":{
"custom_message_global": "login site ok",
"separator": "-"
}
}
To test the capabilities:
{
"mapping": {},
"http": {
"requests": [
{
"name": "google",
"full_url": "https://www.google.fr/",
"method": "GET",
"functions": [
{
"type": "capture",
"src": "%(http.tables.googleLookup.[0].server)",
"pattern": "^(.)",
"groups": [
{ "offset": 0, "save": "%(serverFirstChar)" }
]
}
],
"insecure": 1,
"timeout": 30,
"backend": "curl",
"rtype": "txt",
"parse": [
{
"name": "lookup",
"type": "header",
"re": "Server\\s*:\\s*(\\S+)",
"modifier": "ms",
"entries": [
{ "id": "server", "offset": "1" }
]
}
]
}
]
},
"selection": [
{
"name": "google",
"critical": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"exit": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"formatting": {
"printf_msg":"google check: %s (first server char: %s)",
"printf_var":[
"%(builtin.httpCode.google)",
"%(serverFirstChar)"
],
"display_ok": true
}
}
],
"formatting":{
"custom_message_global": "login site ok",
"separator": "-"
}
}
You should have following output:
OK: google check: 200 (first server char: g)
Checklist
Community contributors & Centreon team
- [X] I have followed the coding style guidelines provided by Centreon
- [ ] I have commented my code, especially new classes, functions or any legacy code modified. (docblock)
- [ ] I have commented my code, especially hard-to-understand areas of the PR.
- [ ] I have rebased my development branch on the base branch (master, maintenance).
Hey @garnier-quentin! Look at https://github.com/centreon/centreon-plugins/pull/4850 because I've moved the parsing outside the call_http function (I put it in parse_structure which is more accurate). It fixes the second issue you're mentioning. It may not fix the first though. I also put the builtin in cache as you did. Just maybe retrieve the parsing-outside-the-call-hhtp part and add it to your PR? It is really useful.
I will check to add your change and have only one PR.
I have done the change @cgagnaire . I dont want to add the parse after the scenario_stopped. Maybe you need to use the parsing to stop the scenario.
I have done the change @cgagnaire . I dont want to add the parse after the scenario_stopped. Maybe you need to use the parsing to stop the scenario.
Thanks @garnier-quentin. I don't think I get it how I can parse something if the API does not answer.
Thanks @garnier-quentin. I don't think I get it how I can parse something if the API does not answer.
Some API provides a code 500/401 with a json response
Thanks @garnier-quentin. I don't think I get it how I can parse something if the API does not answer.
Some API provides a code 500/401 with a json response
Sure some do, but my use case is in case of the host not being available or the service (ie the API) not responding. Your simple test file is too simple, try this one :
{
"mapping": {},
"http": {
"requests": [
{
"name": "google",
"hostname": "127.0.0.2",
"proto": "https",
"port": "443",
"endpoint": "/",
"method": "GET",
"insecure": 1,
"timeout": 30,
"backend": "curl",
"scenario_stopped": "%(builtin.httpCode.google) != 200",
"rtype": "json",
"parse": [
{
"name": "result",
"path": "$..blabla",
"entries": [
{
"id": "bloublou"
}
]
}
]
}
]
},
"selection": [
{
"name": "google",
"critical": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"exit": "defined(%(builtin.httpCode.google)) and %(builtin.httpCode.google) != 200",
"formatting": {
"printf_msg":"google failed: %s",
"printf_var":[
"%(builtin.httpCode.google)"
],
"display_ok": true
}
}
],
"formatting":{
"custom_message_global": "login site ok",
"separator": "-"
}
}
With your version I'll get:
UNKNOWN: Cannot decode response (add --debug option to display returned content)
======> request send
GET https://127.0.0.2:443/
User-Agent: centreon::plugins::backend::http::useragent
======> response done
500 Can't connect to 127.0.0.2:443 (Connection refused)
Content-Type: text/plain
Client-Date: Wed, 06 Mar 2024 17:21:15 GMT
Client-Warning: Internal response
Can't connect to 127.0.0.2:443 (Connection refused)
Connection refused at /usr/share/perl5/vendor_perl/LWP/Protocol/http.pm line 50.
malformed JSON string, neither tag, array, object, number, string or atom, at character offset 0 (before "Can't connect to 127...") at centreon_protocol_http_test.pl line 445.
With mine:
CRITICAL: google failed: 500
======> request send
GET https://127.0.0.2:443/
User-Agent: centreon::plugins::backend::http::useragent
======> response done
500 Can't connect to 127.0.0.2:443 (Connection refused)
Content-Type: text/plain
Client-Date: Wed, 06 Mar 2024 17:20:50 GMT
Client-Warning: Internal response
Can't connect to 127.0.0.2:443 (Connection refused)
Connection refused at /usr/share/perl5/vendor_perl/LWP/Protocol/http.pm line 50.
======> variables
google failed: 500
That's because I'll look at the scenario_stopped directive before parsing the result which here is the LWP failing to connected to the host (as I write this: shouln't it be curl as we use curl backend !?).
With your last config file you'll get:
UNKNOWN: [http > requests > google > 0] unknown or empty table 'googleLookup'. Available tables are (not empty based on your conf) :
======> request send
GET https://127.0.0.2/
User-Agent: centreon::plugins::backend::http::useragent
======> response done
500 Can't connect to 127.0.0.2:443 (Connection refused)
Content-Type: text/plain
Client-Date: Wed, 06 Mar 2024 17:25:04 GMT
Client-Warning: Internal response
Can't connect to 127.0.0.2:443 (Connection refused)
Connection refused at /usr/share/perl5/vendor_perl/LWP/Protocol/http.pm line 50.
I'll get:
CRITICAL: google check: 500 (first server char: ) - Key 'serverFirstChar' not found in ('name', 'builtin.httpMessage.google', 'builtin.currentTime', 'builtin.httpExecutionTime.google', 'builtin.httpCode.google')
======> request send
GET https://127.0.0.2:443/
User-Agent: centreon::plugins::backend::http::useragent
======> response done
500 Can't connect to 127.0.0.2:443 (Connection refused)
Content-Type: text/plain
Client-Date: Wed, 06 Mar 2024 17:26:31 GMT
Client-Warning: Internal response
Can't connect to 127.0.0.2:443 (Connection refused)
Connection refused at /usr/share/perl5/vendor_perl/LWP/Protocol/http.pm line 50.
======> variables
google check: 500 (first server char: )
But by adding a test
selection before the google
selection like:
{
"name": "test",
"critical": "%(builtin.httpCode.google) != 200",
"exit": "%(builtin.httpCode.google) != 200",
"formatting": {
"printf_msg":"API returned HTTP code '%s' with message '%s'",
"printf_var":[
"%(builtin.httpCode.google)",
"%(builtin.httpMessage.google)"
],
"display_ok": true
}
},
I'll get:
CRITICAL: API returned HTTP code '500' with message 'Can't connect to 127.0.0.2:443 (Connection refused)'
======> request send
GET https://127.0.0.2:443/
User-Agent: centreon::plugins::backend::http::useragent
======> response done
500 Can't connect to 127.0.0.2:443 (Connection refused)
Content-Type: text/plain
Client-Date: Wed, 06 Mar 2024 17:37:54 GMT
Client-Warning: Internal response
Can't connect to 127.0.0.2:443 (Connection refused)
Connection refused at /usr/share/perl5/vendor_perl/LWP/Protocol/http.pm line 50.
======> variables
API returned HTTP code '500' with message 'Can't connect to 127.0.0.2:443 (Connection refused)'
That's because the exit
and critical
directives of the google
selection are not matched before parsing, so maybe we could do something about it also.
@cgagnaire i added the attribute scenario_stopped_first
. I also fix the curl backend attribute. It's ok now
Thanks again for the work @garnier-quentin and @cgagnaire ! The code changes will be merged with #5044