Files
zeekayandHanzo Dev 1ab6e799c1 cd: the module is github.com/hanzoai/cd, where it is actually hosted
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.

3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.

go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 21:16:24 -07:00

153 lines
4.3 KiB
Go

package health
import (
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/hanzoai/cd/gitops-engine/pkg/sync/hook"
"github.com/hanzoai/cd/gitops-engine/pkg/utils/kube"
)
// Represents resource health status
type HealthStatusCode string
const (
// Indicates that health assessment failed and actual health status is unknown
HealthStatusUnknown HealthStatusCode = "Unknown"
// Progressing health status means that resource is not healthy but still have a chance to reach healthy state
HealthStatusProgressing HealthStatusCode = "Progressing"
// Resource is 100% healthy
HealthStatusHealthy HealthStatusCode = "Healthy"
// Assigned to resources that are suspended or paused. The typical example is a
// [suspended](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#suspend) CronJob.
HealthStatusSuspended HealthStatusCode = "Suspended"
// Degrade status is used if resource status indicates failure or resource could not reach healthy state
// within some timeout.
HealthStatusDegraded HealthStatusCode = "Degraded"
// Indicates that resource is missing in the cluster.
HealthStatusMissing HealthStatusCode = "Missing"
)
// Implements custom health assessment that overrides built-in assessment
type HealthOverride interface {
GetResourceHealth(obj *unstructured.Unstructured) (*HealthStatus, error)
}
// Holds health assessment results
type HealthStatus struct {
Status HealthStatusCode `json:"status,omitempty"`
Message string `json:"message,omitempty"`
}
// healthOrder is a list of health codes in order of most healthy to least healthy
var healthOrder = []HealthStatusCode{
HealthStatusHealthy,
HealthStatusSuspended,
HealthStatusProgressing,
HealthStatusMissing,
HealthStatusDegraded,
HealthStatusUnknown,
}
// IsWorse returns whether or not the new health status code is a worse condition than the current
func IsWorse(current, new HealthStatusCode) bool {
currentIndex := 0
newIndex := 0
for i, code := range healthOrder {
if current == code {
currentIndex = i
}
if new == code {
newIndex = i
}
}
return newIndex > currentIndex
}
// GetResourceHealth returns the health of a k8s resource
func GetResourceHealth(obj *unstructured.Unstructured, healthOverride HealthOverride) (health *HealthStatus, err error) {
if obj.GetDeletionTimestamp() != nil && !hook.HasHookFinalizer(obj) {
return &HealthStatus{
Status: HealthStatusProgressing,
Message: "Pending deletion",
}, nil
}
if healthOverride != nil {
health, err := healthOverride.GetResourceHealth(obj)
if err != nil {
health = &HealthStatus{
Status: HealthStatusUnknown,
Message: err.Error(),
}
return health, fmt.Errorf("failed to get resource health for %s/%s: %w", obj.GetNamespace(), obj.GetName(), err)
}
if health != nil {
return health, nil
}
}
if healthCheck := GetHealthCheckFunc(obj.GroupVersionKind()); healthCheck != nil {
if health, err = healthCheck(obj); err != nil {
health = &HealthStatus{
Status: HealthStatusUnknown,
Message: err.Error(),
}
}
}
return health, err
}
// GetHealthCheckFunc returns built-in health check function or nil if health check is not supported
func GetHealthCheckFunc(gvk schema.GroupVersionKind) func(obj *unstructured.Unstructured) (*HealthStatus, error) {
switch gvk.Group {
case "apps":
switch gvk.Kind {
case kube.DeploymentKind:
return getDeploymentHealth
case kube.StatefulSetKind:
return getStatefulSetHealth
case kube.ReplicaSetKind:
return getReplicaSetHealth
case kube.DaemonSetKind:
return getDaemonSetHealth
}
case "extensions":
if gvk.Kind == kube.IngressKind {
return getIngressHealth
}
case "apps.hanzo.ai":
if gvk.Kind == "Workflow" {
return getArgoWorkflowHealth
}
case "apiregistration.k8s.io":
if gvk.Kind == kube.APIServiceKind {
return getAPIServiceHealth
}
case "networking.k8s.io":
if gvk.Kind == kube.IngressKind {
return getIngressHealth
}
case "":
switch gvk.Kind {
case kube.ServiceKind:
return getServiceHealth
case kube.PersistentVolumeClaimKind:
return getPVCHealth
case kube.PodKind:
return getPodHealth
}
case "batch":
if gvk.Kind == kube.JobKind {
return getJobHealth
}
case "autoscaling":
if gvk.Kind == kube.HorizontalPodAutoscalerKind {
return getHPAHealth
}
}
return nil
}