Skip to content

Commit fdcc68b

Browse files
committed
Port shell script
1 parent f5c56e7 commit fdcc68b

File tree

2 files changed

+110
-1
lines changed

2 files changed

+110
-1
lines changed

Diff for: zfs-snapshots.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def zfs_list_snapshots():
4848
break
4949
yield stdout_line.decode("utf-8")
5050
return_code = popen.wait()
51-
if return_code:
51+
if return_code > 0:
5252
raise subprocess.CalledProcessError(return_code, cmd)
5353

5454

Diff for: zfs_zpool.py

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import subprocess
4+
from concurrent.futures import ThreadPoolExecutor
5+
from typing import Tuple
6+
7+
from prometheus_client import CollectorRegistry, Gauge, generate_latest
8+
9+
ZPOOL_METADATA_LABELS = ("health", "version", "readonly", "ashift", "autoreplace", "failmode")
10+
11+
12+
def zpool_metadata(registry):
13+
metric = Gauge("zpool", "Constant metric with metadata about the zpool",
14+
labelnames=['zpool_name', *ZPOOL_METADATA_LABELS], namespace='zfs', registry=registry, )
15+
cmd = ('zpool', 'list', '-H', '-o', 'name,' + ",".join(ZPOOL_METADATA_LABELS))
16+
for constant_labels in run(cmd):
17+
metric.labels(*constant_labels).set(1)
18+
19+
20+
def run(cmd):
21+
popen = subprocess.Popen(
22+
cmd, stdout=subprocess.PIPE, env=dict(os.environ, LC_ALL="C")
23+
)
24+
for stdout_line in iter(popen.stdout.readline, ""):
25+
if stdout_line == b"":
26+
break
27+
yield stdout_line.strip().decode("utf-8").split("\t")
28+
29+
return_code = popen.wait()
30+
if return_code > 0:
31+
raise subprocess.CalledProcessError(return_code, cmd)
32+
33+
34+
ZPOOL_INFO_METRICS = (
35+
("size", "Total size of the storage pool", "bytes"),
36+
("free", "The amount of free space available in the pool", "bytes"),
37+
("freeing", "The amount of space waiting to be reclaimed from destroyed filesystems or snapshots", "bytes"),
38+
('dedupratio', "The deduplication ratio", ""),
39+
("fragmentation", "The amount of fragmentation in the pool", "")
40+
)
41+
42+
43+
def zpool_info(registry):
44+
cmd = ('zpool', 'list', '-Hp', '-o', "name," + ','.join([col for (col, *_) in ZPOOL_INFO_METRICS]))
45+
metrics = {}
46+
for line in run(cmd):
47+
for (idx, (col, doc, unit)) in enumerate(ZPOOL_INFO_METRICS, 1):
48+
if col not in metrics:
49+
metrics[col] = Gauge(col, documentation=doc, unit=unit, namespace='zfs_zpool', registry=registry,
50+
labelnames=["zpool_name"])
51+
metrics[col].labels((line[0])).set(float(line[idx]))
52+
53+
54+
DATASET_METADATA_LABELS = ("type", "creation", "mounted", "mountpoint", "checksum", "compression", "readonly",
55+
"version", "dedup", "volblocksize")
56+
57+
DATASET_TYPES = ("filesystem", "volume")
58+
59+
60+
def dataset_metadata(registry):
61+
cmd = ("zfs", "list", "-Hp", "-t", ",".join(DATASET_TYPES), "-o", "name," + ",".join(DATASET_METADATA_LABELS))
62+
metric = Gauge("dataset", documentation="Constant metric with metadata about the zfs dataset", namespace="zfs",
63+
registry=registry, labelnames=["dataset_name", *DATASET_METADATA_LABELS])
64+
for line in run(cmd):
65+
metric.labels(*line).set(1)
66+
67+
68+
DATASET_INFO_METRICS = (
69+
("used", "The amount of space consumed by this dataset and all its descendents", "bytes"),
70+
("available", "The amount of space available to the dataset and all its children", "bytes"),
71+
("referenced",
72+
"The amount of data that is accessible by this dataset, which may or may not be shared with other datasets in the pool",
73+
"bytes"),
74+
("compressratio",
75+
"For non-snapshots, the compression ratio achieved for the used space of this dataset, expressed as a multiplier",
76+
""),
77+
("reservation", "The minimum amount of space guaranteed to a dataset and its descendants", "bytes"),
78+
("refreservation", "The minimum amount of space guaranteed to a dataset, not including its descendents", "bytes"),
79+
("volsize", "For volumes, specifies the logical size of the volume", "bytes")
80+
)
81+
82+
83+
def dataset_metrics(registry):
84+
cmd = ("zfs", "list", "-Hp", "-t", ",".join(DATASET_TYPES), "-o", "name," + ",".join([col for (col, *_) in DATASET_INFO_METRICS]))
85+
metrics = {}
86+
for line in run(cmd):
87+
for (idx, (col, doc, unit)) in enumerate(DATASET_INFO_METRICS, 1):
88+
if col not in metrics:
89+
metrics[col] = Gauge(col, documentation=doc, unit=unit, registry=registry, labelnames=["dataset_name"],
90+
namespace="zfs_dataset")
91+
92+
if line[idx] == "-":
93+
continue
94+
95+
metrics[col].labels((line[0])).set(float(line[idx].rstrip("x")))
96+
97+
98+
def main():
99+
registry = CollectorRegistry()
100+
101+
funcs = (zpool_metadata, zpool_info, dataset_metadata, dataset_metrics)
102+
with ThreadPoolExecutor(max_workers=len(funcs)) as executor:
103+
for func in funcs:
104+
executor.submit(func, registry)
105+
106+
print(generate_latest(registry).decode(), end="")
107+
108+
109+
main()

0 commit comments

Comments
 (0)