mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-03 03:38:15 +00:00
Use PreferAvoidPods annotation to avoid pods being scheduled to specific node.
1. define PreferAvoidPods annotation 2. add PreferAvoidPodsPriority 3. validate AvoidPods in node annotations
This commit is contained in:
@@ -1724,6 +1724,41 @@ func ValidateNodeSelector(nodeSelector *api.NodeSelector, fldPath *field.Path) f
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateAvoidPodsInNodeAnnotations tests that the serialized AvoidPods in Node.Annotations has valid data
|
||||
func ValidateAvoidPodsInNodeAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
avoids, err := api.GetAvoidPodsFromNodeAnnotations(annotations)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("AvoidPods"), api.PreferAvoidPodsAnnotationKey, err.Error()))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if len(avoids.PreferAvoidPods) != 0 {
|
||||
for i, pa := range avoids.PreferAvoidPods {
|
||||
idxPath := fldPath.Child(api.PreferAvoidPodsAnnotationKey).Index(i)
|
||||
allErrs = append(allErrs, validatePreferAvoidPodsEntry(pa, idxPath)...)
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePreferAvoidPodsEntry tests if given PreferAvoidPodsEntry has valid data.
|
||||
func validatePreferAvoidPodsEntry(avoidPodEntry api.PreferAvoidPodsEntry, fldPath *field.Path) field.ErrorList {
|
||||
allErrors := field.ErrorList{}
|
||||
if avoidPodEntry.PodSignature.PodController == nil {
|
||||
allErrors = append(allErrors, field.Required(fldPath.Child("PodSignature"), ""))
|
||||
} else {
|
||||
if *(avoidPodEntry.PodSignature.PodController.Controller) != true {
|
||||
allErrors = append(allErrors,
|
||||
field.Invalid(fldPath.Child("PodSignature").Child("PodController").Child("Controller"),
|
||||
*(avoidPodEntry.PodSignature.PodController.Controller), "must point to a controller"))
|
||||
}
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
// ValidatePreferredSchedulingTerms tests that the specified SoftNodeAffinity fields has valid data
|
||||
func ValidatePreferredSchedulingTerms(terms []api.PreferredSchedulingTerm, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
@@ -2359,10 +2394,14 @@ func ValidateTaintsInNodeAnnotations(annotations map[string]string, fldPath *fie
|
||||
}
|
||||
|
||||
func ValidateNodeSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
if annotations[api.TaintsAnnotationKey] != "" {
|
||||
return ValidateTaintsInNodeAnnotations(annotations, fldPath)
|
||||
allErrs := field.ErrorList{}
|
||||
if annotations[api.PreferAvoidPodsAnnotationKey] != "" {
|
||||
allErrs = append(allErrs, ValidateAvoidPodsInNodeAnnotations(annotations, fldPath)...)
|
||||
}
|
||||
return field.ErrorList{}
|
||||
if annotations[api.TaintsAnnotationKey] != "" {
|
||||
allErrs = append(allErrs, ValidateTaintsInNodeAnnotations(annotations, fldPath)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateNode tests if required fields in the node are set.
|
||||
|
||||
@@ -4375,6 +4375,43 @@ func TestValidateNode(t *testing.T) {
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc",
|
||||
Annotations: map[string]string{
|
||||
api.PreferAvoidPodsAnnotationKey: `
|
||||
{
|
||||
"preferAvoidPods": [
|
||||
{
|
||||
"podSignature": {
|
||||
"podController": {
|
||||
"apiVersion": "v1",
|
||||
"kind": "ReplicationController",
|
||||
"name": "foo",
|
||||
"uid": "abcdef123456",
|
||||
"controller": true
|
||||
}
|
||||
},
|
||||
"reason": "some reason",
|
||||
"message": "some message"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{
|
||||
{Type: api.NodeLegacyHostIP, Address: "something"},
|
||||
},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidateNode(&successCase); len(errs) != 0 {
|
||||
@@ -4539,6 +4576,67 @@ func TestValidateNode(t *testing.T) {
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
"missing-podSignature": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Annotations: map[string]string{
|
||||
api.PreferAvoidPodsAnnotationKey: `
|
||||
{
|
||||
"preferAvoidPods": [
|
||||
{
|
||||
"reason": "some reason",
|
||||
"message": "some message"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
"invalid-podController": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Annotations: map[string]string{
|
||||
api.PreferAvoidPodsAnnotationKey: `
|
||||
{
|
||||
"preferAvoidPods": [
|
||||
{
|
||||
"podSignature": {
|
||||
"podController": {
|
||||
"apiVersion": "v1",
|
||||
"kind": "ReplicationController",
|
||||
"name": "foo",
|
||||
"uid": "abcdef123456",
|
||||
"controller": false
|
||||
}
|
||||
},
|
||||
"reason": "some reason",
|
||||
"message": "some message"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
Status: api.NodeStatus{
|
||||
Addresses: []api.NodeAddress{},
|
||||
Capacity: api.ResourceList{
|
||||
api.ResourceName(api.ResourceCPU): resource.MustParse("10"),
|
||||
api.ResourceName(api.ResourceMemory): resource.MustParse("0"),
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
ExternalID: "external",
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateNode(&v)
|
||||
@@ -4548,14 +4646,16 @@ func TestValidateNode(t *testing.T) {
|
||||
for i := range errs {
|
||||
field := errs[i].Field
|
||||
expectedFields := map[string]bool{
|
||||
"metadata.name": true,
|
||||
"metadata.labels": true,
|
||||
"metadata.annotations": true,
|
||||
"metadata.namespace": true,
|
||||
"spec.externalID": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].key": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].value": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].effect": true,
|
||||
"metadata.name": true,
|
||||
"metadata.labels": true,
|
||||
"metadata.annotations": true,
|
||||
"metadata.namespace": true,
|
||||
"spec.externalID": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].key": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].value": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/taints[0].effect": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/preferAvoidPods[0].PodSignature": true,
|
||||
"metadata.annotations.scheduler.alpha.kubernetes.io/preferAvoidPods[0].PodSignature.PodController.Controller": true,
|
||||
}
|
||||
if val, ok := expectedFields[field]; ok {
|
||||
if !val {
|
||||
@@ -4764,6 +4864,87 @@ func TestValidateNodeUpdate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}, true},
|
||||
{api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
}, api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Annotations: map[string]string{
|
||||
api.PreferAvoidPodsAnnotationKey: `
|
||||
{
|
||||
"preferAvoidPods": [
|
||||
{
|
||||
"podSignature": {
|
||||
"podController": {
|
||||
"apiVersion": "v1",
|
||||
"kind": "ReplicationController",
|
||||
"name": "foo",
|
||||
"uid": "abcdef123456",
|
||||
"controller": true
|
||||
}
|
||||
},
|
||||
"reason": "some reason",
|
||||
"message": "some message"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
Spec: api.NodeSpec{
|
||||
Unschedulable: false,
|
||||
},
|
||||
}, true},
|
||||
{api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
}, api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Annotations: map[string]string{
|
||||
api.PreferAvoidPodsAnnotationKey: `
|
||||
{
|
||||
"preferAvoidPods": [
|
||||
{
|
||||
"reason": "some reason",
|
||||
"message": "some message"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
}, false},
|
||||
{api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
}, api.Node{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Annotations: map[string]string{
|
||||
api.PreferAvoidPodsAnnotationKey: `
|
||||
{
|
||||
"preferAvoidPods": [
|
||||
{
|
||||
"podSignature": {
|
||||
"podController": {
|
||||
"apiVersion": "v1",
|
||||
"kind": "ReplicationController",
|
||||
"name": "foo",
|
||||
"uid": "abcdef123456",
|
||||
"controller": false
|
||||
}
|
||||
},
|
||||
"reason": "some reason",
|
||||
"message": "some message"
|
||||
}
|
||||
]
|
||||
}`,
|
||||
},
|
||||
},
|
||||
}, false},
|
||||
}
|
||||
for i, test := range tests {
|
||||
test.oldNode.ObjectMeta.ResourceVersion = "1"
|
||||
|
||||
Reference in New Issue
Block a user