mirror of
https://github.com/librenms/librenms-agent.git
synced 2024-05-09 09:54:52 +00:00
* Format with isort * Format with Black * Fix CRLF * Format with shellcheck * Fix some warning * Fix PHP style * Dont modifiy check_mk files * Fixes
192 lines
6.7 KiB
Python
192 lines
6.7 KiB
Python
#!/usr/local/bin/python3
|
|
|
|
# FreeNAS 11.1 not support #!/usr/bin/env python3
|
|
|
|
import json
|
|
import subprocess
|
|
|
|
SYSCTL = "/sbin/sysctl"
|
|
ZPOOL = "/usr/local/sbin/zpool"
|
|
|
|
|
|
def percent(numerator, denominator, default=0):
|
|
try:
|
|
return numerator / denominator * 100
|
|
except ZeroDivisionError:
|
|
return default
|
|
|
|
|
|
def main(args):
|
|
p = subprocess.run(
|
|
[SYSCTL, "-q", "kstat.zfs", "vfs.zfs"],
|
|
stdout=subprocess.PIPE,
|
|
universal_newlines=True,
|
|
)
|
|
|
|
if p.returncode != 0:
|
|
return p.returncode
|
|
|
|
def chomp(line):
|
|
bits = [b.strip() for b in line.split(":")]
|
|
try:
|
|
return bits[0], int(bits[1])
|
|
except ValueError:
|
|
return bits[0], bits[1]
|
|
|
|
stats = dict(chomp(line) for line in p.stdout.splitlines() if line)
|
|
if "kstat.zfs.misc.arcstats.recycle_miss" not in stats:
|
|
stats["kstat.zfs.misc.arcstats.recycle_miss"] = 0
|
|
|
|
output = dict()
|
|
|
|
# ARC misc
|
|
output["deleted"] = stats["kstat.zfs.misc.arcstats.deleted"]
|
|
output["evict_skip"] = stats["kstat.zfs.misc.arcstats.evict_skip"]
|
|
output["mutex_skip"] = stats["kstat.zfs.misc.arcstats.mutex_miss"]
|
|
output["recycle_miss"] = stats["kstat.zfs.misc.arcstats.recycle_miss"]
|
|
|
|
# ARC size
|
|
output["target_size_per"] = (
|
|
stats["kstat.zfs.misc.arcstats.c"]
|
|
/ stats["kstat.zfs.misc.arcstats.c_max"]
|
|
* 100
|
|
)
|
|
output["arc_size_per"] = (
|
|
stats["kstat.zfs.misc.arcstats.size"]
|
|
/ stats["kstat.zfs.misc.arcstats.c_max"]
|
|
* 100
|
|
)
|
|
output["target_size_arat"] = (
|
|
stats["kstat.zfs.misc.arcstats.c"] / stats["kstat.zfs.misc.arcstats.c_max"]
|
|
)
|
|
output["min_size_per"] = (
|
|
stats["kstat.zfs.misc.arcstats.c_min"]
|
|
/ stats["kstat.zfs.misc.arcstats.c_max"]
|
|
* 100
|
|
)
|
|
|
|
output["arc_size"] = stats["kstat.zfs.misc.arcstats.size"]
|
|
output["target_size_max"] = stats["kstat.zfs.misc.arcstats.c_max"]
|
|
output["target_size_min"] = stats["kstat.zfs.misc.arcstats.c_min"]
|
|
output["target_size"] = stats["kstat.zfs.misc.arcstats.c"]
|
|
|
|
# ARC size breakdown
|
|
output["mfu_size"] = (
|
|
stats["kstat.zfs.misc.arcstats.size"] - stats["kstat.zfs.misc.arcstats.p"]
|
|
)
|
|
output["p"] = stats["kstat.zfs.misc.arcstats.p"]
|
|
output["rec_used_per"] = (
|
|
stats["kstat.zfs.misc.arcstats.p"] / stats["kstat.zfs.misc.arcstats.size"] * 100
|
|
)
|
|
output["freq_used_per"] = (
|
|
output["mfu_size"] / stats["kstat.zfs.misc.arcstats.size"] * 100
|
|
)
|
|
|
|
# ARC misc efficiency stats
|
|
output["arc_hits"] = stats["kstat.zfs.misc.arcstats.hits"]
|
|
output["arc_misses"] = stats["kstat.zfs.misc.arcstats.misses"]
|
|
output["demand_data_hits"] = stats["kstat.zfs.misc.arcstats.demand_data_hits"]
|
|
output["demand_data_misses"] = stats["kstat.zfs.misc.arcstats.demand_data_misses"]
|
|
output["demand_meta_hits"] = stats["kstat.zfs.misc.arcstats.demand_metadata_hits"]
|
|
output["demand_meta_misses"] = stats[
|
|
"kstat.zfs.misc.arcstats.demand_metadata_misses"
|
|
]
|
|
output["mfu_ghost_hits"] = stats["kstat.zfs.misc.arcstats.mfu_ghost_hits"]
|
|
output["mfu_hits"] = stats["kstat.zfs.misc.arcstats.mfu_hits"]
|
|
output["mru_ghost_hits"] = stats["kstat.zfs.misc.arcstats.mru_ghost_hits"]
|
|
output["mru_hits"] = stats["kstat.zfs.misc.arcstats.mru_hits"]
|
|
output["pre_data_hits"] = stats["kstat.zfs.misc.arcstats.prefetch_data_hits"]
|
|
output["pre_data_misses"] = stats["kstat.zfs.misc.arcstats.prefetch_data_misses"]
|
|
output["pre_meta_hits"] = stats["kstat.zfs.misc.arcstats.prefetch_metadata_hits"]
|
|
output["pre_meta_misses"] = stats[
|
|
"kstat.zfs.misc.arcstats.prefetch_metadata_misses"
|
|
]
|
|
|
|
output["anon_hits"] = output["arc_hits"] - (
|
|
output["mfu_hits"]
|
|
+ output["mru_hits"]
|
|
+ output["mfu_ghost_hits"]
|
|
+ output["mru_ghost_hits"]
|
|
)
|
|
output["arc_accesses_total"] = output["arc_hits"] + output["arc_misses"]
|
|
output["demand_data_total"] = (
|
|
output["demand_data_hits"] + output["demand_data_misses"]
|
|
)
|
|
output["pre_data_total"] = output["pre_data_hits"] + output["pre_data_misses"]
|
|
output["real_hits"] = output["mfu_hits"] + output["mru_hits"]
|
|
|
|
# ARC efficiency percents
|
|
output["cache_hits_per"] = percent(output["arc_hits"], output["arc_accesses_total"])
|
|
output["cache_miss_per"] = percent(
|
|
output["arc_misses"], output["arc_accesses_total"]
|
|
)
|
|
output["actual_hit_per"] = percent(
|
|
output["real_hits"], output["arc_accesses_total"]
|
|
)
|
|
output["data_demand_per"] = percent(
|
|
output["demand_data_hits"], output["demand_data_total"]
|
|
)
|
|
output["data_pre_per"] = percent(output["pre_data_hits"], output["pre_data_total"])
|
|
output["anon_hits_per"] = percent(output["anon_hits"], output["arc_hits"])
|
|
output["mru_per"] = percent(output["mru_hits"], output["arc_hits"])
|
|
output["mfu_per"] = percent(output["mfu_hits"], output["arc_hits"])
|
|
output["mru_ghost_per"] = percent(output["mru_ghost_hits"], output["arc_hits"])
|
|
output["mfu_ghost_per"] = percent(output["mfu_ghost_hits"], output["arc_hits"])
|
|
output["demand_hits_per"] = percent(output["demand_data_hits"], output["arc_hits"])
|
|
output["pre_hits_per"] = percent(output["pre_data_hits"], output["arc_hits"])
|
|
output["meta_hits_per"] = percent(output["demand_meta_hits"], output["arc_hits"])
|
|
output["pre_meta_hits_per"] = percent(output["pre_meta_hits"], output["arc_hits"])
|
|
output["demand_misses_per"] = percent(
|
|
output["demand_data_misses"], output["arc_misses"]
|
|
)
|
|
output["pre_misses_per"] = percent(output["pre_data_misses"], output["arc_misses"])
|
|
output["meta_misses_per"] = percent(
|
|
output["demand_meta_misses"], output["arc_misses"]
|
|
)
|
|
output["pre_meta_misses_per"] = percent(
|
|
output["pre_meta_misses"], output["arc_misses"]
|
|
)
|
|
|
|
# pools
|
|
p = subprocess.run(
|
|
[ZPOOL, "list", "-pH"], stdout=subprocess.PIPE, universal_newlines=True
|
|
)
|
|
if p.returncode != 0:
|
|
return p.returncode
|
|
output["pools"] = []
|
|
fields = [
|
|
"name",
|
|
"size",
|
|
"alloc",
|
|
"free",
|
|
"ckpoint",
|
|
"expandsz",
|
|
"frag",
|
|
"cap",
|
|
"dedup",
|
|
]
|
|
for l in p.stdout.splitlines():
|
|
p = dict(zip(fields, l.split("\t")))
|
|
if p["ckpoint"] == "-":
|
|
p["ckpoint"] = 0
|
|
if p["expandsz"] == "-":
|
|
p["expandsz"] = 0
|
|
p["frag"] = p["frag"].rstrip("%")
|
|
if p["frag"] == "-":
|
|
p["frag"] = 0
|
|
p["cap"] = p["cap"].rstrip("%")
|
|
if p["cap"] == "-":
|
|
p["cap"] = 0
|
|
p["dedup"] = p["dedup"].rstrip("x")
|
|
output["pools"].append(p)
|
|
|
|
print(json.dumps(output))
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
sys.exit(main(sys.argv[1:]))
|