Synchronize all counts (targets, ports, vulnerabilities, credentials) across data sources. This function reads from SQLite database as the single source of truth and applies the 30-ping failure rule to determine which hosts are considered active (alive vs degraded).
()
| 3274 | mesh_tag=_mesh_tag()) |
| 3275 | return jsonify({'success': True, 'result': result}) |
| 3276 | |
| 3277 | |
| 3278 | @app.route('/api/mesh/install', methods=['POST']) |
| 3279 | def mesh_install(): |
| 3280 | """Install the Tailscale client on this unit from the web UI. |
| 3281 | |
| 3282 | A stock Ragnar does not ship Tailscale — the mesh is opt-in — and `update` |
| 3283 | only installs it once a unit has opted in (auth key, boot config, or |
| 3284 | mesh_enabled). This route is the third onboarding path: a fresh unit whose |
| 3285 | operator opened the Mesh tab and wants to start here. Idempotent; the script |
| 3286 | no-ops if Tailscale is already present. |
| 3287 | """ |
| 3288 | global _mesh_installing |
| 3289 | if not mesh_available: |
| 3290 | return jsonify({'success': False, 'error': 'mesh_manager unavailable'}), 503 |
| 3291 | if mesh_manager.installed(): |
| 3292 | return jsonify({'success': True, 'message': 'Tailscale is already installed.', |
| 3293 | 'installing': False}) |
| 3294 | if not os.path.isfile(MESH_INSTALL_SCRIPT): |
| 3295 | return jsonify({'success': False, |
| 3296 | 'message': 'scripts/setup_mesh.sh is missing — reinstall or update Ragnar.'}), 500 |
| 3297 | with _mesh_install_lock: |
| 3298 | if _mesh_installing: |
| 3299 | return jsonify({'success': True, 'message': 'Install already in progress.', |
| 3300 | 'installing': True}) |
| 3301 | _mesh_installing = True |
| 3302 | try: |
| 3303 | open(MESH_INSTALL_LOG, 'w').close() # fresh log per run |
| 3304 | except OSError: |
| 3305 | pass |
| 3306 | threading.Thread(target=_run_mesh_install, daemon=True, name='mesh-install').start() |
| 3307 | return jsonify({'success': True, 'message': 'Tailscale install started.', |
| 3308 | 'installing': True}) |
| 3309 | |
| 3310 | |
| 3311 | @app.route('/api/mesh/install-log', methods=['GET']) |
| 3312 | def mesh_install_log(): |
| 3313 | """Live install log plus whether Tailscale is now present. Polled by the tab.""" |
| 3314 | with _mesh_install_lock: |
| 3315 | installing = _mesh_installing |
| 3316 | log = '' |
| 3317 | try: |
| 3318 | with open(MESH_INSTALL_LOG, 'r') as fh: |
| 3319 | log = fh.read()[-8000:] # tail — the whole apt log is not useful |
| 3320 | except OSError: |
| 3321 | pass |
| 3322 | return jsonify({'success': True, 'installing': installing, |
| 3323 | 'installed': mesh_manager.installed() if mesh_available else False, |
| 3324 | 'log': log}) |
| 3325 | |
| 3326 | |
| 3327 | @app.route('/api/mesh/tunnel', methods=['POST']) |
| 3328 | def mesh_tunnel(): |
| 3329 | """Bring the tunnel up or down without logging out.""" |
| 3330 | if not mesh_available: |
| 3331 | return jsonify({'success': False, 'error': 'mesh_manager unavailable'}), 503 |
| 3332 | data = request.get_json(silent=True) or {} |
| 3333 | ok, message = mesh_manager.set_running(bool(data.get('up', True))) |
no test coverage detected