Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
controller: update MC after application by TuneD (#352)
Tuned Profiles are created by NTO operator and updated by both the operator and its operand. The operand's updates are the source of truth for information such as kernel command-line parameters and presence of the stalld daemon. The operator is informed about this via the status field of the a Tuned Profile that corresponds to a given node. Operator updates are the source of truth about which TuneD profile should be applied. When a new cluster node is added (for example during a cluster scale-up), a new Tuned Profile is created. If the node is quickly added to a MachinePool for which an NTO-managed MachineConfig already exists, this addition will cause NTO to overwrite/update the MachineConfig with data that is incorrectly initialized. If the operand was too slow to correct this update (typically during scale-ups when the operand was not yet running), this would cause unnecessary reboots of nodes sharing the same MachineConfigPool. This PR fixes the behaviour above by letting the operator update the NTO-managed MachineConfigs only once the newly requested Tuned Profile configuration is successfully applied. Other changes: - go mod vendor && go mod tidy Resolves rhbz#2024682 Co-authored-by: Jiri Mencak <jmencak@users.noreply.github.com>
- Loading branch information
Showing
8 changed files
with
263 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package tuned | ||
|
||
import ( | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
tunedv1 "github.com/openshift/cluster-node-tuning-operator/pkg/apis/tuned/v1" | ||
) | ||
|
||
// setStatusCondition returns the result of setting the specified condition in | ||
// the given slice of conditions. | ||
func setStatusCondition(oldConditions []tunedv1.ProfileStatusCondition, condition *tunedv1.ProfileStatusCondition) []tunedv1.ProfileStatusCondition { | ||
condition.LastTransitionTime = metav1.Now() | ||
|
||
newConditions := []tunedv1.ProfileStatusCondition{} | ||
|
||
found := false | ||
for _, c := range oldConditions { | ||
if condition.Type == c.Type { | ||
if condition.Status == c.Status && | ||
condition.Reason == c.Reason && | ||
condition.Message == c.Message { | ||
return oldConditions | ||
} | ||
|
||
found = true | ||
newConditions = append(newConditions, *condition) | ||
} else { | ||
newConditions = append(newConditions, c) | ||
} | ||
} | ||
if !found { | ||
newConditions = append(newConditions, *condition) | ||
} | ||
|
||
return newConditions | ||
} | ||
|
||
// conditionsEqual returns true if and only if the provided slices of conditions | ||
// (ignoring LastTransitionTime) are equal. | ||
func conditionsEqual(oldConditions, newConditions []tunedv1.ProfileStatusCondition) bool { | ||
if len(newConditions) != len(oldConditions) { | ||
return false | ||
} | ||
|
||
for _, conditionA := range oldConditions { | ||
foundMatchingCondition := false | ||
|
||
for _, conditionB := range newConditions { | ||
// Compare every field except LastTransitionTime. | ||
if conditionA.Type == conditionB.Type && | ||
conditionA.Status == conditionB.Status && | ||
conditionA.Reason == conditionB.Reason && | ||
conditionA.Message == conditionB.Message { | ||
foundMatchingCondition = true | ||
break | ||
} | ||
} | ||
|
||
if !foundMatchingCondition { | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
// computeStatusConditions takes the set of Bits 'status', old conditions | ||
// 'conditions' and returns an updated slice of tunedv1.ProfileStatusCondition. | ||
// 'status' contains all the information necessary for creating a new slice of | ||
// conditions apart from LastTransitionTime, which is set based on checking the | ||
// old conditions. | ||
func computeStatusConditions(status Bits, conditions []tunedv1.ProfileStatusCondition) []tunedv1.ProfileStatusCondition { | ||
tunedProfileAppliedCondition := tunedv1.ProfileStatusCondition{ | ||
Type: tunedv1.TunedProfileApplied, | ||
} | ||
tunedDegradedCondition := tunedv1.ProfileStatusCondition{ | ||
Type: tunedv1.TunedDegraded, | ||
} | ||
|
||
if (status & scApplied) != 0 { | ||
tunedProfileAppliedCondition.Status = corev1.ConditionTrue | ||
tunedProfileAppliedCondition.Reason = "AsExpected" | ||
tunedProfileAppliedCondition.Message = "Tuned profile applied." | ||
} else { | ||
tunedProfileAppliedCondition.Status = corev1.ConditionFalse | ||
tunedProfileAppliedCondition.Reason = "Failed" | ||
tunedProfileAppliedCondition.Message = "The Tuned daemon profile application failed." | ||
} | ||
|
||
if (status & scError) != 0 { | ||
tunedDegradedCondition.Status = corev1.ConditionTrue | ||
tunedDegradedCondition.Reason = "TunedError" | ||
tunedDegradedCondition.Message = "Tuned daemon issued one or more error message(s) during profile application." | ||
} else if (status & scWarn) != 0 { | ||
tunedDegradedCondition.Status = corev1.ConditionFalse // consider warnings from Tuned as non-fatal | ||
tunedDegradedCondition.Reason = "TunedWarning" | ||
tunedDegradedCondition.Message = "No error messages observed by applying the Tuned daemon profile, only warning(s)." | ||
} else { | ||
tunedDegradedCondition.Status = corev1.ConditionFalse | ||
tunedDegradedCondition.Reason = "AsExpected" | ||
tunedDegradedCondition.Message = "No warning or error messages observed applying the Tuned daemon profile." | ||
} | ||
|
||
conditions = setStatusCondition(conditions, &tunedProfileAppliedCondition) | ||
conditions = setStatusCondition(conditions, &tunedDegradedCondition) | ||
|
||
return conditions | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters