From b7ecdee87c3b66279bca1a9de688610e40264f7e Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Sun, 21 May 2023 17:07:28 +0200 Subject: [PATCH] update project --- agent_based/squid.py | 199 +++++++++++++++++++++++++++++++++++++ agents/bakery/squid.py | 47 +++++++++ agents/plugins/squid | 34 +++++++ checkman/squid | 48 ++------- gui/metrics/squid.py | 128 ++++++++++++++++++++++++ gui/wato/squid.py | 142 ++++++++++++++++++++++++++ packages/squid | 18 ++++ squid-2.0.2-2023-05-21.mkp | Bin 0 -> 4687 bytes squid.mkp | Bin 0 -> 4687 bytes 9 files changed, 574 insertions(+), 42 deletions(-) create mode 100644 agent_based/squid.py create mode 100755 agents/bakery/squid.py create mode 100755 agents/plugins/squid create mode 100644 gui/metrics/squid.py create mode 100644 gui/wato/squid.py create mode 100644 packages/squid create mode 100644 squid-2.0.2-2023-05-21.mkp create mode 100644 squid.mkp diff --git a/agent_based/squid.py b/agent_based/squid.py new file mode 100644 index 0000000..b719d48 --- /dev/null +++ b/agent_based/squid.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2023-05-20 + +# based on https://github.com/allangood/check_mk/tree/master/plugins/squid +# +# rewritten for cmk 2.x +# +# 2023-05-20: moved to ~/local/lib/check_mk/base/plugins/agent_based/utils +# renamed from check_squid.include to squid.py +# + + +# !/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2023-05-20 + +# based on https://github.com/allangood/check_mk/tree/master/plugins/squid by Allan GooD: allan.cassaro@gmail.com +# +# rewritten for cmk 2.x +# + +# ToDo: add support for multiple instances + +from typing import Dict +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + register, + check_levels, + check_levels_predictive, + Service, + render +) +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( + DiscoveryResult, + CheckResult, +) + + +def parse_squid(string_table) -> Dict[str, float]: + section = {} + for line in string_table: + entry, value = line[0].split('=') + entry = entry.strip() + try: + value = float(value.split('/')[0].strip().split(' ')[0].split('%')[0]) + except ValueError: + continue + if 'kbytes' in entry: + value = value * 1024 + 8 # change kbytes to bits + section[entry] = value + + return section + + +register.agent_section( + name="squid", + parse_function=parse_squid, +) + + +def render_per_second(value: float) -> str: + return f'{value}/s' + + +def render_seconds(value: float) -> str: + return f'{value:0.4f} seconds' + + +squid_map = { + 'Client': { + 'client_http.requests': { + 'label': 'Requests', + 'levels_upper': 'client_requests', + 'metric_name': 'client_requests_per_second', + 'render_func': render_per_second, + }, + 'client_http.errors': { + 'label': 'Errors', + 'levels_upper': 'client_errors', + 'metric_name': 'client_errors_per_second', + 'render_func': render_per_second, + }, + 'client_http.hits': { + 'label': 'Cache Hits', + 'levels_upper': 'client_hits', + 'metric_name': 'client_hits_per_second', + 'render_func': render_per_second, + }, + 'client_http.kbytes_in': { + 'label': 'In', + 'levels_upper': 'client_bytes_in_out', + 'metric_name': 'if_in_bps', + 'render_func': render.networkbandwidth, + }, + 'client_http.kbytes_out': { + 'label': 'Out', + 'levels_upper': 'client_bytes_in_out', + 'metric_name': 'if_out_bps', + 'render_func': render.networkbandwidth, + }, + }, + 'Server': { + 'server.all.requests': { + 'label': 'Requests', + 'levels_upper': 'server_requests', + 'metric_name': 'server_all_requests', + 'render_func': render_per_second, + }, + 'server.all.errors': { + 'label': 'Errors', + 'levels_upper': 'server_errors', + 'metric_name': 'server_all_errors', + 'render_func': render_per_second, + }, + 'server.all.kbytes_in': { + 'label': 'In', + 'levels_upper': 'server_bytes_in_out', + 'metric_name': 'if_in_bps', + 'render_func': render.networkbandwidth, + }, + 'server.all.kbytes_out': { + 'label': 'Out', + 'levels_upper': 'server_bytes_in_out', + 'metric_name': 'if_out_bps', + 'render_func': render.networkbandwidth, + }, + }, + 'CPU': { + 'cpu_usage': { + 'label': 'Usage', + 'levels_upper': 'cpu_usage', + 'metric_name': 'util', + 'render_func': render.percent, + }, + 'cpu_time': { + 'label': 'Time', + 'levels_upper': 'cpu_time', + 'metric_name': 'cpu_time', + 'render_func': render.timespan, + }, + }, + 'DNS': { + 'dns.median_svc_time': { + 'label': 'Median response time', + 'levels_upper': 'dns_time', + 'metric_name': 'dns_median_svc_time', + 'render_func': render_seconds, + }}, +} + + +def discovery_squid(section: Dict[str, float]) -> DiscoveryResult: + for item in squid_map.keys(): + yield Service(item=item) + + +def check_squid(item, params, section: Dict[str, float]) -> CheckResult: + for value in squid_map[item].keys(): + entry = squid_map[item][value] + levels_upper = params.get(entry['levels_upper'], None) + yield from check_levels_predictive( + label=entry['label'], + value=section[value], + levels=levels_upper, + render_func=entry['render_func'], + metric_name=entry['metric_name'], + ) if isinstance(levels_upper, dict) else check_levels( + label=entry['label'], + value=section[value], + levels_upper=levels_upper, + render_func=entry['render_func'], + metric_name=entry['metric_name'], + ) + + +register.check_plugin( + name='squid', + service_name='Squid %s', + discovery_function=discovery_squid, + check_function=check_squid, + check_default_parameters={ + # 'client_requests': (600, 800), + # 'client_hits': (600, 800), + # 'server_requests': (600, 800), + 'dns_time': (2, 4), + 'cpu_usage': (60, 80) + }, + check_ruleset_name='squid', +) diff --git a/agents/bakery/squid.py b/agents/bakery/squid.py new file mode 100755 index 0000000..25a0191 --- /dev/null +++ b/agents/bakery/squid.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2023-05-20 + +# based on https://github.com/allangood/check_mk/tree/master/plugins/squid +# +# rewritten for cmk 2.x +# +# 2023-05-20: moved agent plugin from ~/local/share/check_mk/agents/plugins/linux +# to ~/local/share/check_mk/agents/plugins +# renamed bakery plugin from squid to squid.py + +from pathlib import Path +from cmk.base.cee.plugins.bakery.bakery_api.v1 import ( + FileGenerator, + OS, + Plugin, + PluginConfig, + register +) + + +def get_squid_files(conf) -> FileGenerator: + yield Plugin( + base_os=OS.LINUX, + source=Path('squid'), + # interval=interval, + # timeout=timeout + ) + + yield PluginConfig( + base_os=OS.LINUX, + lines=[f'port={conf["port"]}'], + target=Path('squid.cfg'), + include_header=False, + ) + + +register.bakery_plugin( + name='squid', + files_function=get_squid_files, +) diff --git a/agents/plugins/squid b/agents/plugins/squid new file mode 100755 index 0000000..03aa184 --- /dev/null +++ b/agents/plugins/squid @@ -0,0 +1,34 @@ +#!/bin/bash + +# based on https://github.com/allangood/check_mk/tree/master/plugins/squid by Allan GooD: allan.cassaro@gmail.com +# +# 2023-05-20: changed separator to :sep(0) +# changed section from check_squid to squid +# +# https://etutorials.org/Server+Administration/Squid.+The+definitive+guide/Chapter+14.+Monitoring+Squid/14.2+The+Cache+Manager/ +# +# Table 14-1. Cache manager pages for squidclient mgr:<page> +# +MK_CONFDIR="/etc/check_mk" + + +if [ -e $MK_CONFDIR/squid.cfg ] ; then + . "$MK_CONFDIR"/squid.cfg +fi + +if [ -z "$port" ]; then + port=$(ss -tlpn | grep squid | tr -s ' ' | cut -d' ' -f 4 | cut -d':' -f 2) +fi + + +if type squidclient > /dev/null 2>&1 ; then + echo "<<squid:sep(0)>>>" + + # one squid instance + squidclient -p "$port" -T2 mgr:5min | grep = + + # multiple squid instances + # instance names must be without spaces and with colon char at the end + # squidclient -p 3128 -T2 mgr:5min | grep ' = ' | sed -e 's/^/Instance1:/' + # squidclient -p 3129 -T2 mgr:5min | grep ' = ' | sed -e 's/^/Instance2:/' +fi diff --git a/checkman/squid b/checkman/squid index 08ef898..c4e71db 100644 --- a/checkman/squid +++ b/checkman/squid @@ -1,45 +1,9 @@ -title: Dummy check man page - used as template for new check manuals -agents: linux, windows, aix, solaris, hpux, vms, freebsd, snmp -catalog: see modules/catalog.py for possible values +title: Check for Squid3 (www.squid-cache.org) health +agents: linux +catalog: os/misc license: GPL -distribution: check_mk +distribution: OMD description: - Describe here: (1) what the check actually does, (2) under which - circumstances it goes warning/critical, (3) which devices are supported - by the check, (4) if the check requires a separated plugin or - tool or separate configuration on the target host. + This check checks for Squid3 (www.squid-cache.org) basic health. + You need to install the plugin {squid} into the {plugins} directory of your agent. -item: - Describe the syntax and meaning of the check's item here. Provide all - information one needs if coding a manual check with {checks +=} in {main.mk}. - Give an example. If the check uses {None} as sole item, - then leave out this section. - -examples: - # Give examples for configuration in {main.mk} here. If the check has - # configuration variable, then give example for them here. - - # set default levels to 40 and 60 percent: - foo_default_values = (40, 60) - - # another configuration variable here: - inventory_foo_filter = [ "superfoo", "superfoo2" ] - -perfdata: - Describe precisely the number and meaning of performance variables - the check sends. If it outputs no performance data, then leave out this - section. - -inventory: - Describe how the inventory for the check works. Which items - will it find? Describe the influence of check specific - configuration parameters to the inventory. - -[parameters] -foofirst(int): describe the first parameter here (if parameters are grouped - as tuple) -fooother(string): describe another parameter here. - -[configuration] -foo_default_levels(int, int): Describe global configuration variable of - foo here. Important: also tell the user how they are preset. diff --git a/gui/metrics/squid.py b/gui/metrics/squid.py new file mode 100644 index 0000000..a6bd657 --- /dev/null +++ b/gui/metrics/squid.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2023-05-20 +# +# metrics plugin for squid checks +# +# + +from cmk.gui.i18n import _ + +from cmk.gui.plugins.metrics.utils import ( + check_metrics, + metric_info, + graph_info, + perfometer_info +) + +check_metrics['check_mk-squid'] = { + 'predict_client_requests_per_second': {'auto_graph': False}, + 'predict_client_hits_per_second': {'auto_graph': False}, + 'predict_server_all_requests': {'auto_graph': False}, + 'predict_util': {'auto_graph': False}, +} + + +metric_info['client_hits_per_second'] = {'title': _('Cache hits'), 'unit': '1/s', 'color': '11/a', } +metric_info['client_requests_per_second'] = {'title': _('Requests'), 'unit': '1/s', 'color': '31/a', } +metric_info['client_errors_per_second'] = {'title': _('Errors'), 'unit': '1/s', 'color': '21/a', } + +metric_info['predict_client_hits_per_second'] = {'title': _('Cache hits (Predicted)'), 'unit': '1/s', 'color': '52/a', } +metric_info['predict_client_requests_per_second'] = {'title': _('Requests (Predicted)'), 'unit': '1/s', 'color': '51/a', } + + +graph_info['squid_client'] = { + 'title': _('Squid Client statistics'), + 'metrics': [ + ('client_hits_per_second', 'line'), + ('client_errors_per_second', 'line'), + ('client_requests_per_second', 'line'), + ], + 'scalars': [ + 'client_hits_per_second:warn', + 'client_hits_per_second:crit', + ], +} + +graph_info['squid_client_predicted'] = { + 'title': _('Predicted Squid Client statistics'), + 'metrics': [ + ('predict_client_hits_per_second', '-area'), + ('predict_client_requests_per_second', 'area'), + ], + 'optional_metrics': [ + 'predict_client_hits_per_second', + 'predict_client_requests_per_second' + ], +} + +metric_info['server_all_requests'] = {'title': _('Requests'), 'unit': '1/s', 'color': '31/a', } +metric_info['server_all_errors'] = {'title': _('Errors'), 'unit': '1/s', 'color': '21/a', } + +metric_info['predict_server_all_requests'] = {'title': _('Requests (Predicted)'), 'unit': '1/s', 'color': '51/a', } + +graph_info['squid_server'] = { + 'title': _('Squid Server statistics'), + 'metrics': [ + ('server_all_errors', 'line'), + ('server_all_requests', 'line'), + + ], + 'scalars': [ + 'server_all_requests:warn', + 'server_all_requests:crit', + ], +} + +graph_info['squid_server_predicted'] = { + 'title': _('Predicted Squid Server statistics'), + 'metrics': [ + ('predict_server_all_requests', 'area'), + ], +} + +metric_info['cpu_time'] = {'title': _('CPU time'), 'unit': 's', 'color': '16/a', } +metric_info['predict_util'] = {'title': _('CPU utilization (Predicted)'), 'unit': 's', 'color': '51/a', } + +graph_info['squid_cpu_time'] = { + 'title': _('Squid CPU time'), + 'metrics': [ + ('cpu_time', 'area'), + ], + 'scalars': [ + 'cpu_time:warn', + 'cpu_time:crit', + ], +} + +graph_info['squid_cpu_util_predicted'] = { + 'title': _('Predicted Squid CPU utilization'), + 'metrics': [ + ('predict_util', 'area'), + ], +} + +metric_info['dns_median_svc_time'] = {'title': _('DNS response time'), 'unit': 's', 'color': '26/a', } + +graph_info['squid_dns_median_svc_time'] = { + 'title': _('Squid DNS median response time'), + 'metrics': [ + ('dns_median_svc_time', 'area'), + ], + 'scalars': [ + 'dns_median_svc_time:warn', + 'dns_median_svc_time:crit', + ], +} + +perfometer_info.append({ + 'type': 'logarithmic', + 'metric': 'dns_median_svc_time', + 'half_value': 2, + 'exponent': 2, +}) diff --git a/gui/wato/squid.py b/gui/wato/squid.py new file mode 100644 index 0000000..50bc02a --- /dev/null +++ b/gui/wato/squid.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2023-05-20 + +# based on https://github.com/allangood/check_mk/tree/master/plugins/squid +# +# rewritten for cmk 2.x +# +# 2023-05-20: moved to ~/local/lib/check_mk/gui/plugins/wato +# renamed from check_squid.py to squid-py +# changed client_reqps to client_requests +# changed server_reqps to server_requests +# changed cpu_time to cpu_usage + +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + Integer, + Tuple, + TextInput, + Float, +) +from cmk.gui.plugins.wato.utils import ( + rulespec_registry, + HostRulespec, + RulespecGroupCheckParametersApplications, + CheckParameterRulespecWithItem, + Levels, +) + +from cmk.gui.cee.plugins.wato.agent_bakery.rulespecs.utils import ( + RulespecGroupMonitoringAgentsAgentPlugins, +) + + +def _valuespec_squid(): + return Dictionary( + title=_('Squid Web Proxy (Linux)'), + elements=[ + # ('client_requests', + # Tuple( + # title=_('Set levels for Client Requests'), + # elements=[ + # Integer(title=_('Warning at'), default_value=600, unit='/s'), + # Integer(title=_('Critical at'), default_value=800, unit='/s'), + # ])), + # not sure if client hits as upper levels are use full + # ('client_hits', + # Tuple( + # title=_('Set levels for Client Hits'), + # elements=[ + # Integer(title=_('Warning at'), default_value=600, unit='/s'), + # Integer(title=_('Critical at'), default_value=800, unit='/s'), + # ])), + # ('server_requests', + # Tuple( + # title=_('Set levels for Server Requests'), + # elements=[ + # Integer(title=_('Warning at'), default_value=600, unit='/s'), + # Integer(title=_('Critical at'), default_value=800, unit='/s'), + # ])), + # ('cpu_usage', + # Tuple( + # title=_('Set levels for Squid CPU usage'), + # elements=[ + # Float(title=_('Warning at'), default_value=60.0, unit='%'), + # Float(title=_('Critical at'), default_value=80.0, unit='%') + # ])), + ('client_requests', + Levels( + title=_('Set levels for Client Requests'), + unit='/s', + )), + ('client_hits', + Levels( + title=_('Set levels for Client Hits'), + unit='/s' + )), + ('server_requests', + Levels( + title=_('Set levels for Server Requests'), + unit='/s', + )), + ('cpu_usage', + Levels( + title=_('Set levels for Squid CPU usage'), + unit='%', + default_levels=(60.0, 80.0) + )), + ('dns_time', + Tuple( + title=_('Set levels for DNS response time'), + elements=[ + Float(title=_('Warning at'), default_value=2.0, unit='seconds'), + Float(title=_('Critical at'), default_value=4.0, unit='seconds'), + ])), + ] + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='squid', + group=RulespecGroupCheckParametersApplications, + match_type='dict', + parameter_valuespec=_valuespec_squid, + title=lambda: _('Squid Web Proxy'), + item_spec=lambda: TextInput( + title="Squid counter", + help='Service name without "Squid" i.e. "DNS response time"', + ), + )) + + +def _valuespec_agent_squid(): + return Dictionary( + help=_('The plugin <tt>squid</tt> allows monitoring of Squid Web Proxies.'), + title=_('Squid Web Proxy (Linux)'), + elements=[ + ('port', + Integer( + title=_('Port number'), + help=_('TCP port number that squidclient connects to.'), + default_value=3128, + ) + ) + ] + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupMonitoringAgentsAgentPlugins, + name='agent_config:squid', + valuespec=_valuespec_agent_squid, + ) +) diff --git a/packages/squid b/packages/squid new file mode 100644 index 0000000..f3fa9cf --- /dev/null +++ b/packages/squid @@ -0,0 +1,18 @@ +{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', + 'description': 'Squid3 Health Check\n' + '\n' + 'based on Allan GooD - allan.cassaro@gmail.com work. \n' + 'See https://github.com/allangood/check_mk\n' + '\n' + 'Rewritten for CMK 2.1.x\n', + 'download_url': 'https://thl-cmk.hopto.org', + 'files': {'agent_based': ['squid.py'], + 'agents': ['bakery/squid.py', 'plugins/squid'], + 'checkman': ['squid'], + 'gui': ['wato/squid.py', 'metrics/squid.py']}, + 'name': 'squid', + 'title': 'Squid3 Health Check', + 'version': '2.0.2-2023-05-21', + 'version.min_required': '2.1.0b1', + 'version.packaged': '2.1.0p21', + 'version.usable_until': None} \ No newline at end of file diff --git a/squid-2.0.2-2023-05-21.mkp b/squid-2.0.2-2023-05-21.mkp new file mode 100644 index 0000000000000000000000000000000000000000..368a74d4dd298243d899efaa2fea6214f20e0870 GIT binary patch literal 4687 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 literal 0 HcmV?d00001 diff --git a/squid.mkp b/squid.mkp new file mode 100644 index 0000000000000000000000000000000000000000..368a74d4dd298243d899efaa2fea6214f20e0870 GIT binary patch literal 4687 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 literal 0 HcmV?d00001 -- GitLab