Skip to content

Commit 429ba19

Browse files
committed
usc: Add the MC version cache
1 parent 771bc03 commit 429ba19

File tree

2 files changed

+100
-18
lines changed

2 files changed

+100
-18
lines changed

pkg/updatestatus/nodeinformer.go

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"strings"
7+
"sync"
78
"time"
89

910
corev1 "k8s.io/api/core/v1"
@@ -39,6 +40,10 @@ type nodeInformerController struct {
3940
// sendInsight should be called to send produced insights to the update status controller
4041
sendInsight sendInsightFn
4142

43+
// machineConfigVersionCache caches machine config versions
44+
// The cache stores the name of MC as the key and the release image version as its value which is retrieved from the annotation of the MC.
45+
machineConfigVersionCache machineConfigVersionCache
46+
4247
// now is a function that returns the current time, used for testing
4348
now func() metav1.Time
4449
}
@@ -110,18 +115,6 @@ func (c *nodeInformerController) sync(ctx context.Context, syncCtx factory.SyncC
110115
return fmt.Errorf("failed to determine which machine config pool the node belongs to: %w", err)
111116
}
112117

113-
machineConfigs, err := c.machineConfigs.List(labels.Everything())
114-
if err != nil {
115-
return err
116-
}
117-
118-
machineConfigVersions := map[string]string{}
119-
for _, mc := range machineConfigs {
120-
if openshiftVersion, ok := mc.Annotations[mco.ReleaseImageVersionAnnotationKey]; ok && openshiftVersion != "" {
121-
machineConfigVersions[mc.Name] = openshiftVersion
122-
}
123-
}
124-
125118
var mostRecentVersionInCVHistory string
126119
clusterVersion, err := c.configClient.ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{})
127120
if err != nil {
@@ -132,15 +125,32 @@ func (c *nodeInformerController) sync(ctx context.Context, syncCtx factory.SyncC
132125
}
133126

134127
now := c.now()
135-
if insight := assessNode(node, mcp, machineConfigVersions, mostRecentVersionInCVHistory, now); insight != nil {
128+
if insight := assessNode(node, mcp, c.machineConfigVersionCache.match, mostRecentVersionInCVHistory, now); insight != nil {
136129
msg, err = makeInsightMsgForNode(insight, now)
137130
if err != nil {
138131
klog.Errorf("BUG: Could not create insight message: %v", err)
139132
return nil
140133
}
141134
}
142135
case machineConfigKindName:
143-
return c.reconcileAllNodes(syncCtx.Queue())
136+
machineConfig, err := c.machineConfigs.Get(name)
137+
if err != nil && !kerrors.IsNotFound(err) {
138+
return err
139+
}
140+
if kerrors.IsNotFound(err) {
141+
// The machine config was deleted
142+
if changed := c.machineConfigVersionCache.forget(name); changed {
143+
144+
klog.V(2).Infof("Reconciling all nodes as machine config %q is deleted", name)
145+
return c.reconcileAllNodes(syncCtx.Queue())
146+
}
147+
return nil
148+
}
149+
if changed := c.machineConfigVersionCache.ingest(machineConfig); changed {
150+
klog.V(2).Infof("Reconciling all nodes as machine config %q is refreshed", name)
151+
return c.reconcileAllNodes(syncCtx.Queue())
152+
}
153+
return nil
144154
case machineConfigPoolKindName:
145155
return c.reconcileAllNodes(syncCtx.Queue())
146156
default:
@@ -155,6 +165,52 @@ func (c *nodeInformerController) sync(ctx context.Context, syncCtx factory.SyncC
155165
return nil
156166
}
157167

168+
type machineConfigVersionCache struct {
169+
cache map[string]string
170+
lock sync.Mutex
171+
}
172+
173+
func (c *machineConfigVersionCache) ingest(mc *machineconfigv1.MachineConfig) bool {
174+
c.lock.Lock()
175+
defer c.lock.Unlock()
176+
177+
v, ok := c.cache[mc.Name]
178+
if openshiftVersion, exist := mc.Annotations[mco.ReleaseImageVersionAnnotationKey]; exist && openshiftVersion != "" {
179+
if !ok || v != openshiftVersion {
180+
if c.cache == nil {
181+
c.cache = make(map[string]string)
182+
}
183+
c.cache[mc.Name] = openshiftVersion
184+
klog.V(4).Infof("Cached MachineConfig %s with version %s", mc.Name, openshiftVersion)
185+
return true
186+
}
187+
} else if ok {
188+
delete(c.cache, mc.Name)
189+
klog.V(4).Infof("Deleted MachineConfig %s from the cache as no version can be found", mc.Name)
190+
return true
191+
}
192+
193+
return false
194+
}
195+
196+
func (c *machineConfigVersionCache) forget(name string) bool {
197+
c.lock.Lock()
198+
defer c.lock.Unlock()
199+
if _, ok := c.cache[name]; ok {
200+
delete(c.cache, name)
201+
klog.V(4).Infof("Deleted MachineConfig %s from the cache", name)
202+
return true
203+
}
204+
return false
205+
}
206+
207+
func (c *machineConfigVersionCache) match(config string) (string, bool) {
208+
c.lock.Lock()
209+
defer c.lock.Unlock()
210+
v, ok := c.cache[config]
211+
return v, ok
212+
}
213+
158214
func (c *nodeInformerController) reconcileAllNodes(queue workqueue.TypedRateLimitingInterface[any]) error {
159215
nodes, err := c.nodes.List(labels.Everything())
160216
if err != nil {
@@ -343,16 +399,16 @@ func toPointer(d time.Duration) *metav1.Duration {
343399
return &v
344400
}
345401

346-
func assessNode(node *corev1.Node, mcp *machineconfigv1.MachineConfigPool, machineConfigVersions map[string]string, mostRecentVersionInCVHistory string, now metav1.Time) *updatestatus.NodeStatusInsight {
402+
func assessNode(node *corev1.Node, mcp *machineconfigv1.MachineConfigPool, machineConfigVersionMatcher func(string) (string, bool), mostRecentVersionInCVHistory string, now metav1.Time) *updatestatus.NodeStatusInsight {
347403
if node == nil || mcp == nil {
348404
return nil
349405
}
350406

351407
desiredConfig, ok := node.Annotations[mco.DesiredMachineConfigAnnotationKey]
352408
noDesiredOnNode := !ok
353409
currentConfig := node.Annotations[mco.CurrentMachineConfigAnnotationKey]
354-
currentVersion, foundCurrent := machineConfigVersions[currentConfig]
355-
desiredVersion, foundDesired := machineConfigVersions[desiredConfig]
410+
currentVersion, foundCurrent := machineConfigVersionMatcher(currentConfig)
411+
desiredVersion, foundDesired := machineConfigVersionMatcher(desiredConfig)
356412

357413
lns := mco.NewLayeredNodeState(node)
358414
isUnavailable := lns.IsUnavailable(mcp)

pkg/updatestatus/nodeinformer_test.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import (
1414
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1515
"k8s.io/apimachinery/pkg/labels"
1616
"k8s.io/apimachinery/pkg/runtime"
17+
kerrors "k8s.io/apimachinery/pkg/util/errors"
1718
corelistersv1 "k8s.io/client-go/listers/core/v1"
1819
"k8s.io/client-go/tools/cache"
20+
"k8s.io/klog/v2"
1921

2022
configv1 "github.com/openshift/api/config/v1"
2123
machineconfigv1 "github.com/openshift/api/machineconfiguration/v1"
@@ -149,6 +151,23 @@ func getMCP(name string) *machineconfigv1.MachineConfigPool {
149151
}
150152
}
151153

154+
func (c *nodeInformerController) initializeCaches() error {
155+
var errs []error
156+
157+
machineConfigs, err := c.machineConfigs.List(labels.Everything())
158+
if err != nil {
159+
errs = append(errs, err)
160+
} else {
161+
for _, mc := range machineConfigs {
162+
c.machineConfigVersionCache.ingest(mc)
163+
}
164+
}
165+
166+
klog.V(2).Infof("Stored %d machineConfig versions in the cache", len(c.machineConfigVersionCache.cache))
167+
168+
return kerrors.NewAggregate(errs)
169+
}
170+
152171
func Test_whichMCP(t *testing.T) {
153172
testCases := []struct {
154173
name string
@@ -850,7 +869,10 @@ func Test_assessNode(t *testing.T) {
850869
for _, tc := range testCases {
851870
t.Run(tc.name, func(t *testing.T) {
852871

853-
actual := assessNode(tc.node, tc.mcp, tc.machineConfigVersions, tc.mostRecentVersionInCVHistory, now)
872+
actual := assessNode(tc.node, tc.mcp, func(k string) (string, bool) {
873+
v, ok := tc.machineConfigVersions[k]
874+
return v, ok
875+
}, tc.mostRecentVersionInCVHistory, now)
854876

855877
if diff := cmp.Diff(tc.expected, actual); diff != "" {
856878
t.Errorf("%s: node status insight differs from expected:\n%s", tc.name, diff)
@@ -1022,6 +1044,10 @@ func Test_sync_with_node(t *testing.T) {
10221044
now: func() metav1.Time { return now },
10231045
}
10241046

1047+
if err := controller.initializeCaches(); err != nil {
1048+
t.Errorf("Failed to initialize caches: %v", err)
1049+
}
1050+
10251051
queueKey := nodeInformerControllerQueueKeys(tc.node)[0]
10261052

10271053
actualErr := controller.sync(context.TODO(), newTestSyncContext(queueKey))

0 commit comments

Comments
 (0)