cli/pkg/lab/collector/docker.go
Claude 50da0adcb7 feat: integrate lab dashboard as core lab serve
Port the standalone lab dashboard (lab.lthn.io) into the core CLI as
pkg/lab/ with collectors, handlers, and HTML templates. The dashboard
monitors machines, Docker containers, Forgejo, HuggingFace models,
training runs, and InfluxDB metrics with SSE live updates.

New command: core lab serve --bind :8080

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 05:53:52 +00:00

94 lines
1.8 KiB
Go

package collector
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"time"
"forge.lthn.ai/core/cli/pkg/lab"
)
type Docker struct {
store *lab.Store
}
func NewDocker(s *lab.Store) *Docker {
return &Docker{store: s}
}
func (d *Docker) Name() string { return "docker" }
func (d *Docker) Collect(ctx context.Context) error {
client := &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", "/var/run/docker.sock")
},
},
}
req, err := http.NewRequestWithContext(ctx, "GET", "http://docker/containers/json?all=true", nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
d.store.SetError("docker", err)
return err
}
defer resp.Body.Close()
var containers []struct {
Names []string `json:"Names"`
Image string `json:"Image"`
State string `json:"State"`
Status string `json:"Status"`
Created int64 `json:"Created"`
}
if err := json.NewDecoder(resp.Body).Decode(&containers); err != nil {
d.store.SetError("docker", err)
return err
}
var result []lab.Container
for _, c := range containers {
name := ""
if len(c.Names) > 0 {
name = c.Names[0]
if len(name) > 0 && name[0] == '/' {
name = name[1:]
}
}
created := time.Unix(c.Created, 0)
uptime := ""
if c.State == "running" {
d := time.Since(created)
days := int(d.Hours()) / 24
hours := int(d.Hours()) % 24
if days > 0 {
uptime = fmt.Sprintf("%dd %dh", days, hours)
} else {
uptime = fmt.Sprintf("%dh %dm", hours, int(d.Minutes())%60)
}
}
result = append(result, lab.Container{
Name: name,
Status: c.State,
Image: c.Image,
Uptime: uptime,
Created: created,
})
}
d.store.SetContainers(result)
d.store.SetError("docker", nil)
return nil
}