Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ require (
github.com/google/renameio v0.1.0
github.com/imdario/mergo v0.3.16
github.com/opencontainers/go-digest v1.0.0
github.com/openshift/api v0.0.0-20250425163235-9b80d67473bc
github.com/openshift/api v0.0.0-20250620092249-a8cbc218cd2c
github.com/openshift/client-go v0.0.0-20250425165505-5f55ff6979a1
github.com/openshift/library-go v0.0.0-20250129210218-fe56c2cf5d70
github.com/openshift/runtime-utils v0.0.0-20230921210328-7bdb5b9c177b
Expand Down Expand Up @@ -350,3 +350,7 @@ require (
)

replace k8s.io/kube-openapi => github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0

replace github.com/openshift/client-go => github.com/naseerahkani/client-go v0.0.0-20250722005126-8e9e555e298c

replace github.com/openshift/api => github.com/naseerahkani/api v0.0.0-20250715184238-584477d3b226
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,10 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U=
github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=
github.com/naseerahkani/api v0.0.0-20250715184238-584477d3b226 h1:20I1LGq8ZVQOLkYmKTmMKIn7wqrU6cd0sdW7oW/Xwqg=
github.com/naseerahkani/api v0.0.0-20250715184238-584477d3b226/go.mod h1:yk60tHAmHhtVpJQo3TwVYq2zpuP70iJIFDCmeKMIzPw=
github.com/naseerahkani/client-go v0.0.0-20250722005126-8e9e555e298c h1:f8AqcpybuKmUyGKCvq4pkOHIsgxGMvrmI5+yq6ZFTvo=
github.com/naseerahkani/client-go v0.0.0-20250722005126-8e9e555e298c/go.mod h1:AFenInkrazQ4DaGyy1GXrUQPGdVzv/uXMp6sGbR5bXs=
github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg=
github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
Expand Down Expand Up @@ -513,10 +517,6 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/openshift/api v0.0.0-20250425163235-9b80d67473bc h1:BGKjHtYzBweOSu1UwTnNqtPbJZ4VzOTqVFlUDpP+6U8=
github.com/openshift/api v0.0.0-20250425163235-9b80d67473bc/go.mod h1:yk60tHAmHhtVpJQo3TwVYq2zpuP70iJIFDCmeKMIzPw=
github.com/openshift/client-go v0.0.0-20250425165505-5f55ff6979a1 h1:2HPG58V07TrrSGBviNPd0PY42vYHPPCIEwj/pb9nUlY=
github.com/openshift/client-go v0.0.0-20250425165505-5f55ff6979a1/go.mod h1:kH5mjMfcHCF0tEnxwvNJTLMnlbrEt3Ua+vMVGvBOK5w=
github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0 h1:GPlAy197Jkr+D0T2FNWanamraTdzS/r9ZkT29lxvHaA=
github.com/openshift/kube-openapi v0.0.0-20230816122517-ffc8f001abb0/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
github.com/openshift/library-go v0.0.0-20250129210218-fe56c2cf5d70 h1:VLj8CU9q009xlMuR4wNcqDX4lVa2Ji3u/iYnBLHtQUc=
Expand Down
9 changes: 9 additions & 0 deletions pkg/controller/node/node_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,15 @@ func (ctrl *Controller) updateNode(old, cur interface{}) {
}
}

if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
// check if second part of conditional is necessary
if oldNode.Annotations[daemonconsts.CurrentImageAnnotationKey] != oldNode.Annotations[daemonconsts.DesiredImageAnnotationKey] && curLNS.IsNodeDone() {
ctrl.logPoolNode(pool, curNode, "Completed update to %s", curNode.Annotations[daemonconsts.DesiredImageAnnotationKey])
changed = true
}

}

if !changed {
return
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/daemon/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,22 @@ func (dn *Daemon) update(oldConfig, newConfig *mcfgv1.MachineConfig, skipCertifi
if err != nil {
klog.Errorf("Error making MCN spec for Update Compatible: %v", err)
}

_, newOCLImage := extractOCLImageFromMachineConfig(newConfig)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is responsible for extracting the ocl image from the mc if it exists. I think that function should work, buttt I'm not sure that this reporting should go here for a couple of reasons.

  1. The update workflow is agnostic to OCL, meaning there will be times when we go through this MCD update when we aren't even opted into OCL. Thus, we will be returning empty strings that can cause confusing status messages (so we want to make sure we handle this case).
  2. Also, i think the placement of this is premature because we could be status reporting before the correct image is in place.

I think update is a good place to put this work but we just want to ensure the timing is correct!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add code to handle the empty string case but where do you recommend adding this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe after applyOSChanges has succeeded- meaning the image was pulled and the OS was rebased successfully.

err = upgrademonitor.GenerateAndApplyMachineConfigNodes(
&upgrademonitor.Condition{State: mcfgv1.MachineConfigNodeUpdateExecuted, Reason: string(mcfgv1.MachineConfigNodeImagePulledFromRegistry), Message: fmt.Sprintf("Image %s pulled from registry.", newOCLImage)},
&upgrademonitor.Condition{State: mcfgv1.MachineConfigNodeImagePulledFromRegistry, Reason: fmt.Sprintf("%s%s", string(mcfgv1.MachineConfigNodeUpdateExecuted), string(mcfgv1.MachineConfigNodeImagePulledFromRegistry)), Message: fmt.Sprintf("ask message")},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, it looks like this message "ask message" might be a placeholder.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, do you have any suggestions on the message that should be produced?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

anything that signifies that the image was pulled!

metav1.ConditionUnknown,
metav1.ConditionTrue,
dn.node,
dn.mcfgClient,
dn.featureGatesAccessor,
pool,
)
if err != nil {
klog.Errorf("Error making MCN for Pulling Image from Registry: %v", err)
}

if drain {
if err := dn.performDrain(); err != nil {
return err
Expand Down
19 changes: 19 additions & 0 deletions pkg/operator/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,14 @@ func (optr *Operator) syncMachineConfigNodes(_ *renderConfig, _ *configv1.Cluste
},
},
}

//Add: check if image mode status reporting fg is enables and if yes, use 821-826 as a guideline for configImage initialization
if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
newMCS.Spec.ConfigImage = mcfgv1.MachineConfigNodeSpecConfigImage{
DesiredImage: mcfgv1.ImageDigestFormat(node.Annotations[daemonconsts.DesiredImageAnnotationKey]),
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think how we handle this depends on the decision made this thread on the API review (openshift/api#2383) on whether the configImage value is required or not and what it means for whether OCL is enabled or not.

If configImage should only be present when OCL is enabled (when a node generally has a desiredImage or current Image annotation), then I'd lean towards

  • If either annotation is not nil --> set the desired image ref since image mode is enabled
  • If both annotations are nil --> OCL not enabled, so don't set this object


mcsBytes, err := json.Marshal(newMCS)
if err != nil {
klog.Errorf("error rendering asset for MachineConfigNode %v", err)
Expand All @@ -817,6 +825,7 @@ func (optr *Operator) syncMachineConfigNodes(_ *renderConfig, _ *configv1.Cluste
if err != nil {
return err
}

// if this is the first time we are applying the MCN and the node is ready, set the config version probably
if mcn.Spec.ConfigVersion.Desired == upgrademonitor.NotYetSet {
err = upgrademonitor.GenerateAndApplyMachineConfigNodeSpec(optr.fgAccessor, pool, node, optr.client)
Expand All @@ -825,7 +834,17 @@ func (optr *Operator) syncMachineConfigNodes(_ *renderConfig, _ *configv1.Cluste
}
}

if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
if mcn.Spec.ConfigImage.DesiredImage == upgrademonitor.NotYetSet {
err = upgrademonitor.GenerateAndApplyMachineConfigNodeSpec(optr.fgAccessor, pool, node, optr.client)
if err != nil {
klog.Errorf("Error making MCN spec for Update Compatible: %v", err)
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this duplicative of lines 829-835? If I'm understanding this added conditional correctly, GenerateAndApplyMachineConfigNodeSpec would be called twice if both mcn.Spec.ConfigVersion.Desired and mcn.Spec.ConfigImage.DesiredImage are not yet set. Two questions on this:

  1. Will the desired image value ever be not-yet-set? If so, I'm not sure that's a fair representation of the desiredImage annotation not existing for a node.
  2. Should this be combined with the previous similar check to be something like if mcn.Spec.ConfigVersion.Desired == upgrademonitor.NotYetSet || mcn.Spec.ConfigImage.DesiredImage == <empty-status-value> (where depends on the answer to no. 1) to decrease the extra GenerateAndApplyMachineConfigNodeSpec call?


}

if mcns != nil {
for _, mcn := range mcns.Items {
if _, ok := nodeMap[mcn.Name]; !ok {
Expand Down
52 changes: 47 additions & 5 deletions pkg/upgrademonitor/upgrade_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,14 @@ func generateAndApplyMachineConfigNodes(
mcfgv1.MachineConfigNodeUpdateComplete,
mcfgv1.MachineConfigNodeResumed,
mcfgv1.MachineConfigNodeUpdateDrained,
mcfgv1.MachineConfigNodeUpdateFilesAndOS,
mcfgv1.MachineConfigNodeUpdateFiles,
mcfgv1.MachineConfigNodeUpdateOS,
mcfgv1.MachineConfigNodeUpdateCordoned,
mcfgv1.MachineConfigNodeUpdateRebooted,
mcfgv1.MachineConfigNodeUpdated,
mcfgv1.MachineConfigNodeUpdateUncordoned,
mcfgv1.MachineConfigNodeNodeDegraded,
mcfgv1.MachineConfigNodeImagePulledFromRegistry,
}
allConditionTypes = append(allConditionTypes, singletonConditionTypes...)

Expand Down Expand Up @@ -220,7 +222,11 @@ func generateAndApplyMachineConfigNodes(

case condition.Status != metav1.ConditionFalse && reset:
condition.Status = metav1.ConditionFalse
// ASK: does this message change if OCL is used
condition.Message = fmt.Sprintf("Action during update to %s: %s", newMCNode.Spec.ConfigVersion.Desired, condition.Message)
if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
condition.Message = fmt.Sprintf("")
}
condition.LastTransitionTime = metav1.Now()
}
condition.DeepCopyInto(&newMCNode.Status.Conditions[i])
Expand All @@ -247,7 +253,6 @@ func generateAndApplyMachineConfigNodes(
} else {
newMCNode.Status.ConfigVersion.Desired = desiredAnnotation
}

// Set current version in MCN.Status.ConfigVersion if node annotation exists
if node.Annotations[daemonconsts.CurrentMachineConfigAnnotationKey] != "" {
newMCNode.Status.ConfigVersion.Current = node.Annotations[daemonconsts.CurrentMachineConfigAnnotationKey]
Expand Down Expand Up @@ -290,6 +295,14 @@ func generateAndApplyMachineConfigNodes(
}
}

if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
statusConfigImageApplyImage := machineconfigurationv1.MachineConfigNodeStatusConfigImage().WithDesiredImage(newMCNode.Status.ConfigImage.DesiredImage)
if node.Annotations[daemonconsts.CurrentImageAnnotationKey] != "" {
statusConfigImageApplyImage = statusConfigImageApplyImage.WithCurrentImage(newMCNode.Status.ConfigImage.CurrentImage)
}
Comment on lines +325 to +328

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why does current image have a nil check, but desired does not?


}

mcnodeApplyConfig := machineconfigurationv1.MachineConfigNode(newMCNode.Name).WithStatus(statusApplyConfig)
_, err := mcfgClient.MachineconfigurationV1().MachineConfigNodes().ApplyStatus(context.TODO(), mcnodeApplyConfig, metav1.ApplyOptions{FieldManager: "machine-config-operator", Force: true})
if err != nil {
Expand All @@ -304,6 +317,17 @@ func generateAndApplyMachineConfigNodes(
if newMCNode.Spec.ConfigVersion.Desired == "" {
newMCNode.Spec.ConfigVersion.Desired = NotYetSet
}

if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
newMCNode.Spec.ConfigImage = mcfgv1.MachineConfigNodeSpecConfigImage{
DesiredImage: mcfgv1.ImageDigestFormat(node.Annotations[daemonconsts.DesiredImageAnnotationKey]),
}

if newMCNode.Spec.ConfigImage.DesiredImage == "" {
newMCNode.Spec.ConfigImage.DesiredImage = ""
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem like it would make any change.


}
newMCNode.Name = node.Name
newMCNode.Spec.Pool = mcfgv1.MCOObjectReference{Name: pool}
newMCNode.Spec.Node = mcfgv1.MCOObjectReference{Name: node.Name}
Expand Down Expand Up @@ -379,11 +403,23 @@ func GenerateAndApplyMachineConfigNodeSpec(fgAccessor featuregates.FeatureGateAc
newMCNode.Spec.Node = mcfgv1.MCOObjectReference{
Name: node.Name,
}

if fg.Enabled(features.FeatureGateImageModeStatusReporting) {
newMCNode.Spec.ConfigImage = mcfgv1.MachineConfigNodeSpecConfigImage{
DesiredImage: mcfgv1.ImageDigestFormat(node.Annotations[daemonconsts.DesiredImageAnnotationKey]),
}
// check if it should be empty
if newMCNode.Spec.ConfigImage.DesiredImage == "" {
newMCNode.Spec.ConfigVersion.Desired = NotYetSet

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this may be a copy-paste issue, as I'd expect this to be newMCNode.Spec.ConfigImage.Desired, not newMCNode.Spec.ConfigVersion.Desired.

However, do we want to make the config image values not-yet-set if they are nil, or just leave them empty, I figured we'd leave it empty?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can fix the copy-paste issue. As for the config image value, I put it down as NotYetSet temporarily and depending on how the API changes are finalized, I planned on going back and updating it to empty. Do you think this would be a good approach?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's revisit once the API Is finalized.

}
}

if !needNewMCNode {
nodeRefApplyConfig := machineconfigurationv1.MCOObjectReference().WithName(newMCNode.Spec.Node.Name)
poolRefApplyConfig := machineconfigurationv1.MCOObjectReference().WithName(newMCNode.Spec.Pool.Name)
specconfigVersionApplyConfig := machineconfigurationv1.MachineConfigNodeSpecMachineConfigVersion().WithDesired(newMCNode.Spec.ConfigVersion.Desired)
specApplyConfig := machineconfigurationv1.MachineConfigNodeSpec().WithNode(nodeRefApplyConfig).WithPool(poolRefApplyConfig).WithConfigVersion(specconfigVersionApplyConfig)
specConfigImageApplyConfig := machineconfigurationv1.MachineConfigNodeSpecConfigImage().WithDesiredImage(newMCNode.Spec.ConfigImage.DesiredImage)
specApplyConfig := machineconfigurationv1.MachineConfigNodeSpec().WithNode(nodeRefApplyConfig).WithPool(poolRefApplyConfig).WithConfigVersion(specconfigVersionApplyConfig).WithConfigImage(specConfigImageApplyConfig)
mcnodeApplyConfig := machineconfigurationv1.MachineConfigNode(newMCNode.Name).WithSpec(specApplyConfig)
_, err := mcfgClient.MachineconfigurationV1().MachineConfigNodes().Apply(context.TODO(), mcnodeApplyConfig, metav1.ApplyOptions{FieldManager: "machine-config-operator", Force: true})
if err != nil {
Expand All @@ -397,17 +433,23 @@ func GenerateAndApplyMachineConfigNodeSpec(fgAccessor featuregates.FeatureGateAc
return err
}
}

return nil
}

// createOrGetMachineConfigNode gets the named MCN or returns a boolean indicating we need to create one
func createOrGetMachineConfigNode(mcfgClient mcfgclientset.Interface, node *corev1.Node) (*mcfgv1.MachineConfigNode, bool) {
mcNode, err := mcfgClient.MachineconfigurationV1().MachineConfigNodes().Get(context.TODO(), node.Name, metav1.GetOptions{})
if mcNode.Name == "" || (err != nil && apierrors.IsNotFound(err)) {
if err != nil {
// no existing MCN found since no resource found, no error yet just create a new one
if apierrors.IsNotFound((err)) {
klog.V(4).Infof("MachineConfigNode for node %q not found, will create a new one", node.Name)
return mcNode, true
}
// true error getting existing MCN
klog.Errorf("error getting existing MCN: %v", err)
return mcNode, true
}

return mcNode, false
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading