feat: métriques réseau+hardware serveur+dashboard + API /agents/{id} + iperf3
Serveur:
- Modèles Go: NetworkInterface, HardwareInfo dans Agent + AgentMetrics
- DB: migrations network_info_json + hardware_info_json dans agents
- UpsertAgent: stocke les données lentes si présentes dans le payload
- GetAgents: désérialise network_info_json + hardware_info_json
- GET /api/agents/{id}: endpoint single agent
- docker-compose: service iperf3 (port 5201)
Dashboard:
- Popup détail: section RÉSEAU (tableau interfaces: type, vitesse, MAC, WoL, iperf3)
- Popup détail: section HARDWARE (carte mère, CPU, RAM slots/type/vitesse)
- CSS: .net-table/.net-row pour le tableau réseau
- Font-size global appliqué sur html root (au lieu de body)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+31
-6
@@ -68,6 +68,8 @@ func (d *DB) migrate() error {
|
||||
_, _ = d.conn.Exec(`ALTER TABLE metrics ADD COLUMN smart_hours INTEGER`)
|
||||
_, _ = d.conn.Exec(`ALTER TABLE metrics ADD COLUMN smart_wear INTEGER`)
|
||||
_, _ = d.conn.Exec(`ALTER TABLE metrics ADD COLUMN smart_json TEXT`)
|
||||
_, _ = d.conn.Exec(`ALTER TABLE agents ADD COLUMN network_info_json TEXT`)
|
||||
_, _ = d.conn.Exec(`ALTER TABLE agents ADD COLUMN hardware_info_json TEXT`)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -75,13 +77,27 @@ func (d *DB) Close() { _ = d.conn.Close() }
|
||||
|
||||
func (d *DB) UpsertAgent(m *models.AgentMetrics) error {
|
||||
ts := time.Now().Unix()
|
||||
var netJSON, hwJSON interface{}
|
||||
if len(m.NetworkInfo) > 0 {
|
||||
if b, err := json.Marshal(m.NetworkInfo); err == nil {
|
||||
netJSON = string(b)
|
||||
}
|
||||
}
|
||||
if m.HardwareInfo != nil {
|
||||
if b, err := json.Marshal(m.HardwareInfo); err == nil {
|
||||
hwJSON = string(b)
|
||||
}
|
||||
}
|
||||
_, err := d.conn.Exec(`
|
||||
INSERT INTO agents (id, hostname, ip, status, last_seen, version)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO agents (id, hostname, ip, status, last_seen, version,
|
||||
network_info_json, hardware_info_json)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
ip=excluded.ip, status=excluded.status, last_seen=excluded.last_seen,
|
||||
version=CASE WHEN excluded.version != '' THEN excluded.version ELSE version END`,
|
||||
m.Hostname, m.Hostname, m.IP, m.Status, ts, m.Version)
|
||||
version=CASE WHEN excluded.version != '' THEN excluded.version ELSE version END,
|
||||
network_info_json=CASE WHEN excluded.network_info_json IS NOT NULL THEN excluded.network_info_json ELSE network_info_json END,
|
||||
hardware_info_json=CASE WHEN excluded.hardware_info_json IS NOT NULL THEN excluded.hardware_info_json ELSE hardware_info_json END`,
|
||||
m.Hostname, m.Hostname, m.IP, m.Status, ts, m.Version, netJSON, hwJSON)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -109,7 +125,8 @@ func (d *DB) InsertMetrics(m *models.AgentMetrics) error {
|
||||
}
|
||||
|
||||
func (d *DB) GetAgents() ([]models.Agent, error) {
|
||||
rows, err := d.conn.Query(`SELECT id, hostname, ip, status, last_seen, version FROM agents`)
|
||||
rows, err := d.conn.Query(`SELECT id, hostname, ip, status, last_seen, version,
|
||||
network_info_json, hardware_info_json FROM agents`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -117,9 +134,17 @@ func (d *DB) GetAgents() ([]models.Agent, error) {
|
||||
var agents []models.Agent
|
||||
for rows.Next() {
|
||||
var a models.Agent
|
||||
if err := rows.Scan(&a.ID, &a.Hostname, &a.IP, &a.Status, &a.LastSeen, &a.Version); err != nil {
|
||||
var netJSON, hwJSON *string
|
||||
if err := rows.Scan(&a.ID, &a.Hostname, &a.IP, &a.Status, &a.LastSeen, &a.Version,
|
||||
&netJSON, &hwJSON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if netJSON != nil {
|
||||
_ = json.Unmarshal([]byte(*netJSON), &a.NetworkInfo)
|
||||
}
|
||||
if hwJSON != nil {
|
||||
_ = json.Unmarshal([]byte(*hwJSON), &a.HardwareInfo)
|
||||
}
|
||||
agents = append(agents, a)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user