Coverage for src / server_list / spec / webapi / storage.py: 100%
35 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-31 11:45 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-31 11:45 +0000
1#!/usr/bin/env python3
2"""
3Storage API for ZFS pools and mount points.
4Provides storage information via REST API from SQLite cache.
5"""
7import dataclasses
8from typing import Any
10import flask
12import server_list.spec.data_collector as data_collector
13import server_list.spec.webapi as webapi
15storage_api = flask.Blueprint("storage_api", __name__)
18@storage_api.route("/storage/zfs/<host>", methods=["GET"])
19def get_host_zfs_pools(host: str):
20 """Get ZFS pool information for a specific host."""
21 pools = data_collector.get_zfs_pool_info(host)
23 if pools:
24 return webapi.success_response([dataclasses.asdict(p) for p in pools])
26 return webapi.error_response(f"No ZFS pool data for host: {host}")
29@storage_api.route("/storage/mount/<host>", methods=["GET"])
30def get_host_mounts(host: str):
31 """Get mount point information for a specific host."""
32 mounts = data_collector.get_mount_info(host)
34 if mounts:
35 return webapi.success_response([dataclasses.asdict(m) for m in mounts])
37 return webapi.error_response(f"No mount data for host: {host}")
40@storage_api.route("/storage/batch", methods=["POST"])
41def get_storage_batch():
42 """Get storage information for multiple hosts in a single request.
44 Request body:
45 {
46 "zfs_hosts": ["host1", "host2"], # optional
47 "mount_hosts": ["host3", "host4"] # optional
48 }
50 Response:
51 {
52 "success": true,
53 "data": {
54 "zfs": {
55 "host1": [pools...],
56 "host2": [pools...]
57 },
58 "mount": {
59 "host3": [mounts...],
60 "host4": [mounts...]
61 }
62 }
63 }
64 """
65 body = flask.request.get_json(silent=True)
66 if not body or not isinstance(body, dict):
67 return webapi.error_response("Request body is required", 400)
69 zfs_hosts: list[str] = body.get("zfs_hosts", [])
70 mount_hosts: list[str] = body.get("mount_hosts", [])
72 if not zfs_hosts and not mount_hosts:
73 return webapi.error_response("At least one of zfs_hosts or mount_hosts is required", 400)
75 result: dict[str, dict[str, Any]] = {"zfs": {}, "mount": {}}
77 for host in zfs_hosts:
78 pools = data_collector.get_zfs_pool_info(host)
79 result["zfs"][host] = [dataclasses.asdict(p) for p in pools]
81 for host in mount_hosts:
82 mounts = data_collector.get_mount_info(host)
83 result["mount"][host] = [dataclasses.asdict(m) for m in mounts]
85 return webapi.success_response(result)