feat: Settings changes now apply to real service config files and restart containers
Each service manager now has apply_config() that writes to the actual config:
- network: dhcp_range → dnsmasq.conf (reload cell-dhcp), ntp_servers → chrony.conf
(restart cell-ntp), domain → dnsmasq.conf domain= line
- email: domain → mailserver.env OVERRIDE_HOSTNAME + POSTMASTER_ADDRESS,
restart cell-mail
- wireguard: port/address/private_key → wg0.conf ListenPort/Address/PrivateKey,
restart cell-wireguard
- calendar: port → radicale config hosts=, restart cell-radicale
PUT /api/config now calls apply_config() after persisting JSON, and returns
{restarted: [...], warnings: [...]} so Settings UI can show which containers
were restarted. _restart_container() helper added to BaseServiceManager.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+71
-3
@@ -278,18 +278,86 @@ class NetworkManager(BaseServiceManager):
|
||||
def _reload_dns_service(self):
|
||||
"""Reload DNS service"""
|
||||
try:
|
||||
subprocess.run(['docker', 'exec', 'cell-dns', 'kill', '-HUP', '1'],
|
||||
subprocess.run(['docker', 'exec', 'cell-dns', 'kill', '-HUP', '1'],
|
||||
capture_output=True, timeout=10)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to reload DNS service: {e}")
|
||||
|
||||
|
||||
def _reload_dhcp_service(self):
|
||||
"""Reload DHCP service"""
|
||||
try:
|
||||
subprocess.run(['docker', 'exec', 'cell-dhcp', 'kill', '-HUP', '1'],
|
||||
subprocess.run(['docker', 'exec', 'cell-dhcp', 'kill', '-HUP', '1'],
|
||||
capture_output=True, timeout=10)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to reload DHCP service: {e}")
|
||||
|
||||
def apply_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Write config to real service files and reload/restart affected containers."""
|
||||
restarted = []
|
||||
warnings = []
|
||||
dnsmasq_changed = False
|
||||
|
||||
# DHCP range
|
||||
if 'dhcp_range' in config:
|
||||
try:
|
||||
dhcp_conf = os.path.join(self.config_dir, 'dhcp', 'dnsmasq.conf')
|
||||
if os.path.exists(dhcp_conf):
|
||||
with open(dhcp_conf) as f:
|
||||
lines = f.readlines()
|
||||
lines = [
|
||||
f"dhcp-range={config['dhcp_range']}\n" if l.startswith('dhcp-range=') else l
|
||||
for l in lines
|
||||
]
|
||||
with open(dhcp_conf, 'w') as f:
|
||||
f.writelines(lines)
|
||||
dnsmasq_changed = True
|
||||
except Exception as e:
|
||||
warnings.append(f"dhcp_range write failed: {e}")
|
||||
|
||||
# NTP servers
|
||||
if 'ntp_servers' in config and config['ntp_servers']:
|
||||
try:
|
||||
ntp_conf = os.path.join(self.config_dir, 'ntp', 'chrony.conf')
|
||||
if os.path.exists(ntp_conf):
|
||||
with open(ntp_conf) as f:
|
||||
lines = f.readlines()
|
||||
# Remove existing server lines, add new ones
|
||||
lines = [l for l in lines if not l.startswith('server ')]
|
||||
new_servers = [f"server {s} iburst\n" for s in config['ntp_servers']]
|
||||
lines = new_servers + lines
|
||||
with open(ntp_conf, 'w') as f:
|
||||
f.writelines(lines)
|
||||
self._restart_container('cell-ntp')
|
||||
restarted.append('cell-ntp')
|
||||
except Exception as e:
|
||||
warnings.append(f"ntp_servers write failed: {e}")
|
||||
|
||||
if dnsmasq_changed:
|
||||
self._reload_dhcp_service()
|
||||
restarted.append('cell-dhcp (reloaded)')
|
||||
|
||||
return {'restarted': restarted, 'warnings': warnings}
|
||||
|
||||
def apply_domain(self, domain: str) -> Dict[str, Any]:
|
||||
"""Update domain in dnsmasq config and reload."""
|
||||
restarted = []
|
||||
warnings = []
|
||||
try:
|
||||
dhcp_conf = os.path.join(self.config_dir, 'dhcp', 'dnsmasq.conf')
|
||||
if os.path.exists(dhcp_conf):
|
||||
with open(dhcp_conf) as f:
|
||||
lines = f.readlines()
|
||||
lines = [
|
||||
f"domain={domain}\n" if l.startswith('domain=') else l
|
||||
for l in lines
|
||||
]
|
||||
with open(dhcp_conf, 'w') as f:
|
||||
f.writelines(lines)
|
||||
self._reload_dhcp_service()
|
||||
restarted.append('cell-dhcp (reloaded)')
|
||||
except Exception as e:
|
||||
warnings.append(f"domain write to dnsmasq failed: {e}")
|
||||
return {'restarted': restarted, 'warnings': warnings}
|
||||
|
||||
def test_dns_resolution(self, domain: str) -> Dict:
|
||||
"""Test DNS resolution for a domain using Python socket."""
|
||||
|
||||
Reference in New Issue
Block a user