forked from kudobuilder/kudo
/
ready.go
111 lines (101 loc) · 3.88 KB
/
ready.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package health
import (
"context"
"encoding/json"
"fmt"
kudov1alpha1 "github.com/kudobuilder/kudo/pkg/apis/kudo/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
"k8s.io/apimachinery/pkg/runtime"
"log"
"sigs.k8s.io/controller-runtime/pkg/client"
)
//IsHealthy returns whether an object is healthy. Must be implemented for each type
func IsHealthy(c client.Client, obj runtime.Object) error {
switch obj.(type) {
case *appsv1.StatefulSet:
ss := obj.(*appsv1.StatefulSet)
log.Println("------HEALTH---------")
log.Printf("Looking at Statefulset: %v\n", ss.Name)
b, _ := json.MarshalIndent(ss, "", "\t")
log.Printf("\n%v\n", string(b))
log.Println("---------------------")
if ss.Spec.Replicas == nil {
return fmt.Errorf("replicas not set, so can't be healthy")
}
if ss.Status.ReadyReplicas == *ss.Spec.Replicas {
log.Printf("Statefulset %v is marked healthy\n", ss.Name)
return nil
}
log.Printf("HealthUtil: Statefulset %v is NOT healthy. Not enough ready replicas: %v/%v", ss.Name, ss.Status.ReadyReplicas, ss.Status.Replicas)
return fmt.Errorf("Ready Replicas (%v) does not equal Requested Replicas (%v)", ss.Status.ReadyReplicas, ss.Status.Replicas)
case *appsv1.Deployment:
d := obj.(*appsv1.Deployment)
if d.Spec.Replicas != nil && d.Status.ReadyReplicas == *d.Spec.Replicas {
log.Printf("HealthUtil: Deployment %v is marked healthy", d.Name)
return nil
}
log.Printf("HealthUtil: Deployment %v is NOT healthy. Not enough ready replicas: %v/%v", d.Name, d.Status.ReadyReplicas, *d.Spec.Replicas)
return fmt.Errorf("Ready Replicas (%v) does not equal Requested Replicas (%v)", d.Status.ReadyReplicas, *d.Spec.Replicas)
case *batchv1.Job:
job := obj.(*batchv1.Job)
// job.Status.
if job.Status.Succeeded == int32(1) {
//done!
log.Printf("HealthUtil: Job \"%v\" is marked healthy", job.Name)
return nil
}
return fmt.Errorf("Job \"%v\" still running or failed", job.Name)
case *kudov1alpha1.Instance:
i := obj.(*kudov1alpha1.Instance)
//Instances are healthy when their Active Plan has succeeded
plan := &kudov1alpha1.PlanExecution{}
err := c.Get(context.TODO(), client.ObjectKey{
Name: i.Status.ActivePlan.Name,
Namespace: i.Status.ActivePlan.Namespace,
}, plan)
if err != nil {
log.Printf("Error getting PlaneExecution %v/%v: %v\n", i.Status.ActivePlan.Name, i.Status.ActivePlan.Namespace, err)
return fmt.Errorf("instance active plan not found: %v", err)
}
log.Printf("HealthUtil: Instance %v is in state %v", i.Name, plan.Status.State)
if plan.Status.State == kudov1alpha1.PhaseStateComplete {
return nil
}
return fmt.Errorf("instance's active plan is in state %v", plan.Status.State)
//unless we build logic for what a healthy object is, assume its healthy when created
default:
log.Printf("HealthUtil: Unknown type is marked healthy by default")
return nil
}
}
//IsStepHealthy returns whether each object in the given step is healthy
func IsStepHealthy(c client.Client, step kudov1alpha1.StepStatus) bool {
for _, obj := range step.Objects {
if e := IsHealthy(c, obj); e != nil {
log.Printf("HealthUtil: Step %v is not healthy", step.Name)
return false
}
}
return true
}
//IsPhaseHealthy returns whether each step in the phase is healthy. See IsStepHealthy for step health
func IsPhaseHealthy(phase kudov1alpha1.PhaseStatus) bool {
for _, step := range phase.Steps {
if step.State != kudov1alpha1.PhaseStateComplete {
log.Printf("HealthUtil: Phase %v is not healthy b/c step %v is not healthy", phase.Name, step.Name)
return false
}
}
log.Printf("HealthUtil: Phase %v is healthy", phase.Name)
return true
}
//IsPlanHealthy returns whether each Phase in the plan is healthy. See IsPhaseHealthy for phase health
func IsPlanHealthy(plan kudov1alpha1.PlanExecutionStatus) bool {
for _, phase := range plan.Phases {
if !IsPhaseHealthy(phase) {
return false
}
}
return true
}