forked from kubernetes-sigs/kubebuilder-declarative-pattern
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tracker.go
104 lines (89 loc) · 3.07 KB
/
tracker.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
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package applyset
import (
"reflect"
"k8s.io/apimachinery/pkg/runtime"
)
// objectTrackerList is a list of objectTrackers, containing the state of the objects we are trying to apply.
// objectTrackerList is immutable (though objectTracker is mutable); we copy-on-write when the list changes.
// TODO: Given objectTracker is mutable, should we just make objectTrackerList mutable?
type objectTrackerList struct {
items []objectTracker
}
// objectTracker tracks the state for a single object
type objectTracker struct {
desired ApplyableObject
lastApplied runtime.Object
desiredIsApplied bool
isHealthy bool
}
// objectKey is the key used in maps; we consider objects with the same GVKNN the same.
type objectKey struct {
Group string
Version string
Kind string
Namespace string
Name string
}
// computeKey returns the unique key for the object.
func computeKey(u ApplyableObject) objectKey {
gvk := u.GroupVersionKind()
return objectKey{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
Namespace: u.GetNamespace(),
Name: u.GetName(),
}
}
// setDesiredObjects completely replaces the set of objects we are interested in.
// We aim to reuse the current state where it carries over.
// Because objectTrackerList is immutable, we copy-on-write to a new objectTrackerList and return it.
func (l *objectTrackerList) setDesiredObjects(objects []ApplyableObject) *objectTrackerList {
existingTrackers := make(map[objectKey]*objectTracker)
for i := range l.items {
tracker := &l.items[i]
key := computeKey(tracker.desired)
existingTrackers[key] = tracker
}
newList := &objectTrackerList{}
for _, obj := range objects {
key := computeKey(obj)
// TODO: Detect duplicate keys?
existingTracker := existingTrackers[key]
if existingTracker == nil {
newList.items = append(newList.items, objectTracker{
desired: obj,
lastApplied: nil,
desiredIsApplied: false,
isHealthy: false,
})
} else if reflect.DeepEqual(existingTracker.desired, obj) {
newList.items = append(newList.items, objectTracker{
desired: obj,
lastApplied: existingTracker.lastApplied,
desiredIsApplied: existingTracker.desiredIsApplied,
isHealthy: existingTracker.isHealthy,
})
} else {
newList.items = append(newList.items, objectTracker{
desired: obj,
lastApplied: existingTracker.lastApplied,
desiredIsApplied: false,
isHealthy: existingTracker.isHealthy,
})
}
}
return newList
}