Skip to content

Commit cecfc48

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 cecfc48

File tree

4 files changed

+53
-32
lines changed

4 files changed

+53
-32
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+
ArchitecturePreferredPredicateSkippedMsg = "The node affinity already includes architecture preferences"
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: 3 additions & 2 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.
@@ -188,7 +188,8 @@ func (r *PodReconciler) applyPodPlacementConfigs(ctx context.Context, pod *Pod)
188188
if selector == labels.Nothing() || selector.Matches(labels.Set(pod.Labels)) {
189189
log.Info("Applying namespace-scoped config", "PodPlacementConfig", ppc.Name)
190190
// Apply the configuration, checking for overlaps
191-
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring)
191+
configSource := fmt.Sprintf("%s-%s", multiarchv1beta1.PodPlacementConfigResource, ppc.Name)
192+
pod.SetPreferredArchNodeAffinity(ppc.Spec.Plugins.NodeAffinityScoring, configSource)
192193
}
193194
}
194195
}

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)