diff --git a/pkg/controller/node/node_controller.go b/pkg/controller/node/node_controller.go index 182285c412..c85f0502ef 100644 --- a/pkg/controller/node/node_controller.go +++ b/pkg/controller/node/node_controller.go @@ -8,11 +8,11 @@ import ( "sort" "time" - helpers "github.com/openshift/machine-config-operator/pkg/helpers" - configv1 "github.com/openshift/api/config/v1" features "github.com/openshift/api/features" mcfgv1 "github.com/openshift/api/machineconfiguration/v1" + helpers "github.com/openshift/machine-config-operator/pkg/helpers" + "github.com/openshift/machine-config-operator/pkg/upgrademonitor" cligoinformersv1 "github.com/openshift/client-go/config/informers/externalversions/config/v1" cligolistersv1 "github.com/openshift/client-go/config/listers/config/v1" @@ -1288,14 +1288,22 @@ 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. + // Populate the desired config version and image annotations in the node's MCN + err = upgrademonitor.UpdateMachineConfigNodeSpecDesiredVersion(ctrl.fgHandler, ctrl.client, nodeName, desiredConfig) + if err != nil { + klog.Errorf("error populating MCN for desired config version: %v", err) + } + // Set the desired state to match the pool. newData, err := json.Marshal(lns.Node()) if err != nil { return err diff --git a/pkg/upgrademonitor/upgrade_monitor.go b/pkg/upgrademonitor/upgrade_monitor.go index d58542b8bb..58f8e45321 100644 --- a/pkg/upgrademonitor/upgrade_monitor.go +++ b/pkg/upgrademonitor/upgrade_monitor.go @@ -335,6 +335,45 @@ func isSingletonCondition(singletonConditionTypes []mcfgv1.StateProgress, condit return false } +// UpdateMachineConfigNodeSpecDesiredVersion sets the desired config version value in the `Spec` of +// an existing MachineConfigNode resource +func UpdateMachineConfigNodeSpecDesiredVersion(fgHandler ctrlcommon.FeatureGatesHandler, mcfgClient mcfgclientset.Interface, nodeName string, 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 error situation just in case. + if mcnErr != nil { + // no existing MCN found since no resource found + if apierrors.IsNotFound(mcnErr) { + return fmt.Errorf("MCN for %s node does not exits. Skipping MCN desired annotations spec update.", nodeName) + } + 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 and image 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 {