153 lines
5.1 KiB
Python
153 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import subprocess
|
|
from typing import Dict, Any, List
|
|
import json
|
|
|
|
def get_zfs_pools() -> List[Dict[str, Any]]:
|
|
"""Get information about ZFS pools."""
|
|
try:
|
|
# Get list of pools
|
|
pools = subprocess.check_output(['zpool', 'list', '-H', '-o', 'name,size,alloc,free,health,readonly,dedup,altroot']).decode().strip().split('\n')
|
|
|
|
pool_info = []
|
|
for pool in pools:
|
|
if not pool: # Skip empty lines
|
|
continue
|
|
|
|
name, size, alloc, free, health, readonly, dedup, altroot = pool.split('\t')
|
|
|
|
# Get detailed pool status
|
|
status = subprocess.check_output(['zpool', 'status', name]).decode()
|
|
|
|
# Get pool properties
|
|
properties = subprocess.check_output(['zpool', 'get', 'all', name]).decode()
|
|
|
|
pool_info.append({
|
|
'name': name,
|
|
'size': size,
|
|
'allocated': alloc,
|
|
'free': free,
|
|
'health': health,
|
|
'readonly': readonly == 'on',
|
|
'dedup': dedup,
|
|
'altroot': altroot,
|
|
'status': status,
|
|
'properties': properties
|
|
})
|
|
|
|
return pool_info
|
|
except subprocess.SubprocessError as e:
|
|
print(f"Error getting ZFS pool information: {e}")
|
|
return []
|
|
|
|
def convert_size_to_bytes(size_str: str) -> int:
|
|
"""Convert ZFS size string to bytes."""
|
|
units = {
|
|
'B': 1,
|
|
'K': 1024,
|
|
'M': 1024**2,
|
|
'G': 1024**3,
|
|
'T': 1024**4,
|
|
'P': 1024**5
|
|
}
|
|
|
|
try:
|
|
number = float(size_str[:-1])
|
|
unit = size_str[-1].upper()
|
|
return int(number * units[unit])
|
|
except (ValueError, KeyError):
|
|
return 0
|
|
|
|
def collect_metrics() -> Dict[str, Any]:
|
|
"""Collect ZFS pool metrics."""
|
|
metrics = {
|
|
"entities": []
|
|
}
|
|
|
|
pools = get_zfs_pools()
|
|
|
|
for pool in pools:
|
|
# Pool health status
|
|
metrics['entities'].append({
|
|
'sensor_id': f'zfs_pool_{pool["name"]}_health',
|
|
'name': f'ZFS Pool {pool["name"]} Health',
|
|
'value': pool['health'],
|
|
'state_class': 'measurement',
|
|
'unit_of_measurement': '',
|
|
'device_class': 'enum',
|
|
'icon': 'mdi:database',
|
|
'attributes': {
|
|
'friendly_name': f'ZFS Pool {pool["name"]} Health Status',
|
|
'readonly': pool['readonly'],
|
|
'dedup': pool['dedup'],
|
|
'altroot': pool['altroot']
|
|
}
|
|
})
|
|
|
|
# Pool size
|
|
size_bytes = convert_size_to_bytes(pool['size'])
|
|
metrics['entities'].append({
|
|
'sensor_id': f'zfs_pool_{pool["name"]}_size',
|
|
'name': f'ZFS Pool {pool["name"]} Size',
|
|
'value': str(round(size_bytes / (1024**3), 2)), # Convert to GB
|
|
'state_class': 'measurement',
|
|
'unit_of_measurement': 'GB',
|
|
'device_class': 'data_size',
|
|
'icon': 'mdi:database',
|
|
'attributes': {
|
|
'friendly_name': f'ZFS Pool {pool["name"]} Total Size'
|
|
}
|
|
})
|
|
|
|
# Pool allocated space
|
|
alloc_bytes = convert_size_to_bytes(pool['allocated'])
|
|
metrics['entities'].append({
|
|
'sensor_id': f'zfs_pool_{pool["name"]}_allocated',
|
|
'name': f'ZFS Pool {pool["name"]} Allocated',
|
|
'value': str(round(alloc_bytes / (1024**3), 2)), # Convert to GB
|
|
'state_class': 'measurement',
|
|
'unit_of_measurement': 'GB',
|
|
'device_class': 'data_size',
|
|
'icon': 'mdi:database',
|
|
'attributes': {
|
|
'friendly_name': f'ZFS Pool {pool["name"]} Allocated Space'
|
|
}
|
|
})
|
|
|
|
# Pool free space
|
|
free_bytes = convert_size_to_bytes(pool['free'])
|
|
metrics['entities'].append({
|
|
'sensor_id': f'zfs_pool_{pool["name"]}_free',
|
|
'name': f'ZFS Pool {pool["name"]} Free',
|
|
'value': str(round(free_bytes / (1024**3), 2)), # Convert to GB
|
|
'state_class': 'measurement',
|
|
'unit_of_measurement': 'GB',
|
|
'device_class': 'data_size',
|
|
'icon': 'mdi:database',
|
|
'attributes': {
|
|
'friendly_name': f'ZFS Pool {pool["name"]} Free Space'
|
|
}
|
|
})
|
|
|
|
# Pool usage percentage
|
|
usage_percent = (alloc_bytes / size_bytes * 100) if size_bytes > 0 else 0
|
|
metrics['entities'].append({
|
|
'sensor_id': f'zfs_pool_{pool["name"]}_usage',
|
|
'name': f'ZFS Pool {pool["name"]} Usage',
|
|
'value': str(round(usage_percent, 1)),
|
|
'state_class': 'measurement',
|
|
'unit_of_measurement': '%',
|
|
'device_class': 'power_factor',
|
|
'icon': 'mdi:database',
|
|
'attributes': {
|
|
'friendly_name': f'ZFS Pool {pool["name"]} Usage Percentage'
|
|
}
|
|
})
|
|
|
|
return metrics
|
|
|
|
if __name__ == "__main__":
|
|
# Example usage
|
|
metrics = collect_metrics()
|
|
print(json.dumps(metrics, indent=2)) |