zboxapi 0.0.3__tar.gz → 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.5"
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
import fcntl
|
|
3
|
+
import os
|
|
3
4
|
import re
|
|
4
5
|
import socket
|
|
5
|
-
|
|
6
|
-
# import ssl
|
|
7
6
|
import subprocess
|
|
8
7
|
import time
|
|
9
8
|
from ipaddress import IPv4Address
|
|
@@ -12,10 +11,13 @@ from typing import IO, Annotated
|
|
|
12
11
|
|
|
13
12
|
import uvicorn
|
|
14
13
|
from fastapi import APIRouter, Depends, FastAPI, HTTPException, Security, status
|
|
14
|
+
from fastapi.routing import APIRoute
|
|
15
15
|
from fastapi.security.api_key import APIKey, APIKeyHeader
|
|
16
16
|
from pydantic import AfterValidator, BaseModel
|
|
17
17
|
from pydantic_core import PydanticCustomError
|
|
18
18
|
|
|
19
|
+
from zboxapi import __version__
|
|
20
|
+
|
|
19
21
|
api_key_header = APIKeyHeader(name="access_token", auto_error=False)
|
|
20
22
|
|
|
21
23
|
|
|
@@ -107,29 +109,28 @@ def sort_hosts_lines(item: dict):
|
|
|
107
109
|
)
|
|
108
110
|
|
|
109
111
|
|
|
110
|
-
def
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return {"ip": getattr(obj, ip_key), "fqdn": getattr(obj, fqdn_key)}
|
|
112
|
+
def simplify_operation_ids(api: FastAPI) -> None:
|
|
113
|
+
"""
|
|
114
|
+
Update operation IDs so that generated API clients have simpler function
|
|
115
|
+
names.
|
|
116
|
+
"""
|
|
117
|
+
for route in api.routes:
|
|
118
|
+
if isinstance(route, APIRoute) and not route.operation_id:
|
|
119
|
+
tag = route.tags[0] if route.tags else "default"
|
|
120
|
+
route.operation_id = f"{tag}_{route.name}"
|
|
120
121
|
|
|
121
122
|
|
|
122
|
-
def RecordNotFound(
|
|
123
|
+
def RecordNotFound(ip, fqdn):
|
|
123
124
|
return HTTPException(
|
|
124
|
-
status_code=status.
|
|
125
|
-
detail=f"
|
|
125
|
+
status_code=status.HTTP_404_NOT_FOUND,
|
|
126
|
+
detail=f"DNS record not found: ip={ip}, fqdn={fqdn}",
|
|
126
127
|
)
|
|
127
128
|
|
|
128
129
|
|
|
129
|
-
def RecordAlreadyPresent(
|
|
130
|
+
def RecordAlreadyPresent(ip, fqdn):
|
|
130
131
|
return HTTPException(
|
|
131
132
|
status_code=status.HTTP_406_NOT_ACCEPTABLE,
|
|
132
|
-
detail=f"
|
|
133
|
+
detail=f"DNS record already present: ip={ip}, fqdn={fqdn}",
|
|
133
134
|
)
|
|
134
135
|
|
|
135
136
|
|
|
@@ -176,8 +177,6 @@ class DnsDelete(BaseModel):
|
|
|
176
177
|
class DnsUpdate(BaseModel):
|
|
177
178
|
ip: IPv4Address
|
|
178
179
|
fqdn: FQDN
|
|
179
|
-
new_ip: IPv4Address
|
|
180
|
-
new_fqdn: FQDN
|
|
181
180
|
|
|
182
181
|
|
|
183
182
|
class DnsView(BaseModel):
|
|
@@ -185,71 +184,95 @@ class DnsView(BaseModel):
|
|
|
185
184
|
fqdn: str
|
|
186
185
|
|
|
187
186
|
|
|
188
|
-
|
|
187
|
+
dns_router = APIRouter(prefix="/dns", tags=["dns"])
|
|
189
188
|
|
|
190
189
|
|
|
191
|
-
@
|
|
192
|
-
def
|
|
193
|
-
ip: IPv4Address | None = None,
|
|
194
|
-
fqdn: str | None = None,
|
|
195
|
-
) -> list[DnsView]:
|
|
190
|
+
@dns_router.get("")
|
|
191
|
+
def dns_get_all() -> list[DnsView]:
|
|
196
192
|
with get_hosts_file_object() as hosts_fo:
|
|
197
193
|
hosts_lines = get_hosts_lines(hosts_fo)
|
|
198
|
-
hosts_lines = filter_hosts_file(hosts_lines, ip, fqdn)
|
|
199
194
|
return hosts_lines
|
|
200
195
|
|
|
201
196
|
|
|
202
|
-
@
|
|
203
|
-
def
|
|
197
|
+
@dns_router.get("/{ip}/{fqdn}")
|
|
198
|
+
def dns_get(
|
|
199
|
+
ip: IPv4Address,
|
|
200
|
+
fqdn: FQDN,
|
|
201
|
+
) -> DnsView:
|
|
204
202
|
with get_hosts_file_object() as hosts_fo:
|
|
205
203
|
hosts_lines = get_hosts_lines(hosts_fo)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
204
|
+
hosts_lines = filter_hosts_file(hosts_lines, ip, fqdn)
|
|
205
|
+
if not hosts_lines:
|
|
206
|
+
raise RecordNotFound(ip, fqdn)
|
|
207
|
+
return hosts_lines[0]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@dns_router.post("")
|
|
211
|
+
def dns_add(
|
|
212
|
+
dns_in: DnsCreate,
|
|
213
|
+
) -> list[DnsView]:
|
|
214
|
+
with get_hosts_file_object() as hosts_fo:
|
|
215
|
+
hosts_lines = get_hosts_lines(hosts_fo)
|
|
216
|
+
if filter_hosts_file(hosts_lines, dns_in.ip, dns_in.fqdn):
|
|
217
|
+
raise RecordAlreadyPresent(dns_in.ip, dns_in.fqdn)
|
|
218
|
+
hosts_lines.append({"ip": dns_in.ip, "fqdn": dns_in.fqdn})
|
|
210
219
|
write_hosts_file(hosts_fo, hosts_lines)
|
|
211
220
|
dnsmasq_sighup()
|
|
212
221
|
return hosts_lines
|
|
213
222
|
|
|
214
223
|
|
|
215
|
-
@
|
|
216
|
-
def
|
|
224
|
+
@dns_router.put("/{ip}/{fqdn}")
|
|
225
|
+
def dns_update(
|
|
226
|
+
ip: IPv4Address,
|
|
227
|
+
fqdn: FQDN,
|
|
228
|
+
dns_in: DnsUpdate,
|
|
229
|
+
) -> list[DnsView]:
|
|
217
230
|
with get_hosts_file_object() as hosts_fo:
|
|
218
231
|
hosts_lines = get_hosts_lines(hosts_fo)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
hosts_lines[ix] = ip_fqdn_dict(line, "new_ip", "new_fqdn")
|
|
232
|
+
key = {"ip": ip, "fqdn": fqdn}
|
|
233
|
+
if key not in hosts_lines:
|
|
234
|
+
raise RecordNotFound(ip, fqdn)
|
|
235
|
+
ix = hosts_lines.index(key)
|
|
236
|
+
hosts_lines[ix] = {"ip": dns_in.ip, "fqdn": dns_in.fqdn}
|
|
225
237
|
write_hosts_file(hosts_fo, hosts_lines)
|
|
226
238
|
dnsmasq_sighup()
|
|
227
239
|
return hosts_lines
|
|
228
240
|
|
|
229
241
|
|
|
230
|
-
@
|
|
231
|
-
def
|
|
242
|
+
@dns_router.delete("/{ip}/{fqdn}")
|
|
243
|
+
def dns_delete(
|
|
244
|
+
ip: IPv4Address,
|
|
245
|
+
fqdn: FQDN,
|
|
246
|
+
) -> list[DnsView]:
|
|
232
247
|
with get_hosts_file_object() as hosts_fo:
|
|
233
248
|
hosts_lines = get_hosts_lines(hosts_fo)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
hosts_lines.remove(key)
|
|
249
|
+
key = {"ip": ip, "fqdn": fqdn}
|
|
250
|
+
if key not in hosts_lines:
|
|
251
|
+
raise RecordNotFound(ip, fqdn)
|
|
252
|
+
hosts_lines.remove(key)
|
|
239
253
|
write_hosts_file(hosts_fo, hosts_lines)
|
|
240
254
|
dnsmasq_sighup()
|
|
241
255
|
return hosts_lines
|
|
242
256
|
|
|
243
257
|
|
|
244
|
-
|
|
245
|
-
|
|
258
|
+
zboxapi_root_path = os.getenv("ZBOXAPI_ROOT_PATH", None)
|
|
259
|
+
|
|
260
|
+
app = FastAPI(
|
|
261
|
+
title="zBox API",
|
|
262
|
+
root_path=zboxapi_root_path,
|
|
263
|
+
dependencies=[Depends(validate_api_key)],
|
|
264
|
+
version=__version__,
|
|
265
|
+
)
|
|
266
|
+
app.include_router(dns_router)
|
|
267
|
+
simplify_operation_ids(app)
|
|
268
|
+
|
|
246
269
|
ZPOD_PASSWORD = get_zpod_password()
|
|
247
270
|
|
|
248
271
|
|
|
249
272
|
def launch():
|
|
250
273
|
uvicorn.run(
|
|
251
274
|
app,
|
|
252
|
-
host="
|
|
275
|
+
host="127.0.0.1",
|
|
253
276
|
port=8000,
|
|
254
277
|
)
|
|
255
278
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.0.3"
|
|
File without changes
|