mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 05:03:09 +00:00
[scheduling] Moved pod affinity and anti-affinity from annotations to api
fields. #25319
This commit is contained in:
parent
1854d48238
commit
6a3ad93d6c
@ -486,20 +486,6 @@ const (
|
|||||||
UnsafeSysctlsPodAnnotationKey string = "security.alpha.kubernetes.io/unsafe-sysctls"
|
UnsafeSysctlsPodAnnotationKey string = "security.alpha.kubernetes.io/unsafe-sysctls"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetAffinityFromPod gets the json serialized affinity data from Pod.Annotations
|
|
||||||
// and converts it to the Affinity type in api.
|
|
||||||
func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) {
|
|
||||||
if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" {
|
|
||||||
var affinity Affinity
|
|
||||||
err := json.Unmarshal([]byte(annotations[AffinityAnnotationKey]), &affinity)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &affinity, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
|
// GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations
|
||||||
// and converts it to the []Toleration type in api.
|
// and converts it to the []Toleration type in api.
|
||||||
func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
|
func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) {
|
||||||
|
@ -241,62 +241,6 @@ func TestNodeSelectorRequirementsAsSelector(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAffinityFromPod(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
pod *Pod
|
|
||||||
expectErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
pod: &Pod{},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pod: &Pod{
|
|
||||||
ObjectMeta: ObjectMeta{
|
|
||||||
Annotations: map[string]string{
|
|
||||||
AffinityAnnotationKey: `
|
|
||||||
{"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": {
|
|
||||||
"nodeSelectorTerms": [{
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "foo",
|
|
||||||
"operator": "In",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}}}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pod: &Pod{
|
|
||||||
ObjectMeta: ObjectMeta{
|
|
||||||
Annotations: map[string]string{
|
|
||||||
AffinityAnnotationKey: `
|
|
||||||
{"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": {
|
|
||||||
"nodeSelectorTerms": [{
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "foo",
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range testCases {
|
|
||||||
_, err := GetAffinityFromPodAnnotations(tc.pod.Annotations)
|
|
||||||
if err == nil && tc.expectErr {
|
|
||||||
t.Errorf("[%v]expected error but got none.", i)
|
|
||||||
}
|
|
||||||
if err != nil && !tc.expectErr {
|
|
||||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTaintToString(t *testing.T) {
|
func TestTaintToString(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
taint *Taint
|
taint *Taint
|
||||||
|
@ -331,7 +331,6 @@ func TestEncode_Ptr(t *testing.T) {
|
|||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
|
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
obj := runtime.Object(pod)
|
obj := runtime.Object(pod)
|
||||||
@ -345,7 +344,6 @@ func TestEncode_Ptr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
if !api.Semantic.DeepEqual(obj2, pod) {
|
if !api.Semantic.DeepEqual(obj2, pod) {
|
||||||
t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod))
|
t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ func DeepEqualSafePodSpec() api.PodSpec {
|
|||||||
DNSPolicy: api.DNSClusterFirst,
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +174,6 @@ func SetDefaults_PodSpec(obj *PodSpec) {
|
|||||||
period := int64(DefaultTerminationGracePeriodSeconds)
|
period := int64(DefaultTerminationGracePeriodSeconds)
|
||||||
obj.TerminationGracePeriodSeconds = &period
|
obj.TerminationGracePeriodSeconds = &period
|
||||||
}
|
}
|
||||||
if obj.Affinity == nil {
|
|
||||||
obj.Affinity = &Affinity{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
func SetDefaults_Probe(obj *Probe) {
|
func SetDefaults_Probe(obj *Probe) {
|
||||||
if obj.TimeoutSeconds == 0 {
|
if obj.TimeoutSeconds == 0 {
|
||||||
|
@ -101,10 +101,6 @@ func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList
|
|||||||
|
|
||||||
func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
|
func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
if annotations[api.AffinityAnnotationKey] != "" {
|
|
||||||
allErrs = append(allErrs, ValidateAffinityInPodAnnotations(annotations, fldPath)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if annotations[api.TolerationsAnnotationKey] != "" {
|
if annotations[api.TolerationsAnnotationKey] != "" {
|
||||||
allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
|
allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
|
||||||
}
|
}
|
||||||
@ -1672,7 +1668,14 @@ func validateAffinity(affinity *api.Affinity, fldPath *field.Path) field.ErrorLi
|
|||||||
allErrs = append(allErrs, ValidatePreferredSchedulingTerms(na.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
|
allErrs = append(allErrs, ValidatePreferredSchedulingTerms(na.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if affinity.PodAffinity != nil {
|
||||||
|
allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, fldPath.Child("podAffinity"))...)
|
||||||
|
}
|
||||||
|
if affinity.PodAntiAffinity != nil {
|
||||||
|
allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, fldPath.Child("podAntiAffinity"))...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1968,30 +1971,6 @@ func validatePodAffinity(podAffinity *api.PodAffinity, fldPath *field.Path) fiel
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAffinityInPodAnnotations tests that the serialized Affinity in Pod.Annotations has valid data
|
|
||||||
func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
|
||||||
allErrs := field.ErrorList{}
|
|
||||||
|
|
||||||
affinity, err := api.GetAffinityFromPodAnnotations(annotations)
|
|
||||||
if err != nil {
|
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath, api.AffinityAnnotationKey, err.Error()))
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
if affinity == nil {
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
|
|
||||||
affinityFldPath := fldPath.Child(api.AffinityAnnotationKey)
|
|
||||||
if affinity.PodAffinity != nil {
|
|
||||||
allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, affinityFldPath.Child("podAffinity"))...)
|
|
||||||
}
|
|
||||||
if affinity.PodAntiAffinity != nil {
|
|
||||||
allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, affinityFldPath.Child("podAntiAffinity"))...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allErrs
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
|
// ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data
|
||||||
func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
@ -3076,11 +3076,18 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidatePod(t *testing.T) {
|
func TestValidatePod(t *testing.T) {
|
||||||
validPodSpec := api.PodSpec{
|
validPodSpec := func(affinity *api.Affinity) api.PodSpec {
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
spec := api.PodSpec{
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
RestartPolicy: api.RestartPolicyAlways,
|
||||||
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
|
}
|
||||||
|
if affinity != nil {
|
||||||
|
spec.Affinity = affinity
|
||||||
|
}
|
||||||
|
return spec
|
||||||
}
|
}
|
||||||
|
|
||||||
successCases := []api.Pod{
|
successCases := []api.Pod{
|
||||||
{ // Basic fields.
|
{ // Basic fields.
|
||||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||||
@ -3111,10 +3118,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: validPodSpec(
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
|
||||||
// TODO: Uncomment and move this block and move inside NodeAffinity once
|
// TODO: Uncomment and move this block and move inside NodeAffinity once
|
||||||
// RequiredDuringSchedulingRequiredDuringExecution is implemented
|
// RequiredDuringSchedulingRequiredDuringExecution is implemented
|
||||||
// RequiredDuringSchedulingRequiredDuringExecution: &api.NodeSelector{
|
// RequiredDuringSchedulingRequiredDuringExecution: &api.NodeSelector{
|
||||||
@ -3129,7 +3133,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
Affinity: &api.Affinity{
|
&api.Affinity{
|
||||||
NodeAffinity: &api.NodeAffinity{
|
NodeAffinity: &api.NodeAffinity{
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||||
@ -3160,7 +3164,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
),
|
||||||
},
|
},
|
||||||
{ // Serialized pod affinity in affinity requirements in annotations.
|
{ // Serialized pod affinity in affinity requirements in annotations.
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3179,38 +3183,44 @@ func TestValidatePod(t *testing.T) {
|
|||||||
// "namespaces":["ns"],
|
// "namespaces":["ns"],
|
||||||
// "topologyKey": "zone"
|
// "topologyKey": "zone"
|
||||||
// }]
|
// }]
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {
|
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "In",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"topologyKey": "zone",
|
|
||||||
"namespaces": ["ns"]
|
|
||||||
}],
|
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm": {
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "NotIn",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAffinity: &api.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "zone",
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
|
{
|
||||||
|
Weight: 10,
|
||||||
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{ // Serialized pod anti affinity with different Label Operators in affinity requirements in annotations.
|
{ // Serialized pod anti affinity with different Label Operators in affinity requirements in annotations.
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3229,36 +3239,42 @@ func TestValidatePod(t *testing.T) {
|
|||||||
// "namespaces":["ns"],
|
// "namespaces":["ns"],
|
||||||
// "topologyKey": "zone"
|
// "topologyKey": "zone"
|
||||||
// }]
|
// }]
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAntiAffinity": {
|
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "Exists"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"topologyKey": "zone",
|
|
||||||
"namespaces": ["ns"]
|
|
||||||
}],
|
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm": {
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "DoesNotExist"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "zone",
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
|
{
|
||||||
|
Weight: 10,
|
||||||
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{ // populate tolerations equal operator in annotations.
|
{ // populate tolerations equal operator in annotations.
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3274,7 +3290,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // populate tolerations exists operator in annotations.
|
{ // populate tolerations exists operator in annotations.
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3289,7 +3305,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // empty operator is ok for toleration
|
{ // empty operator is ok for toleration
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3304,7 +3320,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // empty efffect is ok for toleration
|
{ // empty efffect is ok for toleration
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3319,7 +3335,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // docker default seccomp profile
|
{ // docker default seccomp profile
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3329,7 +3345,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "docker/default",
|
api.SeccompPodAnnotationKey: "docker/default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // unconfined seccomp profile
|
{ // unconfined seccomp profile
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3339,7 +3355,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "unconfined",
|
api.SeccompPodAnnotationKey: "unconfined",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // localhost seccomp profile
|
{ // localhost seccomp profile
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3349,7 +3365,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "localhost/foo",
|
api.SeccompPodAnnotationKey: "localhost/foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // localhost seccomp profile for a container
|
{ // localhost seccomp profile for a container
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3359,7 +3375,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompContainerAnnotationKeyPrefix + "foo": "localhost/foo",
|
api.SeccompContainerAnnotationKeyPrefix + "foo": "localhost/foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // default AppArmor profile for a container
|
{ // default AppArmor profile for a container
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3369,7 +3385,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
apparmor.ContainerAnnotationKeyPrefix + "ctr": apparmor.ProfileRuntimeDefault,
|
apparmor.ContainerAnnotationKeyPrefix + "ctr": apparmor.ProfileRuntimeDefault,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // default AppArmor profile for an init container
|
{ // default AppArmor profile for an init container
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3394,7 +3410,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
apparmor.ContainerAnnotationKeyPrefix + "ctr": apparmor.ProfileNamePrefix + "foo",
|
apparmor.ContainerAnnotationKeyPrefix + "ctr": apparmor.ProfileNamePrefix + "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // syntactically valid sysctls
|
{ // syntactically valid sysctls
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3405,7 +3421,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.UnsafeSysctlsPodAnnotationKey: "knet.ipv4.route.min_pmtu=1000",
|
api.UnsafeSysctlsPodAnnotationKey: "knet.ipv4.route.min_pmtu=1000",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
{ // valid opaque integer resources for init container
|
{ // valid opaque integer resources for init container
|
||||||
ObjectMeta: api.ObjectMeta{Name: "valid-opaque-int", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "valid-opaque-int", Namespace: "ns"},
|
||||||
@ -3502,271 +3518,234 @@ func TestValidatePod(t *testing.T) {
|
|||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: validPodSpec(&api.Affinity{
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
NodeAffinity: &api.NodeAffinity{
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||||
Affinity: &api.Affinity{
|
{
|
||||||
NodeAffinity: &api.NodeAffinity{
|
MatchExpressions: []api.NodeSelectorRequirement{
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
{
|
||||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
|
||||||
{
|
|
||||||
MatchExpressions: []api.NodeSelectorRequirement{
|
|
||||||
{
|
|
||||||
|
|
||||||
Key: "key1",
|
Key: "key1",
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
"invalid preferredSchedulingTerm in node affinity, weight should be in range 1-100": {
|
"invalid preferredSchedulingTerm in node affinity, weight should be in range 1-100": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: validPodSpec(&api.Affinity{
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
NodeAffinity: &api.NodeAffinity{
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.PreferredSchedulingTerm{
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
{
|
||||||
Affinity: &api.Affinity{
|
Weight: 199,
|
||||||
NodeAffinity: &api.NodeAffinity{
|
Preference: api.NodeSelectorTerm{
|
||||||
PreferredDuringSchedulingIgnoredDuringExecution: []api.PreferredSchedulingTerm{
|
MatchExpressions: []api.NodeSelectorRequirement{
|
||||||
{
|
{
|
||||||
Weight: 199,
|
Key: "foo",
|
||||||
Preference: api.NodeSelectorTerm{
|
Operator: api.NodeSelectorOpIn,
|
||||||
MatchExpressions: []api.NodeSelectorRequirement{
|
Values: []string{"bar"},
|
||||||
{
|
|
||||||
Key: "foo",
|
|
||||||
Operator: api.NodeSelectorOpIn,
|
|
||||||
Values: []string{"bar"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
"invalid requiredDuringSchedulingIgnoredDuringExecution node selector, nodeSelectorTerms must have at least one term": {
|
"invalid requiredDuringSchedulingIgnoredDuringExecution node selector, nodeSelectorTerms must have at least one term": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: validPodSpec(&api.Affinity{
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
NodeAffinity: &api.NodeAffinity{
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
NodeSelectorTerms: []api.NodeSelectorTerm{},
|
||||||
Affinity: &api.Affinity{
|
|
||||||
NodeAffinity: &api.NodeAffinity{
|
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
|
||||||
NodeSelectorTerms: []api.NodeSelectorTerm{},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
"invalid requiredDuringSchedulingIgnoredDuringExecution node selector term, matchExpressions must have at least one node selector requirement": {
|
"invalid requiredDuringSchedulingIgnoredDuringExecution node selector term, matchExpressions must have at least one node selector requirement": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
},
|
},
|
||||||
Spec: api.PodSpec{
|
Spec: validPodSpec(&api.Affinity{
|
||||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
NodeAffinity: &api.NodeAffinity{
|
||||||
RestartPolicy: api.RestartPolicyAlways,
|
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
||||||
DNSPolicy: api.DNSClusterFirst,
|
NodeSelectorTerms: []api.NodeSelectorTerm{
|
||||||
Affinity: &api.Affinity{
|
{
|
||||||
NodeAffinity: &api.NodeAffinity{
|
MatchExpressions: []api.NodeSelectorRequirement{},
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{
|
|
||||||
NodeSelectorTerms: []api.NodeSelectorTerm{
|
|
||||||
{
|
|
||||||
MatchExpressions: []api.NodeSelectorRequirement{},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
"invalid weight in preferredDuringSchedulingIgnoredDuringExecution in pod affinity annotations, weight should be in range 1-100": {
|
"invalid weight in preferredDuringSchedulingIgnoredDuringExecution in pod affinity annotations, weight should be in range 1-100": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 109,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "NotIn",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAffinity: &api.PodAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
|
{
|
||||||
|
Weight: 109,
|
||||||
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
"invalid labelSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, values should be empty if the operator is Exists": {
|
"invalid labelSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, values should be empty if the operator is Exists": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "Exists",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
|
{
|
||||||
|
Weight: 10,
|
||||||
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
"invalid name space in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, name space shouldbe valid": {
|
"invalid name space in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, name space shouldbe valid": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "Exists",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["INVALID_NAMESPACE"],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
},
|
PodAffinity: &api.PodAffinity{
|
||||||
"invalid labelOperator in preferredDuringSchedulingIgnoredDuringExecution in podantiaffinity annotations, labelOperator should be proper": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
ObjectMeta: api.ObjectMeta{
|
|
||||||
Name: "123",
|
|
||||||
Namespace: "ns",
|
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAntiAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
{
|
||||||
"labelSelector": {
|
Weight: 10,
|
||||||
"matchExpressions": [{
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
"key": "key2",
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"operator": "WrongOp",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"values": ["value1", "value2"]
|
{
|
||||||
}]
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"INVALID_NAMESPACE"},
|
||||||
|
TopologyKey: "region",
|
||||||
},
|
},
|
||||||
"namespaces": ["ns"],
|
},
|
||||||
"topologyKey": "region"
|
},
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
Spec: validPodSpec,
|
|
||||||
},
|
},
|
||||||
"invalid pod affinity, empty topologyKey is not allowed for hard pod affinity": {
|
"invalid pod affinity, empty topologyKey is not allowed for hard pod affinity": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "In",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": ""
|
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAffinity: &api.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
"invalid pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": {
|
"invalid pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAntiAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "In",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": ""
|
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
"invalid pod anti-affinity, empty topologyKey is not allowed for soft pod affinity": {
|
"invalid pod anti-affinity, empty topologyKey is not allowed for soft pod affinity": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "123",
|
Name: "123",
|
||||||
Namespace: "ns",
|
Namespace: "ns",
|
||||||
Annotations: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 10,
|
|
||||||
"podAffinityTerm":
|
|
||||||
{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "key2",
|
|
||||||
"operator": "In",
|
|
||||||
"values": ["value1", "value2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": ["ns"],
|
|
||||||
"topologyKey": ""
|
|
||||||
}
|
|
||||||
}]}}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(&api.Affinity{
|
||||||
|
PodAffinity: &api.PodAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
|
{
|
||||||
|
Weight: 10,
|
||||||
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key2",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"value1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Namespaces: []string{"ns"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
"invalid toleration key": {
|
"invalid toleration key": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3782,7 +3761,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"invalid toleration operator": {
|
"invalid toleration operator": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3798,7 +3777,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"value must be empty when `operator` is 'Exists'": {
|
"value must be empty when `operator` is 'Exists'": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3814,7 +3793,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
}]`,
|
}]`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"must be a valid pod seccomp profile": {
|
"must be a valid pod seccomp profile": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3824,7 +3803,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "foo",
|
api.SeccompPodAnnotationKey: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"must be a valid container seccomp profile": {
|
"must be a valid container seccomp profile": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3834,7 +3813,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompContainerAnnotationKeyPrefix + "foo": "foo",
|
api.SeccompContainerAnnotationKeyPrefix + "foo": "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"must be a non-empty container name in seccomp annotation": {
|
"must be a non-empty container name in seccomp annotation": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3844,7 +3823,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompContainerAnnotationKeyPrefix: "foo",
|
api.SeccompContainerAnnotationKeyPrefix: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"must be a non-empty container profile in seccomp annotation": {
|
"must be a non-empty container profile in seccomp annotation": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3854,7 +3833,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompContainerAnnotationKeyPrefix + "foo": "",
|
api.SeccompContainerAnnotationKeyPrefix + "foo": "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"must be a relative path in a node-local seccomp profile annotation": {
|
"must be a relative path in a node-local seccomp profile annotation": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3864,7 +3843,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "localhost//foo",
|
api.SeccompPodAnnotationKey: "localhost//foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"must not start with '../'": {
|
"must not start with '../'": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3874,7 +3853,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SeccompPodAnnotationKey: "localhost/../foo",
|
api.SeccompPodAnnotationKey: "localhost/../foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"AppArmor profile must apply to a container": {
|
"AppArmor profile must apply to a container": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3901,7 +3880,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
apparmor.ContainerAnnotationKeyPrefix + "ctr": "bad-name",
|
apparmor.ContainerAnnotationKeyPrefix + "ctr": "bad-name",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"only default AppArmor profile may start with runtime/": {
|
"only default AppArmor profile may start with runtime/": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3911,7 +3890,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
apparmor.ContainerAnnotationKeyPrefix + "ctr": "runtime/foo",
|
apparmor.ContainerAnnotationKeyPrefix + "ctr": "runtime/foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"invalid sysctl annotation": {
|
"invalid sysctl annotation": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3921,7 +3900,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SysctlsPodAnnotationKey: "foo:",
|
api.SysctlsPodAnnotationKey: "foo:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"invalid comma-separated sysctl annotation": {
|
"invalid comma-separated sysctl annotation": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3931,7 +3910,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SysctlsPodAnnotationKey: "kernel.msgmax,",
|
api.SysctlsPodAnnotationKey: "kernel.msgmax,",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"invalid unsafe sysctl annotation": {
|
"invalid unsafe sysctl annotation": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3941,7 +3920,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.SysctlsPodAnnotationKey: "foo:",
|
api.SysctlsPodAnnotationKey: "foo:",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"intersecting safe sysctls and unsafe sysctls annotations": {
|
"intersecting safe sysctls and unsafe sysctls annotations": {
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
@ -3952,7 +3931,7 @@ func TestValidatePod(t *testing.T) {
|
|||||||
api.UnsafeSysctlsPodAnnotationKey: "kernel.shmmax=10000000",
|
api.UnsafeSysctlsPodAnnotationKey: "kernel.shmmax=10000000",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: validPodSpec,
|
Spec: validPodSpec(nil),
|
||||||
},
|
},
|
||||||
"invalid opaque integer resource requirement: request must be <= limit": {
|
"invalid opaque integer resource requirement: request must be <= limit": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||||
|
@ -40,7 +40,6 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
RestartPolicy: v1.RestartPolicyAlways,
|
RestartPolicy: v1.RestartPolicyAlways,
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
TerminationGracePeriodSeconds: &period,
|
TerminationGracePeriodSeconds: &period,
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Labels: defaultLabels,
|
Labels: defaultLabels,
|
||||||
@ -52,7 +51,6 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
RestartPolicy: v1.RestartPolicyAlways,
|
RestartPolicy: v1.RestartPolicyAlways,
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
TerminationGracePeriodSeconds: &period,
|
TerminationGracePeriodSeconds: &period,
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -157,7 +155,6 @@ func TestSetDefaultDeployment(t *testing.T) {
|
|||||||
RestartPolicy: v1.RestartPolicyAlways,
|
RestartPolicy: v1.RestartPolicyAlways,
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
TerminationGracePeriodSeconds: &period,
|
TerminationGracePeriodSeconds: &period,
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -132,7 +132,6 @@ func TestMerge(t *testing.T) {
|
|||||||
DNSPolicy: api.DNSClusterFirst,
|
DNSPolicy: api.DNSClusterFirst,
|
||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -54,7 +54,6 @@ func TestDecodeSinglePod(t *testing.T) {
|
|||||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||||
}},
|
}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
json, err := runtime.Encode(testapi.Default.Codec(), pod)
|
json, err := runtime.Encode(testapi.Default.Codec(), pod)
|
||||||
@ -115,7 +114,6 @@ func TestDecodePodList(t *testing.T) {
|
|||||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
|
||||||
}},
|
}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
podList := &v1.PodList{
|
podList := &v1.PodList{
|
||||||
|
@ -188,7 +188,6 @@ func getTestCases(hostname types.NodeName) []*testCase {
|
|||||||
Spec: v1.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
Containers: []v1.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
Containers: []v1.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
Status: v1.PodStatus{
|
Status: v1.PodStatus{
|
||||||
Phase: v1.PodPending,
|
Phase: v1.PodPending,
|
||||||
@ -214,7 +213,6 @@ func getTestCases(hostname types.NodeName) []*testCase {
|
|||||||
ImagePullPolicy: "Always",
|
ImagePullPolicy: "Always",
|
||||||
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
Status: v1.PodStatus{
|
Status: v1.PodStatus{
|
||||||
Phase: v1.PodPending,
|
Phase: v1.PodPending,
|
||||||
|
@ -148,7 +148,6 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||||||
NodeName: string(nodeName),
|
NodeName: string(nodeName),
|
||||||
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
|
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
Status: v1.PodStatus{
|
Status: v1.PodStatus{
|
||||||
Phase: v1.PodPending,
|
Phase: v1.PodPending,
|
||||||
@ -170,7 +169,6 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||||||
DNSPolicy: v1.DNSClusterFirst,
|
DNSPolicy: v1.DNSClusterFirst,
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
|
|
||||||
Containers: []v1.Container{{
|
Containers: []v1.Container{{
|
||||||
Name: "1",
|
Name: "1",
|
||||||
@ -201,7 +199,6 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||||||
NodeName: nodeName,
|
NodeName: nodeName,
|
||||||
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
|
Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
Status: v1.PodStatus{
|
Status: v1.PodStatus{
|
||||||
Phase: v1.PodPending,
|
Phase: v1.PodPending,
|
||||||
@ -216,7 +213,6 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||||||
NodeName: nodeName,
|
NodeName: nodeName,
|
||||||
Containers: []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: ""}},
|
Containers: []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: ""}},
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
},
|
},
|
||||||
Status: v1.PodStatus{
|
Status: v1.PodStatus{
|
||||||
Phase: v1.PodPending,
|
Phase: v1.PodPending,
|
||||||
@ -240,7 +236,6 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||||||
DNSPolicy: v1.DNSClusterFirst,
|
DNSPolicy: v1.DNSClusterFirst,
|
||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
|
|
||||||
Containers: []v1.Container{{
|
Containers: []v1.Container{{
|
||||||
Name: "1",
|
Name: "1",
|
||||||
@ -267,7 +262,6 @@ func TestExtractPodsFromHTTP(t *testing.T) {
|
|||||||
DNSPolicy: v1.DNSClusterFirst,
|
DNSPolicy: v1.DNSClusterFirst,
|
||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
SecurityContext: &v1.PodSecurityContext{},
|
||||||
Affinity: &v1.Affinity{},
|
|
||||||
|
|
||||||
Containers: []v1.Container{{
|
Containers: []v1.Container{{
|
||||||
Name: "2",
|
Name: "2",
|
||||||
|
@ -484,7 +484,8 @@ func TestCriticalPrioritySorting(t *testing.T) {
|
|||||||
Requests: v1.ResourceList{
|
Requests: v1.ResourceList{
|
||||||
"memory": resource.MustParse("90"),
|
"memory": resource.MustParse("90"),
|
||||||
},
|
},
|
||||||
}}}}
|
}}},
|
||||||
|
}
|
||||||
pods := []*v1.Pod{
|
pods := []*v1.Pod{
|
||||||
podWithUidNameNsSpec("000000000", "newpod", "foo", spec),
|
podWithUidNameNsSpec("000000000", "newpod", "foo", spec),
|
||||||
podWithUidNameNsSpec("987654321", "oldpod", "foo", spec),
|
podWithUidNameNsSpec("987654321", "oldpod", "foo", spec),
|
||||||
@ -637,7 +638,8 @@ func TestHandleMemExceeded(t *testing.T) {
|
|||||||
Requests: v1.ResourceList{
|
Requests: v1.ResourceList{
|
||||||
"memory": resource.MustParse("90"),
|
"memory": resource.MustParse("90"),
|
||||||
},
|
},
|
||||||
}}}}
|
}}},
|
||||||
|
}
|
||||||
pods := []*v1.Pod{
|
pods := []*v1.Pod{
|
||||||
podWithUidNameNsSpec("123456789", "newpod", "foo", spec),
|
podWithUidNameNsSpec("123456789", "newpod", "foo", spec),
|
||||||
podWithUidNameNsSpec("987654321", "oldpod", "foo", spec),
|
podWithUidNameNsSpec("987654321", "oldpod", "foo", spec),
|
||||||
|
@ -73,7 +73,6 @@ func validNewPod() *api.Pod {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -660,7 +659,6 @@ func TestEtcdUpdateScheduled(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
}, nil, 1)
|
}, nil, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -689,7 +687,6 @@ func TestEtcdUpdateScheduled(t *testing.T) {
|
|||||||
|
|
||||||
TerminationGracePeriodSeconds: &grace,
|
TerminationGracePeriodSeconds: &grace,
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme))
|
_, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme))
|
||||||
@ -730,7 +727,6 @@ func TestEtcdUpdateStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := storage.Storage.Create(ctx, key, &podStart, nil, 0)
|
err := storage.Storage.Create(ctx, key, &podStart, nil, 0)
|
||||||
@ -755,7 +751,6 @@ func TestEtcdUpdateStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SecurityContext: &api.PodSecurityContext{},
|
SecurityContext: &api.PodSecurityContext{},
|
||||||
Affinity: &api.Affinity{},
|
|
||||||
},
|
},
|
||||||
Status: api.PodStatus{
|
Status: api.PodStatus{
|
||||||
Phase: api.PodRunning,
|
Phase: api.PodRunning,
|
||||||
|
@ -19,7 +19,6 @@ go_library(
|
|||||||
"//pkg/admission:go_default_library",
|
"//pkg/admission:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/api/errors:go_default_library",
|
"//pkg/api/errors:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
@ -56,11 +55,7 @@ func (p *plugin) Admit(attributes admission.Attributes) (err error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
|
return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
|
||||||
}
|
}
|
||||||
affinity, err := api.GetAffinityFromPodAnnotations(pod.Annotations)
|
affinity := pod.Spec.Affinity
|
||||||
if err != nil {
|
|
||||||
glog.V(5).Infof("Invalid Affinity detected, but we will leave handling of this to validation phase")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if affinity != nil && affinity.PodAntiAffinity != nil {
|
if affinity != nil && affinity.PodAntiAffinity != nil {
|
||||||
var podAntiAffinityTerms []api.PodAffinityTerm
|
var podAntiAffinityTerms []api.PodAffinityTerm
|
||||||
if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
|
if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 {
|
||||||
|
@ -32,109 +32,120 @@ func TestInterPodAffinityAdmission(t *testing.T) {
|
|||||||
Spec: api.PodSpec{},
|
Spec: api.PodSpec{},
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
affinity map[string]string
|
affinity *api.Affinity
|
||||||
errorExpected bool
|
errorExpected bool
|
||||||
}{
|
}{
|
||||||
// empty affinity its success.
|
// empty affinity its success.
|
||||||
{
|
{
|
||||||
affinity: map[string]string{},
|
affinity: &api.Affinity{},
|
||||||
errorExpected: false,
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
// what ever topologyKey in preferredDuringSchedulingIgnoredDuringExecution, the admission should success.
|
// what ever topologyKey in preferredDuringSchedulingIgnoredDuringExecution, the admission should success.
|
||||||
{
|
{
|
||||||
affinity: map[string]string{
|
affinity: &api.Affinity{
|
||||||
api.AffinityAnnotationKey: `
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"weight": 5,
|
Weight: 5,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S2"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": "az"
|
TopologyKey: "az",
|
||||||
}
|
},
|
||||||
}]
|
},
|
||||||
}}`,
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
errorExpected: false,
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
// valid topologyKey in requiredDuringSchedulingIgnoredDuringExecution,
|
// valid topologyKey in requiredDuringSchedulingIgnoredDuringExecution,
|
||||||
// plus any topologyKey in preferredDuringSchedulingIgnoredDuringExecution, then admission success.
|
// plus any topologyKey in preferredDuringSchedulingIgnoredDuringExecution, then admission success.
|
||||||
{
|
{
|
||||||
affinity: map[string]string{
|
affinity: &api.Affinity{
|
||||||
api.AffinityAnnotationKey: `
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"weight": 5,
|
Weight: 5,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: api.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S2"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
TopologyKey: "az",
|
||||||
"topologyKey": "az"
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "In",
|
|
||||||
"values":["S2"]
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": "` + metav1.LabelHostname + `"
|
},
|
||||||
}]
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
}}`,
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: metav1.LabelHostname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
errorExpected: false,
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
// valid topologyKey in requiredDuringSchedulingIgnoredDuringExecution then admission success.
|
// valid topologyKey in requiredDuringSchedulingIgnoredDuringExecution then admission success.
|
||||||
{
|
{
|
||||||
affinity: map[string]string{
|
affinity: &api.Affinity{
|
||||||
api.AffinityAnnotationKey: `
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S2"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces":[],
|
TopologyKey: metav1.LabelHostname,
|
||||||
"topologyKey": "` + metav1.LabelHostname + `"
|
},
|
||||||
}]
|
},
|
||||||
}}`,
|
},
|
||||||
},
|
},
|
||||||
errorExpected: false,
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
// invalid topologyKey in requiredDuringSchedulingIgnoredDuringExecution then admission fails.
|
// invalid topologyKey in requiredDuringSchedulingIgnoredDuringExecution then admission fails.
|
||||||
{
|
{
|
||||||
affinity: map[string]string{
|
affinity: &api.Affinity{
|
||||||
api.AffinityAnnotationKey: `
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S2"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces":[],
|
TopologyKey: " zone ",
|
||||||
"topologyKey": " zone "
|
},
|
||||||
}]
|
},
|
||||||
}}`,
|
},
|
||||||
},
|
},
|
||||||
errorExpected: true,
|
errorExpected: true,
|
||||||
},
|
},
|
||||||
@ -161,59 +172,51 @@ func TestInterPodAffinityAdmission(t *testing.T) {
|
|||||||
// }
|
// }
|
||||||
// list of requiredDuringSchedulingIgnoredDuringExecution middle element topologyKey is not valid.
|
// list of requiredDuringSchedulingIgnoredDuringExecution middle element topologyKey is not valid.
|
||||||
{
|
{
|
||||||
affinity: map[string]string{
|
affinity: &api.Affinity{
|
||||||
api.AffinityAnnotationKey: `
|
PodAntiAffinity: &api.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "In",
|
|
||||||
"values":["S2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces":[],
|
|
||||||
"topologyKey": "` + metav1.LabelHostname + `"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S2"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces":[],
|
TopologyKey: metav1.LabelHostname,
|
||||||
"topologyKey": " zone "
|
}, {
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: " zone ",
|
||||||
|
}, {
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: metav1.LabelHostname,
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
"labelSelector": {
|
},
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "In",
|
|
||||||
"values":["S2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": [],
|
|
||||||
"topologyKey": "` + metav1.LabelHostname + `"
|
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
},
|
},
|
||||||
errorExpected: true,
|
errorExpected: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
affinity: map[string]string{
|
|
||||||
api.AffinityAnnotationKey: `
|
|
||||||
{"podAntiAffinity": {
|
|
||||||
"thisIsAInvalidAffinity": [{}
|
|
||||||
}}`,
|
|
||||||
},
|
|
||||||
// however, we should not get error here
|
|
||||||
errorExpected: false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
pod.ObjectMeta.Annotations = test.affinity
|
pod.Spec.Affinity = test.affinity
|
||||||
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil))
|
||||||
|
|
||||||
if test.errorExpected && err == nil {
|
if test.errorExpected && err == nil {
|
||||||
|
@ -46,6 +46,7 @@ go_test(
|
|||||||
"//plugin/pkg/scheduler/algorithm:go_default_library",
|
"//plugin/pkg/scheduler/algorithm:go_default_library",
|
||||||
"//plugin/pkg/scheduler/algorithm/priorities/util:go_default_library",
|
"//plugin/pkg/scheduler/algorithm/priorities/util:go_default_library",
|
||||||
"//plugin/pkg/scheduler/schedulercache:go_default_library",
|
"//plugin/pkg/scheduler/schedulercache:go_default_library",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/labels",
|
"//vendor:k8s.io/apimachinery/pkg/labels",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -904,10 +904,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, err := v1.GetAffinityFromPodAnnotations(pod.Annotations)
|
affinity := pod.Spec.Affinity
|
||||||
if err != nil {
|
|
||||||
return false, nil, err
|
|
||||||
}
|
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -1008,11 +1005,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, err := v1.GetAffinityFromPodAnnotations(existingPod.Annotations)
|
affinity := existingPod.Spec.Affinity
|
||||||
if err != nil {
|
|
||||||
catchError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if affinity == nil {
|
if affinity == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1040,10 +1033,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, err := v1.GetAffinityFromPodAnnotations(existingPod.Annotations)
|
affinity := pod.Spec.Affinity
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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 {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -118,10 +118,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, err := v1.GetAffinityFromPodAnnotations(pod.Annotations)
|
affinity := pod.Spec.Affinity
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
hasAffinityConstraints := affinity != nil && affinity.PodAffinity != nil
|
hasAffinityConstraints := affinity != nil && affinity.PodAffinity != nil
|
||||||
hasAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil
|
hasAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil
|
||||||
|
|
||||||
@ -142,10 +139,7 @@ func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, node
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
existingPodAffinity, err := v1.GetAffinityFromPodAnnotations(existingPod.Annotations)
|
existingPodAffinity := existingPod.Spec.Affinity
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil
|
existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil
|
||||||
existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil
|
existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil
|
||||||
|
|
||||||
|
@ -65,188 +65,203 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
"security": "S2",
|
"security": "S2",
|
||||||
}
|
}
|
||||||
// considered only preferredDuringSchedulingIgnoredDuringExecution in pod affinity
|
// considered only preferredDuringSchedulingIgnoredDuringExecution in pod affinity
|
||||||
stayWithS1InRegion := map[string]string{
|
stayWithS1InRegion := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAffinity: &v1.PodAffinity{
|
||||||
{"podAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 5,
|
|
||||||
"podAffinityTerm": {
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "In",
|
|
||||||
"values":["S1"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": [],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
}
|
|
||||||
stayWithS2InRegion := map[string]string{
|
|
||||||
v1.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {
|
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
|
||||||
"weight": 6,
|
|
||||||
"podAffinityTerm": {
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "In",
|
|
||||||
"values":["S2"]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": [],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
}
|
|
||||||
affinity3 := map[string]string{
|
|
||||||
v1.AffinityAnnotationKey: `
|
|
||||||
{"podAffinity": {
|
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [
|
|
||||||
{
|
{
|
||||||
"weight": 8,
|
Weight: 5,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "NotIn",
|
Key: "security",
|
||||||
"values":["S1"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}, {
|
Values: []string{"S1"},
|
||||||
"key": "security",
|
},
|
||||||
"operator": "In",
|
},
|
||||||
"values":["S2"]
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
TopologyKey: "region",
|
||||||
"topologyKey": "region"
|
},
|
||||||
}
|
},
|
||||||
}, {
|
},
|
||||||
"weight": 2,
|
},
|
||||||
"podAffinityTerm": {
|
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "Exists"
|
|
||||||
}, {
|
|
||||||
"key": "wrongkey",
|
|
||||||
"operator": "DoesNotExist"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": [],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}}`,
|
|
||||||
}
|
}
|
||||||
hardAffinity := map[string]string{
|
stayWithS2InRegion := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAffinity: &v1.PodAffinity{
|
||||||
{"podAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [
|
|
||||||
{
|
{
|
||||||
"labelSelector":{
|
Weight: 6,
|
||||||
"matchExpressions": [{
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"key": "security",
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"operator": "In",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"values": ["S1", "value2"]
|
{
|
||||||
}]
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": "region"
|
},
|
||||||
}, {
|
},
|
||||||
"labelSelector": {
|
|
||||||
"matchExpressions": [{
|
|
||||||
"key": "security",
|
|
||||||
"operator": "Exists"
|
|
||||||
}, {
|
|
||||||
"key": "wrongkey",
|
|
||||||
"operator": "DoesNotExist"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"namespaces": [],
|
|
||||||
"topologyKey": "region"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}}`,
|
|
||||||
}
|
}
|
||||||
awayFromS1InAz := map[string]string{
|
affinity3 := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAffinity: &v1.PodAffinity{
|
||||||
{"podAntiAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"weight": 5,
|
Weight: 8,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S1"]
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
}]
|
Values: []string{"S1"},
|
||||||
|
}, {
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
}, {
|
||||||
"topologyKey": "az"
|
Weight: 2,
|
||||||
}
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
}]
|
LabelSelector: &metav1.LabelSelector{
|
||||||
}}`,
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
}, {
|
||||||
|
Key: "wrongkey",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
hardAffinity := &v1.Affinity{
|
||||||
|
PodAffinity: &v1.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
}, {
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
}, {
|
||||||
|
Key: "wrongkey",
|
||||||
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
awayFromS1InAz := &v1.Affinity{
|
||||||
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
|
{
|
||||||
|
Weight: 5,
|
||||||
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "az",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
// to stay away from security S2 in any az.
|
// to stay away from security S2 in any az.
|
||||||
awayFromS2InAz := map[string]string{
|
awayFromS2InAz := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"weight": 5,
|
Weight: 5,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S2"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "az",
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": "az"
|
},
|
||||||
}
|
},
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
}
|
}
|
||||||
// to stay with security S1 in same region, stay away from security S2 in any az.
|
// to stay with security S1 in same region, stay away from security S2 in any az.
|
||||||
stayWithS1InRegionAwayFromS2InAz := map[string]string{
|
stayWithS1InRegionAwayFromS2InAz := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAffinity: &v1.PodAffinity{
|
||||||
{"podAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"weight": 8,
|
Weight: 8,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S1"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "region",
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": "region"
|
},
|
||||||
}
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
"podAntiAffinity": {
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"weight": 5,
|
{
|
||||||
"podAffinityTerm": {
|
Weight: 5,
|
||||||
"labelSelector": {
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "security",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values":["S2"]
|
Key: "security",
|
||||||
}]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "az",
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": "az"
|
},
|
||||||
}
|
},
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -257,7 +272,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
test string
|
test string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: map[string]string{}}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine2", Labels: labelRgIndia}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine2", Labels: labelRgIndia}},
|
||||||
@ -270,7 +285,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
// the node(machine3) that don't have the label {"region": "whatever the value is"} (mismatch the topology key) but that have existing pods that match the labelSelector get low score
|
// the node(machine3) that don't have the label {"region": "whatever the value is"} (mismatch the topology key) but that have existing pods that match the labelSelector get low score
|
||||||
// the node(machine2) that have the label {"region": "China"} (match the topology key) but that have existing pods that mismatch the labelSelector get low score
|
// the node(machine2) that have the label {"region": "China"} (match the topology key) but that have existing pods that mismatch the labelSelector get low score
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegion}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
@ -290,7 +305,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
// the node3(machine3) that have the label {"region": "India"}, match the topology key but have a different label value, don't have existing pods that match the labelSelector,
|
// the node3(machine3) that have the label {"region": "India"}, match the topology key but have a different label value, don't have existing pods that match the labelSelector,
|
||||||
// get a low score.
|
// get a low score.
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Annotations: stayWithS1InRegion}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegion}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
},
|
},
|
||||||
@ -307,7 +322,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
// Then, nodes in regionChina get higher score than nodes in regionIndia, and all the nodes in regionChina should get a same score(high score),
|
// Then, nodes in regionChina get higher score than nodes in regionIndia, and all the nodes in regionChina should get a same score(high score),
|
||||||
// while all the nodes in regionIndia should get another same score(low score).
|
// while all the nodes in regionIndia should get another same score(low score).
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS2InRegion}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS2InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
@ -328,7 +343,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
},
|
},
|
||||||
// Test with the different operators and values for pod affinity scheduling preference, including some match failures.
|
// Test with the different operators and values for pod affinity scheduling preference, including some match failures.
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: affinity3}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: affinity3}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
@ -347,8 +362,8 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegion}},
|
{Spec: v1.PodSpec{NodeName: "machine1", Affinity: stayWithS1InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2, Annotations: stayWithS2InRegion}},
|
{Spec: v1.PodSpec{NodeName: "machine2", Affinity: stayWithS2InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
},
|
},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
||||||
@ -361,8 +376,8 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: hardAffinity}},
|
{Spec: v1.PodSpec{NodeName: "machine1", Affinity: hardAffinity}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2, Annotations: hardAffinity}},
|
{Spec: v1.PodSpec{NodeName: "machine2", Affinity: hardAffinity}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
},
|
},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
||||||
@ -380,7 +395,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
// there are 2 nodes, say node1 and node2, both nodes have pods that match the labelSelector and have topology-key in node.Labels.
|
// there are 2 nodes, say node1 and node2, both nodes have pods that match the labelSelector and have topology-key in node.Labels.
|
||||||
// But there are more pods on node1 that match the preference than node2. Then, node1 get a lower score than node2.
|
// But there are more pods on node1 that match the preference than node2. Then, node1 get a lower score than node2.
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS1InAz}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
@ -393,7 +408,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
test: "Anti Affinity: pod that doesnot match existing pods in node will get high score ",
|
test: "Anti Affinity: pod that doesnot match existing pods in node will get high score ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS1InAz}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
@ -406,7 +421,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
test: "Anti Affinity: pod that does not matches topology key & matches the pods in nodes will get higher score comparing to others ",
|
test: "Anti Affinity: pod that does not matches topology key & matches the pods in nodes will get higher score comparing to others ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS1InAz}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
@ -423,8 +438,8 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS2InAz}},
|
{Spec: v1.PodSpec{NodeName: "machine1", Affinity: awayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2, Annotations: awayFromS1InAz}},
|
{Spec: v1.PodSpec{NodeName: "machine2", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
},
|
},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelAzAz1}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelAzAz1}},
|
||||||
@ -435,7 +450,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
},
|
},
|
||||||
// Test both affinity and anti-affinity
|
// Test both affinity and anti-affinity
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegionAwayFromS2InAz}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
@ -452,7 +467,7 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
// so that all the pods of a RC/service can stay in a same region but trying to separate with each other
|
// so that all the pods of a RC/service can stay in a same region but trying to separate with each other
|
||||||
// machine-1,machine-3,machine-4 are in ChinaRegion others machin-2,machine-5 are in IndiaRegion
|
// machine-1,machine-3,machine-4 are in ChinaRegion others machin-2,machine-5 are in IndiaRegion
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegionAwayFromS2InAz}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
@ -478,12 +493,12 @@ func TestInterPodAffinityPriority(t *testing.T) {
|
|||||||
// for Affinity symmetry, the weights are: 0, 0, 8, 0
|
// for Affinity symmetry, the weights are: 0, 0, 8, 0
|
||||||
// for Anti Affinity symmetry, the weights are: 0, 0, 0, -5
|
// for Anti Affinity symmetry, the weights are: 0, 0, 0, -5
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegionAwayFromS2InAz}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine3"}, ObjectMeta: v1.ObjectMeta{Annotations: stayWithS1InRegionAwayFromS2InAz}},
|
{Spec: v1.PodSpec{NodeName: "machine3", Affinity: stayWithS1InRegionAwayFromS2InAz}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine4"}, ObjectMeta: v1.ObjectMeta{Annotations: awayFromS1InAz}},
|
{Spec: v1.PodSpec{NodeName: "machine4", Affinity: awayFromS1InAz}},
|
||||||
},
|
},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
||||||
@ -527,23 +542,23 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) {
|
|||||||
labelAzAz1 := map[string]string{
|
labelAzAz1 := map[string]string{
|
||||||
"az": "az1",
|
"az": "az1",
|
||||||
}
|
}
|
||||||
hardPodAffinity := map[string]string{
|
hardPodAffinity := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAffinity: &v1.PodAffinity{
|
||||||
{"podAffinity": {
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [
|
|
||||||
{
|
{
|
||||||
"labelSelector":{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "service",
|
{
|
||||||
"operator": "In",
|
Key: "service",
|
||||||
"values": ["S1"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
TopologyKey: "region",
|
||||||
"topologyKey": "region"
|
},
|
||||||
}
|
},
|
||||||
]
|
},
|
||||||
}}`,
|
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
@ -556,8 +571,8 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) {
|
|||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelServiceS1}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelServiceS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}},
|
{Spec: v1.PodSpec{NodeName: "machine1", Affinity: hardPodAffinity}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}},
|
{Spec: v1.PodSpec{NodeName: "machine2", Affinity: hardPodAffinity}},
|
||||||
},
|
},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
||||||
@ -571,8 +586,8 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) {
|
|||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelServiceS1}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelServiceS1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}},
|
{Spec: v1.PodSpec{NodeName: "machine1", Affinity: hardPodAffinity}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}},
|
{Spec: v1.PodSpec{NodeName: "machine2", Affinity: hardPodAffinity}},
|
||||||
},
|
},
|
||||||
nodes: []*v1.Node{
|
nodes: []*v1.Node{
|
||||||
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
{ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}},
|
||||||
@ -612,24 +627,26 @@ func TestSoftPodAntiAffinityWithFailureDomains(t *testing.T) {
|
|||||||
podLabel1 := map[string]string{
|
podLabel1 := map[string]string{
|
||||||
"security": "S1",
|
"security": "S1",
|
||||||
}
|
}
|
||||||
antiAffinity1 := map[string]string{
|
antiAffinity1 := &v1.Affinity{
|
||||||
v1.AffinityAnnotationKey: `
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
{"podAntiAffinity": {
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
|
||||||
"preferredDuringSchedulingIgnoredDuringExecution": [{
|
{
|
||||||
"weight": 5,
|
Weight: 5,
|
||||||
"podAffinityTerm": {
|
PodAffinityTerm: v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"matchExpressions": [{
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"key": "security",
|
{
|
||||||
"operator": "In",
|
Key: "security",
|
||||||
"values":["S1"]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
}]
|
Values: []string{"S1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "",
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
},
|
||||||
"topologyKey": ""
|
},
|
||||||
}
|
},
|
||||||
}]
|
|
||||||
}}`,
|
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
@ -640,7 +657,7 @@ func TestSoftPodAntiAffinityWithFailureDomains(t *testing.T) {
|
|||||||
test string
|
test string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1, Annotations: antiAffinity1}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: antiAffinity1}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
||||||
@ -654,7 +671,7 @@ func TestSoftPodAntiAffinityWithFailureDomains(t *testing.T) {
|
|||||||
test: "Soft Pod Anti Affinity: when the topologyKey is emtpy, match among topologyKeys indicated by failure domains.",
|
test: "Soft Pod Anti Affinity: when the topologyKey is emtpy, match among topologyKeys indicated by failure domains.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1, Annotations: antiAffinity1}},
|
pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: antiAffinity1}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
||||||
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}},
|
||||||
|
@ -38,18 +38,9 @@ func PriorityMetadata(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.Nod
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
affinity := pod.Spec.Affinity
|
|
||||||
annotationAffinity, err := v1.GetAffinityFromPodAnnotations(pod.Annotations)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if annotationAffinity != nil {
|
|
||||||
affinity.PodAffinity = annotationAffinity.PodAffinity
|
|
||||||
affinity.PodAntiAffinity = annotationAffinity.PodAntiAffinity
|
|
||||||
}
|
|
||||||
return &priorityMetadata{
|
return &priorityMetadata{
|
||||||
nonZeroRequest: getNonZeroRequests(pod),
|
nonZeroRequest: getNonZeroRequests(pod),
|
||||||
podTolerations: tolerations,
|
podTolerations: tolerations,
|
||||||
affinity: affinity,
|
affinity: pod.Spec.Affinity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,11 +209,8 @@ func (n *NodeInfo) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hasPodAffinityConstraints(pod *v1.Pod) bool {
|
func hasPodAffinityConstraints(pod *v1.Pod) bool {
|
||||||
affinity, err := v1.GetAffinityFromPodAnnotations(pod.Annotations)
|
affinity := pod.Spec.Affinity
|
||||||
if err != nil || affinity == nil {
|
return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil)
|
||||||
return false
|
|
||||||
}
|
|
||||||
return affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// addPod adds pod information to this NodeInfo.
|
// addPod adds pod information to this NodeInfo.
|
||||||
|
@ -175,9 +175,6 @@ func SetDefaults_PodSpec(obj *PodSpec) {
|
|||||||
period := int64(DefaultTerminationGracePeriodSeconds)
|
period := int64(DefaultTerminationGracePeriodSeconds)
|
||||||
obj.TerminationGracePeriodSeconds = &period
|
obj.TerminationGracePeriodSeconds = &period
|
||||||
}
|
}
|
||||||
if obj.Affinity == nil {
|
|
||||||
obj.Affinity = &Affinity{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
func SetDefaults_Probe(obj *Probe) {
|
func SetDefaults_Probe(obj *Probe) {
|
||||||
if obj.TimeoutSeconds == 0 {
|
if obj.TimeoutSeconds == 0 {
|
||||||
|
@ -44,8 +44,7 @@ var masterNodes sets.String
|
|||||||
|
|
||||||
type pausePodConfig struct {
|
type pausePodConfig struct {
|
||||||
Name string
|
Name string
|
||||||
Affinity string
|
Affinity *v1.Affinity
|
||||||
NodeAffinity *v1.Affinity
|
|
||||||
Annotations, Labels, NodeSelector map[string]string
|
Annotations, Labels, NodeSelector map[string]string
|
||||||
Resources *v1.ResourceRequirements
|
Resources *v1.ResourceRequirements
|
||||||
}
|
}
|
||||||
@ -241,7 +240,7 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
podName := "without-label"
|
podName := "without-label"
|
||||||
_, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{
|
_, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
NodeAffinity: &v1.Affinity{
|
Affinity: &v1.Affinity{
|
||||||
NodeAffinity: &v1.NodeAffinity{
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||||
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
||||||
@ -303,7 +302,7 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
|
|
||||||
createPausePod(f, pausePodConfig{
|
createPausePod(f, pausePodConfig{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
NodeAffinity: &v1.Affinity{
|
Affinity: &v1.Affinity{
|
||||||
NodeAffinity: &v1.NodeAffinity{
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||||
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
||||||
@ -350,7 +349,7 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
labelPodName := "with-labels"
|
labelPodName := "with-labels"
|
||||||
pod := createPausePod(f, pausePodConfig{
|
pod := createPausePod(f, pausePodConfig{
|
||||||
Name: labelPodName,
|
Name: labelPodName,
|
||||||
NodeAffinity: &v1.Affinity{
|
Affinity: &v1.Affinity{
|
||||||
NodeAffinity: &v1.NodeAffinity{
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||||
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
||||||
@ -392,24 +391,24 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
_, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{
|
_, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
Labels: map[string]string{"name": "without-label"},
|
Labels: map[string]string{"name": "without-label"},
|
||||||
Affinity: `{
|
Affinity: &v1.Affinity{
|
||||||
"podAffinity": {
|
PodAffinity: &v1.PodAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"weight": 0,
|
{
|
||||||
"podAffinityTerm": {
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"labelSelector": {
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"matchExpressions": [{
|
{
|
||||||
"key": "service",
|
Key: "security",
|
||||||
"operator": "DoesNotExist",
|
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||||
"values":["securityscan"]
|
Values: []string{"securityscan"},
|
||||||
}]
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"namespaces": [],
|
TopologyKey: "kubernetes.io/hostname",
|
||||||
"topologyKey": "kubernetes.io/hostname"
|
},
|
||||||
}
|
},
|
||||||
}]
|
},
|
||||||
}
|
},
|
||||||
}`,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if err == nil || !errors.IsInvalid(err) {
|
if err == nil || !errors.IsInvalid(err) {
|
||||||
@ -427,20 +426,24 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
podName := "without-label-" + string(uuid.NewUUID())
|
podName := "without-label-" + string(uuid.NewUUID())
|
||||||
createPausePod(f, pausePodConfig{
|
createPausePod(f, pausePodConfig{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
Affinity: `{
|
Affinity: &v1.Affinity{
|
||||||
"podAffinity": {
|
PodAffinity: &v1.PodAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"labelSelector":{
|
{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "service",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values": ["securityscan", "value2"]
|
Key: "service",
|
||||||
}]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"securityscan", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: "kubernetes.io/hostname",
|
||||||
},
|
},
|
||||||
"topologyKey": "kubernetes.io/hostname"
|
},
|
||||||
}]
|
},
|
||||||
}
|
},
|
||||||
}`,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
waitForScheduler()
|
waitForScheduler()
|
||||||
@ -462,21 +465,25 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
labelPodName := "with-podaffinity-" + string(uuid.NewUUID())
|
labelPodName := "with-podaffinity-" + string(uuid.NewUUID())
|
||||||
pod := createPausePod(f, pausePodConfig{
|
pod := createPausePod(f, pausePodConfig{
|
||||||
Name: labelPodName,
|
Name: labelPodName,
|
||||||
Affinity: `{
|
Affinity: &v1.Affinity{
|
||||||
"podAffinity": {
|
PodAffinity: &v1.PodAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "security",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values": ["S1", "value2"]
|
Key: "security",
|
||||||
}]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: k,
|
||||||
|
Namespaces: []string{ns},
|
||||||
},
|
},
|
||||||
"topologyKey": "` + k + `",
|
},
|
||||||
"namespaces":["` + ns + `"]
|
},
|
||||||
}]
|
},
|
||||||
}
|
|
||||||
}`,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// check that pod got scheduled. We intentionally DO NOT check that the
|
// check that pod got scheduled. We intentionally DO NOT check that the
|
||||||
@ -529,21 +536,25 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
Name: labelPodName,
|
Name: labelPodName,
|
||||||
Labels: map[string]string{"service": "Diff"},
|
Labels: map[string]string{"service": "Diff"},
|
||||||
NodeSelector: map[string]string{k: v}, // only launch on our two nodes, contradicting the podAntiAffinity
|
NodeSelector: map[string]string{k: v}, // only launch on our two nodes, contradicting the podAntiAffinity
|
||||||
Affinity: `{
|
Affinity: &v1.Affinity{
|
||||||
"podAntiAffinity": {
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"labelSelector":{
|
{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "service",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values": ["S1", "value2"]
|
Key: "security",
|
||||||
}]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1", "value2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: k,
|
||||||
|
Namespaces: []string{ns},
|
||||||
},
|
},
|
||||||
"topologyKey": "` + k + `",
|
},
|
||||||
"namespaces": ["` + ns + `"]
|
},
|
||||||
}]
|
},
|
||||||
}
|
|
||||||
}`,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
waitForScheduler()
|
waitForScheduler()
|
||||||
@ -565,29 +576,31 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
labelPodName := "with-podaffinity-" + string(uuid.NewUUID())
|
labelPodName := "with-podaffinity-" + string(uuid.NewUUID())
|
||||||
pod := createPausePod(f, pausePodConfig{
|
pod := createPausePod(f, pausePodConfig{
|
||||||
Name: labelPodName,
|
Name: labelPodName,
|
||||||
Affinity: `{
|
Affinity: &v1.Affinity{
|
||||||
"podAffinity": {
|
PodAffinity: &v1.PodAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"labelSelector":{
|
{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "security",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values": ["S1", "value2"]
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1", "value2"},
|
||||||
|
}, {
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpNotIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
}, {
|
||||||
|
Key: "security",
|
||||||
|
Operator: metav1.LabelSelectorOpExists,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
TopologyKey: k,
|
||||||
"key": "security",
|
|
||||||
"operator": "NotIn",
|
|
||||||
"values": ["S2"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "security",
|
|
||||||
"operator":"Exists"
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
"topologyKey": "` + k + `"
|
},
|
||||||
}]
|
},
|
||||||
}
|
},
|
||||||
}`,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// check that pod got scheduled. We intentionally DO NOT check that the
|
// check that pod got scheduled. We intentionally DO NOT check that the
|
||||||
@ -745,15 +758,6 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
func initPausePod(f *framework.Framework, conf pausePodConfig) *v1.Pod {
|
func initPausePod(f *framework.Framework, conf pausePodConfig) *v1.Pod {
|
||||||
if conf.Affinity != "" {
|
|
||||||
if conf.Annotations == nil {
|
|
||||||
conf.Annotations = map[string]string{
|
|
||||||
v1.AffinityAnnotationKey: conf.Affinity,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
conf.Annotations[v1.AffinityAnnotationKey] = conf.Affinity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pod := &v1.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: conf.Name,
|
Name: conf.Name,
|
||||||
@ -762,7 +766,7 @@ func initPausePod(f *framework.Framework, conf pausePodConfig) *v1.Pod {
|
|||||||
},
|
},
|
||||||
Spec: v1.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
NodeSelector: conf.NodeSelector,
|
NodeSelector: conf.NodeSelector,
|
||||||
Affinity: conf.NodeAffinity,
|
Affinity: conf.Affinity,
|
||||||
Containers: []v1.Container{
|
Containers: []v1.Container{
|
||||||
{
|
{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
@ -808,7 +812,7 @@ func runPodAndGetNodeName(f *framework.Framework, conf pausePodConfig) string {
|
|||||||
func createPodWithNodeAffinity(f *framework.Framework) *v1.Pod {
|
func createPodWithNodeAffinity(f *framework.Framework) *v1.Pod {
|
||||||
return createPausePod(f, pausePodConfig{
|
return createPausePod(f, pausePodConfig{
|
||||||
Name: "with-nodeaffinity-" + string(uuid.NewUUID()),
|
Name: "with-nodeaffinity-" + string(uuid.NewUUID()),
|
||||||
NodeAffinity: &v1.Affinity{
|
Affinity: &v1.Affinity{
|
||||||
NodeAffinity: &v1.NodeAffinity{
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||||
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
||||||
@ -831,32 +835,40 @@ func createPodWithNodeAffinity(f *framework.Framework) *v1.Pod {
|
|||||||
func createPodWithPodAffinity(f *framework.Framework, topologyKey string) *v1.Pod {
|
func createPodWithPodAffinity(f *framework.Framework, topologyKey string) *v1.Pod {
|
||||||
return createPausePod(f, pausePodConfig{
|
return createPausePod(f, pausePodConfig{
|
||||||
Name: "with-podantiaffinity-" + string(uuid.NewUUID()),
|
Name: "with-podantiaffinity-" + string(uuid.NewUUID()),
|
||||||
Affinity: `{
|
Affinity: &v1.Affinity{
|
||||||
"podAffinity": {
|
PodAffinity: &v1.PodAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "security",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values":["S1"]
|
Key: "security",
|
||||||
}]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: topologyKey,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"topologyKey": "` + topologyKey + `"
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
"podAntiAffinity": {
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
||||||
"requiredDuringSchedulingIgnoredDuringExecution": [{
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
||||||
"labelSelector": {
|
{
|
||||||
"matchExpressions": [{
|
LabelSelector: &metav1.LabelSelector{
|
||||||
"key": "security",
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
"operator": "In",
|
{
|
||||||
"values":["S2"]
|
Key: "security",
|
||||||
}]
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"S2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TopologyKey: topologyKey,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"topologyKey": "` + topologyKey + `"
|
},
|
||||||
}]
|
},
|
||||||
}
|
|
||||||
}`,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user