Check if we've switched networks and clear old data if so
()
| 3938 | download_name=os.path.basename(target), mimetype='application/x-ndjson') |
| 3939 | |
| 3940 | |
| 3941 | @app.route('/api/rusense/diagnostics', methods=['GET']) |
| 3942 | def rusense_diagnostics(): |
| 3943 | """One-shot deep diagnostics bundle for CSI-node debugging. Runs the exact |
| 3944 | server-side commands a human would (tcpdump on the CSI UDP port, journalctl |
| 3945 | for the sensing engine, ss/systemctl, system + wifi state, binary md5s) AND |
| 3946 | the sensing-server API snapshots, so the Nodes-tab 'Download logs' captures |
| 3947 | EVERYTHING in one file. Local route; the webapp runs as root so the shell |
| 3948 | commands work. ?secs=6 controls the tcpdump window (2-20).""" |
| 3949 | import subprocess |
| 3950 | import hashlib |
| 3951 | try: |
| 3952 | secs = int(request.args.get('secs', 6)) |
| 3953 | except (TypeError, ValueError): |
| 3954 | secs = 6 |
| 3955 | secs = max(2, min(20, secs)) |
| 3956 | |
| 3957 | def run(cmd, timeout=12): |
| 3958 | try: |
| 3959 | r = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) |
| 3960 | return {'cmd': ' '.join(cmd), 'rc': r.returncode, |
| 3961 | 'stdout': (r.stdout or '')[-24000:], 'stderr': (r.stderr or '')[-4000:]} |
| 3962 | except FileNotFoundError: |
| 3963 | return {'cmd': ' '.join(cmd), 'error': 'command not installed'} |
| 3964 | except subprocess.TimeoutExpired: |
| 3965 | return {'cmd': ' '.join(cmd), 'error': f'timeout after {timeout}s'} |
| 3966 | except Exception as exc: |
| 3967 | return {'cmd': ' '.join(cmd), 'error': str(exc)} |
| 3968 | |
| 3969 | def md5(path): |
| 3970 | try: |
| 3971 | h = hashlib.md5() |
| 3972 | with open(path, 'rb') as fh: |
| 3973 | for chunk in iter(lambda: fh.read(65536), b''): |
| 3974 | h.update(chunk) |
| 3975 | return h.hexdigest() |
| 3976 | except Exception as exc: |
| 3977 | return f'err: {exc}' |
| 3978 | |
| 3979 | # tcpdump the CSI UDP port for `secs` (bounded by packet count too). `-i any` |
| 3980 | # is portable; the raw lines carry source IP + payload length per packet. |
| 3981 | udp = run(['timeout', str(secs), 'tcpdump', '-i', 'any', '-n', '-c', '500', |
| 3982 | 'udp', 'port', '5005'], timeout=secs + 8) |
| 3983 |
no test coverage detected