Skip to content

Commit 4263b5e

Browse files
authored
Add mounts API (#32)
1 parent 622970c commit 4263b5e

File tree

6 files changed

+410
-0
lines changed

6 files changed

+410
-0
lines changed

aiohasupervisor/models/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@
6262
ServiceState,
6363
ShutdownOptions,
6464
)
65+
from aiohasupervisor.models.mounts import (
66+
CIFSMountRequest,
67+
CIFSMountResponse,
68+
MountCifsVersion,
69+
MountsInfo,
70+
MountsOptions,
71+
MountState,
72+
MountType,
73+
MountUsage,
74+
NFSMountRequest,
75+
NFSMountResponse,
76+
)
6577
from aiohasupervisor.models.network import (
6678
AccessPoint,
6779
AuthMethod,
@@ -228,4 +240,14 @@
228240
"Service",
229241
"ServiceState",
230242
"ShutdownOptions",
243+
"CIFSMountRequest",
244+
"CIFSMountResponse",
245+
"MountCifsVersion",
246+
"MountsInfo",
247+
"MountsOptions",
248+
"MountState",
249+
"MountType",
250+
"MountUsage",
251+
"NFSMountRequest",
252+
"NFSMountResponse",
231253
]

aiohasupervisor/models/mounts.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""Models for Supervisor mounts."""
2+
3+
from abc import ABC
4+
from dataclasses import dataclass, field
5+
from enum import StrEnum
6+
from pathlib import PurePath
7+
from typing import Literal
8+
9+
from .base import Request, ResponseData
10+
11+
# --- ENUMS ----
12+
13+
14+
class MountType(StrEnum):
15+
"""MountType type."""
16+
17+
CIFS = "cifs"
18+
NFS = "nfs"
19+
20+
21+
class MountUsage(StrEnum):
22+
"""MountUsage type."""
23+
24+
BACKUP = "backup"
25+
MEDIA = "media"
26+
SHARE = "share"
27+
28+
29+
class MountState(StrEnum):
30+
"""MountState type."""
31+
32+
ACTIVE = "active"
33+
ACTIVATING = "activating"
34+
DEACTIVATING = "deactivating"
35+
FAILED = "failed"
36+
INACTIVE = "inactive"
37+
MAINTENANCE = "maintenance"
38+
RELOADING = "reloading"
39+
40+
41+
class MountCifsVersion(StrEnum):
42+
"""Mount CIFS version."""
43+
44+
LEGACY_1_0 = "1.0"
45+
LEGACY_2_0 = "2.0"
46+
47+
48+
# --- OBJECTS ----
49+
50+
51+
@dataclass(frozen=True)
52+
class Mount(ABC):
53+
"""Mount ABC type."""
54+
55+
usage: MountUsage
56+
server: str
57+
port: int | None = field(kw_only=True, default=None)
58+
59+
60+
@dataclass(frozen=True)
61+
class CIFSMount(ABC):
62+
"""CIFSMount ABC type."""
63+
64+
share: str
65+
version: MountCifsVersion | None = field(kw_only=True, default=None)
66+
67+
68+
@dataclass(frozen=True)
69+
class NFSMount(ABC):
70+
"""NFSMount ABC type."""
71+
72+
path: PurePath
73+
74+
75+
@dataclass(frozen=True)
76+
class MountResponse(ABC):
77+
"""MountResponse model."""
78+
79+
name: str
80+
read_only: bool
81+
state: MountState | None
82+
83+
84+
@dataclass(frozen=True)
85+
class MountRequest(ABC): # noqa: B024
86+
"""MountRequest model."""
87+
88+
read_only: bool | None = field(kw_only=True, default=None)
89+
90+
91+
@dataclass(frozen=True, slots=True)
92+
class CIFSMountResponse(Mount, MountResponse, CIFSMount, ResponseData):
93+
"""CIFSMountResponse model."""
94+
95+
type: Literal[MountType.CIFS]
96+
97+
98+
@dataclass(frozen=True, slots=True)
99+
class NFSMountResponse(Mount, MountResponse, NFSMount, ResponseData):
100+
"""NFSMountResponse model."""
101+
102+
type: Literal[MountType.NFS]
103+
104+
105+
@dataclass(frozen=True, slots=True)
106+
class CIFSMountRequest(Mount, MountRequest, CIFSMount, Request):
107+
"""CIFSMountRequest model."""
108+
109+
type: Literal[MountType.CIFS] = field(init=False, default=MountType.CIFS)
110+
username: str | None = field(kw_only=True, default=None)
111+
password: str | None = field(kw_only=True, default=None)
112+
113+
114+
@dataclass(frozen=True, slots=True)
115+
class NFSMountRequest(Mount, MountRequest, NFSMount, Request):
116+
"""NFSMountRequest model."""
117+
118+
type: Literal[MountType.NFS] = field(init=False, default=MountType.NFS)
119+
120+
121+
@dataclass(frozen=True, slots=True)
122+
class MountsInfo(ResponseData):
123+
"""MountsInfo model."""
124+
125+
default_backup_mount: str | None
126+
mounts: list[CIFSMountResponse | NFSMountResponse]
127+
128+
129+
@dataclass(frozen=True, slots=True)
130+
class MountsOptions(Request):
131+
"""MountsOptions model."""
132+
133+
default_backup_mount: str | None

aiohasupervisor/mounts.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Mounts client for Supervisor."""
2+
3+
from .client import _SupervisorComponentClient
4+
from .models.mounts import CIFSMountRequest, MountsInfo, MountsOptions, NFSMountRequest
5+
6+
7+
class MountsClient(_SupervisorComponentClient):
8+
"""Handle mounts access in supervisor."""
9+
10+
async def info(self) -> MountsInfo:
11+
"""Get mounts info."""
12+
result = await self._client.get("mounts")
13+
return MountsInfo.from_dict(result.data)
14+
15+
async def options(self, options: MountsOptions) -> None:
16+
"""Set mounts options."""
17+
await self._client.post("mounts/options", json=options.to_dict())
18+
19+
async def create_mount(
20+
self, name: str, config: CIFSMountRequest | NFSMountRequest
21+
) -> None:
22+
"""Create a new mount."""
23+
await self._client.post("mounts", json={"name": name, **config.to_dict()})
24+
25+
async def update_mount(
26+
self, name: str, config: CIFSMountRequest | NFSMountRequest
27+
) -> None:
28+
"""Update an existing mount."""
29+
await self._client.put(f"mounts/{name}", json=config.to_dict())
30+
31+
async def delete_mount(self, name: str) -> None:
32+
"""Delete an existing mount."""
33+
await self._client.delete(f"mounts/{name}")
34+
35+
async def reload_mount(self, name: str) -> None:
36+
"""Reload details of an existing mount."""
37+
await self._client.post(f"mounts/{name}/reload")

aiohasupervisor/root.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .homeassistant import HomeAssistantClient
1212
from .host import HostClient
1313
from .models.root import AvailableUpdate, AvailableUpdates, RootInfo
14+
from .mounts import MountsClient
1415
from .network import NetworkClient
1516
from .os import OSClient
1617
from .resolution import ResolutionClient
@@ -33,6 +34,7 @@ def __init__(
3334
self._os = OSClient(self._client)
3435
self._backups = BackupsClient(self._client)
3536
self._discovery = DiscoveryClient(self._client)
37+
self._mounts = MountsClient(self._client)
3638
self._network = NetworkClient(self._client)
3739
self._host = HostClient(self._client)
3840
self._resolution = ResolutionClient(self._client)
@@ -65,6 +67,11 @@ def discovery(self) -> DiscoveryClient:
6567
"""Get discovery component client."""
6668
return self._discovery
6769

70+
@property
71+
def mounts(self) -> MountsClient:
72+
"""Get mounts component client."""
73+
return self._mounts
74+
6875
@property
6976
def network(self) -> NetworkClient:
7077
"""Get network component client."""

tests/fixtures/mounts_info.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"result": "ok",
3+
"data": {
4+
"default_backup_mount": "Test",
5+
"mounts": [
6+
{
7+
"share": "backup",
8+
"server": "test.local",
9+
"name": "Test",
10+
"type": "cifs",
11+
"usage": "backup",
12+
"read_only": false,
13+
"version": null,
14+
"state": "active"
15+
},
16+
{
17+
"share": "share",
18+
"server": "test2.local",
19+
"name": "Test2",
20+
"type": "cifs",
21+
"usage": "share",
22+
"read_only": true,
23+
"version": "2.0",
24+
"port": 12345,
25+
"state": "active"
26+
},
27+
{
28+
"server": "test3.local",
29+
"name": "Test2",
30+
"type": "nfs",
31+
"usage": "media",
32+
"read_only": false,
33+
"path": "media",
34+
"state": "active"
35+
}
36+
]
37+
}
38+
}

0 commit comments

Comments
 (0)