diff --git a/models/actions/runner.go b/models/actions/runner.go index b1bf8450dc..27ff09340c 100644 --- a/models/actions/runner.go +++ b/models/actions/runner.go @@ -118,8 +118,17 @@ func (r *ActionRunner) StatusName() string { return strings.ToLower(strings.TrimPrefix(r.Status().String(), "RUNNER_STATUS_")) } +// DisplayStatusName returns the status name for display, considering health status +// Returns "unhealthy" if the runner is online but has health issues +func (r *ActionRunner) DisplayStatusName() string { + if r.IsOnline() && !r.IsHealthy() { + return "unhealthy" + } + return r.StatusName() +} + func (r *ActionRunner) StatusLocaleName(lang translation.Locale) string { - return lang.TrString("actions.runners.status." + r.StatusName()) + return lang.TrString("actions.runners.status." + r.DisplayStatusName()) } func (r *ActionRunner) IsOnline() bool { diff --git a/modules/structs/actions_capabilities.go b/modules/structs/actions_capabilities.go index a2d965faec..730828c231 100644 --- a/modules/structs/actions_capabilities.go +++ b/modules/structs/actions_capabilities.go @@ -21,6 +21,15 @@ type DiskInfo struct { UsedPercent float64 `json:"used_percent"` } +// CPUInfo holds CPU load information for a runner +type CPUInfo struct { + NumCPU int `json:"num_cpu"` + LoadAvg1m float64 `json:"load_avg_1m"` + LoadAvg5m float64 `json:"load_avg_5m"` + LoadAvg15m float64 `json:"load_avg_15m"` + LoadPercent float64 `json:"load_percent"` +} + // DistroInfo holds Linux distribution information type DistroInfo struct { ID string `json:"id,omitempty"` // e.g., "ubuntu", "debian", "fedora" @@ -52,6 +61,7 @@ type RunnerCapability struct { Features *CapabilityFeatures `json:"features,omitempty"` Limitations []string `json:"limitations,omitempty"` Disk *DiskInfo `json:"disk,omitempty"` + CPU *CPUInfo `json:"cpu,omitempty"` Bandwidth *BandwidthInfo `json:"bandwidth,omitempty"` SuggestedLabels []string `json:"suggested_labels,omitempty"` } diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 722946a09a..47d34f8e18 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -3702,6 +3702,7 @@ "actions.runners.status.idle": "Idle", "actions.runners.status.active": "Active", "actions.runners.status.offline": "Offline", + "actions.runners.status.unhealthy": "Unhealthy", "actions.runners.version": "Version", "actions.runners.reset_registration_token": "Reset registration token", "actions.runners.reset_registration_token_confirm": "Would you like to invalidate the current token and generate a new one?", diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index e24dd35513..bbe2b5b8b9 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -610,6 +610,7 @@ func RunnerStatusJSON(ctx *context.Context) { "id": runner.ID, "name": runner.Name, "is_online": runner.IsOnline(), + "is_healthy": runner.IsHealthy(), "status": runner.StatusLocaleName(ctx.Locale), "version": runner.Version, "labels": runner.AgentLabels, @@ -628,6 +629,15 @@ func RunnerStatusJSON(ctx *context.Context) { "used_percent": caps.Disk.UsedPercent, } } + if caps.CPU != nil { + response["cpu"] = map[string]any{ + "num_cpu": caps.CPU.NumCPU, + "load_avg_1m": caps.CPU.LoadAvg1m, + "load_avg_5m": caps.CPU.LoadAvg5m, + "load_avg_15m": caps.CPU.LoadAvg15m, + "load_percent": caps.CPU.LoadPercent, + } + } if caps.Bandwidth != nil { bw := map[string]any{ "download_mbps": caps.Bandwidth.DownloadMbps, @@ -676,6 +686,7 @@ func RunnersStatusJSON(ctx *context.Context) { item := map[string]any{ "id": runner.ID, "is_online": runner.IsOnline(), + "is_healthy": runner.IsHealthy(), "status": runner.StatusLocaleName(ctx.Locale), "version": runner.Version, } diff --git a/templates/shared/actions/runner_edit.tmpl b/templates/shared/actions/runner_edit.tmpl index 220e17fa4d..9be1373cca 100644 --- a/templates/shared/actions/runner_edit.tmpl +++ b/templates/shared/actions/runner_edit.tmpl @@ -4,7 +4,7 @@
{{.Name}}