feat: DDNS self-healing heartbeat + manual re-register endpoint
Unit Tests / test (push) Successful in 15m26s

- DDNSTokenExpired exception triggers auto re-register in update_ip()
  so cells recover silently after a DDNS DB reset
- POST /api/ddns/register lets the user force re-registration from Settings
- Re-register button in Settings → External Domain & DDNS (pic_ngo only)
- 3 new tests covering register endpoint: wrong provider, missing name, success

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 15:05:27 -04:00
parent cde177966d
commit 0b31d02f10
5 changed files with 106 additions and 3 deletions
+24
View File
@@ -561,6 +561,30 @@ def update_ddns_config():
return jsonify({'error': str(e)}), 500
@bp.route('/api/ddns/register', methods=['POST'])
def ddns_register():
"""Trigger (re-)registration with the configured DDNS provider."""
try:
from app import config_manager
ddns_cfg = config_manager.configs.get('ddns', {})
if ddns_cfg.get('provider') != 'pic_ngo':
return jsonify({'error': 'Re-registration only supported for pic_ngo provider'}), 400
identity = config_manager.configs.get('_identity', {})
cell_name = identity.get('cell_name', os.environ.get('CELL_NAME', ''))
if not cell_name:
return jsonify({'error': 'cell_name not configured'}), 400
from ddns_manager import DDNSManager as _DDNSManager
_mgr = _DDNSManager(config_manager)
result = _mgr.register(cell_name, '')
new_sub = result.get('subdomain', f'{cell_name}.pic.ngo')
config_manager.set_identity_field('domain_name', new_sub)
logger.info('DDNS registered via /api/ddns/register: cell_name=%r subdomain=%r', cell_name, new_sub)
return jsonify({'registered': True, 'subdomain': new_sub})
except Exception as e:
logger.error('Error in /api/ddns/register: %s', e)
return jsonify({'error': str(e)}), 500
@bp.route('/api/config/pending', methods=['GET'])
def get_pending_config():
from app import config_manager