Fix network panel: include netscan devices; fix Scan Now to queue agent command

This commit is contained in:
2026-05-30 03:26:53 +00:00
parent e08b80a6c6
commit 50c06722bb
2 changed files with 44 additions and 22 deletions
+22 -1
View File
@@ -149,7 +149,28 @@ if ($action === 'scan') {
]; ];
} }
// 3. External services we can actually ping from DO // 3. Netscan-discovered devices (PVE1 nmap push — status from last scan)
$discovered = JarvisDB::query(
'SELECT ip, mac, hostname, device_type, status, last_seen FROM network_devices
WHERE (alias IS NULL OR alias = "") AND last_seen > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
ORDER BY ip'
);
foreach ($discovered as $dev) {
if (in_array($dev['ip'], $agentIPs)) continue;
$devices[] = [
'ip' => $dev['ip'],
'name' => $dev['hostname'] ?: ($dev['device_type'] ?: $dev['ip']),
'mac' => $dev['mac'],
'type' => $dev['device_type'] ?: 'device',
'alive' => $dev['status'] === 'online',
'status' => $dev['status'],
'last_seen' => $dev['last_seen'],
'source' => 'netscan',
'deletable' => false,
];
}
// 4. External services we can actually ping from DO
$external = [ $external = [
['ip' => '134.209.72.226', 'name' => 'FusionPBX DO', 'type' => 'server'], ['ip' => '134.209.72.226', 'name' => 'FusionPBX DO', 'type' => 'server'],
]; ];
+22 -21
View File
@@ -88,23 +88,20 @@ if ($action) {
j(JarvisDB::query('SELECT id,ip,mac,hostname,alias,device_type,status,last_seen FROM network_devices ORDER BY status="online" DESC, COALESCE(alias,hostname,ip)')); j(JarvisDB::query('SELECT id,ip,mac,hostname,alias,device_type,status,last_seen FROM network_devices ORDER BY status="online" DESC, COALESCE(alias,hostname,ip)'));
case 'network_scan': case 'network_scan':
// Trigger immediate nmap scan via PVE1 // Queue shell command to PVE1 agent — it runs jarvis-netscan.sh and pushes results back
$out = shell_exec("sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@10.48.200.90 'nmap -sn --send-ip 10.48.200.0/24 2>/dev/null' 2>/dev/null"); $pve1 = JarvisDB::single('SELECT agent_id FROM registered_agents WHERE ip_address="10.48.200.90" AND status="online" LIMIT 1');
$count = 0; if (!$pve1) {
if ($out) { $pve1 = JarvisDB::single('SELECT agent_id FROM registered_agents WHERE hostname LIKE "%pve%" AND status="online" LIMIT 1');
$cur = null; }
foreach (explode("\n", $out) as $line) { if ($pve1) {
$line = trim($line); JarvisDB::execute(
if (preg_match('/Nmap scan report for (?:(\S+) \()?(\d+\.\d+\.\d+\.\d+)\)?/', $line, $m)) { 'INSERT INTO agent_commands (agent_id, command_type, command_data, status) VALUES (?,?,?,?)',
if ($cur) { self_upsert_device($cur); $count++; } [$pve1['agent_id'], 'shell', json_encode(['command'=>'/usr/local/bin/jarvis-netscan.sh','allowed'=>true]), 'pending']
$cur = ['hostname' => ($m[1] && $m[1] !== $m[2]) ? $m[1] : null, 'ip' => $m[2], 'mac' => null, 'vendor' => null]; );
} elseif ($cur && preg_match('/MAC Address: ([0-9A-Fa-f:]{17}) \(([^)]+)\)/i', $line, $m)) { j(['ok' => true, 'queued' => true, 'note' => 'Scan command sent to PVE1 agent — results in ~40 seconds']);
$cur['mac'] = strtolower($m[1]); $cur['vendor'] = $m[2] !== 'Unknown' ? $m[2] : null; } else {
} j(['ok' => false, 'note' => 'PVE1 agent offline — scan will run automatically via cron in < 3 minutes']);
}
if ($cur) { self_upsert_device($cur); $count++; }
} }
j(['ok' => true, 'found' => $count]);
case 'network_save': case 'network_save':
$id = (int)($_POST['id'] ?? 0); $id = (int)($_POST['id'] ?? 0);
@@ -762,15 +759,19 @@ function renderNetwork() {
async function scanNow() { async function scanNow() {
const btn = document.getElementById('scanBtn'); const btn = document.getElementById('scanBtn');
btn.textContent = 'SCANNING...'; btn.disabled = true; btn.textContent = 'QUEUING...'; btn.disabled = true;
const fd = new FormData(); fd.append('action','network_scan'); const fd = new FormData(); fd.append('action','network_scan');
try { try {
const r = await fetch(location.href,{method:'POST',body:fd}); const r = await fetch(location.href,{method:'POST',body:fd});
const d = await r.json(); const d = await r.json();
if (d.ok) { toast(`Scan complete — ${d.found} devices found`,'ok'); loadNetwork(); } if (d.ok && d.queued) {
else toast(d.error||'Scan failed','err'); toast('Scan queued — refreshing in 45s...','ok');
} catch(e){ toast('Scan failed','err'); } setTimeout(()=>{ loadNetwork(); }, 45000);
btn.textContent = 'SCAN NOW'; btn.disabled = false; } else {
toast(d.note || 'Scan scheduled via cron','ok');
}
} catch(e){ toast('Request failed','err'); }
setTimeout(()=>{ btn.textContent='SCAN NOW'; btn.disabled=false; }, 5000);
} }
function netModal(id=0, ip='', alias='', type='') { function netModal(id=0, ip='', alias='', type='') {