Skip to content

Commit 12c5914

Browse files
committed
MULTIARCH-5369 Improve transparency for PreferredDuringSchedulingIgnoredDuringExecution configuration
This improves user experience by providing clear feedback about: 1. The precedence order: PPC (by priority) → CPPC 2. Which configuration successfully set preferences 3. When and why configurations were overridden or skipped Labels added: - multiarch.openshift.io/preferred-affinity-source: tracks config source - LabelValueAllDuplicates: indicates all architectures were duplicates Events added: - ArchAwarePreferredAffinityAllDuplicates: all architectures already set - ArchAwarePreferredAffinityPluginDisabled: plugin not enabled
1 parent 4a6c5e1 commit 12c5914

File tree

4 files changed

+62
-35
lines changed

4 files changed

+62
-35
lines changed

controllers/podplacement/events.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@ const (
1111
ArchitectureAwareSchedulingGateRemovalFailure = "ArchAwareSchedGateRemovalFailed"
1212
ArchitectureAwareSchedulingGateRemovalSuccess = "ArchAwareSchedGateRemovalSuccess"
1313
NoSupportedArchitecturesFound = "NoSupportedArchitecturesFound"
14+
ArchitecturePreferredAffinityAllDuplicates = "ArchAwarePreferredAffinityAllDuplicates"
15+
ArchitecturePreferredAffinityPluginDisabled = "ArchAwarePreferredAffinityPluginDisabled"
1416

15-
SchedulingGateAddedMsg = "Successfully gated with the " + utils.SchedulingGateName + " scheduling gate"
16-
SchedulingGateRemovalSuccessMsg = "Successfully removed the " + utils.SchedulingGateName + " scheduling gate"
17-
SchedulingGateRemovalFailureMsg = "Failed to remove the scheduling gate \"" + utils.SchedulingGateName + "\""
18-
ArchitecturePredicatesConflictMsg = "All the scheduling predicates already include architecture-specific constraints"
19-
ArchitecturePredicateSetupMsg = "Set the supported architectures to "
20-
ArchitecturePreferredPredicateSetupMsg = "Set the architecture preferences in the nodeAffinity"
21-
ArchitecturePreferredPredicateSkippedMsg = "The node affinity already includes architecture preferences"
22-
ImageArchitectureInspectionErrorMsg = "Failed to retrieve the supported architectures: "
23-
NoSupportedArchitecturesFoundMsg = "Pod cannot be scheduled due to incompatible image architectures; container images have no supported architectures in common"
24-
ArchitectureAwareGatedPodIgnoredMsg = "The gated pod has been modified and is no longer eligible for architecture-aware scheduling"
25-
ImageInspectionErrorMaxRetriesMsg = "Failed to retrieve the supported architectures after multiple retries"
17+
SchedulingGateAddedMsg = "Successfully gated with the " + utils.SchedulingGateName + " scheduling gate"
18+
SchedulingGateRemovalSuccessMsg = "Successfully removed the " + utils.SchedulingGateName + " scheduling gate"
19+
SchedulingGateRemovalFailureMsg = "Failed to remove the scheduling gate \"" + utils.SchedulingGateName + "\""
20+
ArchitecturePredicatesConflictMsg = "All the scheduling predicates already include architecture-specific constraints"
21+
ArchitecturePredicateSetupMsg = "Set the supported architectures to "
22+
ArchitecturePreferredPredicateSetupMsg = "Set the architecture preferences in the nodeAffinity: "
23+
ArchitecturePreferredAffinityAllDuplicatesMsg = "All specified architecture preferences were already set by higher-priority configurations"
24+
ArchitecturePreferredAffinityPluginDisabledMsg = "NodeAffinityScoring plugin is not enabled"
25+
ImageArchitectureInspectionErrorMsg = "Failed to retrieve the supported architectures: "
26+
NoSupportedArchitecturesFoundMsg = "Pod cannot be scheduled due to incompatible image architectures; container images have no supported architectures in common"
27+
ArchitectureAwareGatedPodIgnoredMsg = "The gated pod has been modified and is no longer eligible for architecture-aware scheduling"
28+
ImageInspectionErrorMaxRetriesMsg = "Failed to retrieve the supported architectures after multiple retries"
2629
)

controllers/podplacement/pod_model.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ func (pod *Pod) setRequiredArchNodeAffinity(requirement corev1.NodeSelectorRequi
167167
}
168168

169169
// SetPreferredArchNodeAffinity sets the node affinity for the pod to the preferences given in the ClusterPodPlacementConfig.
170-
func (pod *Pod) SetPreferredArchNodeAffinity(nodeAffinity *plugins.NodeAffinityScoring) {
170+
// The configSource parameter identifies which configuration is setting the preferences (e.g., "ClusterPodPlacementConfig" or "PodPlacementConfig/my-ppc").
171+
func (pod *Pod) SetPreferredArchNodeAffinity(nodeAffinity *plugins.NodeAffinityScoring, configSource string) {
171172
log := ctrllog.FromContext(pod.Ctx())
172173
if pod.Spec.Affinity == nil {
173174
pod.Spec.Affinity = &corev1.Affinity{}
@@ -183,6 +184,7 @@ func (pod *Pod) SetPreferredArchNodeAffinity(nodeAffinity *plugins.NodeAffinityS
183184

184185
seenArchitectures := pod.getExistingPreferredArchitectures()
185186
var preferredSchedulingTerms []corev1.PreferredSchedulingTerm
187+
var skippedArchitectures []string
186188
for _, nodeAffinityScoringPlatformTerm := range nodeAffinity.Platforms {
187189
if !seenArchitectures[nodeAffinityScoringPlatformTerm.Architecture] {
188190
preferredSchedulingTerm := corev1.PreferredSchedulingTerm{
@@ -200,7 +202,8 @@ func (pod *Pod) SetPreferredArchNodeAffinity(nodeAffinity *plugins.NodeAffinityS
200202
preferredSchedulingTerms = append(preferredSchedulingTerms, preferredSchedulingTerm)
201203
seenArchitectures[nodeAffinityScoringPlatformTerm.Architecture] = true
202204
} else {
203-
log.Info("Preferred affinity for pod is already set", "Architecture", nodeAffinityScoringPlatformTerm.Architecture, "Weight", nodeAffinityScoringPlatformTerm.Weight, "Pod.Name", pod.Name, "Pod.Namespace", pod.Namespace)
205+
skippedArchitectures = append(skippedArchitectures, nodeAffinityScoringPlatformTerm.Architecture)
206+
log.Info("Preferred affinity for pod is already set", "Architecture", nodeAffinityScoringPlatformTerm.Architecture, "Weight", nodeAffinityScoringPlatformTerm.Weight, "Pod.Name", pod.Name, "Pod.Namespace", pod.Namespace, "ConfigSource", configSource)
204207
}
205208
}
206209

@@ -210,7 +213,19 @@ func (pod *Pod) SetPreferredArchNodeAffinity(nodeAffinity *plugins.NodeAffinityS
210213
pod.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution = append(
211214
pod.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution, preferredSchedulingTerms...)
212215
pod.EnsureLabel(utils.PreferredNodeAffinityLabel, utils.NodeAffinityLabelValueSet)
213-
pod.PublishEvent(corev1.EventTypeNormal, ArchitectureAwareNodeAffinitySet, ArchitecturePreferredPredicateSetupMsg)
216+
// Set the source label to track which configuration set the preferred affinity
217+
// If multiple configs contribute, this will show the most recent one that added preferences
218+
pod.EnsureLabel(utils.PreferredNodeAffinitySourceLabel, configSource)
219+
pod.PublishEvent(corev1.EventTypeNormal, ArchitectureAwareNodeAffinitySet, fmt.Sprintf("%s %s", ArchitecturePreferredPredicateSetupMsg, configSource))
220+
}
221+
222+
// If all architectures were already set by higher-priority configs, emit an event
223+
if preferredSchedulingTerms == nil && len(skippedArchitectures) > 0 {
224+
log.Info("All architectures from config were already set", "ConfigSource", configSource, "SkippedArchitectures", skippedArchitectures)
225+
// Mark that all architectures from this config were duplicates
226+
pod.EnsureLabel(utils.PreferredNodeAffinityLabel, utils.LabelValueAllDuplicates)
227+
pod.PublishEvent(corev1.EventTypeNormal, ArchitecturePreferredAffinityAllDuplicates,
228+
fmt.Sprintf("%s (source: %s, architectures: %s)", ArchitecturePreferredAffinityAllDuplicatesMsg, configSource, strings.Join(skippedArchitectures, ", ")))
214229
}
215230
}
216231

controllers/podplacement/pod_reconciler.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func (r *PodReconciler) processPod(ctx context.Context, pod *Pod) {
122122
r.applyPodPlacementConfigs(ctx, pod)
123123

124124
if cppc != nil && cppc.PluginsEnabled(common.NodeAffinityScoringPluginName) {
125-
pod.SetPreferredArchNodeAffinity(cppc.Spec.Plugins.NodeAffinityScoring)
125+
pod.SetPreferredArchNodeAffinity(cppc.Spec.Plugins.NodeAffinityScoring, multiarchv1beta1.ClusterPodPlacementConfigKind)
126126
}
127127

128128
// Prepare the requirement for the node affinity.
@@ -144,9 +144,15 @@ func (r *PodReconciler) processPod(ctx context.Context, pod *Pod) {
144144
}
145145
// If the pod has been processed successfully or the max retries have been reached, remove the scheduling gate.
146146
if err == nil || pod.maxRetries() {
147-
if pod.Labels[utils.PreferredNodeAffinityLabel] == utils.LabelValueNotSet {
148-
pod.PublishEvent(corev1.EventTypeNormal, ArchitectureAwareNodeAffinitySet,
149-
ArchitecturePreferredPredicateSkippedMsg)
147+
// Check why preferred affinity was not set and emit appropriate event
148+
preferredAffinityLabel := pod.Labels[utils.PreferredNodeAffinityLabel]
149+
if preferredAffinityLabel == utils.LabelValueNotSet {
150+
// Plugin was never enabled
151+
pod.PublishEvent(corev1.EventTypeNormal, ArchitecturePreferredAffinityPluginDisabled,
152+
ArchitecturePreferredAffinityPluginDisabledMsg)
153+
} else if preferredAffinityLabel == utils.LabelValueAllDuplicates {
154+
// All architectures were already set (this label is set in SetPreferredArchNodeAffinity when all are duplicates)
155+
// Event already emitted in SetPreferredArchNodeAffinity, no need to emit again
150156
}
151157

152158
log.V(1).Info("Removing the scheduling gate from pod.")
@@ -188,7 +194,8 @@ func (r *PodReconciler) applyPodPlacementConfigs(ctx context.Context, pod *Pod)
188194
if selector == labels.Nothing() || selector.Matches(labels.Set(pod.Labels)) {
189195
log.Info("Applying namespace-scoped config", "PodPlacementConfig", ppc.Name)
190196
// Apply the configuration, checking for overlaps
191-
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring)
197+
configSource := fmt.Sprintf("%s-%s", multiarchv1beta1.PodPlacementConfigResource, ppc.Name)
198+
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring, configSource)
192199
}
193200
}
194201
}

pkg/utils/const.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,24 @@ const (
2121
)
2222

2323
const (
24-
ArchLabel = "kubernetes.io/arch"
25-
NodeAffinityLabel = "multiarch.openshift.io/node-affinity"
26-
PreferredNodeAffinityLabel = "multiarch.openshift.io/preferred-node-affinity"
27-
NodeAffinityLabelValueSet = "set"
28-
LabelValueNotSet = "not-set"
29-
HostnameLabel = "kubernetes.io/hostname"
30-
SchedulingGateLabel = "multiarch.openshift.io/scheduling-gate"
31-
SchedulingGateLabelValueGated = "gated"
32-
SchedulingGateLabelValueRemoved = "removed"
33-
PodPlacementFinalizerName = "finalizers.multiarch.openshift.io/pod-placement"
34-
SingleArchLabel = "multiarch.openshift.io/single-arch"
35-
MultiArchLabel = "multiarch.openshift.io/multi-arch"
36-
NoSupportedArchLabel = "multiarch.openshift.io/no-supported-arch"
37-
ImageInspectionErrorLabel = "multiarch.openshift.io/image-inspect-error"
38-
ImageInspectionErrorCountLabel = "multiarch.openshift.io/image-inspect-error-count"
39-
LabelGroup = "multiarch.openshift.io"
24+
ArchLabel = "kubernetes.io/arch"
25+
NodeAffinityLabel = "multiarch.openshift.io/node-affinity"
26+
PreferredNodeAffinityLabel = "multiarch.openshift.io/preferred-node-affinity"
27+
PreferredNodeAffinitySourceLabel = "multiarch.openshift.io/preferred-affinity-source"
28+
NodeAffinityLabelValueSet = "set"
29+
LabelValueNotSet = "not-set"
30+
LabelValueAllDuplicates = "all-duplicates"
31+
HostnameLabel = "kubernetes.io/hostname"
32+
SchedulingGateLabel = "multiarch.openshift.io/scheduling-gate"
33+
SchedulingGateLabelValueGated = "gated"
34+
SchedulingGateLabelValueRemoved = "removed"
35+
PodPlacementFinalizerName = "finalizers.multiarch.openshift.io/pod-placement"
36+
SingleArchLabel = "multiarch.openshift.io/single-arch"
37+
MultiArchLabel = "multiarch.openshift.io/multi-arch"
38+
NoSupportedArchLabel = "multiarch.openshift.io/no-supported-arch"
39+
ImageInspectionErrorLabel = "multiarch.openshift.io/image-inspect-error"
40+
ImageInspectionErrorCountLabel = "multiarch.openshift.io/image-inspect-error-count"
41+
LabelGroup = "multiarch.openshift.io"
4042
)
4143

4244
const (

0 commit comments

Comments
 (0)