From f8def7da4f3d75f616bfc76e6e279fe9671fb47d Mon Sep 17 00:00:00 2001
From: thl-cmk <thl-cmk@outlook.com>
Date: Sat, 21 Oct 2023 17:30:14 +0000
Subject: [PATCH] Delete curl.py

---
 agent_based/curl.py | 561 --------------------------------------------
 1 file changed, 561 deletions(-)
 delete mode 100644 agent_based/curl.py

diff --git a/agent_based/curl.py b/agent_based/curl.py
deleted file mode 100644
index 34030d6..0000000
--- a/agent_based/curl.py
+++ /dev/null
@@ -1,561 +0,0 @@
-#!/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  : 2022-02-15
-
-#
-# based on the work by Christian Wirtz doc[at]snowheaven[dot]de
-#
-# 2022-02-15: rewritten for cmk 2.0
-# 2022-02-20: removed url_effective from format file (bad output on linux: "url_effective":http://"https//checkmk.com")
-#             added num_connects, num_redirects, size_download, size_header, speed_download
-#             added redirect_url, remote_ip, scheme, http_version, http_connect
-# 2022-02-22: added params for all values
-# 2022-02-23: changed items on service info line
-# 2022-02-28: added expected_strings and state_item_not_found option
-# 2022-03-05: added support for search in header strings
-# 2022-03-06: added support for tls/certificate information
-# 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
-# 2022-03-22: added curl_error_code_to_ignore and http_error_code_to_ignore options
-# 2022-04-06: removed .replace('://', ': //'))  from json.loads() so service name is without space
-# 2022-04-26: made http(s) URLs clickable
-# 2022-05-15: added workaround for raise ValueError("Cannot render negative timespan")
-# 2022-05-17: fixed wrong import path for  _TIME_UNITS and _gen_timespan_chunks
-# 2023-06-07: moved gui files to ~/local/lib/chek_mk/gui/plugins/...
-#
-
-# Example output from agent:
-#
-# <<<curl>>>
-# {
-#     "thl-cmk.hopto.org": {
-#         "url": "https://thl-cmk.hopto.org",
-#         "data": {
-#             "ssl_verify_result": "0",
-#             "http_return_code": "000",
-#             "time_namelookup": "0,000000",
-#             "time_connect": "0,000000",
-#             "time_appconnect": "0,000000",
-#             "time_pretransfer": "0,000000",
-#             "time_redirect": "0,000000",
-#             "time_starttransfer": "0,000000",
-#             "time_total": "0,000000",
-#             "http_connect": "000",
-#             "http_version": "0",
-#             "num_connects": "0",
-#             "num_redirects": "0",
-#             "redirect_url": "",
-#             "remote_ip": "",
-#             "scheme": "(nil)",
-#             "size_download": "0",
-#             "size_header": "0",
-#             "speed_download": "0,000",
-#         },
-#         "error_level": "6"
-#     }
-# }
-#
-
-import json
-import time
-from typing import Dict, Any, List, Iterable
-from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
-    DiscoveryResult,
-    CheckResult,
-)
-
-from cmk.base.plugins.agent_based.agent_based_api.v1 import (
-    register,
-    Service,
-    State,
-    check_levels,
-    Result,
-    render,
-)
-
-#
-# start workaround for :  raise ValueError("Cannot render negative timespan")
-#
-from cmk.base.api.agent_based.render import (
-    _TIME_UNITS,
-    _gen_timespan_chunks,
-)
-
-
-def timespan(seconds: float) -> str:
-    """Render a time span in seconds
-
-    Example:
-        >>> timespan(1606721)
-        '18 days 14 hours'
-        >>> timespan(0.0001)
-        '100 microseconds'
-
-    """
-    if seconds >= 0:
-        ts = " ".join(_gen_timespan_chunks(float(seconds), nchunks=2))
-    else:
-        seconds = -1 * seconds
-        ts = " ".join(_gen_timespan_chunks(float(seconds), nchunks=2))
-        ts = f"-{ts}"
-    if ts == "0 %s" % _TIME_UNITS[-1][0]:
-        ts = "0 seconds"
-    return ts
-
-#
-# end workaround for :  raise ValueError("Cannot render negative timespan")
-#
-
-
-_curl_error_codes = {
-    1: 'Unsupported protocol. This build of curl has no support for this protocol.',
-    2: 'Failed to initialize.',
-    3: 'URL malformed. The syntax was not correct.',
-    4: 'A feature or option that was needed to perform the desired request was not enabled or was explicitly '
-       'disabled at build-time. To make curl able to do this, you probably need another build of libcurl.',
-    5: 'Could not resolve proxy. The given proxy host could not be resolved.',
-    6: 'Could not resolve host. The given remote host could not be resolved.',
-    7: 'Failed to connect to host.',
-    8: 'Weird server reply. The server sent data curl could not parse.',
-    9: 'FTP access denied. The server denied login or denied access to the particular resource or directory you '
-       'wanted to reach. Most often you tried to change to a directory that does not exist on the server.',
-    10: 'FTP accept failed. While waiting for the server to connect back when an active FTP session is used, '
-        'an error code was sent over the control connection or similar.',
-    11: 'FTP weird PASS reply. Curl could not parse the reply sent to the PASS request.',
-    12: 'During an active FTP session while waiting for the server to connect back to curl, the timeout expired.',
-    13: 'FTP weird PASV reply, Curl could not parse the reply sent to the PASV request.',
-    14: 'FTP weird 227 format. Curl could not parse the 227-line the server sent.',
-    15: 'FTP cannot use host. Could not resolve the host IP we got in the 227-line.',
-    16: 'HTTP/2 error. A problem was detected in the HTTP2 framing layer. This is somewhat generic and can be one '
-        'out of several problems, see the error message for details.',
-    17: 'FTP could not set binary. Could not change transfer method to binary.',
-    18: 'Partial file. Only a part of the file was transferred.',
-    19: 'FTP could not download/access the given file, the RETR (or similar) command failed.',
-    21: 'FTP quote error. A quote command returned error from the server.',
-    22: 'HTTP page not retrieved. The requested url was not found or returned another error with the HTTP error '
-        'code being 400 or above. This return code only appears if --fail is used.',
-    23: 'Write error. Curl could not write data to a local filesystem or similar.',
-    25: 'FTP could not STOR file. The server denied the STOR operation, used for FTP uploading.',
-    26: 'Read error. Various reading problems.',
-    27: 'Out of memory. A memory allocation request failed.',
-    28: 'Operation timeout. The specified time-out period was reached according to the conditions.',
-    30: 'FTP PORT failed. The PORT command failed. Not all FTP servers support the PORT command, '
-        'try doing a transfer using PASV instead!',
-    31: 'FTP could not use REST. The REST command failed. This command is used for resumed FTP transfers.',
-    33: 'HTTP range error. The range "command" did not work.',
-    34: 'HTTP post error. Internal post-request generation error.',
-    35: 'SSL connect error. The SSL handshaking failed.',
-    36: 'Bad download resume. Could not continue an earlier aborted download.',
-    37: 'FILE could not read file. Failed to open the file. Permissions?',
-    38: 'LDAP cannot bind. LDAP bind operation failed.',
-    39: 'LDAP search failed.',
-    41: 'Function not found. A required LDAP function was not found.',
-    42: 'Aborted by callback. An application told curl to abort the operation.',
-    43: 'Internal error. A function was called with a bad parameter.',
-    45: 'Interface error. A specified outgoing interface could not be used.',
-    47: 'Too many redirects. When following redirects, curl hit the maximum amount.',
-    48: 'Unknown option specified to libcurl. This indicates that you passed a weird option to curl that was'
-        ' passed on to libcurl and rejected. Read up in the manual!',
-    49: 'Malformed telnet option.',
-    51: 'The peer\'s SSL certificate or SSH MD5 fingerprint was not OK.',
-    52: 'The server did not reply anything, which here is considered an error.',
-    53: 'SSL crypto engine not found.',
-    54: 'Cannot set SSL crypto engine as default.',
-    55: 'Failed sending network data.',
-    56: 'Failure in receiving network data.',
-    58: 'Problem with the local certificate.',
-    59: 'Could not use specified SSL cipher.',
-    60: 'Peer certificate cannot be authenticated with known CA certificates.',
-    61: 'Unrecognized transfer encoding.',
-    62: 'Invalid LDAP URL.',
-    63: 'Maximum file size exceeded.',
-    64: 'Requested FTP SSL level failed.',
-    65: 'Sending the data requires a rewind that failed.',
-    66: 'Failed to initialise SSL Engine.',
-    67: 'The user name, password, or similar was not accepted and curl failed to log in.',
-    68: 'File not found on TFTP server.',
-    69: 'Permission problem on TFTP server.',
-    70: 'Out of disk space on TFTP server.',
-    71: 'Illegal TFTP operation.',
-    72: 'Unknown TFTP transfer ID.',
-    73: 'File already exists (TFTP).',
-    74: 'No such user (TFTP).',
-    75: 'Character conversion failed.',
-    76: 'Character conversion functions required.',
-    77: 'Problem reading the SSL CA cert (path? access rights?).',
-    78: 'The resource referenced in the URL does not exist.',
-    79: 'An unspecified error occurred during the SSH session.',
-    80: 'Failed to shut down the SSL connection.',
-    82: 'Could not load CRL file, missing or wrong format.',
-    83: 'Issuer check failed.',
-    84: 'The FTP PRET command failed.',
-    85: 'Mismatch of RTSP CSeq numbers.',
-    86: 'Mismatch of RTSP Session Identifiers.',
-    87: 'Unable to parse FTP file list.',
-    88: 'FTP chunk callback reported error.',
-    89: 'No connection available, the session will be queued.',
-    90: 'SSL public key does not matched pinned public key.',
-    91: 'Invalid SSL certificate status.',
-    92: 'Stream error in HTTP/2 framing layer.',
-    93: 'An API function was called from inside a callback.',
-    94: 'An authentication function returned an error.',
-    95: 'A problem was detected in the HTTP/3 layer. This is somewhat generic and can be one out of '
-        'several problems, see the error message for details.',
-    96: 'QUIC connection error. This error may be caused by an SSL library error. QUIC is the '
-        'protocol used for HTTP/3 transfers.',
-}
-
-
-def _get_tls_info(tls_lines: List[str]):
-    tls_infos = {}
-    alpn_offerings = []
-    for line in tls_lines:
-        line = line.strip()
-        if line.startswith('subject: '):
-            tls_infos.update({'subject': line[9:]})
-        elif line.startswith('start date: '):
-            tls_infos.update({'start_date': line[12:]})
-        elif line.startswith('expire date: '):
-            tls_infos.update({'expire_date': line[13:]})
-            time_left = time.mktime(  # 'Feb 16 10:18:08 2022 GMT'
-                time.strptime(tls_infos['expire_date'], '%b %d %H:%M:%S %Y %Z')
-            ) - time.mktime(time.gmtime())
-            tls_infos.update({'time_left': time_left})
-        elif line.startswith('subjectAltName: '):
-            tls_infos.update({'subject_alternate_name': line[21:]})
-        elif line.startswith('issuer: '):
-            tls_infos.update({'issuer': line[8:]})
-        elif line.startswith('ALPN, offering '):
-            alpn_offerings.append(line[15:])
-        elif line.startswith('ALPN, server accepted to use '):
-            tls_infos.update({'alpn_accepted': line[29:]})
-        elif line.startswith('SSL certificate verify result: '):
-            tls_infos.update({'ssl_verify_result': line[31:]})
-        elif line.startswith('SSL connection using '):
-            tls_version, cipher = line[21:].split(' / ')
-            tls_infos.update({'tls_version_used': tls_version})
-            tls_infos.update({'cipher_used': cipher})
-        elif line.startswith('CAfile'):
-            tls_infos.update({'ca_file': line[8:]})
-        elif line.startswith('CApath'):
-            tls_infos.update({'ca_path': line[8:]})
-
-    tls_infos.update({'alpn_offerings': alpn_offerings})
-
-    return tls_infos
-
-
-def parse_curl(string_table):
-    try:
-        # section = json.loads(string_table[0][0].replace('://', ': //'))  # removed so service name is without space
-        section = json.loads(string_table[0][0])
-    except (IndexError, TypeError, json.JSONDecodeError):
-        return {}
-    if 'ERROR' not in section.keys():
-        if len(string_table) > 1:
-            # insert splitter, split (and implicit remove splitter), avoid removal of '}{'
-            for line in string_table[1][0].replace('}{', '}|||{').split('|||'):
-                # '{'thl-cmk.hopto.org': {'expected_strings': [['string1', 1], ['string2', 1], ['html', 0]]}}'
-                try:
-                    # line = line.replace('://', ': //')  # removed so service name is without space
-                    line = json.loads(line)
-                except json.JSONDecodeError:
-                    continue
-                # get first key from line
-                key = list(line.keys())[0]
-                # update section data for key
-                section[key].update(line[key])
-                for key in section.keys():
-                    if section[key].get('TLS_INFO'):
-                        tls_info = _get_tls_info(section[key]['TLS_INFO'])
-                        section[key].update({'tls_info': tls_info})
-                        # section[key].pop('TLS_INFO')
-        return section
-
-
-def discovery_curl(section: Dict[str, Any]) -> DiscoveryResult:
-    for key in section.keys():
-        yield Service(item=key)
-
-
-def check_curl(item, params, section: Dict[str, Any]) -> CheckResult:
-    try:
-        _data = section[item]
-    except KeyError:
-        yield Result(state=State(params['state_item_not_found']), notice='Item not found in agent data')
-        return
-
-    # url = _data['url'].replace('://', ': //')  # ugly workaround to stop cmk from replacing the url
-    http_return_code = _data['data']['http_code']
-    ssl_verify_result = _data['data']['ssl_verify_result']
-    curl_error_code = int(_data['data']['exitcode'])
-
-    # yield Result(state=State.OK, notice=f'URL from cfg: {url}')
-    for key, label in [
-        ('url', 'URL'),
-        ('redirect_url', 'URL redirect'),
-        ('url_effective', 'URL effective'),
-        ('referer', 'Referer'),
-    ]:
-        if _data['data'].get(key):
-            value = _data['data'][key]
-            if value.startswith('http'):
-                if params.get('clickable_url'):
-                    value = f'<a href={value} target="blank">{value}</a>'
-                else:
-                    value = f'{value.replace("://", ": //")}'   # ugly workaround to stop cmk from replacing the url
-            yield Result(state=State.OK, notice=f'{label}: {value}')
-
-    if curl_error_code != 0:
-        if curl_error_code in params['curl_error_code_to_ignore']:
-            yield Result(
-                state=State.OK,
-                notice=f'curl error code: {curl_error_code}, {_curl_error_codes.get(curl_error_code, "N/A")}')
-        else:
-            yield Result(
-                state=State(params['state_curl_result_not_0']),
-                summary=f'curl error code: {curl_error_code} see details',
-                details=f'curl error code: {curl_error_code}, {_curl_error_codes.get(curl_error_code, "N/A")}'
-            )
-
-    if http_return_code < 400:  # no connect, Ok, Redirect
-        yield Result(state=State.OK, notice=f'HTTP Return code: {http_return_code}')
-    else:
-        if http_return_code in params['http_error_code_to_ignore']:
-            yield Result(
-                state=State.OK, notice=f'HTTP Return code: {http_return_code}'
-            )
-        else:
-            yield Result(
-                state=State(params['state_http_result_not_200']),
-                notice=f'HTTP Return code: {http_return_code}'
-            )
-
-    if ssl_verify_result == 0:
-        yield Result(state=State.OK, notice=f'SSL verify result: {ssl_verify_result}')
-    else:
-        yield Result(state=State(params['state_verify_sll_not_0']), summary=f'SSL verify result: {ssl_verify_result}')
-
-    for key, label in [
-        ('scheme', 'Scheme (protocol)'),
-        ('http_version', 'HTTP version'),
-        ('method', 'Method'),
-        ('content_type', 'Content type'),
-        ('remote_ip', 'Remote IP'),
-        ('http_connect', 'Proxy connect code'),
-        ('errormsg', 'Error message'),
-        ('curl_version', 'cURL version'),
-    ]:
-        if _data['data'].get(key):
-            yield Result(state=State.OK, notice=f'{label}: {_data["data"][key]}')
-
-    if _data.get('curl_options'):
-        yield Result(state=State.OK, notice=f'cURL options: {_data["curl_options"]}')
-
-    if _data.get('expected_response'):
-        for expected_string, result in _data['expected_response']:
-            if result == 0:
-                yield Result(state=State.OK, notice=f'Response string: "{expected_string}" found')
-            else:
-                yield Result(
-                    state=State(params['state_expected_str_not_found']),
-                    notice=f'Response string: "{expected_string}" not found'
-                )
-
-    if _data.get('expected_header'):
-        for header_strings, result in _data['expected_header']:
-            if result == 0:
-                yield Result(state=State.OK, notice=f'Header string: "{header_strings}" found')
-            else:
-                yield Result(
-                    state=State(params['state_header_str_not_found']),
-                    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
-        if _data.get('RESPONSE_HEADER'):
-            for line in _data['RESPONSE_HEADER']:
-                if line.startswith('Last-Modified: '):
-                    max_age = time.mktime(time.gmtime()) - time.mktime(
-                        time.strptime(line[15:], '%a, %d %b %Y %H:%M:%S %Z'))  # 'Fri, 18 Jun 2021 18:17:33 GMT'
-        if max_age:
-            yield from check_levels(
-                label='Last modified',
-                value=max_age,
-                render_func=render.timespan,
-                notice_only=True,
-                levels_upper=(max_age_warn, max_age_crit),
-            )
-        else:
-            yield Result(state=State(max_age_state), notice='Last-Modified: Document modification date unknown')
-
-    if _data.get('tls_info', {}).get('subject'):
-        yield Result(state=State.OK, notice=f' ')
-        yield Result(state=State.OK, notice=f'Certificate info:')
-
-        for key, label in [
-            ('subject', 'Subject'),
-            ('issuer', 'Issuer'),
-            ('subject_alternate_name', 'Subject alternate name'),
-            ('start_date', 'Start date'),
-            ('expire_date', 'Expire date'),
-            ('tls_version_used', 'TLS Version used'),
-            ('cipher_used', 'Cipher used'),
-            ('ssl_verify_result', 'SSL verify result'),
-            ('ca_file', 'CA file'),
-            ('ca_path', 'CA path'),
-        ]:
-            if _data['tls_info'].get(key):
-                yield Result(state=State.OK, notice=f'{label}: {_data["tls_info"][key]}')
-
-        if _data['tls_info'].get('time_left'):
-            if params['cert_time_left'].get('upper'):
-                warn, crit = params['cert_time_left'].get('upper')
-                upper = (warn * 86400, crit * 86400)
-            else:
-                upper = None
-
-            if params['cert_time_left'].get('lower'):
-                warn, crit = params['cert_time_left'].get('lower')
-                lower = (warn * 86400, crit * 86400)
-            else:
-                lower = None
-
-            yield from check_levels(
-                label='Certificate time left',
-                value=_data['tls_info']['time_left'],
-                metric_name='cert_time_left',
-                render_func=timespan,
-                notice_only=True,
-                levels_upper=upper,
-                levels_lower=lower,
-            )
-
-    yield Result(state=State.OK, notice=f' ')
-    yield Result(state=State.OK, notice=f'Performance data:')
-
-    def _render_string(v):
-        return f'{v}'
-
-    for key, label, notice_only, render_func in [
-        # times
-        ('time_namelookup', 'Time name lookup', True, render.timespan,),
-        ('time_connect', 'Time connect', True, render.timespan,),
-        ('time_appconnect', 'Time app connect', True, render.timespan,),
-        ('time_pretransfer', 'Time pre transfer', True, render.timespan,),
-        ('time_redirect', 'Time redirect', True, render.timespan,),
-        ('time_starttransfer', 'Time start transfer', True, render.timespan,),
-        ('time_total', 'Time total', False, render.timespan,),
-        # counts
-        ('num_connects', '# of connects', True, _render_string, ),
-        ('num_redirects', '# of redirects', True, _render_string, ),
-        ('num_headers', '# of headers', True, _render_string, ),
-        # sizes
-        ('size_download', 'Size download', False, render.bytes,),
-        ('size_upload', 'Size upload', True, render.bytes,),
-        ('size_header', 'Size header', True, render.bytes,),
-        ('size_request', 'Size request', True, render.bytes,),
-        # speed
-        ('speed_download', 'Speed download', False, render.networkbandwidth,),
-        ('speed_upload', 'Speed upload', True, render.networkbandwidth,),
-    ]:
-        if _data['data'].get(key):
-            value = _data['data'][key]
-            if value != 0:
-                yield from check_levels(
-                    label=label,
-                    value=value,
-                    metric_name=key,
-                    notice_only=notice_only,
-                    render_func=render_func,
-                    levels_lower=params[key].get('lower'),
-                    levels_upper=params[key].get('upper'),
-                )
-
-    show_request_header, show_response_headers, show_session_info, show_raw_data = params['show_additional_info']
-    if show_request_header and _data.get('REQUEST_HEADER'):
-        yield Result(state=State.OK, notice=f' ')
-        yield Result(state=State.OK, notice=f'Request headers:')
-        for line in _data['REQUEST_HEADER']:
-            if line:
-                yield Result(state=State.OK, notice=f'{line}')
-
-    if show_response_headers and _data.get('RESPONSE_HEADER'):
-        yield Result(state=State.OK, notice=f' ')
-        yield Result(state=State.OK, notice=f'Response headers:')
-        for line in _data['RESPONSE_HEADER']:
-            if line:
-                yield Result(state=State.OK, notice=f'{line}')
-
-    if show_session_info and _data.get('TLS_INFO'):
-        yield Result(state=State.OK, notice=f' ')
-        yield Result(state=State.OK, notice=f'TLS/SSL/SSH info:')
-        for line in _data['TLS_INFO']:
-            if line:
-                yield Result(state=State.OK, notice=f'{line}')
-
-    if show_raw_data:
-        yield Result(state=State.OK, notice=f' ')
-        yield Result(state=State.OK, notice=f'RAW data:')
-        yield Result(state=State.OK, notice=f'{_data}')
-
-
-register.agent_section(
-    name="curl",
-    parse_function=parse_curl,
-)
-
-register.check_plugin(
-    name='curl',
-    service_name='cURL %s',
-    discovery_function=discovery_curl,
-    check_function=check_curl,
-    check_default_parameters={
-        'show_additional_info': (None, None, None, None),
-        'max_age': (None, None, None),
-        'state_item_not_found': 3,
-        'state_http_result_not_200': 1,
-        'http_error_code_to_ignore': [],
-        'state_curl_result_not_0': 1,
-        'curl_error_code_to_ignore': [],
-        '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': {},
-        'time_pretransfer': {},
-        'time_redirect': {},
-        'time_starttransfer': {},
-        'time_total': {},
-        'num_connects': {},
-        'num_redirects': {},
-        'num_headers': {},
-        'size_download': {},
-        'size_upload': {},
-        'size_header': {},
-        'size_request': {},
-        'speed_download': {},
-        'speed_upload': {},
-        'cert_time_left': {},
-    },
-    check_ruleset_name='curl'
-)
-- 
GitLab