| Variable | Default | Description |
|----------|---------|-------------|
| `FRONTEND_DIR` | /app/frontend | Frontend directory |
-| `DB_FILE` | /data/database.db | SQLite file |
+| `DATA_PATH`| /data | Data Path for DB and Backups |
+| `DB_FILE` | database.db | SQLite file |
| `DB_RESET` | false | Reset DB on every startup |
| `LOG_LEVEL` | info | Log level |
| `LOG_TO_FILE` | false | Enable file logging |
-| `LOG_FILE` | /data/app.log | Application log file |
-| `LOG_ACCESS_FILE` | /data/access.log | HTTP access log |
+| `LOG_FILE` | app.log | Application log file |
+| `LOG_ACCESS_FILE` | access.log | HTTP access log |
| `DOMAIN` | example.com | Public domain |
| `PUBLIC_IP` | 127.0.0.1 | Public IP |
| `HTTP_PORT` | 8000 | Internal HTTP port |
| `DNS_HOST_FILE` | {DOMAIN}/hosts.inc | BIND9 Hosts file |
| `DNS_ALIAS_FILE` | {DOMAIN}/alias.inc | BIND9 Alias file |
| `DNS_REVERSE_FILE` | reverse/hosts.inc | BIND9 Reverse Hosts file |
+| `DHCP_CFG_PATH` | /dns/etc | KEA Configuration folder |
+| `DHCP4_HOST_FILE` | hosts-ipv4.json | KEA-DHCP4 Hosts file |
+| `DHCP6_HOST_FILE` | hosts-ipv6.json | KEA-DHCP6 Hosts file |
---
- [ ] Perform **commit + push** on Git
- [ ] Regenerate **from scratch**:
- [ ] **BIND (DNS)** configuration
- - [ ] **Kea (DHCP)** configuration
+ - [X] hosts configuration
+ - [ ] alias configuration
+ - [X] reverse configuration
+ - [ ] IPv6 configuration
+ - [X] **Kea (DHCP)** configuration
+ - [X] IPv4 configuration
+ - [X] IPv6 configuration
- [ ] Reload services:
- [ ] BIND
- [ ] Kea
import os
# Import Routers
from backend.routes.about import router as about_router
+from backend.routes.backup import router as backup_router
from backend.routes.health import router as health_router
from backend.routes.login import router as login_router
from backend.routes.hosts import router as hosts_router
"DNS: path=%s | host file=%s | alias file=%s | reverse file=%s",
settings.DNS_CFG_PATH, settings.DNS_HOST_FILE, settings.DNS_ALIAS_FILE, settings.DNS_REVERSE_FILE
)
+ logger.info(
+ "DHCP: path=%s | ipv4 host file=%s | ipv6 host file=%s",
+ settings.DHCP_CFG_PATH, settings.DHCP4_HOST_FILE, settings.DHCP6_HOST_FILE
+ )
# ------------------------------------------------------------------------------
# Shutdown log
# Routers
# ------------------------------------------------------------------------------
app.include_router(about_router)
+app.include_router(backup_router)
app.include_router(health_router)
app.include_router(login_router)
app.include_router(hosts_router)
--- /dev/null
+# backend/routes/backup.py
+
+# import standard modules
+from fastapi import APIRouter, Request, Response
+from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
+import asyncio
+import json
+import os
+import ipaddress
+import time
+# Import local modules
+from backend.db.hosts import get_hosts
+# Import Settings
+from settings.settings import settings
+
+# Create Router
+router = APIRouter()
+
+# ---------------------------------------------------------
+# API ENDPOINTS
+# ---------------------------------------------------------
+@router.get("/api/backup")
+async def apt_dns_reload(request: Request):
+ start_ns = time.monotonic_ns()
+
+ # Inizializzazioni
+ error = False
+ message = None
+ code = None
+ status = None
+ dns_hosts = []
+ dns_reverse = []
+
+ try:
+ # Get Hosts List
+ hosts = get_hosts()
+
+ # Backup Hosts DB
+ path = settings.DATA_PATH + "/hosts.json"
+ with open(path, "w", encoding="utf-8") as f:
+ for h in hosts:
+ f.write(json.dumps(h, ensure_ascii=False) + "\n")
+
+ except Exception as err:
+ error = True
+ message = str(err).strip()
+
+ if error:
+ code = "BACKUP_ERROR"
+ # default del messaggio se vuoto o None
+ if not message:
+ message = "BACKUP error"
+ status = "failure"
+ #http_status = 500
+ else:
+ code = "BACKUP_OK"
+ message = "BACKUP executed successfully"
+ status = "success"
+ #http_status = 200
+
+ took_ms = (time.monotonic_ns() - start_ns) / 1_000_000
+
+ payload = {
+ "code": code,
+ "status": status,
+ "message": message,
+ "details": {
+ "took_ms": took_ms
+ }
+ }
+ return JSONResponse(content=payload)
+ #return JSONResponse(content=payload, status_code=http_status)
# import standard modules
from fastapi import APIRouter, Request, Response
-from fastapi.responses import FileResponse, RedirectResponse
+from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
import asyncio
+import json
import os
import ipaddress
import time
-
+# Import local modules
+from backend.db.hosts import get_hosts
# Import Settings
from settings.settings import settings
async def apt_dhcp_reload(request: Request):
start_ns = time.monotonic_ns()
- await asyncio.sleep(0.2)
+ # Inizializzazioni
+ error = False
+ message = None
+ code = None
+ status = None
+ kea4_hosts = []
+ kea6_hosts = []
+
+ try:
+ # Get Hosts List
+ hosts = get_hosts()
+
+ # Convert hosts into the kea structure
+ for h in hosts:
+ if h.get("ipv4") and h.get("mac"):
+ kea4_hosts.append({
+ "hostname": h.get("name"),
+ "hw-address": h.get("mac"),
+ "ip-address": h.get("ipv4"),
+ })
+ if h.get("ipv6") and h.get("mac"):
+ kea6_hosts.append({
+ "hostname": h.get("name"),
+ "hw-address": h.get("mac"),
+ "ip-address": h.get("ipv6"),
+ })
+
+ # Save DHCP4 Configuration
+ path = settings.DHCP4_HOST_FILE
+ with open(path, "w", encoding="utf-8") as f:
+ json.dump(kea4_hosts, f, indent=4, ensure_ascii=False)
+
+ # Save DHCP6 Configuration
+ path = settings.DHCP6_HOST_FILE
+ with open(path, "w", encoding="utf-8") as f:
+ json.dump(kea6_hosts, f, indent=4, ensure_ascii=False)
+
+ except Exception as err:
+ error = True
+ message = str(err).strip()
+
+ if error:
+ code = "DHCP_RELOAD_ERROR"
+ # default del messaggio se vuoto o None
+ if not message:
+ message = "DHCP reload error"
+ status = "failure"
+ #http_status = 500
+ else:
+ code = "DHCP_RELOAD_OK"
+ message = "DHCP configuration reload successfully"
+ status = "success"
+ #http_status = 200
- end_ns = time.monotonic_ns()
- took_ms = (end_ns - start_ns)
+ took_ms = (time.monotonic_ns() - start_ns) / 1_000_000
- return {
- "code": "DHCP_RELOAD_OK",
- "status": "success",
- "message": "DHCP configuration reload successfully",
+ payload = {
+ "code": code,
+ "status": status,
+ "message": message,
"details": {
"took_ms": took_ms
}
}
+ return JSONResponse(content=payload)
+ #return JSONResponse(content=payload, status_code=http_status)
# Get Hosts List
hosts = get_hosts()
- # Save DNS Configuration
+ # Save DNS Hosts Configuration
path = settings.DNS_HOST_FILE
with open(path, "w", encoding="utf-8") as f:
for h in hosts:
line = f"{h.get('name')}\t\t IN\tA\t{h.get('ipv4')}\n"
f.write(line)
- path = settings.DNS_HOST_FILE + ".json"
+ # Save DNS Reverse Configuration
+ path = settings.DNS_REVERSE_FILE
with open(path, "w", encoding="utf-8") as f:
- #json.dump(hosts, f, indent=4, ensure_ascii=False)
for h in hosts:
- f.write(json.dumps(h, ensure_ascii=False) + "\n")
+ ip = h.get('ipv4')
+ if ip:
+ parts = ip.split(".")
+ rev = f"{parts[-1]}.{parts[-2]}"
+ line = f"{rev}\t\t IN PTR\t{h.get('name')}.{settings.DOMAIN}\n"
+ f.write(line)
except Exception as err:
error = True
}
}
return JSONResponse(content=payload)
+ #return JSONResponse(content=payload, status_code=http_status)
volumes:
- ${DOCKER_CFG_DIR}/network:/data
- ${DOCKER_CFG_DIR}/bind9:/dns
+ - ${DOCKER_CFG_DIR}/kea:/dhcp
networks:
- proxy
# ---------------------------------------------------------
FRONTEND_DIR = "/app/frontend"
+# ---------------------------------------------------------
+# Data Path (DB + Backup)
+# ---------------------------------------------------------
+DATA_PATH = "/data"
+
# ---------------------------------------------------------
# Database
# ---------------------------------------------------------
-DB_FILE = "/data/database.db"
+DB_FILE = "database.db"
DB_RESET = False
# ---------------------------------------------------------
# ---------------------------------------------------------
LOG_LEVEL = "INFO"
LOG_TO_FILE = False
-LOG_FILE = "/data/app.log"
-LOG_ACCESS_FILE = "/data/access.log"
+LOG_FILE = "app.log"
+LOG_ACCESS_FILE = "access.log"
# ---------------------------------------------------------
# Host
DNS_HOST_FILE=f"{DOMAIN}/hosts.inc"
DNS_ALIAS_FILE=f"{DOMAIN}/alias.inc"
DNS_REVERSE_FILE="reverse/hosts.inc"
+
+# ---------------------------------------------------------
+# DHCP
+# ---------------------------------------------------------
+DHCP_CFG_PATH="/dhcp/etc"
+DHCP4_HOST_FILE="hosts-ipv4.json"
+DHCP6_HOST_FILE="hosts-ipv6.json"
BASEIMG_NAME: str = Field(default_factory=lambda: config.BASEIMG_NAME)
BASEIMG_VERSION: str = Field(default_factory=lambda: config.BASEIMG_VERSION)
+ # DATA_PATH
+ DATA_PATH: str = Field(default_factory=lambda: os.getenv("DATA_PATH", default.DATA_PATH))
+
# Frontend
FRONTEND_DIR: str = Field(default_factory=lambda: os.getenv("FRONTEND_DIR", default.FRONTEND_DIR))
DNS_HOST_FILE: str = Field(default_factory=lambda: os.getenv("DNS_HOST_FILE", default.DNS_HOST_FILE))
DNS_ALIAS_FILE: str = Field(default_factory=lambda: os.getenv("DNS_ALIAS_FILE", default.DNS_ALIAS_FILE))
DNS_REVERSE_FILE: str = Field(default_factory=lambda: os.getenv("DNS_REVERSE_FILE", default.DNS_REVERSE_FILE))
+ # DHCP
+ DHCP_CFG_PATH: str = Field(default_factory=lambda: os.getenv("DHCP_CFG_PATH", default.DHCP_CFG_PATH))
+ DHCP4_HOST_FILE: str = Field(default_factory=lambda: os.getenv("DHCP4_HOST_FILE", default.DHCP4_HOST_FILE))
+ DHCP6_HOST_FILE: str = Field(default_factory=lambda: os.getenv("DHCP6_HOST_FILE", default.DHCP6_HOST_FILE))
def model_post_init(self, __context) -> None:
if self.DEVEL:
else:
object.__setattr__(self, "APP_VERSION", self.APP_VERSION)
- # Update Files
+ # Database
+ self.DB_FILE = self.DATA_PATH + "/" + self.DB_FILE
+ self.LOG_FILE = self.DATA_PATH + "/" + self.LOG_FILE
+ self.LOG_ACCESS_FILE = self.DATA_PATH + "/" + self.LOG_ACCESS_FILE
+
+ # Update DNS Files
if self.DOMAIN.lower() != default.DOMAIN.lower():
self.DNS_HOST_FILE = self.DNS_HOST_FILE.replace(default.DOMAIN, self.DOMAIN)
self.DNS_ALIAS_FILE = self.DNS_ALIAS_FILE.replace(default.DOMAIN, self.DOMAIN)
self.DNS_HOST_FILE = self.DNS_CFG_PATH + "/" + self.DNS_HOST_FILE
self.DNS_ALIAS_FILE = self.DNS_CFG_PATH + "/" + self.DNS_ALIAS_FILE
self.DNS_REVERSE_FILE = self.DNS_CFG_PATH + "/" + self.DNS_REVERSE_FILE
+
+ # Update DHCP Files
+ self.DHCP4_HOST_FILE = self.DHCP_CFG_PATH + "/" + self.DHCP4_HOST_FILE
+ self.DHCP6_HOST_FILE = self.DHCP_CFG_PATH + "/" + self.DHCP6_HOST_FILE
+
# ---------------------------------------------------------
# Singleton
# ---------------------------------------------------------