Initial commit
This commit is contained in:
135
agent_based/minecraft.py
Normal file
135
agent_based/minecraft.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
|
||||
# omd su monitoring
|
||||
#
|
||||
# cd ~/local/lib/python3/cmk_addons/plugins/minecraft/agent_based
|
||||
|
||||
|
||||
from cmk.agent_based.v2 import AgentSection, CheckPlugin, Service, Result, State, Metric, check_levels, IgnoreResults, get_value_store, check_levels
|
||||
|
||||
def parse_minecraft(string_table):
|
||||
# Join all fragments into one JSON string
|
||||
raw = "".join(string_table[0]).strip()
|
||||
if not raw:
|
||||
raise ValueError("Empty JSON section received")
|
||||
|
||||
try:
|
||||
data = json.loads(raw)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON: {e}")
|
||||
return data
|
||||
|
||||
|
||||
def discover_minecraft(section):
|
||||
for srv in section:
|
||||
name = srv.get("server_name", "default")
|
||||
yield Service(item=name) # Hauptservice
|
||||
|
||||
rcon = srv.get("rcon")
|
||||
if isinstance(rcon, dict):
|
||||
for world in rcon.get("worlds", []):
|
||||
world_name = world.get("world")
|
||||
if world_name:
|
||||
yield Service(item=f"{name} - World: {world_name}")
|
||||
|
||||
|
||||
##########################################################################################################################
|
||||
def check_minecraft(item, section):
|
||||
value_store = get_value_store()
|
||||
|
||||
if " - World: " in item:
|
||||
server, world = item.split(" - World: ", 1)
|
||||
# world specific service for tps / ticktime
|
||||
else:
|
||||
# server service
|
||||
server = item
|
||||
world = None
|
||||
|
||||
|
||||
# look for server data and put it inside srv
|
||||
srv = next((s for s in section if s.get("server_name") == server), None)
|
||||
if not srv:
|
||||
yield Result(state=State.UNKNOWN, summary=f"No data for server {server}")
|
||||
return
|
||||
|
||||
# at this point we have data
|
||||
status = srv.get("status", {})
|
||||
rcon = srv.get("rcon", {}) # is null if we have no data
|
||||
|
||||
# check if something is in error (status or rcon)
|
||||
status_error = status.get("error") if isinstance(status, dict) else None
|
||||
rcon_error = rcon.get("error") if isinstance(rcon, dict) else None
|
||||
|
||||
if status_error or rcon_error:
|
||||
error_text = status_error or rcon_error
|
||||
|
||||
fail_count = value_store.get("fail_count", 0) + 1
|
||||
value_store["fail_count"] = fail_count
|
||||
|
||||
if fail_count >= 5:
|
||||
yield Result(state=State.CRIT, summary=f"{error_text} (Failed {fail_count} times)")
|
||||
return
|
||||
else:
|
||||
yield IgnoreResults()
|
||||
return
|
||||
else:
|
||||
value_store["fail_count"] = 0
|
||||
|
||||
|
||||
|
||||
if world is None:
|
||||
# Main server service
|
||||
online = status.get("player_online", 0)
|
||||
maxp = status.get("player_max", 0)
|
||||
|
||||
player_list = status.get("player_list", "-")
|
||||
motd = status.get("motd", "-")
|
||||
server_version = status.get("server_version", "-")
|
||||
|
||||
yield Result(state=State.OK, summary=f"{online}/{maxp} players online", details=f"MOTD: {motd}\nVersion: {server_version}\nPlayers: {online}/{maxp}\nPlayer: {player_list}")
|
||||
yield Metric("player_online", online)
|
||||
yield Metric("player_max", maxp)
|
||||
|
||||
ping = status.get("ping")
|
||||
if ping is not None:
|
||||
yield Metric("ping_ms", ping)
|
||||
|
||||
protocol = status.get("protocol_version")
|
||||
if protocol is not None:
|
||||
yield Metric("protocol_version", protocol)
|
||||
|
||||
|
||||
else:
|
||||
# World-specific service
|
||||
if isinstance(rcon, dict):
|
||||
for w in rcon.get("worlds", []):
|
||||
if w.get("world") == world:
|
||||
tps = w.get("tps")
|
||||
tick = w.get("tick")
|
||||
|
||||
yield Result(state=State.OK, summary=f"TPS: {tps} - Tick: {tick} ms", details=f"TPS: {tps}\nTick Time: {tick} ms")
|
||||
|
||||
if tps is not None:
|
||||
yield Metric("tps", tps)
|
||||
|
||||
if tick is not None:
|
||||
yield Metric("tick_time", tick)
|
||||
|
||||
return
|
||||
yield Result(state=State.UNKNOWN, summary=f"No data for world {world}")
|
||||
|
||||
|
||||
|
||||
|
||||
agent_section_minecraft = AgentSection(
|
||||
name = "minecraft",
|
||||
parse_function = parse_minecraft,
|
||||
)
|
||||
|
||||
check_plugin_minecraft = CheckPlugin(
|
||||
name = "minecraft",
|
||||
service_name = "Minecraft %s",
|
||||
discovery_function = discover_minecraft,
|
||||
check_function = check_minecraft,
|
||||
)
|
||||
Reference in New Issue
Block a user