diff --git a/pkg/controller/node/node_controller.go b/pkg/controller/node/node_controller.go index 182285c412..209bbd2f98 100644 --- a/pkg/controller/node/node_controller.go +++ b/pkg/controller/node/node_controller.go @@ -9,6 +9,7 @@ import ( "time" helpers "github.com/openshift/machine-config-operator/pkg/helpers" + "github.com/openshift/machine-config-operator/pkg/upgrademonitor" configv1 "github.com/openshift/api/config/v1" features "github.com/openshift/api/features" @@ -1288,14 +1289,16 @@ func (ctrl *Controller) updateCandidateNode(mosc *mcfgv1.MachineOSConfig, mosb * } lns := ctrlcommon.NewLayeredNodeState(oldNode) + desiredConfig := "" if !layered { lns.SetDesiredStateFromPool(pool) + desiredConfig = pool.Spec.Configuration.Name } else { lns.SetDesiredStateFromMachineOSConfig(mosc, mosb) + desiredConfig = mosb.Spec.MachineConfig.Name } // Set the desired state to match the pool. - newData, err := json.Marshal(lns.Node()) if err != nil { return err @@ -1306,6 +1309,12 @@ func (ctrl *Controller) updateCandidateNode(mosc *mcfgv1.MachineOSConfig, mosb * return nil } + // Populate the desired config version and image annotations in the node's MCN + err = upgrademonitor.UpdateMachineConfigNodeSpecDesiredAnnotation(ctrl.fgHandler, ctrl.client, nodeName, desiredConfig) + if err != nil { + klog.Errorf("error populating MCN for desired config version and image updates: %v", err) + } + klog.V(4).Infof("Pool %s: layered=%v node %s update is needed", pool.Name, layered, nodeName) patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, corev1.Node{}) if err != nil { diff --git a/pkg/upgrademonitor/upgrade_monitor.go b/pkg/upgrademonitor/upgrade_monitor.go index d58542b8bb..fe494df6ea 100644 --- a/pkg/upgrademonitor/upgrade_monitor.go +++ b/pkg/upgrademonitor/upgrade_monitor.go @@ -335,6 +335,42 @@ func isSingletonCondition(singletonConditionTypes []mcfgv1.StateProgress, condit return false } +// UpdateMachineConfigNodeSpecDesiredAnnotation sets the desired config version in the `Spec` of an +// existing MachineConfigNode resource +func UpdateMachineConfigNodeSpecDesiredAnnotation(fgHandler ctrlcommon.FeatureGatesHandler, mcfgClient mcfgclientset.Interface, nodeName, desiredConfig string) error { + if fgHandler == nil { + return nil + } + + // Check that the MachineConfigNode feature gate is enabled + if !fgHandler.Enabled(features.FeatureGateMachineConfigNodes) { + klog.Infof("MachineConfigNode FeatureGate is not enabled.") + return nil + } + + // Get the existing MCN + mcn, mcnErr := mcfgClient.MachineconfigurationV1().MachineConfigNodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) + // Note that this function is only intended to update the Spec of an existing MCN. We should + // not reach this point if there is not an existing MCN for a node, but we need to handle the + // DNE and other potential error situations just in case. + if mcnErr != nil { + return mcnErr + } + + // Set the desired config annotation + mcn.Spec.ConfigVersion.Desired = NotYetSet + if desiredConfig != "" { + mcn.Spec.ConfigVersion.Desired = desiredConfig + } + + // Update the MCN resource + if _, err := mcfgClient.MachineconfigurationV1().MachineConfigNodes().Update(context.TODO(), mcn, metav1.UpdateOptions{FieldManager: "machine-config-operator"}); err != nil { + return fmt.Errorf("failed to update the %s mcn spec with the new desired config value: %w", nodeName, err) + } + + return nil +} + // GenerateAndApplyMachineConfigNodeSpec generates and applies a new MCN spec based off the node state func GenerateAndApplyMachineConfigNodeSpec(fgHandler ctrlcommon.FeatureGatesHandler, pool string, node *corev1.Node, mcfgClient mcfgclientset.Interface) error { if fgHandler == nil || node == nil {