Coverage for volexport/api_volume.py: 87%
60 statements
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-20 14:19 +0000
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-20 14:19 +0000
1import datetime
2from fastapi import APIRouter, HTTPException
3from pydantic import BaseModel
4from .config import config
5from .lvm2 import LV, VG
7router = APIRouter()
10class VolumeCreateRequest(BaseModel):
11 name: str
12 size: int
15class VolumeCreateResponse(BaseModel):
16 name: str
17 size: int
18 device: str
21class VolumeReadResponse(BaseModel):
22 name: str
23 created: datetime.datetime
24 size: int
25 used: int
28class VolumeUpdateRequest(BaseModel):
29 size: int | None = None
30 readonly: bool | None = None
33class PoolStats(BaseModel):
34 total: int
35 used: int
36 free: int
37 volumes: int
40@router.get("/volume")
41def list_volume():
42 return [VolumeReadResponse.model_validate(x) for x in LV(config.VG).volume_list()]
45@router.post("/volume")
46def create_volume(arg: VolumeCreateRequest):
47 return VolumeCreateResponse.model_validate(LV(config.VG, arg.name).create(size=arg.size))
50@router.get("/volume/{name}")
51def read_volume(name):
52 res = LV(config.VG, name).volume_read()
53 if res is None:
54 raise HTTPException(status_code=404, detail="volume not found")
55 return VolumeReadResponse.model_validate(res)
58@router.delete("/volume/{name}")
59def delete_volume(name) -> dict:
60 LV(config.VG, name).delete()
61 return {}
64@router.post("/volume/{name}")
65def update_volume(name, arg: VolumeUpdateRequest) -> VolumeReadResponse:
66 if arg.readonly is not None:
67 LV(config.VG, name).read_only(arg.readonly)
68 if arg.size is not None:
69 LV(config.VG, name).resize(arg.size)
70 return VolumeReadResponse.model_validate(LV(config.VG, name).volume_read())
73@router.get("/stats/volume")
74def stats_volume() -> PoolStats:
75 info = VG(config.VG).get()
76 if info is None:
77 raise HTTPException(status_code=404, detail="pool not found")
78 vols = info.get("Cur LV", 0)
79 pesize = int(info["PE Size"].removesuffix(" B"))
80 total_pe = int(info["Total PE"])
81 alloc_pe = int(info["Alloc PE / Size"].split()[0])
82 free_pe = int(info["Free PE / Size"].split()[0])
83 return PoolStats(total=pesize * total_pe, used=pesize * alloc_pe, free=pesize * free_pe, volumes=vols)