Collection of CheckMK checks (see https://checkmk.com/). All checks and plugins are provided as is. Absolutely no warranty. Send any comments to thl-cmk[at]outlook[dot]com

Skip to content
Snippets Groups Projects
Commit a3805d52 authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

update project

parent 64b46819
No related branches found
No related tags found
No related merge requests found
......@@ -22,6 +22,7 @@
# 2022-03-10: optimized code for perfdata
# 2022-03-12: added cafile and capath to Cert info section
# added max_age
# 2022-03-18: added regex pattern match
#
# Example output from agent:
......@@ -58,7 +59,7 @@
import json
import time
from typing import Dict, Any, Optional, Tuple, List
from typing import Dict, Any, List
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
DiscoveryResult,
CheckResult,
......@@ -244,16 +245,6 @@ def discovery_curl(section: Dict[str, Any]) -> DiscoveryResult:
def check_curl(item, params, section: Dict[str, Any]) -> CheckResult:
def _convert_levels(levels: Optional[Tuple[Optional[float], Optional[float]]]):
warn = None
crit = None
if levels:
if levels[0]:
warn = levels[0] / 1000 # convert ms to s
if levels[1]:
crit = levels[1] / 1000
return warn, crit
try:
_data = section[item]
except KeyError:
......@@ -329,6 +320,14 @@ def check_curl(item, params, section: Dict[str, Any]) -> CheckResult:
notice=f'Header string: "{header_strings}" not found'
)
regex_match, regex_no_match, regex_missing = params['state_for_regex']
if _data.get('regex') == 0: # match
yield Result(state=State(regex_match), notice='Regex state: pattern matches')
elif _data.get('regex') == 1: # no match
yield Result(state=State(regex_no_match), notice='Regex state: pattern don\'t matches')
elif not _data.get('regex'): # missing info
yield Result(state=State(regex_missing), notice='Regex state: missing pattern match info')
max_age_warn, max_age_crit, max_age_state = params['max_age']
if max_age_warn:
max_age = None
......@@ -478,6 +477,7 @@ register.check_plugin(
'state_verify_sll_not_0': 1,
'state_expected_str_not_found': 1,
'state_header_str_not_found': 1,
'state_for_regex': (0, 1, 0),
'time_namelookup': {},
'time_connect': {},
'time_appconnect': {},
......
......@@ -38,7 +38,8 @@
# 2022-03-13: moved curl_item files to curl sub directory under MK_CONFDIR
# changed url/service_name from separate dict entries to tuple
# changed headers to read from curl_item_x.header file
#
# 2022-03-15: moved curl options from curl.cfg to curl_item_#.options
# added regex pattern match
from pathlib import Path
from typing import List, Tuple, Dict
......@@ -112,7 +113,6 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
field_separator: str = '|' # needs matching separator in the shell scripts
options_separator: str = ' '
options = conf[1].copy()
ca_certs = []
url_cfg_lines = []
url_list = options['url_list']
......@@ -133,7 +133,9 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
for entry in url_list:
curl_item += 1
options_array = []
header_arry = []
header_array = []
regex_option = 'no_regex'
save_output = False
# get service name and url, first try new format, then old format
try:
service_name, url = entry['curl_service']
......@@ -141,6 +143,8 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
service_name = entry['service_name']
url = entry['url']
options_array.append(f'--url "{url}"')
url_settings = default_settings.copy()
# merge per url settings with default settings
url_settings.update(entry.get('url_settings', {}))
......@@ -204,7 +208,7 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
url_settings.pop('user_auth')
if url_settings.get('expected_strings'):
options_array.append(f'-o {_temp_path}curl_output')
save_output = True
yield PluginConfig(
base_os=_os,
lines=url_settings['expected_strings'],
......@@ -212,8 +216,6 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
include_header=False,
)
url_settings.pop('expected_strings')
else:
options_array.append(_curl_output)
if url_settings.get('header_strings'):
options_array.append(f'--dump-header {_temp_path}curl_header')
......@@ -265,7 +267,7 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
if url_settings.get('request_headers'):
for header in url_settings['request_headers']:
key, value = header
header_arry.append(f'{key}:{value}')
header_array.append(f'{key}:{value}')
# options_array.append(f'--header "{key}:{value}"')
url_settings.pop('request_headers')
......@@ -276,7 +278,7 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
api_key = password_store.extract(api_key[1])
else:
api_key = api_key[1]
header_arry.append(f'{api_header}:{api_key}')
header_array.append(f'{api_header}:{api_key}')
# options_array.append(f'--header "{api_header}:{api_key}"')
url_settings.pop('api_key_header')
......@@ -322,7 +324,7 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
url_settings.pop('advanced_settings')
if url_settings.get('post_binary'):
header_arry.append(f'content-type: {url_settings["post_binary"][0]}')
header_array.append(f'content-type: {url_settings["post_binary"][0]}')
yield PluginConfig(
base_os=_os,
lines=[url_settings["post_binary"][1]],
......@@ -332,10 +334,36 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
options_array.append(f'--data-binary @{_conf_path}curl/curl_item_{curl_item}.post_binary')
url_settings.pop('post_raw')
if header_arry:
if url_settings.get('regex_response'):
regex_str, no_case, multi_line = url_settings['regex_response']
if regex_str:
save_output = True
yield PluginConfig(
base_os=_os,
lines=[regex_str],
target=Path(f'curl/curl_item_{curl_item}.regex'),
include_header=False,
)
if no_case:
regex_option = 'nocase'
else:
regex_option = 'case'
if multi_line:
regex_option += '_multiline'
else:
regex_option += '_nomultiline'
url_settings.pop('regex_response')
if save_output:
options_array.append(f'-o {_temp_path}curl_output')
else:
options_array.append(_curl_output)
if header_array:
yield PluginConfig(
base_os=_os,
lines=header_arry,
lines=header_array,
target=Path(f'curl/curl_item_{curl_item}.header'),
include_header=False,
)
......@@ -349,9 +377,16 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
curl_options = curl_options.replace(' ', ' ')
url_cfg_lines.append(
f'{service_name}{field_separator}'
f'"{url}"{field_separator}'
f'{curl_options.strip()}{field_separator}'
f'curl_item_{curl_item}'
# f'"{url}"{field_separator}'
# f'{curl_options.strip()}{field_separator}'
f'curl_item_{curl_item}{field_separator}'
f'{regex_option}{field_separator}'
)
yield PluginConfig(
base_os=_os,
lines=options_array,
target=Path(f'curl/curl_item_{curl_item}.options'),
include_header=True,
)
yield Plugin(
......@@ -361,12 +396,7 @@ def get_curl_files(conf: Tuple[str, Dict[str, List[any]]]) -> FileGenerator:
interval=interval,
timeout=timeout,
)
yield PluginConfig(
base_os=_os,
lines=url_cfg_lines,
target=Path('curl.cfg'),
include_header=False,
)
yield PluginConfig(
base_os=_os,
lines=url_cfg_lines,
......
......@@ -24,7 +24,8 @@ Wrapper around: https://curl.se/
2022-03-11: added --verbose --stderr $TEMP_DIR\curl_session to CURL_OPTIONS
2022-03-12: fixed escapes for json format in TLS_INFO
2022-03-13: moved curl_item files to curl sub directory under $MK_CONFDIR
2022-03-15: moved curl options from curl.cfg to curl_item_#.options
2022-03-15: added regex pattern match
#>
$TEMP_DIR="c:\windows\temp"
......@@ -73,27 +74,26 @@ function Find-CurlStrings {
)
if (Test-Path -Path "$SEARCH_FILE" -PathType Leaf) {
if (Test-Path -Path "$MK_CONFDIR/curl/$CURL_ITEM.$SEARCH_EXTENSION" -PathType Leaf) {
$CURL_STRING="FIRST"
$ROUND="FIRST"
$CURL_FILE=Get-Content $SEARCH_FILE -Raw
$CURL_RESULT="$CURL_RESULT{""$SERVICE_NAME"":{""$JSON_KEY"":["
foreach($SEARCH_STRING in Get-Content $MK_CONFDIR/curl/$CURL_ITEM.$SEARCH_EXTENSION) {
if ( $CURL_STRING -eq "SECOND" ) {
foreach($LINE in Get-Content $MK_CONFDIR/curl/$CURL_ITEM.$SEARCH_EXTENSION) {
if ( $ROUND -eq "SECOND" ) {
$CURL_RESULT="$CURL_RESULT,"
} else {
$CURL_STRING="SECOND"
$ROUND="SECOND"
}
$CURL_SEARCH=$CURL_FILE.IndexOf($SEARCH_STRING)
$CURL_SEARCH=$CURL_FILE.IndexOf($LINE)
# change to match grep return codes
if ($CURL_SEARCH -ne -1){
$CURL_SEARCH = 0
} else {
$CURL_SEARCH = 1
}
$CURL_RESULT="$CURL_RESULT[""$SEARCH_STRING"", $CURL_SEARCH]"
$CURL_RESULT="$CURL_RESULT[""$LINE"", $CURL_SEARCH]"
}
$CURL_RESULT="$CURL_RESULT]}}"
}
# Remove-Item -Path $SEARCH_FILE
}
return $CURL_RESULT
}
......@@ -105,25 +105,51 @@ function Find-CurlSessionInfo {
)
if (Test-Path -Path "$CURL_SESSION_FILE" -PathType Leaf) {
$CURL_RESULT = "$CURL_RESULT{""$SERVICE_NAME"":{""$JSON_KEY"":["
$CURL_STRING="FIRST"
$ROUND="FIRST"
foreach($LINE in Get-Content "$CURL_SESSION_FILE") {
if ($LINE[0] -eq "$SEARCH_MARKER") {
$LINE = $LINE.Substring(1, $LINE.Length -1).trim() -replace """", "\"""
if ( $CURL_STRING -eq "SECOND" ) {
if ( $ROUND -eq "SECOND" ) {
$CURL_RESULT="$CURL_RESULT,"
} else {
$CURL_STRING="SECOND"
$ROUND="SECOND"
}
$CURL_RESULT="$CURL_RESULT""$LINE"""
}
}
$CURL_RESULT="$CURL_RESULT]}}"
# Remove-Item -Path $CURL_SESSION_FILE
}
# return $CURL_RESULT even if it not altered
return $CURL_RESULT
}
function Find-CurlRegex {
if (Test-Path -Path "$CURL_OUTPUT" -PathType Leaf) {
if (Test-Path -Path "$MK_CONFDIR/curl/$CURL_ITEM.regex" -PathType Leaf) {
if ($CURL_REG_MULTI -eq "multiline") {
$CURL_REG_MULTI = "(?sm)"
} else {
$CURL_REG_MULTI = ""
}
$CURL_FILE=Get-Content "$CURL_OUTPUT" -Raw
foreach($LINE in Get-Content "$MK_CONFDIR/curl/$CURL_ITEM.regex") {
if ($CURL_REG_CASE -eq "case") {
$CURL_REG_RESULT= $CURL_FILE -cmatch "$CURL_REG_MULTI$LINE"
} else {
$CURL_REG_RESULT= $CURL_FILE -match "$CURL_REG_MULTI$LINE"
}
}
if ("$CURL_REG_RESULT" -eq "True") {
$CURL_REG_RESULT = 0
} else {
$CURL_REG_RESULT = 1
}
$CURL_RESULT = "$CURL_RESULT{""$SERVICE_NAME"":{""regex"":$CURL_REG_RESULT}}"
}
}
return $CURL_RESULT
}
function Cleanup {
if (Test-Path -Path $CURL_OUTPUT -PathType Leaf) {
Remove-Item -Path $CURL_OUTPUT
......@@ -141,9 +167,10 @@ Write-Host -NoNewline "{"
foreach($LINE in Get-Content $CURL_CONFIG) {
$SERVICE_NAME=$LINE.split("|")[0]
$URL=$LINE.split("|")[1]
$OPTIONS=$LINE.split("|")[2]
$CURL_ITEM=$LINE.split("|")[3]
$CURL_ITEM=$LINE.split("|")[1]
$CURL_REGEX=$LINE.split("|")[2]
$CURL_REG_CASE=$CURL_REGEX.split("_")[0]
$CURL_REG_MULTI=$CURL_REGEX.split("_")[1]
if ( $CURL_RUN -eq "SECOND") {
Write-Host -NoNewline ","
......@@ -154,7 +181,8 @@ foreach($LINE in Get-Content $CURL_CONFIG) {
Cleanup
Write-Host -NoNewline """$SERVICE_NAME"":{""data"":"
$RUN="$CURL_EXECUTABLE $CURL_OPTIONS --url $URL $OPTIONS"
# $RUN="$CURL_EXECUTABLE $CURL_OPTIONS --url $URL $OPTIONS"
$RUN="$CURL_EXECUTABLE $CURL_OPTIONS --config $MK_CONFDIR/curl/$CURL_ITEM.options"
$RESULT = . cmd /c "$RUN"
Write-Host -NoNewline $RESULT
# Write-Host -NoNewline ",""curl_options"":""$CURL_OPTIONS $OPTIONS"""
......@@ -175,6 +203,9 @@ foreach($LINE in Get-Content $CURL_CONFIG) {
# collect response header
$CURL_RESULT=Find-CurlSessionInfo -SEARCH_MARKER "<" -JSON_KEY "RESPONSE_HEADER"
# check for regex match
$CURL_RESULT=Find-CurlRegex
}
Write-Output "}"
......
......@@ -18,7 +18,10 @@
# 2022-03-06: added support for ssl/tls session info
# 2022-03-11: added --verbose --stderr $TEMP_DIR/curl_session to CURL_OPTIONS
# 2022-03-13: moved curl_item files to curl sub directory under $MK_CONFDIR
# 2022-03-15: moved curl options from curl.cfg to curl_item_#.options
# 2022-03-17: added regex pattern match
#
# ToDo: add plugin timeout enforcement
CONF_DIR="/etc/check_mk"
......@@ -27,7 +30,7 @@ TEMP_DIR="/var/tmp"
CURL_OPTIONS="-q -w %{json} -s --verbose --stderr $TEMP_DIR/curl_session"
CURL_CONFIG=curl.cfg
CURL_RUN=FIRST
CURL_RUN="FIRST"
CURL_OUTPUT="$TEMP_DIR/curl_output"
CURL_HEADER="$TEMP_DIR/curl_header"
CURL_SESSION_FILE="$TEMP_DIR/curl_session"
......@@ -38,17 +41,17 @@ function find_curl_strings {
# check for expected strings in response
if [ -f "$1" ]; then
if [ -f "$CONF_DIR/curl/$CURL_ITEM.$2" ]; then
local CURL_STRING=FIRST
local ROUND="FIRST"
CURL_RESULT=$CURL_RESULT$(printf '{"%s":{"%s":[' "$SERVICE_NAME" "$3")
while read -r SEARCH_STRING; do
if [ "$CURL_STRING" = "SECOND" ]; then
while read -r LINE; do
if [ "$ROUND" = "SECOND" ]; then
CURL_RESULT=$CURL_RESULT$(printf ',')
else
CURL_STRING="SECOND"
ROUND="SECOND"
fi
# ToDo: remove grep, read $CURL_OUTPUT to $CURL_FILE and search in there
grep "$SEARCH_STRING" "$1" > /dev/null
CURL_RESULT=$CURL_RESULT$(printf '["%s", %s]' "$SEARCH_STRING" $?)
grep -q -s "$LINE" "$1"
CURL_RESULT=$CURL_RESULT$(printf '["%s", %s]' "$LINE" $?)
done <"$CONF_DIR/curl/$CURL_ITEM.$2"
CURL_RESULT=$CURL_RESULT$(printf ']}}')
fi
......@@ -60,13 +63,13 @@ function find_curl_session_info {
# usage: search_marker json_key replace_new_line
if [ -f "$CURL_SESSION_FILE" ]; then
CURL_RESULT="$CURL_RESULT"$(printf '{"%s":{"%s":[' "$SERVICE_NAME" "$2")
local CURL_STRING="FIRST"
local ROUND="FIRST"
while read -r LINE; do
if [ "${LINE:0:1}" = "$1" ]; then
if [ "$CURL_STRING" = "SECOND" ]; then
if [ "$ROUND" = "SECOND" ]; then
CURL_RESULT=$CURL_RESULT$(printf ',')
else
CURL_STRING="SECOND"
ROUND="SECOND"
fi
LINE=${LINE//"\""/"\\\""}
if [ "$3" = "YES" ]; then
......@@ -83,6 +86,33 @@ function find_curl_session_info {
fi
}
function find_curl_regex {
local GREP_OPTIONS="-q -s -o -z -P"
if [ -f "$CURL_OUTPUT" ]; then
if [ -f "$CONF_DIR/curl/$CURL_ITEM.regex" ]; then
if [ "$CURL_REG_MULTI" = "multiline" ]; then
CURL_REG_MULTI="(?sm)"
else
CURL_REG_MULTI=""
fi
while read -r LINE; do
if [ "$CURL_REG_CASE" = "case" ]; then
LINE="'$CURL_REG_MULTI$LINE'"
eval grep $GREP_OPTIONS $LINE "$CURL_OUTPUT"
CURL_REG_RESULT=$?
else
GREP_OPTIONS="$GREP_OPTIONS"" -i"
LINE="'$CURL_REG_MULTI$LINE'"
eval grep $GREP_OPTIONS $LINE $CURL_OUTPUT
CURL_REG_RESULT=$?
fi
CURL_RESULT=$CURL_RESULT$(printf '{"%s":{"regex":%s}}' "$SERVICE_NAME" "$CURL_REG_RESULT")
done < "$CONF_DIR/curl/$CURL_ITEM.regex"
fi
fi
}
function cleanup {
if [ -f "$CURL_OUTPUT" ]; then
rm "$CURL_OUTPUT"
......@@ -125,10 +155,11 @@ printf "{"
while read -r LINE; do
SERVICE_NAME=$(echo "$LINE" | awk -F'|' '{print $1}')
URL=$(echo "$LINE" | awk -F'|' '{print $2}')
# shellcheck disable=SC2207
OPTIONS=$(echo "$LINE" | awk -F'|' '{print $3}')
CURL_ITEM=$(echo "$LINE" | awk -F'|' '{print $4}')
CURL_ITEM=$(echo "$LINE" | awk -F'|' '{print $2}')
CURL_REGEX=$(echo "$LINE" | awk -F'|' '{print $3}')
CURL_REG_CASE=$(echo "$CURL_REGEX" | awk -F'_' '{print $1}')
CURL_REG_MULTI=$(echo "$CURL_REGEX" | awk -F'_' '{print $2}')
# FIELDS=($(awk -F"|" '{$1=$1} 1' <<<"${LINE}"))
if [ "$CURL_RUN" = "SECOND" ]; then
......@@ -140,8 +171,7 @@ while read -r LINE; do
cleanup
printf '"%s":{"data":' "$SERVICE_NAME"
eval "$CURL_EXECUTABLE" "$CURL_OPTIONS" --url "$URL" "$OPTIONS"
# printf ',"curl_options":"%s %s"' "$CURL_OPTIONS" "$OPTIONS"
eval "$CURL_EXECUTABLE" "$CURL_OPTIONS" --config "$CONF_DIR/curl/$CURL_ITEM.options"
printf '}'
# check for expected strings in response
......@@ -158,6 +188,9 @@ while read -r LINE; do
# retrieve response header
find_curl_session_info "<" "RESPONSE_HEADER" "YES"
# check for regex match
find_curl_regex
done <"$CURL_CONFIG"
printf "}\n"
......@@ -180,8 +213,7 @@ unset CURL_HEADER
unset CURL_SESSION_FILE
unset SERVICE_NAME
unset URL
unset OPTIONS
unset LINE
unset ERROR_LEVEL
unset CURL_REG_CASE
unset CURL_REG_MULTI
exit 0
No preview for this file type
......@@ -24,7 +24,7 @@
'name': 'curl',
'num_files': 7,
'title': 'cURL agent plugin',
'version': '20220314.v0.1.0',
'version': '20220318.v0.1.1',
'version.min_required': '2.0.0',
'version.packaged': '2021.09.20',
'version.usable_until': None}
\ No newline at end of file
......@@ -19,7 +19,6 @@ from cmk.gui.plugins.metrics import (
metric_info,
graph_info,
perfometer_info,
check_metrics,
)
metric_info['time_namelookup'] = {
......
......@@ -47,13 +47,12 @@
# 2022-03-13: added post data
# made some entries fordable (Default options/Per URL settings, CA Cert)
# changed url and service_name to curl_service tuple
# changed headers to listof tuple
#
# changed headers to list of tuple
# 2022-03-15: added regex pattern match for bakery
# 2022-03-18: added regex pattern match for check
# from typing import Optional, List, Dict
from cmk.gui.i18n import _
from cmk.gui.exceptions import MKUserError
# from cmk.gui.valuespec import Optional as _Optional
from cmk.gui.valuespec import (
Dictionary,
ListOf,
......@@ -72,7 +71,7 @@ from cmk.gui.valuespec import (
Optional,
Foldable,
Age,
Url,
# Url,
UploadOrPasteTextFile,
)
from cmk.gui.plugins.wato import (
......@@ -154,6 +153,24 @@ _curl_check_elements = [
title=_('State on expected header not found'),
help=_('Monitoring state if one expected header string is not found in the cURL output. Default is WARN.')
)),
('state_for_regex',
Tuple(
title=_('State for regex pattern match'),
elements=[
MonitoringState(
default_value=0,
title=_('State on regex pattern match'),
),
MonitoringState(
default_value=1,
title=_('State on regex pattern don\'t match'),
),
MonitoringState(
default_value=0,
title=_('State on regex pattern match info missing'),
),
],
)),
('show_additional_info',
Tuple(
title=_('Show additional info'),
......@@ -274,7 +291,7 @@ rulespec_registry.register(
_option_curl_service = ('curl_service',
Tuple(
title=_('cURL service'),
#title=_('cURL service'),
elements=[
TextUnicode(
title=_('Service name'),
......@@ -316,6 +333,19 @@ _option_redirects = ('redirects',
]
))
_option_regex_response = ('regex_response',
Tuple(
title=_('Regular expression to expect in content'),
elements=[
TextUnicode(
label=_('Regular expression'),
placeholder=_('If empty regex search will be disabled')
),
Checkbox('Case insensitive'),
Checkbox('Multiline string matching'),
]
))
_option_advanced_settings = ('advanced_settings',
Tuple(
title='Advanced settings',
......@@ -855,6 +885,7 @@ _option_url_settings = ('url_settings',
_url_max_time,
_url_speed_limit,
_url_speed_time,
_option_regex_response,
_url_compressed,
_option_post,
_url_api_key_header,
......@@ -905,23 +936,24 @@ def _option_url_transform_cur_service(params):
_option_url = ('url_list',
ListOf(
Transform(
Dictionary(
elements=[
_option_curl_service,
_option_url_settings,
],
required_keys=['curl_service',],
Foldable(
ListOf(
Transform(
Dictionary(
elements=[
_option_curl_service,
_option_url_settings,
],
required_keys=['curl_service', ],
),
forth=_option_url_transform_cur_service
),
forth=_option_url_transform_cur_service
),
add_label=_('Add URL'),
movable=True,
title=_('URLs to check'),
allow_empty=False,
validate=_validate_service_names,
))
add_label=_('Add URL'),
movable=True,
title=_('URLs to check'),
allow_empty=False,
validate=_validate_service_names,
)))
_option_default_settings = ('default_settings',
Foldable(
......@@ -939,6 +971,7 @@ _option_default_settings = ('default_settings',
_option_max_time,
_option_speed_limit,
_option_speed_time,
_option_regex_response,
_options_compressed,
_option_post,
_option_api_key_header,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment