fix: DDNS register() always sends public IP and saves token to correct location
Unit Tests / test (push) Successful in 15m27s
Unit Tests / test (push) Successful in 15m27s
Two bugs that prevented registration from working after wizard completion: 1. register(name, '') sent empty IP; server stored blank A record. Now calls _get_public_ip() when ip is empty so the A record is always set correctly. 2. Token was saved to _identity.domain.ddns.token (TypeError when domain is a string) instead of the top-level ddns config where update_ip() reads it. Subdomain also now correctly written to _identity.domain_name. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+14
-12
@@ -386,27 +386,29 @@ class DDNSManager(BaseServiceManager):
|
||||
def register(self, name: str, ip: str) -> dict:
|
||||
"""Register the cell's subdomain with the configured provider.
|
||||
|
||||
Stores the returned token in the identity config under
|
||||
identity['domain']['ddns']['token'] and records the subdomain.
|
||||
Fetches the public IP via ipify when ip is empty.
|
||||
Stores the returned token in the top-level ddns config (where
|
||||
update_ip reads it) and updates _identity.domain_name.
|
||||
Returns the dict from provider.register().
|
||||
"""
|
||||
provider = self.get_provider()
|
||||
if provider is None:
|
||||
raise DDNSError("No DDNS provider configured")
|
||||
|
||||
if not ip:
|
||||
ip = _get_public_ip() or ''
|
||||
|
||||
result = provider.register(name, ip)
|
||||
|
||||
# Persist token + subdomain back into identity
|
||||
identity = self._identity()
|
||||
domain_cfg = dict(identity.get('domain', {}))
|
||||
ddns_cfg = dict(domain_cfg.get('ddns', {}))
|
||||
if 'token' in result:
|
||||
ddns_cfg['token'] = result['token']
|
||||
if 'subdomain' in result:
|
||||
ddns_cfg['subdomain'] = result['subdomain']
|
||||
domain_cfg['ddns'] = ddns_cfg
|
||||
if self.config_manager is not None:
|
||||
self.config_manager.set_identity_field('domain', domain_cfg)
|
||||
# Token lives in the top-level ddns config so update_ip() can find it
|
||||
if 'token' in result:
|
||||
ddns_cfg = dict(self.config_manager.configs.get('ddns', {}))
|
||||
ddns_cfg['token'] = result['token']
|
||||
self.config_manager.set_ddns_config(ddns_cfg)
|
||||
# Keep domain_name in identity up to date
|
||||
if 'subdomain' in result:
|
||||
self.config_manager.set_identity_field('domain_name', result['subdomain'])
|
||||
|
||||
self._last_ip = ip
|
||||
return result
|
||||
|
||||
@@ -307,22 +307,50 @@ class TestUpdateIp(unittest.TestCase):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestRegister(unittest.TestCase):
|
||||
def test_register_stores_token_in_config(self):
|
||||
def test_register_stores_token_in_ddns_config(self):
|
||||
cm = _make_config_manager(ddns_cfg={'provider': 'pic_ngo'})
|
||||
mgr = DDNSManager(config_manager=cm)
|
||||
|
||||
mock_provider = MagicMock()
|
||||
mock_provider.register.return_value = {'token': 'new_tok', 'subdomain': 'alpha'}
|
||||
mock_provider.register.return_value = {'token': 'new_tok', 'subdomain': 'alpha.pic.ngo'}
|
||||
mgr.get_provider = MagicMock(return_value=mock_provider)
|
||||
|
||||
result = mgr.register('alpha', '1.2.3.4')
|
||||
self.assertEqual(result['token'], 'new_tok')
|
||||
|
||||
# set_identity_field('domain', ...) should have been called
|
||||
cm.set_identity_field.assert_called_once()
|
||||
field_name, field_value = cm.set_identity_field.call_args[0]
|
||||
self.assertEqual(field_name, 'domain')
|
||||
self.assertEqual(field_value['ddns']['token'], 'new_tok')
|
||||
# Token saved to top-level ddns config so update_ip() can find it
|
||||
cm.set_ddns_config.assert_called_once()
|
||||
saved_ddns = cm.set_ddns_config.call_args[0][0]
|
||||
self.assertEqual(saved_ddns['token'], 'new_tok')
|
||||
|
||||
# Subdomain saved to _identity.domain_name
|
||||
cm.set_identity_field.assert_called_once_with('domain_name', 'alpha.pic.ngo')
|
||||
|
||||
def test_register_fetches_public_ip_when_empty(self):
|
||||
cm = _make_config_manager(ddns_cfg={'provider': 'pic_ngo'})
|
||||
mgr = DDNSManager(config_manager=cm)
|
||||
|
||||
mock_provider = MagicMock()
|
||||
mock_provider.register.return_value = {'token': 't', 'subdomain': 'alpha.pic.ngo'}
|
||||
mgr.get_provider = MagicMock(return_value=mock_provider)
|
||||
|
||||
with patch('ddns_manager._get_public_ip', return_value='5.6.7.8') as mock_ip:
|
||||
mgr.register('alpha', '')
|
||||
mock_ip.assert_called_once()
|
||||
mock_provider.register.assert_called_once_with('alpha', '5.6.7.8')
|
||||
|
||||
def test_register_uses_provided_ip_without_fetching(self):
|
||||
cm = _make_config_manager(ddns_cfg={'provider': 'pic_ngo'})
|
||||
mgr = DDNSManager(config_manager=cm)
|
||||
|
||||
mock_provider = MagicMock()
|
||||
mock_provider.register.return_value = {'token': 't', 'subdomain': 'alpha.pic.ngo'}
|
||||
mgr.get_provider = MagicMock(return_value=mock_provider)
|
||||
|
||||
with patch('ddns_manager._get_public_ip') as mock_ip:
|
||||
mgr.register('alpha', '1.2.3.4')
|
||||
mock_ip.assert_not_called()
|
||||
mock_provider.register.assert_called_once_with('alpha', '1.2.3.4')
|
||||
|
||||
def test_register_raises_when_no_provider(self):
|
||||
cm = _make_config_manager()
|
||||
|
||||
Reference in New Issue
Block a user