HPA: Enable DV support for Name and Kind

This commit is contained in:
darshansreenivas 2025-12-16 22:01:13 -08:00
parent 4925c6bea4
commit 97e154e2b7
8 changed files with 332 additions and 6 deletions

View file

@ -58,6 +58,51 @@ func RegisterValidations(scheme *runtime.Scheme) error {
return nil
}
// Validate_CrossVersionObjectReference validates an instance of CrossVersionObjectReference according
// to declarative validation rules in the API schema.
func Validate_CrossVersionObjectReference(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv1.CrossVersionObjectReference) (errs field.ErrorList) {
// field autoscalingv1.CrossVersionObjectReference.Kind
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("kind"), &obj.Kind, safe.Field(oldObj, func(oldObj *autoscalingv1.CrossVersionObjectReference) *string { return &oldObj.Kind }), oldObj != nil)...)
// field autoscalingv1.CrossVersionObjectReference.Name
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("name"), &obj.Name, safe.Field(oldObj, func(oldObj *autoscalingv1.CrossVersionObjectReference) *string { return &oldObj.Name }), oldObj != nil)...)
// field autoscalingv1.CrossVersionObjectReference.APIVersion has no validation
return errs
}
// Validate_HorizontalPodAutoscaler validates an instance of HorizontalPodAutoscaler according
// to declarative validation rules in the API schema.
func Validate_HorizontalPodAutoscaler(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv1.HorizontalPodAutoscaler) (errs field.ErrorList) {
@ -85,7 +130,19 @@ func Validate_HorizontalPodAutoscaler(ctx context.Context, op operation.Operatio
// Validate_HorizontalPodAutoscalerSpec validates an instance of HorizontalPodAutoscalerSpec according
// to declarative validation rules in the API schema.
func Validate_HorizontalPodAutoscalerSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv1.HorizontalPodAutoscalerSpec) (errs field.ErrorList) {
// field autoscalingv1.HorizontalPodAutoscalerSpec.ScaleTargetRef has no validation
// field autoscalingv1.HorizontalPodAutoscalerSpec.ScaleTargetRef
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv1.CrossVersionObjectReference, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call the type's validation function
errs = append(errs, Validate_CrossVersionObjectReference(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("scaleTargetRef"), &obj.ScaleTargetRef, safe.Field(oldObj, func(oldObj *autoscalingv1.HorizontalPodAutoscalerSpec) *autoscalingv1.CrossVersionObjectReference {
return &oldObj.ScaleTargetRef
}), oldObj != nil)...)
// field autoscalingv1.HorizontalPodAutoscalerSpec.MinReplicas
errs = append(errs,

View file

@ -50,6 +50,51 @@ func RegisterValidations(scheme *runtime.Scheme) error {
return nil
}
// Validate_CrossVersionObjectReference validates an instance of CrossVersionObjectReference according
// to declarative validation rules in the API schema.
func Validate_CrossVersionObjectReference(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.CrossVersionObjectReference) (errs field.ErrorList) {
// field autoscalingv2.CrossVersionObjectReference.Kind
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("kind"), &obj.Kind, safe.Field(oldObj, func(oldObj *autoscalingv2.CrossVersionObjectReference) *string { return &oldObj.Kind }), oldObj != nil)...)
// field autoscalingv2.CrossVersionObjectReference.Name
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
errs = append(errs, e...)
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
return
}(fldPath.Child("name"), &obj.Name, safe.Field(oldObj, func(oldObj *autoscalingv2.CrossVersionObjectReference) *string { return &oldObj.Name }), oldObj != nil)...)
// field autoscalingv2.CrossVersionObjectReference.APIVersion has no validation
return errs
}
// Validate_HorizontalPodAutoscaler validates an instance of HorizontalPodAutoscaler according
// to declarative validation rules in the API schema.
func Validate_HorizontalPodAutoscaler(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.HorizontalPodAutoscaler) (errs field.ErrorList) {
@ -70,14 +115,39 @@ func Validate_HorizontalPodAutoscaler(ctx context.Context, op operation.Operatio
return &oldObj.Spec
}), oldObj != nil)...)
// field autoscalingv2.HorizontalPodAutoscaler.Status has no validation
// field autoscalingv2.HorizontalPodAutoscaler.Status
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv2.HorizontalPodAutoscalerStatus, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call the type's validation function
errs = append(errs, Validate_HorizontalPodAutoscalerStatus(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("status"), &obj.Status, safe.Field(oldObj, func(oldObj *autoscalingv2.HorizontalPodAutoscaler) *autoscalingv2.HorizontalPodAutoscalerStatus {
return &oldObj.Status
}), oldObj != nil)...)
return errs
}
// Validate_HorizontalPodAutoscalerSpec validates an instance of HorizontalPodAutoscalerSpec according
// to declarative validation rules in the API schema.
func Validate_HorizontalPodAutoscalerSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.HorizontalPodAutoscalerSpec) (errs field.ErrorList) {
// field autoscalingv2.HorizontalPodAutoscalerSpec.ScaleTargetRef has no validation
// field autoscalingv2.HorizontalPodAutoscalerSpec.ScaleTargetRef
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv2.CrossVersionObjectReference, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call the type's validation function
errs = append(errs, Validate_CrossVersionObjectReference(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("scaleTargetRef"), &obj.ScaleTargetRef, safe.Field(oldObj, func(oldObj *autoscalingv2.HorizontalPodAutoscalerSpec) *autoscalingv2.CrossVersionObjectReference {
return &oldObj.ScaleTargetRef
}), oldObj != nil)...)
// field autoscalingv2.HorizontalPodAutoscalerSpec.MinReplicas
errs = append(errs,
@ -117,7 +187,147 @@ func Validate_HorizontalPodAutoscalerSpec(ctx context.Context, op operation.Oper
return
}(fldPath.Child("maxReplicas"), &obj.MaxReplicas, safe.Field(oldObj, func(oldObj *autoscalingv2.HorizontalPodAutoscalerSpec) *int32 { return &oldObj.MaxReplicas }), oldObj != nil)...)
// field autoscalingv2.HorizontalPodAutoscalerSpec.Metrics has no validation
// field autoscalingv2.HorizontalPodAutoscalerSpec.Metrics
errs = append(errs,
func(fldPath *field.Path, obj, oldObj []autoscalingv2.MetricSpec, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// iterate the list and call the type's validation function
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_MetricSpec)...)
return
}(fldPath.Child("metrics"), obj.Metrics, safe.Field(oldObj, func(oldObj *autoscalingv2.HorizontalPodAutoscalerSpec) []autoscalingv2.MetricSpec {
return oldObj.Metrics
}), oldObj != nil)...)
// field autoscalingv2.HorizontalPodAutoscalerSpec.Behavior has no validation
return errs
}
// Validate_HorizontalPodAutoscalerStatus validates an instance of HorizontalPodAutoscalerStatus according
// to declarative validation rules in the API schema.
func Validate_HorizontalPodAutoscalerStatus(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.HorizontalPodAutoscalerStatus) (errs field.ErrorList) {
// field autoscalingv2.HorizontalPodAutoscalerStatus.ObservedGeneration has no validation
// field autoscalingv2.HorizontalPodAutoscalerStatus.LastScaleTime has no validation
// field autoscalingv2.HorizontalPodAutoscalerStatus.CurrentReplicas has no validation
// field autoscalingv2.HorizontalPodAutoscalerStatus.DesiredReplicas has no validation
// field autoscalingv2.HorizontalPodAutoscalerStatus.CurrentMetrics
errs = append(errs,
func(fldPath *field.Path, obj, oldObj []autoscalingv2.MetricStatus, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// iterate the list and call the type's validation function
errs = append(errs, validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_MetricStatus)...)
return
}(fldPath.Child("currentMetrics"), obj.CurrentMetrics, safe.Field(oldObj, func(oldObj *autoscalingv2.HorizontalPodAutoscalerStatus) []autoscalingv2.MetricStatus {
return oldObj.CurrentMetrics
}), oldObj != nil)...)
// field autoscalingv2.HorizontalPodAutoscalerStatus.Conditions has no validation
return errs
}
// Validate_MetricSpec validates an instance of MetricSpec according
// to declarative validation rules in the API schema.
func Validate_MetricSpec(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.MetricSpec) (errs field.ErrorList) {
// field autoscalingv2.MetricSpec.Type has no validation
// field autoscalingv2.MetricSpec.Object
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv2.ObjectMetricSource, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call field-attached validations
earlyReturn := false
if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj); len(e) != 0 {
earlyReturn = true
}
if earlyReturn {
return // do not proceed
}
// call the type's validation function
errs = append(errs, Validate_ObjectMetricSource(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("object"), obj.Object, safe.Field(oldObj, func(oldObj *autoscalingv2.MetricSpec) *autoscalingv2.ObjectMetricSource { return oldObj.Object }), oldObj != nil)...)
// field autoscalingv2.MetricSpec.Pods has no validation
// field autoscalingv2.MetricSpec.Resource has no validation
// field autoscalingv2.MetricSpec.ContainerResource has no validation
// field autoscalingv2.MetricSpec.External has no validation
return errs
}
// Validate_MetricStatus validates an instance of MetricStatus according
// to declarative validation rules in the API schema.
func Validate_MetricStatus(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.MetricStatus) (errs field.ErrorList) {
// field autoscalingv2.MetricStatus.Type has no validation
// field autoscalingv2.MetricStatus.Object
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv2.ObjectMetricStatus, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && equality.Semantic.DeepEqual(obj, oldObj) {
return nil
}
// call the type's validation function
errs = append(errs, Validate_ObjectMetricStatus(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("object"), obj.Object, safe.Field(oldObj, func(oldObj *autoscalingv2.MetricStatus) *autoscalingv2.ObjectMetricStatus { return oldObj.Object }), oldObj != nil)...)
// field autoscalingv2.MetricStatus.Pods has no validation
// field autoscalingv2.MetricStatus.Resource has no validation
// field autoscalingv2.MetricStatus.ContainerResource has no validation
// field autoscalingv2.MetricStatus.External has no validation
return errs
}
// Validate_ObjectMetricSource validates an instance of ObjectMetricSource according
// to declarative validation rules in the API schema.
func Validate_ObjectMetricSource(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.ObjectMetricSource) (errs field.ErrorList) {
// field autoscalingv2.ObjectMetricSource.DescribedObject
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv2.CrossVersionObjectReference, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call the type's validation function
errs = append(errs, Validate_CrossVersionObjectReference(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("describedObject"), &obj.DescribedObject, safe.Field(oldObj, func(oldObj *autoscalingv2.ObjectMetricSource) *autoscalingv2.CrossVersionObjectReference {
return &oldObj.DescribedObject
}), oldObj != nil)...)
// field autoscalingv2.ObjectMetricSource.Target has no validation
// field autoscalingv2.ObjectMetricSource.Metric has no validation
return errs
}
// Validate_ObjectMetricStatus validates an instance of ObjectMetricStatus according
// to declarative validation rules in the API schema.
func Validate_ObjectMetricStatus(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *autoscalingv2.ObjectMetricStatus) (errs field.ErrorList) {
// field autoscalingv2.ObjectMetricStatus.Metric has no validation
// field autoscalingv2.ObjectMetricStatus.Current has no validation
// field autoscalingv2.ObjectMetricStatus.DescribedObject
errs = append(errs,
func(fldPath *field.Path, obj, oldObj *autoscalingv2.CrossVersionObjectReference, oldValueCorrelated bool) (errs field.ErrorList) {
// don't revalidate unchanged data
if oldValueCorrelated && op.Type == operation.Update && (obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj)) {
return nil
}
// call the type's validation function
errs = append(errs, Validate_CrossVersionObjectReference(ctx, op, fldPath, obj, oldObj)...)
return
}(fldPath.Child("describedObject"), &obj.DescribedObject, safe.Field(oldObj, func(oldObj *autoscalingv2.ObjectMetricStatus) *autoscalingv2.CrossVersionObjectReference {
return &oldObj.DescribedObject
}), oldObj != nil)...)
return errs
}

View file

@ -84,7 +84,7 @@ func validateHorizontalPodAutoscalerSpec(autoscaler autoscaling.HorizontalPodAut
func ValidateCrossVersionObjectReference(ref autoscaling.CrossVersionObjectReference, fldPath *field.Path, opts CrossVersionObjectReferenceValidationOptions) field.ErrorList {
allErrs := field.ErrorList{}
if len(ref.Kind) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("kind"), ""))
allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "").MarkCoveredByDeclarative())
} else {
for _, msg := range content.IsPathSegmentName(ref.Kind) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg))
@ -92,7 +92,7 @@ func ValidateCrossVersionObjectReference(ref autoscaling.CrossVersionObjectRefer
}
if len(ref.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "").MarkCoveredByDeclarative())
} else {
for _, msg := range content.IsPathSegmentName(ref.Name) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg))

View file

@ -29,6 +29,7 @@ import (
var apiVersions = []string{"v1", "v2"}
func TestDeclarativeValidate(t *testing.T) {
for _, apiVersion := range apiVersions {
testDeclarativeValidate(t, apiVersion)
}
@ -62,6 +63,18 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
field.Invalid(field.NewPath("spec", "maxReplicas"), int32(-1), "must be greater than or equal to 1").WithOrigin("minimum"),
},
},
"invalid scaleTargetRef - missing name": {
input: makeValidHPA(tweakName("")),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "scaleTargetRef", "name"), ""),
},
},
"invalid scaleTargetRef - missing kind": {
input: makeValidHPA(tweakKind("")),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "scaleTargetRef", "kind"), ""),
},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
@ -106,6 +119,20 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) {
field.Invalid(field.NewPath("spec", "maxReplicas"), int32(-1), "must be greater than or equal to 1").WithOrigin("minimum"),
},
},
"invalid update name": {
oldObj: makeValidHPA(),
updateObj: makeValidHPA(tweakName("")),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "scaleTargetRef", "name"), ""),
},
},
"invalid update kind": {
oldObj: makeValidHPA(),
updateObj: makeValidHPA(tweakKind("")),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec", "scaleTargetRef", "kind"), ""),
},
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
@ -155,3 +182,15 @@ func tweakMaxReplicas(replicas int32) func(*api.HorizontalPodAutoscaler) {
hpa.Spec.MaxReplicas = replicas
}
}
func tweakName(name string) func(*api.HorizontalPodAutoscaler) {
return func(hpa *api.HorizontalPodAutoscaler) {
hpa.Spec.ScaleTargetRef.Name = name
}
}
func tweakKind(kind string) func(*api.HorizontalPodAutoscaler) {
return func(hpa *api.HorizontalPodAutoscaler) {
hpa.Spec.ScaleTargetRef.Kind = kind
}
}

View file

@ -88,9 +88,13 @@ message ContainerResourceMetricStatus {
// +structType=atomic
message CrossVersionObjectReference {
// kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +required
// +k8s:required
optional string kind = 1;
// name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// +required
// +k8s:required
optional string name = 2;
// apiVersion is the API version of the referent
@ -250,6 +254,7 @@ message MetricSpec {
// object refers to a metric describing a single kubernetes object
// (for example, hits-per-second on an Ingress object).
// +optional
// +k8s:optional
optional ObjectMetricSource object = 2;
// pods refers to a metric describing each pod in the current scale target

View file

@ -26,9 +26,13 @@ import (
// +structType=atomic
type CrossVersionObjectReference struct {
// kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +required
// +k8s:required
Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"`
// name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// +required
// +k8s:required
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
// apiVersion is the API version of the referent
@ -206,6 +210,7 @@ type MetricSpec struct {
// object refers to a metric describing a single kubernetes object
// (for example, hits-per-second on an Ingress object).
// +optional
// +k8s:optional
Object *ObjectMetricSource `json:"object,omitempty" protobuf:"bytes,2,opt,name=object"`
// pods refers to a metric describing each pod in the current scale target

View file

@ -67,9 +67,13 @@ message ContainerResourceMetricStatus {
// CrossVersionObjectReference contains enough information to let you identify the referred resource.
message CrossVersionObjectReference {
// kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +required
// +k8s:required
optional string kind = 1;
// name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// +required
// +k8s:required
optional string name = 2;
// apiVersion is the API version of the referent
@ -334,6 +338,7 @@ message MetricSpec {
// object refers to a metric describing a single kubernetes object
// (for example, hits-per-second on an Ingress object).
// +optional
// +k8s:optional
optional ObjectMetricSource object = 2;
// pods refers to a metric describing each pod in the current scale target

View file

@ -91,9 +91,13 @@ type HorizontalPodAutoscalerSpec struct {
// CrossVersionObjectReference contains enough information to let you identify the referred resource.
type CrossVersionObjectReference struct {
// kind is the kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +required
// +k8s:required
Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"`
// name is the name of the referent; More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
// +required
// +k8s:required
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
// apiVersion is the API version of the referent
@ -111,6 +115,7 @@ type MetricSpec struct {
// object refers to a metric describing a single kubernetes object
// (for example, hits-per-second on an Ingress object).
// +optional
// +k8s:optional
Object *ObjectMetricSource `json:"object,omitempty" protobuf:"bytes,2,opt,name=object"`
// pods refers to a metric describing each pod in the current scale target