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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zboxapi
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary:
5
5
  Author: Kelby Valenti
6
6
  Author-email: kelby.valenti@gmail.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "zboxapi"
3
- version = "0.0.3"
3
+ version = "0.0.5"
4
4
  description = ""
5
5
  authors = ["Kelby Valenti <kelby.valenti@gmail.com>", "Timo Sugliani <timo.sugliani@gmail.com>"]
6
6
  readme = "README.md"
@@ -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 make_list(obj):
111
- return obj if isinstance(obj, list) else [obj]
112
-
113
-
114
- def ip_fqdn_str(obj, ip_key="ip", fqdn_key="fqdn"):
115
- return f"ip={getattr(obj, ip_key)}, fqdn={getattr(obj, fqdn_key)}"
116
-
117
-
118
- def ip_fqdn_dict(obj, ip_key="ip", fqdn_key="fqdn"):
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(obj, ip_key="ip", fqdn_key="fqdn"):
123
+ def RecordNotFound(ip, fqdn):
123
124
  return HTTPException(
124
- status_code=status.HTTP_406_NOT_ACCEPTABLE,
125
- detail=f"Record not found: {ip_fqdn_str(obj, ip_key, fqdn_key)}",
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(obj, ip_key="ip", fqdn_key="fqdn"):
130
+ def RecordAlreadyPresent(ip, fqdn):
130
131
  return HTTPException(
131
132
  status_code=status.HTTP_406_NOT_ACCEPTABLE,
132
- detail=f"Record already present: {ip_fqdn_str(obj, ip_key, fqdn_key)}",
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
- hosts_router = APIRouter(prefix="/hosts", tags=["hosts"])
187
+ dns_router = APIRouter(prefix="/dns", tags=["dns"])
189
188
 
190
189
 
191
- @hosts_router.get("")
192
- def get_hosts(
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
- @hosts_router.post("")
203
- def add_hosts(lines_in: list[DnsCreate] | DnsCreate) -> list[DnsView]:
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
- for line in make_list(lines_in):
207
- if filter_hosts_file(hosts_lines, line.ip, line.fqdn):
208
- raise RecordAlreadyPresent(line)
209
- hosts_lines.append(ip_fqdn_dict(line))
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
- @hosts_router.put("")
216
- def update_hosts(lines_in: list[DnsUpdate] | DnsUpdate) -> list[DnsView]:
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
- for line in make_list(lines_in):
220
- key = ip_fqdn_dict(line)
221
- if key not in hosts_lines:
222
- raise RecordNotFound(line)
223
- ix = hosts_lines.index(key)
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
- @hosts_router.delete("")
231
- def delete_hosts(lines_in: list[DnsDelete] | DnsDelete) -> list[DnsView]:
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
- for line in make_list(lines_in):
235
- key = ip_fqdn_dict(line)
236
- if key not in hosts_lines:
237
- raise RecordNotFound(line)
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
- app = FastAPI(title="zPod zBox API", dependencies=[Depends(validate_api_key)])
245
- app.include_router(hosts_router)
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="zbox",
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