Netzwerkeinstellungen: netplan/systemd-networkd als drittes Backend + DHCP-Interface-Default-Fix
Auf einer echten, frisch installierten Ubuntu-24.04-VM (192.168.80.114, Standard-Setup, Netz per DHCP) zeigten sich zwei reale Bugs: 1. Systemeinstellungen > Netzwerkeinstellungen: 'Kein unterstütztes Backend erkannt' trotz laufendem Netz -- _detect_network_backend() kannte nur NetworkManager und dhcpcd, nicht netplan/systemd-networkd, den mit Abstand haeufigsten Fall auf einem normalen Ubuntu-Host. Neues drittes Backend 'netplan' ergaenzt: Erkennung ueber systemd-networkd + vorhandenes netplan-Binary, Moduserkennung ueber das 'dynamic'-Flag des Kernels auf der aktuellen Adresse, Anwenden ueber eine eigene Override-Datei (/etc/netplan/90-poe-manager.yaml, gewinnt alphabetisch gegen z.B. cloud-inits 50-*.yaml) plus Aufruf von netplan apply, Backup/Auto-Rollback wie bei den anderen Backends. Live verifiziert: Anwenden loeste echten DHCP-Lease-Renew aus, nach Ablauf der 45s-Bestaetigungsfrist wurde die Override-Datei automatisch wieder entfernt (Rollback funktioniert). 2. DHCP-Konfiguration: 'Keine IPv4-Adresse auf eth0 gefunden', obwohl das Interface-Dropdown korrekt 'enp1s0' zeigte -- DHCP_DEFAULTS hatte 'eth0' hart kodiert (Annahme aus einer aelteren Testumgebung), was auf Systemen mit Predictable Network Interface Names schlicht nicht existiert. _load_dhcp_settings() korrigiert das jetzt: liegt der gespeicherte/Default-Wert nicht unter den tatsaechlich vorhandenen Schnittstellen, wird automatisch die erste echte vorgeschlagen. Neue Abhaengigkeit PyYAML fuer das Schreiben der netplan-Override-Datei.
This commit is contained in:
@@ -290,17 +290,25 @@ risikolos über `hostnamectl set-hostname` gesetzt (kein Revert-Timer nötig,
|
|||||||
da eine Änderung nicht die Erreichbarkeit kappt).
|
da eine Änderung nicht die Erreichbarkeit kappt).
|
||||||
|
|
||||||
- **Backend-Erkennung**: prüft, ob NetworkManager oder dhcpcd aktiv ist
|
- **Backend-Erkennung**: prüft, ob NetworkManager oder dhcpcd aktiv ist
|
||||||
(`systemctl is-active`). Ist keins von beiden aktiv, bleibt die Seite
|
(`systemctl is-active`); ist keins von beiden aktiv, aber `systemd-networkd`
|
||||||
bewusst **rein lesend** (Status wird trotzdem angezeigt) — ohne
|
aktiv und `netplan` installiert, wird **netplan** angenommen — der Standard
|
||||||
zuverlässige Erkennung des Backends keine Änderung, um nicht ins Blaue zu
|
auf einem frisch installierten Ubuntu (Server wie Cloud-Image). Ist keins
|
||||||
raten.
|
der drei erkennbar, bleibt die Seite bewusst **rein lesend** (Status wird
|
||||||
|
trotzdem angezeigt) — ohne zuverlässige Erkennung des Backends keine
|
||||||
|
Änderung, um nicht ins Blaue zu raten.
|
||||||
- **Anzeige**: aktuelles Interface, IP/Prefix, Gateway, DNS-Server sowie
|
- **Anzeige**: aktuelles Interface, IP/Prefix, Gateway, DNS-Server sowie
|
||||||
Modus (DHCP/Statisch) — Modus wird backend-spezifisch ermittelt
|
Modus (DHCP/Statisch) — Modus wird backend-spezifisch ermittelt
|
||||||
(`nmcli ipv4.method` bzw. ein `static ip_address=`-Eintrag im
|
(`nmcli ipv4.method`, ein `static ip_address=`-Eintrag im betreffenden
|
||||||
betreffenden `interface`-Block von `/etc/dhcpcd.conf`).
|
`interface`-Block von `/etc/dhcpcd.conf`, bzw. bei netplan am `dynamic`-Flag
|
||||||
|
des Kernels auf der aktuellen Adresse — zuverlässiger als die u.U. mehreren
|
||||||
|
überlagernden YAML-Dateien unter `/etc/netplan/` selbst zu parsen).
|
||||||
- **Änderung**: Interface, Modus (DHCP/Statisch), bei Statisch zusätzlich
|
- **Änderung**: Interface, Modus (DHCP/Statisch), bei Statisch zusätzlich
|
||||||
IP/Prefix/Gateway, sowie unabhängig davon eigene DNS-Server (funktioniert
|
IP/Prefix/Gateway, sowie unabhängig davon eigene DNS-Server (funktioniert
|
||||||
in beiden Modi — z.B. IP per DHCP, aber feste DNS-Server).
|
in beiden Modi — z.B. IP per DHCP, aber feste DNS-Server). Bei netplan
|
||||||
|
landet die Änderung in einer eigenen, niedrig priorisierten Override-Datei
|
||||||
|
(`/etc/netplan/90-poe-manager.yaml`) statt in der vom Distributor bzw.
|
||||||
|
cloud-init mitgelieferten — netplan wendet Dateien alphabetisch an, spätere
|
||||||
|
Werte gewinnen pro Schlüssel, damit bleibt die Original-Datei unangetastet.
|
||||||
- **Sicherheitsnetz** (wie `netplan try`): vor jeder Änderung wird die
|
- **Sicherheitsnetz** (wie `netplan try`): vor jeder Änderung wird die
|
||||||
vorherige Konfiguration gesichert. Nach dem Anwenden läuft ein
|
vorherige Konfiguration gesichert. Nach dem Anwenden läuft ein
|
||||||
Hintergrund-Timer (Standard 45s) — wird die Änderung nicht **explizit
|
Hintergrund-Timer (Standard 45s) — wird die Änderung nicht **explizit
|
||||||
@@ -308,14 +316,14 @@ da eine Änderung nicht die Erreichbarkeit kappt).
|
|||||||
erreichbar ist), rollt die App automatisch auf die gesicherte
|
erreichbar ist), rollt die App automatisch auf die gesicherte
|
||||||
Konfiguration zurück. Verhindert, dass ein Tippfehler bei IP/Gateway den
|
Konfiguration zurück. Verhindert, dass ein Tippfehler bei IP/Gateway den
|
||||||
Host von der Web-UI/SSH abschneidet.
|
Host von der Web-UI/SSH abschneidet.
|
||||||
- Da diese Session ausschließlich in WSL (eigene virtuelle Netzwerkschicht,
|
- Live gegen eine echte Ubuntu-24.04-VM verifiziert (Standard-Installation,
|
||||||
weder NetworkManager noch dhcpcd) läuft, konnte der Anwenden-Pfad nicht
|
Netz per DHCP über netplan/systemd-networkd bezogen) — sowohl die
|
||||||
gegen eine echte Instanz verifiziert werden — Erkennung/Statusanzeige
|
Erkennung/Statusanzeige als auch der komplette Anwenden-Pfad inkl. der
|
||||||
sind live getestet (korrekte "kein Backend erkannt"-Erkennung + rein
|
eigenen Override-Datei. NetworkManager und dhcpcd sind zusätzlich per
|
||||||
lesender Fallback), Anwenden/Rollback-Logik gegen beide Backends per
|
gemockten `subprocess.run`/Dateizugriffen verifiziert (inkl. eines echten
|
||||||
gemockten `subprocess.run`/Dateizugriffen inkl. eines echten
|
|
||||||
`dhcpcd.conf`-Rewrites und eines vollständigen Anwenden-dann-Auto-
|
`dhcpcd.conf`-Rewrites und eines vollständigen Anwenden-dann-Auto-
|
||||||
Rollback-Durchlaufs verifiziert.
|
Rollback-Durchlaufs), da in der WSL-Entwicklungsumgebung keins von beiden
|
||||||
|
verfügbar ist.
|
||||||
|
|
||||||
## Änderungslog
|
## Änderungslog
|
||||||
|
|
||||||
|
|||||||
+98
-8
@@ -20,6 +20,7 @@ from cryptography.hazmat.primitives import hashes
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import base64, ipaddress, shutil, socket, sqlite3, glob, json, os, re, secrets, subprocess, threading, time, traceback
|
import base64, ipaddress, shutil, socket, sqlite3, glob, json, os, re, secrets, subprocess, threading, time, traceback
|
||||||
import paramiko
|
import paramiko
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
class _SendAllSocketProxy:
|
class _SendAllSocketProxy:
|
||||||
@@ -1244,13 +1245,17 @@ def run_check_now():
|
|||||||
|
|
||||||
NETWORK_REVERT_SECONDS = 45
|
NETWORK_REVERT_SECONDS = 45
|
||||||
_pending_network_revert = {} # {"timer": Timer, "backend":..., "interface":..., "backup": {...}}
|
_pending_network_revert = {} # {"timer": Timer, "backend":..., "interface":..., "backup": {...}}
|
||||||
|
# Eigene netplan-Override-Datei (siehe _apply_network_config) — bewusst nicht
|
||||||
|
# die von cloud-init/dem Distributor mitgelieferte Datei, damit ein Rollback
|
||||||
|
# nie versehentlich fremden Inhalt überschreibt.
|
||||||
|
NETPLAN_CONFIG_PATH = "/etc/netplan/90-poe-manager.yaml"
|
||||||
|
|
||||||
|
|
||||||
def _detect_network_backend():
|
def _detect_network_backend():
|
||||||
"""Rein lesend: welcher der beiden gängigen Netzwerk-Manager auf
|
"""Rein lesend: welcher der gängigen Netzwerk-Manager ist aktiv? Keine
|
||||||
Debian/Raspberry Pi OS ist aktiv? Keine Annahme, falls keins von
|
Annahme, falls keiner läuft (z.B. in dieser WSL-Testumgebung, die ihr
|
||||||
beiden läuft (z.B. in dieser WSL-Testumgebung, die ihr Netz über den
|
Netz über den Hyper-V-Adapter bezieht) — dann bleibt die Seite bewusst
|
||||||
Hyper-V-Adapter bezieht) — dann bleibt die Seite bewusst rein lesend."""
|
rein lesend."""
|
||||||
for service, name in (("NetworkManager", "networkmanager"), ("dhcpcd", "dhcpcd")):
|
for service, name in (("NetworkManager", "networkmanager"), ("dhcpcd", "dhcpcd")):
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(["systemctl", "is-active", service], capture_output=True, text=True, timeout=5)
|
result = subprocess.run(["systemctl", "is-active", service], capture_output=True, text=True, timeout=5)
|
||||||
@@ -1258,6 +1263,17 @@ def _detect_network_backend():
|
|||||||
return name
|
return name
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# Standard-Ubuntu (Server- wie Cloud-Images) verwaltet sein Netz
|
||||||
|
# inzwischen über netplan + systemd-networkd statt NetworkManager oder
|
||||||
|
# dhcpcd — mit Abstand der häufigste Fall auf einem "normalen" frisch
|
||||||
|
# installierten Ubuntu-Host (live an einer echten Ubuntu-24.04-VM
|
||||||
|
# verifiziert, die ihre IP per DHCP bezieht).
|
||||||
|
try:
|
||||||
|
result = subprocess.run(["systemctl", "is-active", "systemd-networkd"], capture_output=True, text=True, timeout=5)
|
||||||
|
if result.stdout.strip() == "active" and shutil.which("netplan"):
|
||||||
|
return "netplan"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
@@ -1301,6 +1317,12 @@ def _read_network_state(interface, backend):
|
|||||||
mode = "static" if re.search(r"^\s*static\s+ip_address=", block, re.M) else "dhcp"
|
mode = "static" if re.search(r"^\s*static\s+ip_address=", block, re.M) else "dhcp"
|
||||||
except OSError:
|
except OSError:
|
||||||
mode = "dhcp"
|
mode = "dhcp"
|
||||||
|
elif backend == "netplan":
|
||||||
|
# Netplan/systemd-networkd markiert eine per DHCP bezogene Adresse
|
||||||
|
# im Kernel mit "dynamic" — zuverlässiger als die YAML-Dateien unter
|
||||||
|
# /etc/netplan/ zu parsen (mehrere Dateien können sich überlagern).
|
||||||
|
if net_info.get("ok"):
|
||||||
|
mode = "dhcp" if net_info.get("dynamic") else "static"
|
||||||
return {**net_info, "dns": _read_resolv_conf_dns(), "mode": mode, "backend": backend}
|
return {**net_info, "dns": _read_resolv_conf_dns(), "mode": mode, "backend": backend}
|
||||||
|
|
||||||
|
|
||||||
@@ -1328,6 +1350,15 @@ def _backup_network_config(interface, backend):
|
|||||||
backup["nm_connection"] = dev_out.stdout.split(":", 1)[1].strip() if ":" in dev_out.stdout else None
|
backup["nm_connection"] = dev_out.stdout.split(":", 1)[1].strip() if ":" in dev_out.stdout else None
|
||||||
except Exception:
|
except Exception:
|
||||||
backup["nm_connection"] = None
|
backup["nm_connection"] = None
|
||||||
|
elif backend == "netplan":
|
||||||
|
# Eigene Override-Datei sichern statt der von cloud-init/dem
|
||||||
|
# Distributor mitgelieferten Dateien — None heißt "existierte vorher
|
||||||
|
# nicht", dann löscht der Revert sie wieder statt sie leer zu lassen.
|
||||||
|
try:
|
||||||
|
with open(NETPLAN_CONFIG_PATH, encoding="utf-8") as f:
|
||||||
|
backup["netplan_conf"] = f.read()
|
||||||
|
except OSError:
|
||||||
|
backup["netplan_conf"] = None
|
||||||
return backup
|
return backup
|
||||||
|
|
||||||
|
|
||||||
@@ -1381,7 +1412,38 @@ def _apply_network_config(backend, interface, mode, ip, prefix, gateway, dns_lis
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return False, str(e)
|
return False, str(e)
|
||||||
|
|
||||||
return False, "Kein unterstütztes Netzwerk-Backend erkannt (weder NetworkManager noch dhcpcd aktiv)."
|
if backend == "netplan":
|
||||||
|
try:
|
||||||
|
eth_cfg = {}
|
||||||
|
if mode == "static":
|
||||||
|
eth_cfg["dhcp4"] = False
|
||||||
|
eth_cfg["addresses"] = [f"{ip}/{prefix}"]
|
||||||
|
if gateway:
|
||||||
|
eth_cfg["routes"] = [{"to": "default", "via": gateway}]
|
||||||
|
else:
|
||||||
|
eth_cfg["dhcp4"] = True
|
||||||
|
if dns_list:
|
||||||
|
# Ohne diesen Override würde networkd die eigenen
|
||||||
|
# DNS-Server mit den per DHCP gelieferten zusammen
|
||||||
|
# verwenden, statt sie wie bei den anderen Backends
|
||||||
|
# (ipv4.ignore-auto-dns / dhcpcd) vollständig zu ersetzen.
|
||||||
|
eth_cfg["dhcp4-overrides"] = {"use-dns": False}
|
||||||
|
if dns_list:
|
||||||
|
eth_cfg["nameservers"] = {"addresses": dns_list}
|
||||||
|
doc = {"network": {"version": 2, "ethernets": {interface: eth_cfg}}}
|
||||||
|
# Eigene, niedrig priorisierte Datei statt der von cloud-init
|
||||||
|
# mitgelieferten (z.B. 50-cloud-init.yaml) — netplan wendet
|
||||||
|
# Dateien in alphabetischer Reihenfolge an und lässt spätere
|
||||||
|
# Werte pro Schlüssel gewinnen, das ist hier der etablierte Weg
|
||||||
|
# für eigene Overrides statt die Distributor-Datei zu editieren.
|
||||||
|
with open(NETPLAN_CONFIG_PATH, "w", encoding="utf-8") as f:
|
||||||
|
yaml.safe_dump(doc, f, default_flow_style=False)
|
||||||
|
os.chmod(NETPLAN_CONFIG_PATH, 0o600)
|
||||||
|
return _dhcp_run_privileged(["netplan", "apply"], timeout=20)
|
||||||
|
except Exception as e:
|
||||||
|
return False, str(e)
|
||||||
|
|
||||||
|
return False, "Kein unterstütztes Netzwerk-Backend erkannt (weder NetworkManager, dhcpcd noch netplan aktiv)."
|
||||||
|
|
||||||
|
|
||||||
def _revert_network_config(token):
|
def _revert_network_config(token):
|
||||||
@@ -1403,6 +1465,19 @@ def _revert_network_config(token):
|
|||||||
"networkmanager", backup["interface"],
|
"networkmanager", backup["interface"],
|
||||||
backup["mode"], backup.get("ip"), backup.get("prefix"), backup.get("gateway"), backup.get("dns", []),
|
backup["mode"], backup.get("ip"), backup.get("prefix"), backup.get("gateway"), backup.get("dns", []),
|
||||||
)
|
)
|
||||||
|
elif backup["backend"] == "netplan":
|
||||||
|
if backup.get("netplan_conf") is not None:
|
||||||
|
with open(NETPLAN_CONFIG_PATH, "w", encoding="utf-8") as f:
|
||||||
|
f.write(backup["netplan_conf"])
|
||||||
|
else:
|
||||||
|
# Datei existierte vor der Änderung nicht (erste Netplan-
|
||||||
|
# Änderung über diese Seite) — dann muss sie beim Rollback
|
||||||
|
# auch wieder verschwinden statt leer zurückzubleiben.
|
||||||
|
try:
|
||||||
|
os.remove(NETPLAN_CONFIG_PATH)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
subprocess.run(["netplan", "apply"], timeout=20)
|
||||||
log_action_system("settings.network_revert", backup["interface"], "automatisch nach Timeout zurückgerollt")
|
log_action_system("settings.network_revert", backup["interface"], "automatisch nach Timeout zurückgerollt")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.error("Network auto-revert failed: %s", e)
|
app.logger.error("Network auto-revert failed: %s", e)
|
||||||
@@ -1571,7 +1646,17 @@ DHCP_OPTION_TYPE_KEYS = {t[0] for t in DHCP_OPTION_TYPES}
|
|||||||
|
|
||||||
|
|
||||||
def _load_dhcp_settings():
|
def _load_dhcp_settings():
|
||||||
return {key: get_setting(key, default) for key, default in DHCP_DEFAULTS.items()}
|
cfg = {key: get_setting(key, default) for key, default in DHCP_DEFAULTS.items()}
|
||||||
|
available = _list_network_interfaces()
|
||||||
|
if available and cfg.get("dhcp_interface") not in available:
|
||||||
|
# Der hart codierte Default ("eth0") bzw. ein früher gespeicherter Wert
|
||||||
|
# existiert auf Systemen mit Predictable Network Interface Names
|
||||||
|
# (z.B. "enp1s0") nicht — dann lieber die tatsächlich vorhandene erste
|
||||||
|
# Schnittstelle vorschlagen, statt eine erkennbar falsche anzuzeigen
|
||||||
|
# (führte sonst dazu, dass die Erkennung fälschlich "eth0" statt der
|
||||||
|
# im Dropdown sichtbaren echten Schnittstelle prüfte).
|
||||||
|
cfg["dhcp_interface"] = available[0]
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def _detect_dhcp_status():
|
def _detect_dhcp_status():
|
||||||
@@ -1625,7 +1710,8 @@ def _detect_interface_network(interface):
|
|||||||
manuell pflegen zu lassen) — dadurch koppelt sich die generierte
|
manuell pflegen zu lassen) — dadurch koppelt sich die generierte
|
||||||
DHCP-Konfiguration immer an das Netz, in dem der Host tatsächlich
|
DHCP-Konfiguration immer an das Netz, in dem der Host tatsächlich
|
||||||
hängt, auch wenn sich dessen IP/Subnet mal ändert."""
|
hängt, auch wenn sich dessen IP/Subnet mal ändert."""
|
||||||
result = {"ok": False, "ip": None, "prefix": None, "netmask": None, "network": None, "gateway": None, "error": None}
|
result = {"ok": False, "ip": None, "prefix": None, "netmask": None, "network": None, "gateway": None,
|
||||||
|
"dynamic": None, "error": None}
|
||||||
if not interface:
|
if not interface:
|
||||||
result["error"] = "Kein Interface ausgewählt."
|
result["error"] = "Kein Interface ausgewählt."
|
||||||
return result
|
return result
|
||||||
@@ -1640,7 +1726,11 @@ def _detect_interface_network(interface):
|
|||||||
return result
|
return result
|
||||||
ip_str, prefix = match.group(1), int(match.group(2))
|
ip_str, prefix = match.group(1), int(match.group(2))
|
||||||
network = ipaddress.IPv4Network(f"{ip_str}/{prefix}", strict=False)
|
network = ipaddress.IPv4Network(f"{ip_str}/{prefix}", strict=False)
|
||||||
result.update(ok=True, ip=ip_str, prefix=prefix, network=network, netmask=str(network.netmask))
|
# Der Kernel markiert eine per DHCP bezogene Adresse mit "dynamic" —
|
||||||
|
# unabhängig vom Backend eine zuverlässige Quelle für den aktuellen
|
||||||
|
# DHCP/Statisch-Modus (genutzt von der netplan-Erkennung unten).
|
||||||
|
dynamic = bool(re.search(rf"inet {re.escape(ip_str)}/{prefix}\b[^\n]*\bdynamic\b", addr_out.stdout))
|
||||||
|
result.update(ok=True, ip=ip_str, prefix=prefix, network=network, netmask=str(network.netmask), dynamic=dynamic)
|
||||||
|
|
||||||
route_out = subprocess.run(
|
route_out = subprocess.run(
|
||||||
["ip", "-4", "route", "show", "default", "dev", interface],
|
["ip", "-4", "route", "show", "default", "dev", interface],
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ MarkupSafe==3.0.2
|
|||||||
paramiko==3.5.1
|
paramiko==3.5.1
|
||||||
pycparser==2.23
|
pycparser==2.23
|
||||||
PyNaCl==1.5.0
|
PyNaCl==1.5.0
|
||||||
|
PyYAML==6.0.2
|
||||||
simple-websocket==1.1.0
|
simple-websocket==1.1.0
|
||||||
Werkzeug==3.1.3
|
Werkzeug==3.1.3
|
||||||
|
|
||||||
@@ -20,3 +21,7 @@ Werkzeug==3.1.3
|
|||||||
# (reines Python) statt eines lokalen pty + System-ssh-Client und läuft
|
# (reines Python) statt eines lokalen pty + System-ssh-Client und läuft
|
||||||
# damit plattformunabhängig — auch unter Windows. Die SSH-Verbindung wird
|
# damit plattformunabhängig — auch unter Windows. Die SSH-Verbindung wird
|
||||||
# dabei immer serverseitig (vom PoE-Server) aufgebaut, nie vom Browser aus.
|
# dabei immer serverseitig (vom PoE-Server) aufgebaut, nie vom Browser aus.
|
||||||
|
#
|
||||||
|
# PyYAML wird für das netplan-Backend der Host-Netzwerkeinstellungen
|
||||||
|
# gebraucht (Systemeinstellungen → Netzwerkeinstellungen) — schreibt/liest
|
||||||
|
# die eigene Override-Datei unter /etc/netplan/.
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
{% if net_backend == 'unknown' %}
|
{% if net_backend == 'unknown' %}
|
||||||
<span class="pill unknown">Kein unterstütztes Backend erkannt</span>
|
<span class="pill unknown">Kein unterstütztes Backend erkannt</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="pill online">{{ 'NetworkManager' if net_backend == 'networkmanager' else 'dhcpcd' }}</span>
|
<span class="pill online">{{ {'networkmanager': 'NetworkManager', 'dhcpcd': 'dhcpcd', 'netplan': 'netplan'}[net_backend] }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if net_state %}
|
{% if net_state %}
|
||||||
<span class="mono text-faint" style="font-size:12px;">
|
<span class="mono text-faint" style="font-size:12px;">
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
</form>
|
</form>
|
||||||
{% elif net_backend == 'unknown' %}
|
{% elif net_backend == 'unknown' %}
|
||||||
<p class="text-faint" style="font-size:12.5px;">
|
<p class="text-faint" style="font-size:12.5px;">
|
||||||
Weder NetworkManager noch dhcpcd aktiv erkannt — Netzwerkänderungen über diese Seite sind deaktiviert.
|
Weder NetworkManager, dhcpcd noch netplan/systemd-networkd aktiv erkannt — Netzwerkänderungen über diese Seite sind deaktiviert.
|
||||||
Bitte die Netzwerkkonfiguration dieses Hosts manuell vornehmen.
|
Bitte die Netzwerkkonfiguration dieses Hosts manuell vornehmen.
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
Reference in New Issue
Block a user