/
k8s_lookup.go
113 lines (98 loc) · 3.46 KB
/
k8s_lookup.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
112
113
package util
import (
"context"
"github.com/armory/spinnaker-operator/pkg/apis/spinnaker/interfaces"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
"time"
)
//go:generate mockgen -destination=k8s_lookup_mocks.go -package util -source k8s_lookup.go
const MaxChecksWaitingForSpinnakerStability = 2
type Ik8sLookup interface {
GetSpinnakerDeployments(instance interfaces.SpinnakerService) ([]appsv1.Deployment, error)
GetSpinnakerServiceImageFromDeployment(p v1.PodSpec) string
GetPodsByDeployment(instance interfaces.SpinnakerService, deployment appsv1.Deployment) ([]v1.Pod, error)
GetReplicaSetByPod(instance interfaces.SpinnakerService, pod v1.Pod) (*appsv1.ReplicaSet, error)
HasExceededMaxWaitingTime(instance interfaces.SpinnakerService, pod v1.Pod) (bool, error)
}
func NewK8sLookup(client client.Client) K8sLookup {
return K8sLookup{
client: client,
}
}
type K8sLookup struct {
client client.Client
}
// getSpinnakerServices returns the name of the image
func (l K8sLookup) GetSpinnakerDeployments(instance interfaces.SpinnakerService) ([]appsv1.Deployment, error) {
// Get current deployment owned by the service
list := &appsv1.DeploymentList{}
err := l.client.List(context.TODO(), list, client.InNamespace(instance.GetNamespace()), client.MatchingLabels{"app.kubernetes.io/managed-by": "spinnaker-operator"})
if err != nil {
return nil, err
}
if len(list.Items) == 0 {
return []appsv1.Deployment{}, nil
} else {
return list.Items, nil
}
}
// getSpinnakerServiceImageFromDeployment returns the name of the image
func (l K8sLookup) GetSpinnakerServiceImageFromDeployment(p v1.PodSpec) string {
for _, c := range p.Containers {
if strings.HasPrefix(c.Name, "spin-") {
return c.Image
}
}
// Default to first container if it exists
if len(p.Containers) > 0 {
return p.Containers[0].Image
}
return ""
}
// GetPodsByDeployment returns the list of pods that belongs to a deployment
func (l K8sLookup) GetPodsByDeployment(instance interfaces.SpinnakerService, deployment appsv1.Deployment) ([]v1.Pod, error) {
list := &v1.PodList{}
err := l.client.List(context.TODO(), list, client.InNamespace(instance.GetNamespace()), client.MatchingLabels{"app.kubernetes.io/name": deployment.Labels["app.kubernetes.io/name"]})
if err != nil {
return nil, err
}
if len(list.Items) == 0 {
return []v1.Pod{}, nil
} else {
return list.Items, nil
}
}
// GetReplicaSetByPod returns the replica set that belongs to a pod
func (l K8sLookup) GetReplicaSetByPod(instance interfaces.SpinnakerService, pod v1.Pod) (*appsv1.ReplicaSet, error) {
rs := &appsv1.ReplicaSet{}
rsName := ""
for _, or := range pod.GetOwnerReferences() {
if or.Kind == "ReplicaSet" {
rsName = or.Name
}
}
key := client.ObjectKey{instance.GetNamespace(), rsName}
err := l.client.Get(context.TODO(), key, rs)
if err != nil {
return &appsv1.ReplicaSet{}, err
}
return rs, nil
}
// hasExceededMaxWaitingTime validate if a replicaset has exceeded max waiting time
func (l K8sLookup) HasExceededMaxWaitingTime(instance interfaces.SpinnakerService, pod v1.Pod) (bool, error) {
rs, err := l.GetReplicaSetByPod(instance, pod)
if err != nil {
return false, err
}
if rs.Status.AvailableReplicas != rs.Status.Replicas || rs.Status.ReadyReplicas != rs.Status.Replicas {
diff := time.Now().Sub(rs.CreationTimestamp.Time)
if diff.Minutes() > MaxChecksWaitingForSpinnakerStability {
return true, nil
}
return false, nil
}
return false, nil
}