mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-02 08:17:26 +00:00
Merge pull request #51889 from guangxuli/pod_affinity_error
Automatic merge from submit-queue (batch tested with PRs 52168, 48939, 51889, 52051, 50396). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.. Add specific errors for pod affinity predicates **What this PR does / why we need it**: Add specific error for pod affinity predicates **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # fix https://github.com/kubernetes/kubernetes/issues/51655 **Special notes for your reviewer**: none **Release note**: none
This commit is contained in:
commit
507e21e7b9
@ -30,24 +30,27 @@ var (
|
|||||||
// be made to pass by removing pods, or you change an existing predicate so that
|
// be made to pass by removing pods, or you change an existing predicate so that
|
||||||
// it can never be made to pass by removing pods, you need to add the predicate
|
// it can never be made to pass by removing pods, you need to add the predicate
|
||||||
// failure error in nodesWherePreemptionMightHelp() in scheduler/core/generic_scheduler.go
|
// failure error in nodesWherePreemptionMightHelp() in scheduler/core/generic_scheduler.go
|
||||||
ErrDiskConflict = newPredicateFailureError("NoDiskConflict")
|
ErrDiskConflict = newPredicateFailureError("NoDiskConflict")
|
||||||
ErrVolumeZoneConflict = newPredicateFailureError("NoVolumeZoneConflict")
|
ErrVolumeZoneConflict = newPredicateFailureError("NoVolumeZoneConflict")
|
||||||
ErrNodeSelectorNotMatch = newPredicateFailureError("MatchNodeSelector")
|
ErrNodeSelectorNotMatch = newPredicateFailureError("MatchNodeSelector")
|
||||||
ErrPodAffinityNotMatch = newPredicateFailureError("MatchInterPodAffinity")
|
ErrPodAffinityNotMatch = newPredicateFailureError("MatchInterPodAffinity")
|
||||||
ErrTaintsTolerationsNotMatch = newPredicateFailureError("PodToleratesNodeTaints")
|
ErrPodAffinityRulesNotMatch = newPredicateFailureError("PodAffinityRulesNotMatch")
|
||||||
ErrPodNotMatchHostName = newPredicateFailureError("HostName")
|
ErrPodAntiAffinityRulesNotMatch = newPredicateFailureError("PodAntiAffinityRulesNotMatch")
|
||||||
ErrPodNotFitsHostPorts = newPredicateFailureError("PodFitsHostPorts")
|
ErrExistingPodsAntiAffinityRulesNotMatch = newPredicateFailureError("ExistingPodsAntiAffinityRulesNotMatch")
|
||||||
ErrNodeLabelPresenceViolated = newPredicateFailureError("CheckNodeLabelPresence")
|
ErrTaintsTolerationsNotMatch = newPredicateFailureError("PodToleratesNodeTaints")
|
||||||
ErrServiceAffinityViolated = newPredicateFailureError("CheckServiceAffinity")
|
ErrPodNotMatchHostName = newPredicateFailureError("HostName")
|
||||||
ErrMaxVolumeCountExceeded = newPredicateFailureError("MaxVolumeCount")
|
ErrPodNotFitsHostPorts = newPredicateFailureError("PodFitsHostPorts")
|
||||||
ErrNodeUnderMemoryPressure = newPredicateFailureError("NodeUnderMemoryPressure")
|
ErrNodeLabelPresenceViolated = newPredicateFailureError("CheckNodeLabelPresence")
|
||||||
ErrNodeUnderDiskPressure = newPredicateFailureError("NodeUnderDiskPressure")
|
ErrServiceAffinityViolated = newPredicateFailureError("CheckServiceAffinity")
|
||||||
ErrNodeOutOfDisk = newPredicateFailureError("NodeOutOfDisk")
|
ErrMaxVolumeCountExceeded = newPredicateFailureError("MaxVolumeCount")
|
||||||
ErrNodeNotReady = newPredicateFailureError("NodeNotReady")
|
ErrNodeUnderMemoryPressure = newPredicateFailureError("NodeUnderMemoryPressure")
|
||||||
ErrNodeNetworkUnavailable = newPredicateFailureError("NodeNetworkUnavailable")
|
ErrNodeUnderDiskPressure = newPredicateFailureError("NodeUnderDiskPressure")
|
||||||
ErrNodeUnschedulable = newPredicateFailureError("NodeUnschedulable")
|
ErrNodeOutOfDisk = newPredicateFailureError("NodeOutOfDisk")
|
||||||
ErrNodeUnknownCondition = newPredicateFailureError("NodeUnknownCondition")
|
ErrNodeNotReady = newPredicateFailureError("NodeNotReady")
|
||||||
ErrVolumeNodeConflict = newPredicateFailureError("NoVolumeNodeConflict")
|
ErrNodeNetworkUnavailable = newPredicateFailureError("NodeNetworkUnavailable")
|
||||||
|
ErrNodeUnschedulable = newPredicateFailureError("NodeUnschedulable")
|
||||||
|
ErrNodeUnknownCondition = newPredicateFailureError("NodeUnknownCondition")
|
||||||
|
ErrVolumeNodeConflict = newPredicateFailureError("NoVolumeNodeConflict")
|
||||||
// ErrFakePredicate is used for test only. The fake predicates returning false also returns error
|
// ErrFakePredicate is used for test only. The fake predicates returning false also returns error
|
||||||
// as ErrFakePredicate.
|
// as ErrFakePredicate.
|
||||||
ErrFakePredicate = newPredicateFailureError("FakePredicateError")
|
ErrFakePredicate = newPredicateFailureError("FakePredicateError")
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package predicates
|
package predicates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -970,8 +971,9 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta algorithm
|
|||||||
if node == nil {
|
if node == nil {
|
||||||
return false, nil, fmt.Errorf("node not found")
|
return false, nil, fmt.Errorf("node not found")
|
||||||
}
|
}
|
||||||
if !c.satisfiesExistingPodsAntiAffinity(pod, meta, nodeInfo) {
|
if failedPredicates, error := c.satisfiesExistingPodsAntiAffinity(pod, meta, nodeInfo); failedPredicates != nil {
|
||||||
return false, []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, nil
|
failedPredicates := append([]algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, failedPredicates)
|
||||||
|
return false, failedPredicates, error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now check if <pod> requirements will be satisfied on this node.
|
// Now check if <pod> requirements will be satisfied on this node.
|
||||||
@ -979,8 +981,9 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta algorithm
|
|||||||
if affinity == nil || (affinity.PodAffinity == nil && affinity.PodAntiAffinity == nil) {
|
if affinity == nil || (affinity.PodAffinity == nil && affinity.PodAntiAffinity == nil) {
|
||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
if !c.satisfiesPodsAffinityAntiAffinity(pod, nodeInfo, affinity) {
|
if failedPredicates, error := c.satisfiesPodsAffinityAntiAffinity(pod, nodeInfo, affinity); failedPredicates != nil {
|
||||||
return false, []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, nil
|
failedPredicates := append([]algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, failedPredicates)
|
||||||
|
return false, failedPredicates, error
|
||||||
}
|
}
|
||||||
|
|
||||||
if glog.V(10) {
|
if glog.V(10) {
|
||||||
@ -1150,10 +1153,10 @@ func (c *PodAffinityChecker) getMatchingAntiAffinityTerms(pod *v1.Pod, allPods [
|
|||||||
|
|
||||||
// Checks if scheduling the pod onto this node would break any anti-affinity
|
// Checks if scheduling the pod onto this node would break any anti-affinity
|
||||||
// rules indicated by the existing pods.
|
// rules indicated by the existing pods.
|
||||||
func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) bool {
|
func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (algorithm.PredicateFailureReason, error) {
|
||||||
node := nodeInfo.Node()
|
node := nodeInfo.Node()
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return false
|
return ErrExistingPodsAntiAffinityRulesNotMatch, fmt.Errorf("Node is nil")
|
||||||
}
|
}
|
||||||
var matchingTerms map[string][]matchingPodAntiAffinityTerm
|
var matchingTerms map[string][]matchingPodAntiAffinityTerm
|
||||||
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
||||||
@ -1163,25 +1166,28 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
|
|||||||
// present in nodeInfo. Pods on other nodes pass the filter.
|
// present in nodeInfo. Pods on other nodes pass the filter.
|
||||||
filteredPods, err := c.podLister.FilteredList(nodeInfo.Filter, labels.Everything())
|
filteredPods, err := c.podLister.FilteredList(nodeInfo.Filter, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to get all pods, %+v", err)
|
errMessage := fmt.Sprintf("Failed to get all pods, %+v", err)
|
||||||
return false
|
glog.Error(errMessage)
|
||||||
|
return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage)
|
||||||
}
|
}
|
||||||
if matchingTerms, err = c.getMatchingAntiAffinityTerms(pod, filteredPods); err != nil {
|
if matchingTerms, err = c.getMatchingAntiAffinityTerms(pod, filteredPods); err != nil {
|
||||||
glog.Errorf("Failed to get all terms that pod %+v matches, err: %+v", podName(pod), err)
|
errMessage := fmt.Sprintf("Failed to get all terms that pod %+v matches, err: %+v", podName(pod), err)
|
||||||
return false
|
glog.Error(errMessage)
|
||||||
|
return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, terms := range matchingTerms {
|
for _, terms := range matchingTerms {
|
||||||
for i := range terms {
|
for i := range terms {
|
||||||
term := &terms[i]
|
term := &terms[i]
|
||||||
if len(term.term.TopologyKey) == 0 {
|
if len(term.term.TopologyKey) == 0 {
|
||||||
glog.Error("Empty topologyKey is not allowed except for PreferredDuringScheduling pod anti-affinity")
|
errMessage := fmt.Sprintf("Empty topologyKey is not allowed except for PreferredDuringScheduling pod anti-affinity")
|
||||||
return false
|
glog.Error(errMessage)
|
||||||
|
return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage)
|
||||||
}
|
}
|
||||||
if priorityutil.NodesHaveSameTopologyKey(node, term.node, term.term.TopologyKey) {
|
if priorityutil.NodesHaveSameTopologyKey(node, term.node, term.term.TopologyKey) {
|
||||||
glog.V(10).Infof("Cannot schedule pod %+v onto node %v,because of PodAntiAffinityTerm %v",
|
glog.V(10).Infof("Cannot schedule pod %+v onto node %v,because of PodAntiAffinityTerm %v",
|
||||||
podName(pod), node.Name, term.term)
|
podName(pod), node.Name, term.term)
|
||||||
return false
|
return ErrExistingPodsAntiAffinityRulesNotMatch, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1191,27 +1197,27 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
|
|||||||
glog.Infof("Schedule Pod %+v on Node %+v is allowed, existing pods anti-affinity rules satisfied.",
|
glog.Infof("Schedule Pod %+v on Node %+v is allowed, existing pods anti-affinity rules satisfied.",
|
||||||
podName(pod), node.Name)
|
podName(pod), node.Name)
|
||||||
}
|
}
|
||||||
return true
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if scheduling the pod onto this node would break any rules of this pod.
|
// Checks if scheduling the pod onto this node would break any rules of this pod.
|
||||||
func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, nodeInfo *schedulercache.NodeInfo, affinity *v1.Affinity) bool {
|
func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, nodeInfo *schedulercache.NodeInfo, affinity *v1.Affinity) (algorithm.PredicateFailureReason, error) {
|
||||||
node := nodeInfo.Node()
|
node := nodeInfo.Node()
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return false
|
return ErrPodAffinityRulesNotMatch, fmt.Errorf("Node is nil")
|
||||||
}
|
}
|
||||||
filteredPods, err := c.podLister.FilteredList(nodeInfo.Filter, labels.Everything())
|
filteredPods, err := c.podLister.FilteredList(nodeInfo.Filter, labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return ErrPodAffinityRulesNotMatch, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check all affinity terms.
|
// Check all affinity terms.
|
||||||
for _, term := range getPodAffinityTerms(affinity.PodAffinity) {
|
for _, term := range getPodAffinityTerms(affinity.PodAffinity) {
|
||||||
termMatches, matchingPodExists, err := c.anyPodMatchesPodAffinityTerm(pod, filteredPods, node, &term)
|
termMatches, matchingPodExists, err := c.anyPodMatchesPodAffinityTerm(pod, filteredPods, node, &term)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v, err: %v",
|
errMessage := fmt.Sprintf("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v, err: %v", podName(pod), node.Name, term, err)
|
||||||
podName(pod), node.Name, term, err)
|
glog.Error(errMessage)
|
||||||
return false
|
return ErrPodAffinityRulesNotMatch, errors.New(errMessage)
|
||||||
}
|
}
|
||||||
if !termMatches {
|
if !termMatches {
|
||||||
// If the requirement matches a pod's own labels are namespace, and there are
|
// If the requirement matches a pod's own labels are namespace, and there are
|
||||||
@ -1220,20 +1226,20 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node
|
|||||||
if matchingPodExists {
|
if matchingPodExists {
|
||||||
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v",
|
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v",
|
||||||
podName(pod), node.Name, term)
|
podName(pod), node.Name, term)
|
||||||
return false
|
return ErrPodAffinityRulesNotMatch, nil
|
||||||
}
|
}
|
||||||
namespaces := priorityutil.GetNamespacesFromPodAffinityTerm(pod, &term)
|
namespaces := priorityutil.GetNamespacesFromPodAffinityTerm(pod, &term)
|
||||||
selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector)
|
selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Cannot parse selector on term %v for pod %v. Details %v",
|
errMessage := fmt.Sprintf("Cannot parse selector on term %v for pod %v. Details %v", term, podName(pod), err)
|
||||||
term, podName(pod), err)
|
glog.Error(errMessage)
|
||||||
return false
|
return ErrPodAffinityRulesNotMatch, errors.New(errMessage)
|
||||||
}
|
}
|
||||||
match := priorityutil.PodMatchesTermsNamespaceAndSelector(pod, namespaces, selector)
|
match := priorityutil.PodMatchesTermsNamespaceAndSelector(pod, namespaces, selector)
|
||||||
if !match {
|
if !match {
|
||||||
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v",
|
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v",
|
||||||
podName(pod), node.Name, term)
|
podName(pod), node.Name, term)
|
||||||
return false
|
return ErrPodAffinityRulesNotMatch, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1244,7 +1250,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node
|
|||||||
if err != nil || termMatches {
|
if err != nil || termMatches {
|
||||||
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAntiAffinityTerm %v, err: %v",
|
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAntiAffinityTerm %v, err: %v",
|
||||||
podName(pod), node.Name, term, err)
|
podName(pod), node.Name, term, err)
|
||||||
return false
|
return ErrPodAntiAffinityRulesNotMatch, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1254,7 +1260,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node
|
|||||||
glog.Infof("Schedule Pod %+v on Node %+v is allowed, pod affinity/anti-affinity constraints satisfied.",
|
glog.Infof("Schedule Pod %+v on Node %+v is allowed, pod affinity/anti-affinity constraints satisfied.",
|
||||||
podName(pod), node.Name)
|
podName(pod), node.Name)
|
||||||
}
|
}
|
||||||
return true
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodToleratesNodeTaints checks if a pod tolerations can tolerate the node taints
|
// PodToleratesNodeTaints checks if a pod tolerations can tolerate the node taints
|
||||||
|
@ -2024,11 +2024,12 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
podLabel2 := map[string]string{"security": "S1"}
|
podLabel2 := map[string]string{"security": "S1"}
|
||||||
node1 := v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: labels1}}
|
node1 := v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: labels1}}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
pods []*v1.Pod
|
pods []*v1.Pod
|
||||||
node *v1.Node
|
node *v1.Node
|
||||||
fits bool
|
fits bool
|
||||||
test string
|
test string
|
||||||
|
expectFailureReasons []algorithm.PredicateFailureReason
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
pod: new(v1.Pod),
|
pod: new(v1.Pod),
|
||||||
@ -2124,10 +2125,11 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel, Namespace: "ns"}}},
|
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel, Namespace: "ns"}}},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "Does not satisfy the PodAffinity with labelSelector because of diff Namespace",
|
test: "Does not satisfy the PodAffinity with labelSelector because of diff Namespace",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2154,10 +2156,11 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "Doesn't satisfy the PodAffinity because of unmatching labelSelector with the existing pod",
|
test: "Doesn't satisfy the PodAffinity because of unmatching labelSelector with the existing pod",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2250,10 +2253,11 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "The labelSelector requirements(items of matchExpressions) are ANDed, the pod cannot schedule onto the node because one of the matchExpression item don't match.",
|
test: "The labelSelector requirements(items of matchExpressions) are ANDed, the pod cannot schedule onto the node because one of the matchExpression item don't match.",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2416,10 +2420,11 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "satisfies the PodAffinity but doesn't satisfies the PodAntiAffinity with the existing pod",
|
test: "satisfies the PodAffinity but doesn't satisfies the PodAntiAffinity with the existing pod",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2489,9 +2494,10 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{Labels: podLabel},
|
ObjectMeta: metav1.ObjectMeta{Labels: podLabel},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfies PodAntiAffinity symmetry with the existing pod",
|
test: "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfies PodAntiAffinity symmetry with the existing pod",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrExistingPodsAntiAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2519,10 +2525,11 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "pod matches its own Label in PodAffinity and that matches the existing pod Labels",
|
test: "pod matches its own Label in PodAffinity and that matches the existing pod Labels",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2555,9 +2562,10 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{Labels: podLabel},
|
ObjectMeta: metav1.ObjectMeta{Labels: podLabel},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
node: &node1,
|
node: &node1,
|
||||||
fits: false,
|
fits: false,
|
||||||
test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. doesn't satisfy PodAntiAffinity symmetry with the existing pod",
|
test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. doesn't satisfy PodAntiAffinity symmetry with the existing pod",
|
||||||
|
expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrExistingPodsAntiAffinityRulesNotMatch},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2595,7 +2603,6 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. satisfy PodAntiAffinity symmetry with the existing pod",
|
test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. satisfy PodAntiAffinity symmetry with the existing pod",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expectedFailureReasons := []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
node := test.node
|
node := test.node
|
||||||
@ -2613,12 +2620,9 @@ func TestInterPodAffinity(t *testing.T) {
|
|||||||
nodeInfo := schedulercache.NewNodeInfo(podsOnNode...)
|
nodeInfo := schedulercache.NewNodeInfo(podsOnNode...)
|
||||||
nodeInfo.SetNode(test.node)
|
nodeInfo.SetNode(test.node)
|
||||||
nodeInfoMap := map[string]*schedulercache.NodeInfo{test.node.Name: nodeInfo}
|
nodeInfoMap := map[string]*schedulercache.NodeInfo{test.node.Name: nodeInfo}
|
||||||
fits, reasons, err := fit.InterPodAffinityMatches(test.pod, PredicateMetadata(test.pod, nodeInfoMap), nodeInfo)
|
fits, reasons, _ := fit.InterPodAffinityMatches(test.pod, PredicateMetadata(test.pod, nodeInfoMap), nodeInfo)
|
||||||
if err != nil {
|
if !fits && !reflect.DeepEqual(reasons, test.expectFailureReasons) {
|
||||||
t.Errorf("%s: unexpected error %v", test.test, err)
|
t.Errorf("%s: unexpected failure reasons: %v, want: %v", test.test, reasons, test.expectFailureReasons)
|
||||||
}
|
|
||||||
if !fits && !reflect.DeepEqual(reasons, expectedFailureReasons) {
|
|
||||||
t.Errorf("%s: unexpected failure reasons: %v, want: %v", test.test, reasons, expectedFailureReasons)
|
|
||||||
}
|
}
|
||||||
if fits != test.fits {
|
if fits != test.fits {
|
||||||
t.Errorf("%s: expected %v got %v", test.test, test.fits, fits)
|
t.Errorf("%s: expected %v got %v", test.test, test.fits, fits)
|
||||||
@ -2645,12 +2649,13 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
pods []*v1.Pod
|
pods []*v1.Pod
|
||||||
nodes []v1.Node
|
nodes []v1.Node
|
||||||
fits map[string]bool
|
nodesExpectAffinityFailureReasons [][]algorithm.PredicateFailureReason
|
||||||
test string
|
fits map[string]bool
|
||||||
nometa bool
|
test string
|
||||||
|
nometa bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{
|
pod: &v1.Pod{
|
||||||
@ -2688,6 +2693,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
"machine2": true,
|
"machine2": true,
|
||||||
"machine3": false,
|
"machine3": false,
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{nil, nil, {ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch}},
|
||||||
test: "A pod can be scheduled onto all the nodes that have the same topology key & label value with one of them has an existing pod that match the affinity rules",
|
test: "A pod can be scheduled onto all the nodes that have the same topology key & label value with one of them has an existing pod that match the affinity rules",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2736,6 +2742,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"region": "r1", "hostname": "h1"}}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"region": "r1", "hostname": "h1"}}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"region": "r1", "hostname": "h2"}}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"region": "r1", "hostname": "h2"}}},
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{nil, nil},
|
||||||
fits: map[string]bool{
|
fits: map[string]bool{
|
||||||
"nodeA": false,
|
"nodeA": false,
|
||||||
"nodeB": true,
|
"nodeB": true,
|
||||||
@ -2775,6 +2782,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"zone": "az1", "hostname": "h1"}}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"zone": "az1", "hostname": "h1"}}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"zone": "az2", "hostname": "h2"}}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"zone": "az2", "hostname": "h2"}}},
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{nil, nil},
|
||||||
fits: map[string]bool{
|
fits: map[string]bool{
|
||||||
"nodeA": true,
|
"nodeA": true,
|
||||||
"nodeB": true,
|
"nodeB": true,
|
||||||
@ -2812,6 +2820,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"region": "r1", "hostname": "nodeA"}}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"region": "r1", "hostname": "nodeA"}}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"region": "r1", "hostname": "nodeB"}}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"region": "r1", "hostname": "nodeB"}}},
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}},
|
||||||
fits: map[string]bool{
|
fits: map[string]bool{
|
||||||
"nodeA": false,
|
"nodeA": false,
|
||||||
"nodeB": false,
|
"nodeB": false,
|
||||||
@ -2849,6 +2858,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: labelRgChinaAzAz1}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: labelRgChinaAzAz1}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}},
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, nil},
|
||||||
fits: map[string]bool{
|
fits: map[string]bool{
|
||||||
"nodeA": false,
|
"nodeA": false,
|
||||||
"nodeB": false,
|
"nodeB": false,
|
||||||
@ -2912,6 +2922,12 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeD", Labels: labelRgUS}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeD", Labels: labelRgUS}},
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{
|
||||||
|
{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch},
|
||||||
|
{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch},
|
||||||
|
{ErrPodAffinityNotMatch, ErrExistingPodsAntiAffinityRulesNotMatch},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
fits: map[string]bool{
|
fits: map[string]bool{
|
||||||
"nodeA": false,
|
"nodeA": false,
|
||||||
"nodeB": false,
|
"nodeB": false,
|
||||||
@ -2986,6 +3002,11 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: labelRgChinaAzAz1}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: labelRgChinaAzAz1}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}},
|
||||||
},
|
},
|
||||||
|
nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{
|
||||||
|
{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch},
|
||||||
|
{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
fits: map[string]bool{
|
fits: map[string]bool{
|
||||||
"nodeA": false,
|
"nodeA": false,
|
||||||
"nodeB": false,
|
"nodeB": false,
|
||||||
@ -2994,12 +3015,12 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
test: "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that match the inter pod affinity rule. The pod can not be scheduled onto nodeA, nodeB, but can be schedulerd onto nodeC (NodeC has an existing pod that match the inter pod affinity rule but in different namespace)",
|
test: "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that match the inter pod affinity rule. The pod can not be scheduled onto nodeA, nodeB, but can be schedulerd onto nodeC (NodeC has an existing pod that match the inter pod affinity rule but in different namespace)",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
affinityExpectedFailureReasons := []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}
|
|
||||||
selectorExpectedFailureReasons := []algorithm.PredicateFailureReason{ErrNodeSelectorNotMatch}
|
selectorExpectedFailureReasons := []algorithm.PredicateFailureReason{ErrNodeSelectorNotMatch}
|
||||||
|
|
||||||
for _, test := range tests {
|
for indexTest, test := range tests {
|
||||||
nodeListInfo := FakeNodeListInfo(test.nodes)
|
nodeListInfo := FakeNodeListInfo(test.nodes)
|
||||||
for _, node := range test.nodes {
|
for indexNode, node := range test.nodes {
|
||||||
var podsOnNode []*v1.Pod
|
var podsOnNode []*v1.Pod
|
||||||
for _, pod := range test.pods {
|
for _, pod := range test.pods {
|
||||||
if pod.Spec.NodeName == node.Name {
|
if pod.Spec.NodeName == node.Name {
|
||||||
@ -3021,12 +3042,9 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) {
|
|||||||
meta = PredicateMetadata(test.pod, nodeInfoMap)
|
meta = PredicateMetadata(test.pod, nodeInfoMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fits, reasons, err := testFit.InterPodAffinityMatches(test.pod, meta, nodeInfo)
|
fits, reasons, _ := testFit.InterPodAffinityMatches(test.pod, meta, nodeInfo)
|
||||||
if err != nil {
|
if !fits && !reflect.DeepEqual(reasons, test.nodesExpectAffinityFailureReasons[indexNode]) {
|
||||||
t.Errorf("%s: unexpected error %v", test.test, err)
|
t.Errorf("index: %d test: %s unexpected failure reasons: %v expect: %v", indexTest, test.test, reasons, test.nodesExpectAffinityFailureReasons[indexNode])
|
||||||
}
|
|
||||||
if !fits && !reflect.DeepEqual(reasons, affinityExpectedFailureReasons) {
|
|
||||||
t.Errorf("%s: unexpected failure reasons: %v", test.test, reasons)
|
|
||||||
}
|
}
|
||||||
affinity := test.pod.Spec.Affinity
|
affinity := test.pod.Spec.Affinity
|
||||||
if affinity != nil && affinity.NodeAffinity != nil {
|
if affinity != nil && affinity.NodeAffinity != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user