-
Notifications
You must be signed in to change notification settings - Fork 0
/
semantic.go
162 lines (143 loc) · 3.89 KB
/
semantic.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package semantic
import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"knative.dev/networking/pkg/apis/networking"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
)
// Semantic can do semantic deep equality checks for Kubernetes API objects.
//
// For a given comparison function
//
// comp(a, b interface{})
//
// 'a' should always be the desired state, and 'b' the current state for
// DeepDerivative comparisons to work as expected.
var Semantic = conversion.EqualitiesOrDie(
deploymentEqual,
knServiceEqual,
serviceAccountEqual,
)
// eq is an instance of Equalities for internal deep derivative comparisons
// of API objects. Adapted from "k8s.io/apimachinery/pkg/api/equality".Semantic.
var eq = conversion.EqualitiesOrDie(
func(a, b resource.Quantity) bool {
if a.IsZero() {
return true
}
return a.Cmp(b) == 0
},
func(a, b metav1.Time) bool { // e.g. metadata.creationTimestamp
if a.IsZero() {
return true
}
return a.UTC() == b.UTC()
},
func(a, b int64) bool { // e.g. metadata.generation
if a == 0 {
return true
}
return a == b
},
// Needed because DeepDerivative compares int values directly, which
// doesn't yield the expected result with defaulted int32 probe fields.
func(a, b *corev1.Probe) bool {
if a == nil {
return true
}
if b == nil {
return false
}
if a.InitialDelaySeconds != 0 && a.InitialDelaySeconds != b.InitialDelaySeconds {
return false
}
if a.TimeoutSeconds != 0 && a.TimeoutSeconds != b.TimeoutSeconds {
return false
}
if a.PeriodSeconds != 0 && a.PeriodSeconds != b.PeriodSeconds {
return false
}
if a.SuccessThreshold != 0 && a.SuccessThreshold != b.SuccessThreshold {
return false
}
if a.FailureThreshold != 0 && a.FailureThreshold != b.FailureThreshold {
return false
}
return (conversion.Equalities{}).DeepDerivative(a.ProbeHandler, b.ProbeHandler)
},
// Needed because DeepDerivative compares EnvVar.Value string fields
// without considering EnvVar as a whole. If an EnvVar is specified, we
// consider its value to be intentional and force the comparison.
func(a, b corev1.EnvVar) bool {
if a.Name != b.Name || a.Value != b.Value {
return false
}
return (conversion.Equalities{}).DeepDerivative(a.ValueFrom, b.ValueFrom)
},
func(a, b map[string]string) bool {
removableLabels := []string{networking.VisibilityLabelKey}
for _, l := range removableLabels {
if a[l] != b[l] {
return false
}
}
return (conversion.Equalities{}).DeepDerivative(a, b)
},
)
// deploymentEqual returns whether two Deployments are semantically equivalent.
func deploymentEqual(a, b *appsv1.Deployment) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
if !eq.DeepDerivative(&a.ObjectMeta, &b.ObjectMeta) {
return false
}
if !eq.DeepDerivative(&a.Spec, &b.Spec) {
return false
}
return true
}
// knServiceEqual returns whether two Knative Services are semantically equivalent.
func knServiceEqual(a, b *servingv1.Service) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
if !eq.DeepDerivative(&a.ObjectMeta, &b.ObjectMeta) {
return false
}
if !eq.DeepDerivative(&a.Spec.Template, &b.Spec.Template) {
return false
}
return true
}
// serviceAccountEqual returns whether two ServiceAccounts are semantically equivalent.
func serviceAccountEqual(a, b *corev1.ServiceAccount) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
if !eq.DeepDerivative(&a.ObjectMeta, &b.ObjectMeta) {
return false
}
if !eq.DeepDerivative(&a.Secrets, &b.Secrets) {
return false
}
if !eq.DeepDerivative(&a.ImagePullSecrets, &b.ImagePullSecrets) {
return false
}
if !eq.DeepDerivative(&a.AutomountServiceAccountToken, &b.AutomountServiceAccountToken) {
return false
}
return true
}