mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 01:06:27 +00:00
Cleanup work to enable feature gating annotations
This commit is contained in:
parent
32c4683242
commit
2bcd63c524
@ -27,9 +27,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsOpaqueIntResourceName returns true if the resource name has the opaque
|
// IsOpaqueIntResourceName returns true if the resource name has the opaque
|
||||||
@ -281,7 +279,8 @@ const (
|
|||||||
ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
|
ObjectTTLAnnotationKey string = "node.alpha.kubernetes.io/ttl"
|
||||||
|
|
||||||
// AffinityAnnotationKey represents the key of affinity data (json serialized)
|
// AffinityAnnotationKey represents the key of affinity data (json serialized)
|
||||||
// in the Annotations of a Pod. TODO remove in 1.7
|
// in the Annotations of a Pod.
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
|
AffinityAnnotationKey string = "scheduler.alpha.kubernetes.io/affinity"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -606,7 +605,7 @@ func RemoveTaint(node *Node, taint *Taint) (*Node, bool, error) {
|
|||||||
|
|
||||||
// GetAffinityFromPodAnnotations gets the json serialized affinity data from Pod.Annotations
|
// GetAffinityFromPodAnnotations gets the json serialized affinity data from Pod.Annotations
|
||||||
// and converts it to the Affinity type in api.
|
// and converts it to the Affinity type in api.
|
||||||
// TODO remove for 1.7
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) {
|
func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) {
|
||||||
if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" {
|
if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" {
|
||||||
var affinity Affinity
|
var affinity Affinity
|
||||||
@ -618,26 +617,3 @@ func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, er
|
|||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconcile api and annotation affinity definitions.
|
|
||||||
// TODO remove for 1.7
|
|
||||||
func ReconcileAffinity(pod *Pod) *Affinity {
|
|
||||||
affinity := pod.Spec.Affinity
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.AffinityInAnnotations) {
|
|
||||||
annotationsAffinity, _ := GetAffinityFromPodAnnotations(pod.Annotations)
|
|
||||||
if affinity == nil && annotationsAffinity != nil {
|
|
||||||
affinity = annotationsAffinity
|
|
||||||
} else if annotationsAffinity != nil {
|
|
||||||
if affinity != nil && affinity.NodeAffinity == nil && annotationsAffinity.NodeAffinity != nil {
|
|
||||||
affinity.NodeAffinity = annotationsAffinity.NodeAffinity
|
|
||||||
}
|
|
||||||
if affinity != nil && affinity.PodAffinity == nil && annotationsAffinity.PodAffinity != nil {
|
|
||||||
affinity.PodAffinity = annotationsAffinity.PodAffinity
|
|
||||||
}
|
|
||||||
if affinity != nil && affinity.PodAntiAffinity == nil && annotationsAffinity.PodAntiAffinity != nil {
|
|
||||||
affinity.PodAntiAffinity = annotationsAffinity.PodAntiAffinity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affinity
|
|
||||||
}
|
|
||||||
|
@ -17,14 +17,12 @@ limitations under the License.
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddToNodeAddresses(t *testing.T) {
|
func TestAddToNodeAddresses(t *testing.T) {
|
||||||
@ -647,6 +645,7 @@ func TestSysctlsFromPodAnnotation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestGetAffinityFromPodAnnotations(t *testing.T) {
|
func TestGetAffinityFromPodAnnotations(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
pod *Pod
|
pod *Pod
|
||||||
@ -702,124 +701,3 @@ func TestGetAffinityFromPodAnnotations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReconcileAffinity(t *testing.T) {
|
|
||||||
baseAffinity := &Affinity{
|
|
||||||
NodeAffinity: &NodeAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &NodeSelector{
|
|
||||||
NodeSelectorTerms: []NodeSelectorTerm{
|
|
||||||
{
|
|
||||||
MatchExpressions: []NodeSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "foo",
|
|
||||||
Operator: NodeSelectorOpIn,
|
|
||||||
Values: []string{"bar", "value2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PodAffinity: &PodAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "security",
|
|
||||||
Operator: metav1.LabelSelectorOpDoesNotExist,
|
|
||||||
Values: []string{"securityscan"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: "topologyKey1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PodAntiAffinity: &PodAntiAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: []PodAffinityTerm{
|
|
||||||
{
|
|
||||||
LabelSelector: &metav1.LabelSelector{
|
|
||||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "service",
|
|
||||||
Operator: metav1.LabelSelectorOpIn,
|
|
||||||
Values: []string{"S1", "value2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TopologyKey: "topologyKey2",
|
|
||||||
Namespaces: []string{"ns1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeAffinityAnnotation := map[string]string{
|
|
||||||
AffinityAnnotationKey: `
|
|
||||||
{"nodeAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [
|
|
||||||
{
|
|
||||||
"weight": 2,
|
|
||||||
"preference": {"matchExpressions": [
|
|
||||||
{
|
|
||||||
"key": "foo",
|
|
||||||
"operator": "In", "values": ["bar"]
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
}
|
|
||||||
]}}`,
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
pod *Pod
|
|
||||||
expected *Affinity
|
|
||||||
annotationsEnabled bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
pod: &Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Annotations: nodeAffinityAnnotation,
|
|
||||||
},
|
|
||||||
Spec: PodSpec{
|
|
||||||
Affinity: baseAffinity,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: baseAffinity,
|
|
||||||
annotationsEnabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pod: &Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Annotations: nodeAffinityAnnotation,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: &Affinity{
|
|
||||||
NodeAffinity: &NodeAffinity{
|
|
||||||
PreferredDuringSchedulingIgnoredDuringExecution: []PreferredSchedulingTerm{
|
|
||||||
{
|
|
||||||
Weight: 2,
|
|
||||||
Preference: NodeSelectorTerm{
|
|
||||||
MatchExpressions: []NodeSelectorRequirement{
|
|
||||||
{
|
|
||||||
Key: "foo",
|
|
||||||
Operator: NodeSelectorOpIn,
|
|
||||||
Values: []string{"bar"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
annotationsEnabled: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("AffinityInAnnotations=%t", tc.annotationsEnabled))
|
|
||||||
affinity := ReconcileAffinity(tc.pod)
|
|
||||||
if affinity != tc.expected {
|
|
||||||
t.Errorf("[%v]did not get expected affinity. got: %v instead of %v", i, affinity, tc.expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -67,7 +67,11 @@ const (
|
|||||||
// Note: This feature is not supported for `BestEffort` pods.
|
// Note: This feature is not supported for `BestEffort` pods.
|
||||||
ExperimentalCriticalPodAnnotation utilfeature.Feature = "ExperimentalCriticalPodAnnotation"
|
ExperimentalCriticalPodAnnotation utilfeature.Feature = "ExperimentalCriticalPodAnnotation"
|
||||||
|
|
||||||
|
// owner: @davidopp
|
||||||
|
// alpha: v1.6
|
||||||
|
//
|
||||||
// Determines if affinity defined in annotations should be processed
|
// Determines if affinity defined in annotations should be processed
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
AffinityInAnnotations utilfeature.Feature = "AffinityInAnnotations"
|
AffinityInAnnotations utilfeature.Feature = "AffinityInAnnotations"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ go_test(
|
|||||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||||
|
"//vendor:k8s.io/apiserver/pkg/util/feature",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -585,7 +585,7 @@ func podMatchesNodeLabels(pod *v1.Pod, node *v1.Node) bool {
|
|||||||
// 5. zero-length non-nil []NodeSelectorRequirement matches no nodes also, just for simplicity
|
// 5. zero-length non-nil []NodeSelectorRequirement matches no nodes also, just for simplicity
|
||||||
// 6. non-nil empty NodeSelectorRequirement is not allowed
|
// 6. non-nil empty NodeSelectorRequirement is not allowed
|
||||||
nodeAffinityMatches := true
|
nodeAffinityMatches := true
|
||||||
affinity := v1.ReconcileAffinity(pod)
|
affinity := schedulercache.ReconcileAffinity(pod)
|
||||||
if affinity != nil && affinity.NodeAffinity != nil {
|
if affinity != nil && affinity.NodeAffinity != nil {
|
||||||
nodeAffinity := affinity.NodeAffinity
|
nodeAffinity := affinity.NodeAffinity
|
||||||
// if no required NodeAffinity requirements, will do no-op, means select all nodes.
|
// if no required NodeAffinity requirements, will do no-op, means select all nodes.
|
||||||
@ -897,7 +897,7 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now check if <pod> requirements will be satisfied on this node.
|
// Now check if <pod> requirements will be satisfied on this node.
|
||||||
affinity := v1.ReconcileAffinity(pod)
|
affinity := schedulercache.ReconcileAffinity(pod)
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -1001,7 +1001,7 @@ func getMatchingAntiAffinityTerms(pod *v1.Pod, nodeInfoMap map[string]*scheduler
|
|||||||
}
|
}
|
||||||
var nodeResult []matchingPodAntiAffinityTerm
|
var nodeResult []matchingPodAntiAffinityTerm
|
||||||
for _, existingPod := range nodeInfo.PodsWithAffinity() {
|
for _, existingPod := range nodeInfo.PodsWithAffinity() {
|
||||||
affinity := v1.ReconcileAffinity(existingPod)
|
affinity := schedulercache.ReconcileAffinity(existingPod)
|
||||||
if affinity == nil {
|
if affinity == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1029,7 +1029,7 @@ func getMatchingAntiAffinityTerms(pod *v1.Pod, nodeInfoMap map[string]*scheduler
|
|||||||
func (c *PodAffinityChecker) getMatchingAntiAffinityTerms(pod *v1.Pod, allPods []*v1.Pod) ([]matchingPodAntiAffinityTerm, error) {
|
func (c *PodAffinityChecker) getMatchingAntiAffinityTerms(pod *v1.Pod, allPods []*v1.Pod) ([]matchingPodAntiAffinityTerm, error) {
|
||||||
var result []matchingPodAntiAffinityTerm
|
var result []matchingPodAntiAffinityTerm
|
||||||
for _, existingPod := range allPods {
|
for _, existingPod := range allPods {
|
||||||
affinity := v1.ReconcileAffinity(existingPod)
|
affinity := schedulercache.ReconcileAffinity(existingPod)
|
||||||
if affinity != nil && affinity.PodAntiAffinity != nil {
|
if affinity != nil && affinity.PodAntiAffinity != nil {
|
||||||
existingPodNode, err := c.info.GetNodeInfo(existingPod.Spec.NodeName)
|
existingPodNode, err := c.info.GetNodeInfo(existingPod.Spec.NodeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3581,7 +3581,7 @@ func TestVolumeZonePredicate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove for 1.7
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestPodAnnotationFitsSelector(t *testing.T) {
|
func TestPodAnnotationFitsSelector(t *testing.T) {
|
||||||
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -4000,7 +4000,7 @@ func TestPodAnnotationFitsSelector(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove for 1.7
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestInterPodAffinityAnnotations(t *testing.T) {
|
func TestInterPodAffinityAnnotations(t *testing.T) {
|
||||||
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
||||||
podLabel := map[string]string{"service": "securityscan"}
|
podLabel := map[string]string{"service": "securityscan"}
|
||||||
@ -4555,7 +4555,7 @@ func TestInterPodAffinityAnnotations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove for 1.7
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestInterPodAffinityAnnotationsWithMultipleNodes(t *testing.T) {
|
func TestInterPodAffinityAnnotationsWithMultipleNodes(t *testing.T) {
|
||||||
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
||||||
podLabelA := map[string]string{
|
podLabelA := map[string]string{
|
||||||
|
@ -67,6 +67,7 @@ go_test(
|
|||||||
"//plugin/pkg/scheduler/schedulercache:go_default_library",
|
"//plugin/pkg/scheduler/schedulercache:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
"//vendor:k8s.io/apiserver/pkg/util/feature",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func (p *podAffinityPriorityMap) processTerms(terms []v1.WeightedPodAffinityTerm
|
|||||||
// Symmetry need to be considered for preferredDuringSchedulingIgnoredDuringExecution from podAffinity & podAntiAffinity,
|
// Symmetry need to be considered for preferredDuringSchedulingIgnoredDuringExecution from podAffinity & podAntiAffinity,
|
||||||
// symmetry need to be considered for hard requirements from podAffinity
|
// symmetry need to be considered for hard requirements from podAffinity
|
||||||
func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) {
|
func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) {
|
||||||
affinity := v1.ReconcileAffinity(pod)
|
affinity := schedulercache.ReconcileAffinity(pod)
|
||||||
hasAffinityConstraints := affinity != nil && affinity.PodAffinity != nil
|
hasAffinityConstraints := affinity != nil && affinity.PodAffinity != nil
|
||||||
hasAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil
|
hasAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, node
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
existingPodAffinity := v1.ReconcileAffinity(existingPod)
|
existingPodAffinity := schedulercache.ReconcileAffinity(existingPod)
|
||||||
existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil
|
existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil
|
||||||
existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil
|
existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil
|
||||||
|
|
||||||
|
@ -615,7 +615,7 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove for 1.7
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestInterPodAffinityAnnotationsPriority(t *testing.T) {
|
func TestInterPodAffinityAnnotationsPriority(t *testing.T) {
|
||||||
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
||||||
labelRgChina := map[string]string{
|
labelRgChina := map[string]string{
|
||||||
@ -1089,7 +1089,7 @@ func TestInterPodAffinityAnnotationsPriority(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove for 1.7
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestHardPodAffinityAnnotationsSymmetricWeight(t *testing.T) {
|
func TestHardPodAffinityAnnotationsSymmetricWeight(t *testing.T) {
|
||||||
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
||||||
podLabelServiceS1 := map[string]string{
|
podLabelServiceS1 := map[string]string{
|
||||||
|
@ -41,6 +41,6 @@ func PriorityMetadata(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.Nod
|
|||||||
return &priorityMetadata{
|
return &priorityMetadata{
|
||||||
nonZeroRequest: getNonZeroRequests(pod),
|
nonZeroRequest: getNonZeroRequests(pod),
|
||||||
podTolerations: tolerations,
|
podTolerations: tolerations,
|
||||||
affinity: v1.ReconcileAffinity(pod),
|
affinity: schedulercache.ReconcileAffinity(pod),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ func CalculateNodeAffinityPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *s
|
|||||||
affinity = priorityMeta.affinity
|
affinity = priorityMeta.affinity
|
||||||
} else {
|
} else {
|
||||||
// We couldn't parse metadata - fallback to the podspec.
|
// We couldn't parse metadata - fallback to the podspec.
|
||||||
affinity = v1.ReconcileAffinity(pod)
|
affinity = schedulercache.ReconcileAffinity(pod)
|
||||||
}
|
}
|
||||||
|
|
||||||
var count int32
|
var count int32
|
||||||
|
@ -179,6 +179,7 @@ func TestNodeAffinityPriority(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
func TestNodeAffinityAnnotationsPriority(t *testing.T) {
|
func TestNodeAffinityAnnotationsPriority(t *testing.T) {
|
||||||
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
utilfeature.DefaultFeatureGate.Set("AffinityInAnnotations=true")
|
||||||
label1 := map[string]string{"foo": "bar"}
|
label1 := map[string]string{"foo": "bar"}
|
||||||
|
@ -14,23 +14,29 @@ go_library(
|
|||||||
"cache.go",
|
"cache.go",
|
||||||
"interface.go",
|
"interface.go",
|
||||||
"node_info.go",
|
"node_info.go",
|
||||||
|
"reconcile_affinity.go",
|
||||||
"util.go",
|
"util.go",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
|
"//pkg/features:go_default_library",
|
||||||
"//plugin/pkg/scheduler/algorithm/priorities/util:go_default_library",
|
"//plugin/pkg/scheduler/algorithm/priorities/util:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
|
"//vendor:k8s.io/apiserver/pkg/util/feature",
|
||||||
"//vendor:k8s.io/client-go/tools/cache",
|
"//vendor:k8s.io/client-go/tools/cache",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = ["cache_test.go"],
|
srcs = [
|
||||||
|
"cache_test.go",
|
||||||
|
"reconcile_affinity_test.go",
|
||||||
|
],
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
@ -39,6 +45,7 @@ go_test(
|
|||||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||||
|
"//vendor:k8s.io/apiserver/pkg/util/feature",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ func (n *NodeInfo) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hasPodAffinityConstraints(pod *v1.Pod) bool {
|
func hasPodAffinityConstraints(pod *v1.Pod) bool {
|
||||||
affinity := v1.ReconcileAffinity(pod)
|
affinity := ReconcileAffinity(pod)
|
||||||
return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil)
|
return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
plugin/pkg/scheduler/schedulercache/reconcile_affinity.go
Normal file
53
plugin/pkg/scheduler/schedulercache/reconcile_affinity.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package schedulercache
|
||||||
|
|
||||||
|
import (
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reconcile api and annotation affinity definitions.
|
||||||
|
// When alpha affinity feature is not enabled, always take affinity
|
||||||
|
// from PodSpec.When alpha affinity feature is enabled, if affinity
|
||||||
|
// is not set in PodSpec, take affinity from annotation.
|
||||||
|
// When alpha affinity feature is enabled, if affinity is set in PodSpec,
|
||||||
|
// take node affinity, pod affinity, and pod anti-affinity individually
|
||||||
|
// using the following rule: take affinity from PodSpec if it is defined,
|
||||||
|
// otherwise take from annotation if it is defined.
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
|
func ReconcileAffinity(pod *v1.Pod) *v1.Affinity {
|
||||||
|
affinity := pod.Spec.Affinity
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.AffinityInAnnotations) {
|
||||||
|
annotationsAffinity, _ := v1.GetAffinityFromPodAnnotations(pod.Annotations)
|
||||||
|
if affinity == nil && annotationsAffinity != nil {
|
||||||
|
affinity = annotationsAffinity
|
||||||
|
} else if annotationsAffinity != nil {
|
||||||
|
if affinity != nil && affinity.NodeAffinity == nil && annotationsAffinity.NodeAffinity != nil {
|
||||||
|
affinity.NodeAffinity = annotationsAffinity.NodeAffinity
|
||||||
|
}
|
||||||
|
if affinity != nil && affinity.PodAffinity == nil && annotationsAffinity.PodAffinity != nil {
|
||||||
|
affinity.PodAffinity = annotationsAffinity.PodAffinity
|
||||||
|
}
|
||||||
|
if affinity != nil && affinity.PodAntiAffinity == nil && annotationsAffinity.PodAntiAffinity != nil {
|
||||||
|
affinity.PodAntiAffinity = annotationsAffinity.PodAntiAffinity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return affinity
|
||||||
|
}
|
151
plugin/pkg/scheduler/schedulercache/reconcile_affinity_test.go
Normal file
151
plugin/pkg/scheduler/schedulercache/reconcile_affinity_test.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package schedulercache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
|
func TestReconcileAffinity(t *testing.T) {
|
||||||
|
baseAffinity := &v1.Affinity{
|
||||||
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||||
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
||||||
|
{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"bar", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
Values: []string{"securityscan"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "topologyKey1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "service",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "topologyKey2",
|
||||||
|
Namespaces: []string{"ns1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeAffinityAnnotation := map[string]string{
|
||||||
|
v1.AffinityAnnotationKey: `
|
||||||
|
{"nodeAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [
|
||||||
|
{
|
||||||
|
"weight": 2,
|
||||||
|
"preference": {"matchExpressions": [
|
||||||
|
{
|
||||||
|
"key": "foo",
|
||||||
|
"operator": "In", "values": ["bar"]
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
}
|
||||||
|
]}}`,
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
pod *v1.Pod
|
||||||
|
expected *v1.Affinity
|
||||||
|
annotationsEnabled bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// affinity is set in both PodSpec and annotations; take from PodSpec.
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Annotations: nodeAffinityAnnotation,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Affinity: baseAffinity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: baseAffinity,
|
||||||
|
annotationsEnabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// affinity is only set in annotation; take from annotation.
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Annotations: nodeAffinityAnnotation,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: &v1.Affinity{
|
||||||
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.PreferredSchedulingTerm{
|
||||||
|
{
|
||||||
|
Weight: 2,
|
||||||
|
Preference: v1.NodeSelectorTerm{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
annotationsEnabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
utilfeature.DefaultFeatureGate.Set(fmt.Sprintf("AffinityInAnnotations=%t", tc.annotationsEnabled))
|
||||||
|
affinity := ReconcileAffinity(tc.pod)
|
||||||
|
if !reflect.DeepEqual(affinity, tc.expected) {
|
||||||
|
t.Errorf("[%v] Did not get expected affinity:\n\n%v\n\n. got:\n\n %v", i, tc.expected, affinity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -108,7 +108,10 @@ type FeatureGate interface {
|
|||||||
// alpha: v1.5
|
// alpha: v1.5
|
||||||
ExperimentalHostUserNamespaceDefaulting() bool
|
ExperimentalHostUserNamespaceDefaulting() bool
|
||||||
|
|
||||||
AnninityInAnnotations() bool
|
// owner: @davidopp
|
||||||
|
// alpha: v1.6
|
||||||
|
// TODO: remove when alpha support for affinity is removed
|
||||||
|
AffinityInAnnotations() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
|
// featureGate implements FeatureGate as well as pflag.Value for flag parsing.
|
||||||
|
Loading…
Reference in New Issue
Block a user