1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
#!/usr/bin/env python3
# Periodic job to update LDAP storageAvailable[/] from regular servers.
# See also storage_ldap.py for special storages.
from functools import lru_cache
import n.ldap
import os
import socket
import ssl
import sys
'''
def get_free_space(path):
import subprocess
result = subprocess.run(["findmnt", "-J", "-b", "--df", path],
stdout=subprocess.PIPE)
result = json.loads(result.stdout)
for fs in result["filesystems"]:
return fs["size"], fs["size"] - fs["used"]
'''
@lru_cache()
def zpool_list():
import subprocess
result = subprocess.run(["zpool", "list", "-p"],
stdout=subprocess.PIPE)
keys = None
tab = {}
for line in result.stdout.decode().splitlines():
line = line.split()
if not keys:
keys = line
else:
row = dict(zip(keys, line))
tab[row["NAME"]] = row
return tab
def get_zpool_space(path):
path = path.lstrip("/")
pools = zpool_list()
total_b = int(pools[path]["SIZE"])
alloc_b = int(pools[path]["ALLOC"])
free_b = int(pools[path]["FREE"])
return total_b, free_b
def get_free_space(path):
if path.startswith("ZFS/"):
pool = path.split("/")[1]
return get_zpool_space(pool)
stat = os.statvfs(path)
return (stat.f_bsize * stat.f_blocks,
stat.f_bsize * stat.f_bfree)
def ldap_find_device_dn(ad, device):
for dn, attrs in ad.search(ad.base,
n.ldap.SCOPE_SUBTREE,
"(&(objectClass=device)(cn=%s))",
[device],
["1.1"]):
return dn
def ldap_update_device(ad, device_dn, total_mb, free_mb):
ad.modify(device_dn, replace={"storageCapacity": str(total_mb),
"storageAvailable": str(free_mb)})
BYTES_PER_MB = 1024 * 1024
if os.getuid() == 0:
n.ldap.use_system_keytab()
args = sys.argv[1:]
if args:
volumes = [a.split("=", 1) for a in args]
else:
volumes = [(socket.gethostname(), "/")]
ad = n.ldap.Directory()
print("Bound as", ad.whoami())
for (device, vol_path) in volumes:
(total_bytes, free_bytes) = get_free_space(vol_path)
total_mb = total_bytes // BYTES_PER_MB
free_mb = free_bytes // BYTES_PER_MB
# Reduce precision to reduce LDAP updates
total_mb -= total_mb % 100
free_mb -= free_mb % 100
print("Volume '%s' at %s has ~%s MiB free out of ~%s MiB" % (device, vol_path, free_mb, total_mb))
device_dn = ldap_find_device_dn(ad, device)
if device_dn:
print("Updating", device_dn)
ldap_update_device(ad, device_dn, total_mb, free_mb)
else:
raise KeyError("Device %r not found in LDAP" % device)
|