mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #20703 from mwielgus/hpa-cm-validation
Auto commit by PR queue bot
This commit is contained in:
		@@ -17,6 +17,7 @@ limitations under the License.
 | 
				
			|||||||
package validation
 | 
					package validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@@ -27,6 +28,7 @@ import (
 | 
				
			|||||||
	unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation"
 | 
						unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation"
 | 
				
			||||||
	apivalidation "k8s.io/kubernetes/pkg/api/validation"
 | 
						apivalidation "k8s.io/kubernetes/pkg/api/validation"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/extensions"
 | 
						"k8s.io/kubernetes/pkg/apis/extensions"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/controller/podautoscaler"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/labels"
 | 
						"k8s.io/kubernetes/pkg/labels"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/intstr"
 | 
						"k8s.io/kubernetes/pkg/util/intstr"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/sets"
 | 
						"k8s.io/kubernetes/pkg/util/sets"
 | 
				
			||||||
@@ -85,9 +87,34 @@ func ValidateSubresourceReference(ref extensions.SubresourceReference, fldPath *
 | 
				
			|||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func validateHorizontalPodAutoscalerAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
						if annotationValue, found := annotations[podautoscaler.HpaCustomMetricsTargetAnnotationName]; found {
 | 
				
			||||||
 | 
							// Try to parse the annotation
 | 
				
			||||||
 | 
							var targetList extensions.CustomMetricTargetList
 | 
				
			||||||
 | 
							if err := json.Unmarshal([]byte(annotationValue), &targetList); err != nil {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations"), annotations, "failed to parse custom metrics target annotation"))
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if len(targetList.Items) == 0 {
 | 
				
			||||||
 | 
									allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items"), "custom metrics target must not be empty"))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for _, target := range targetList.Items {
 | 
				
			||||||
 | 
									if target.Name == "" {
 | 
				
			||||||
 | 
										allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items", "name"), "missing custom metric target name"))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if target.TargetValue.MilliValue() <= 0 {
 | 
				
			||||||
 | 
										allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations", "items", "value"), target.TargetValue, "custom metric target value must be greater than 0"))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList {
 | 
					func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList {
 | 
				
			||||||
	allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata"))
 | 
						allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata"))
 | 
				
			||||||
	allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...)
 | 
						allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, validateHorizontalPodAutoscalerAnnotations(autoscaler.Annotations, field.NewPath("metadata"))...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/unversioned"
 | 
						"k8s.io/kubernetes/pkg/api/unversioned"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/apis/extensions"
 | 
						"k8s.io/kubernetes/pkg/apis/extensions"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/controller/podautoscaler"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/intstr"
 | 
						"k8s.io/kubernetes/pkg/util/intstr"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,6 +61,24 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
 | 
				
			|||||||
				MaxReplicas: 5,
 | 
									MaxReplicas: 5,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
									Name:      "myautoscaler",
 | 
				
			||||||
 | 
									Namespace: api.NamespaceDefault,
 | 
				
			||||||
 | 
									Annotations: map[string]string{
 | 
				
			||||||
 | 
										podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"20\"}]}",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								Spec: extensions.HorizontalPodAutoscalerSpec{
 | 
				
			||||||
 | 
									ScaleRef: extensions.SubresourceReference{
 | 
				
			||||||
 | 
										Kind:        "ReplicationController",
 | 
				
			||||||
 | 
										Name:        "myrc",
 | 
				
			||||||
 | 
										Subresource: "scale",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									MinReplicas: newInt(1),
 | 
				
			||||||
 | 
									MaxReplicas: 5,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, successCase := range successCases {
 | 
						for _, successCase := range successCases {
 | 
				
			||||||
		if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
 | 
							if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
 | 
				
			||||||
@@ -204,6 +223,90 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
			msg: "must be greater than 0",
 | 
								msg: "must be greater than 0",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{
 | 
				
			||||||
 | 
									ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
										Name:      "myautoscaler",
 | 
				
			||||||
 | 
										Namespace: api.NamespaceDefault,
 | 
				
			||||||
 | 
										Annotations: map[string]string{
 | 
				
			||||||
 | 
											podautoscaler.HpaCustomMetricsTargetAnnotationName: "broken",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: extensions.HorizontalPodAutoscalerSpec{
 | 
				
			||||||
 | 
										ScaleRef: extensions.SubresourceReference{
 | 
				
			||||||
 | 
											Kind:        "ReplicationController",
 | 
				
			||||||
 | 
											Name:        "myrc",
 | 
				
			||||||
 | 
											Subresource: "scale",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										MinReplicas: newInt(1),
 | 
				
			||||||
 | 
										MaxReplicas: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								msg: "failed to parse custom metrics target annotation",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{
 | 
				
			||||||
 | 
									ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
										Name:      "myautoscaler",
 | 
				
			||||||
 | 
										Namespace: api.NamespaceDefault,
 | 
				
			||||||
 | 
										Annotations: map[string]string{
 | 
				
			||||||
 | 
											podautoscaler.HpaCustomMetricsTargetAnnotationName: "{}",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: extensions.HorizontalPodAutoscalerSpec{
 | 
				
			||||||
 | 
										ScaleRef: extensions.SubresourceReference{
 | 
				
			||||||
 | 
											Kind:        "ReplicationController",
 | 
				
			||||||
 | 
											Name:        "myrc",
 | 
				
			||||||
 | 
											Subresource: "scale",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										MinReplicas: newInt(1),
 | 
				
			||||||
 | 
										MaxReplicas: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								msg: "custom metrics target must not be empty",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{
 | 
				
			||||||
 | 
									ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
										Name:      "myautoscaler",
 | 
				
			||||||
 | 
										Namespace: api.NamespaceDefault,
 | 
				
			||||||
 | 
										Annotations: map[string]string{
 | 
				
			||||||
 | 
											podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"value\":\"20\"}]}",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: extensions.HorizontalPodAutoscalerSpec{
 | 
				
			||||||
 | 
										ScaleRef: extensions.SubresourceReference{
 | 
				
			||||||
 | 
											Kind:        "ReplicationController",
 | 
				
			||||||
 | 
											Name:        "myrc",
 | 
				
			||||||
 | 
											Subresource: "scale",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										MinReplicas: newInt(1),
 | 
				
			||||||
 | 
										MaxReplicas: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								msg: "missing custom metric target name",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{
 | 
				
			||||||
 | 
									ObjectMeta: api.ObjectMeta{
 | 
				
			||||||
 | 
										Name:      "myautoscaler",
 | 
				
			||||||
 | 
										Namespace: api.NamespaceDefault,
 | 
				
			||||||
 | 
										Annotations: map[string]string{
 | 
				
			||||||
 | 
											podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"0\"}]}",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: extensions.HorizontalPodAutoscalerSpec{
 | 
				
			||||||
 | 
										ScaleRef: extensions.SubresourceReference{
 | 
				
			||||||
 | 
											Kind:        "ReplicationController",
 | 
				
			||||||
 | 
											Name:        "myrc",
 | 
				
			||||||
 | 
											Subresource: "scale",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										MinReplicas: newInt(1),
 | 
				
			||||||
 | 
										MaxReplicas: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								msg: "custom metric target value must be greater than 0",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, c := range errorCases {
 | 
						for _, c := range errorCases {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ const (
 | 
				
			|||||||
	// TODO: make it a flag or HPA spec element.
 | 
						// TODO: make it a flag or HPA spec element.
 | 
				
			||||||
	tolerance = 0.1
 | 
						tolerance = 0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	HpaCustomMetricsDefinitionAnnotationName = "alpha/definiton.custom-metrics.podautoscaler.kubernetes.io"
 | 
						HpaCustomMetricsTargetAnnotationName = "alpha/target.custom-metrics.podautoscaler.kubernetes.io"
 | 
				
			||||||
	HpaCustomMetricsStatusAnnotationName = "alpha/status.custom-metrics.podautoscaler.kubernetes.io"
 | 
						HpaCustomMetricsStatusAnnotationName = "alpha/status.custom-metrics.podautoscaler.kubernetes.io"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,7 +190,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpa extensions.HorizontalPodA
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cmAnnotation, cmAnnotationFound := hpa.Annotations[HpaCustomMetricsDefinitionAnnotationName]; cmAnnotationFound {
 | 
						if cmAnnotation, cmAnnotationFound := hpa.Annotations[HpaCustomMetricsTargetAnnotationName]; cmAnnotationFound {
 | 
				
			||||||
		cmDesiredReplicas, cmStatus, cmTimestamp, err = a.computeReplicasForCustomMetrics(hpa, scale, cmAnnotation)
 | 
							cmDesiredReplicas, cmStatus, cmTimestamp, err = a.computeReplicasForCustomMetrics(hpa, scale, cmAnnotation)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			a.eventRecorder.Event(&hpa, api.EventTypeWarning, "FailedComputeCMReplicas", err.Error())
 | 
								a.eventRecorder.Event(&hpa, api.EventTypeWarning, "FailedComputeCMReplicas", err.Error())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -110,7 +110,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset {
 | 
				
			|||||||
				t.Fatalf("Failed to marshal cm: %v", err)
 | 
									t.Fatalf("Failed to marshal cm: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			obj.Items[0].Annotations = make(map[string]string)
 | 
								obj.Items[0].Annotations = make(map[string]string)
 | 
				
			||||||
			obj.Items[0].Annotations[HpaCustomMetricsDefinitionAnnotationName] = string(b)
 | 
								obj.Items[0].Annotations[HpaCustomMetricsTargetAnnotationName] = string(b)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return true, obj, nil
 | 
							return true, obj, nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user