From 411db4711b1532fe67f6a8dfc0801f4cde48854d Mon Sep 17 00:00:00 2001 From: cmk-bonobo Date: Sat, 2 Dec 2023 13:56:12 +0100 Subject: [PATCH] Initial commit, 2nd try --- .../plugins/agent_based/hal9001_status.py | 49 ++++++++ .../plugins/agent_based/hal9001_storages.py | 112 ++++++++++++++++++ .../base/plugins/agent_based/hal9001_users.py | 60 ++++++++++ 3 files changed, 221 insertions(+) create mode 100644 local/lib/python3/cmk/base/plugins/agent_based/hal9001_status.py create mode 100644 local/lib/python3/cmk/base/plugins/agent_based/hal9001_storages.py create mode 100644 local/lib/python3/cmk/base/plugins/agent_based/hal9001_users.py diff --git a/local/lib/python3/cmk/base/plugins/agent_based/hal9001_status.py b/local/lib/python3/cmk/base/plugins/agent_based/hal9001_status.py new file mode 100644 index 0000000..07d24e8 --- /dev/null +++ b/local/lib/python3/cmk/base/plugins/agent_based/hal9001_status.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +import time +from pprint import pprint +from .agent_based_api.v1 import get_value_store, get_rate, register, render, Service, Result, State, Metric + +# just a simple service withoot item +def discover_hal9001_status(section): + yield(Service()) + +def check_hal9001_status(section): + status = section["status"] + version = section["version"] + username = section["username"] + ipaddress = section["ipaddress"] + # check what status is reported and set state accordingly + if status == "ok": + state = State.OK + elif status == "update available": + state = State.WARN + elif status == "storage down": + state = State.CRIT + else: + state = State.UNKOWN + # no metrics, just a simple service + summary = f'Status is "{status}", Version is "{version}"' + details = f'User/IP used for access is "{username}/{ipaddress}"' + yield(Result(state=state, summary=summary, details=details)) + +def parse_hal9001_status_section(string_table): + parsed_data = {} + # we only expect one line with four entries + line = string_table[0] + parsed_data["status"] = line[0] + parsed_data["version"] = line[1] + parsed_data["username"] = line[2] + parsed_data["ipaddress"] = line[3] + return parsed_data + +register.agent_section( + name = "hal9001_status", + parse_function = parse_hal9001_status_section, +) + +register.check_plugin( + name = "hal9001_status", + service_name = "HAL Overall information", + discovery_function = discover_hal9001_status, + check_function = check_hal9001_status, +) \ No newline at end of file diff --git a/local/lib/python3/cmk/base/plugins/agent_based/hal9001_storages.py b/local/lib/python3/cmk/base/plugins/agent_based/hal9001_storages.py new file mode 100644 index 0000000..4c72b08 --- /dev/null +++ b/local/lib/python3/cmk/base/plugins/agent_based/hal9001_storages.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +import time +import random +from pprint import pprint +from .agent_based_api.v1 import get_value_store, get_rate, register, render, Service, Result, State, Metric + +def getStateUpper(levels, value): + warn, crit = levels + if value >= crit: + return State.CRIT + if value >= warn: + return State.WARN + return State.OK + +# services with item --> storageid and usage of value_store (to be able to calculate rates) +def discover_hal9001_storages(section): + for key in section: + yield(Service(item = key)) + +def check_hal9001_storages(item, params, section): + curr_time = time.time() # needed for calculating rates + storageid = item + # get all values from section + realname = section[storageid][0] + ul_bytes = section[storageid][1] + dl_bytes = section[storageid][2] + + # these are the keys for our value_store + vs_key_ul = f"hal_{storageid}_ul" + vs_key_dl = f"hal_{storageid}_dl" + vs_key_time = f"hal_{storageid}_time" # this is necessary only because we did not get get_rate() to work + + # we have to persist our upload/download values so that we can calculate rates + value_store = get_value_store() + # get the values from last run + ul_last = value_store.get(vs_key_ul, 0) + dl_last = value_store.get(vs_key_dl, 0) + time_last = value_store.get(vs_key_time, 0) + # store the new values + value_store[vs_key_ul] = ul_bytes + value_store[vs_key_dl] = dl_bytes + value_store[vs_key_time] = curr_time + + # now calculate the rates + # in theory this should work with calls to get_rate() - but unfortunately + # these calls cause an error, why, how to call function get_rate() correctly?? TBD + ''' + File "/omd/sites/ttw/lib/python3/cmk/base/api/agent_based/utils.py", line 494, in get_rate + if not last_state or len(last_state) != 2: + TypeError: object of type 'int' has no len() + ''' + #ul_rate = get_rate(value_store, f"{storageid}_ul", curr_time, ul_bytes, raise_overflow=True) + #dl_rate = get_rate(value_store, f"{storageid}_dl", curr_time, dl_bytes, raise_overflow=True) + + time_delta = curr_time - time_last + # avoid dividing by null and getting negative rates + if time_delta <= 0: + ul_rate = 1024.0 + dl_rate = 2048.0 + else: + ul_rate = (ul_bytes - ul_last)/time_delta + dl_rate = (dl_bytes - dl_last)/time_delta + + # levels are defined as MBytes/s in our rule, so we have to adjust this here + # because we are getting Bytes/s from our rate calculation + warn, crit = params["levels_hal_storages_rates"] + warn = warn*(1024**2) + crit = crit*(1024**2) + levels = (warn, crit) + + # create graphs for upload/download rates + yield Metric("hal_storages_upload_rate", ul_rate, levels=levels) + yield Metric("hal_storages_download_rate", dl_rate, levels=levels) + + # calculate state of service based on levels given as parameter + state_ul = getStateUpper(levels, ul_rate) + state_dl = getStateUpper(levels, dl_rate) + summary_ul = f"Upload rate of '{realname}' is {render.iobandwidth(ul_rate)}" + summary_dl = f"Download rate of '{realname}' is {render.iobandwidth(dl_rate)}" + details_ul = f"Upload since last check: {render.bytes(ul_bytes)}" + details_dl = f"Download since last check: {render.bytes(dl_bytes)}" + + # create services + yield(Result(state=state_ul, summary=summary_ul, details=details_ul)) + yield(Result(state=state_dl, summary=summary_dl, details=details_dl)) + +def parse_hal9001_storages_section(string_table): + # convert the raw output of the agent section in an meaningful structure, do type conversions and so on + parsed_data = {} + for line in string_table: + storageid = line[0] + realname = line[1] + upload = int(float(line[2])) + download = int(float(line[3])) + parsed_data[f"{storageid}"] = [realname, upload, download] + return parsed_data + +register.agent_section( + name = "hal9001_storages", + parse_function = parse_hal9001_storages_section, +) + +register.check_plugin( + name = "hal9001_storages", + service_name = "HAL Storage information %s", + discovery_function = discover_hal9001_storages, + check_function = check_hal9001_storages, + check_default_parameters = { + "levels_hal_storages_rates": (200.0, 300.0), + }, + check_ruleset_name="hal9001_storages_storage_rates", +) \ No newline at end of file diff --git a/local/lib/python3/cmk/base/plugins/agent_based/hal9001_users.py b/local/lib/python3/cmk/base/plugins/agent_based/hal9001_users.py new file mode 100644 index 0000000..716242a --- /dev/null +++ b/local/lib/python3/cmk/base/plugins/agent_based/hal9001_users.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import time +from pprint import pprint +from .agent_based_api.v1 import get_value_store, get_rate, register, render, Service, Result, State, Metric + +def getStateUpper(levels, value): + warn, crit = levels + if value >= crit: + return State.CRIT + if value >= warn: + return State.WARN + return State.OK + +# services with item --> userid +def discover_hal9001_users(section): + for key in section: + yield(Service(item = key)) + +def check_hal9001_users(item, params, section): + userid = item + # get all values from section + realname = section[userid][0] + used_bytes = section[userid][1] + quota_max_bytes = section[userid][2] + # calculate percentage of max quota used + quota_used_percent = used_bytes * 100 / quota_max_bytes + # create a graph with storage usage in percent of max quota + levels = params["levels_hal_users_quota_used"] + yield Metric("hal_users_quota_used", quota_used_percent, levels=levels) + # calculate state of service based on levels given as parameter + state = getStateUpper(levels, quota_used_percent) + summary = f"Used quota of {realname} is {render.percent(quota_used_percent)}, {render.disksize(used_bytes)} of {render.disksize(quota_max_bytes)} used" + yield(Result(state=state, summary=summary)) + +def parse_hal9001_users_section(string_table): + # convert the raw output of the agent section in an meaningful structure, do type conversions and so on + parsed_data = {} + for line in string_table: + userid = line[0] + realname = line[1] + quota_used = float(line[2]) + quota_total = float(line[3]) + parsed_data[f"{userid}"] = [realname, quota_used, quota_total] + return parsed_data + +register.agent_section( + name = "hal9001_users", + parse_function = parse_hal9001_users_section, +) + +register.check_plugin( + name = "hal9001_users", + service_name = "HAL User information %s", + discovery_function = discover_hal9001_users, + check_function = check_hal9001_users, + check_default_parameters = { + "levels_hal_users_quota_used": (65.0, 85.0), + }, + check_ruleset_name="hal9001_users_storage_levels", +) \ No newline at end of file