From 0fec7b0f7e2dfd4b0c6c57e086472546f6c69efa Mon Sep 17 00:00:00 2001 From: Arjun Naik Date: Wed, 21 Oct 2020 11:29:17 +0200 Subject: [PATCH] Added functionality and API for pod autoscaling based on container resources Signed-off-by: Arjun Naik --- api/openapi-spec/swagger.json | 125 ++- pkg/apis/autoscaling/types.go | 48 + pkg/apis/autoscaling/v1/conversion.go | 49 + .../autoscaling/v1/zz_generated.conversion.go | 86 ++ pkg/apis/autoscaling/v2beta1/conversion.go | 48 + .../v2beta1/zz_generated.conversion.go | 86 ++ .../v2beta2/zz_generated.conversion.go | 160 +++- pkg/apis/autoscaling/validation/BUILD | 1 + pkg/apis/autoscaling/validation/validation.go | 79 +- .../autoscaling/validation/validation_test.go | 329 +++++++ pkg/apis/autoscaling/zz_generated.deepcopy.go | 44 + pkg/apis/core/v1/validation/validation.go | 7 +- .../core/v1/validation/validation_test.go | 56 ++ pkg/controller/podautoscaler/horizontal.go | 94 +- .../podautoscaler/horizontal_test.go | 81 +- .../legacy_replica_calculator_test.go | 67 +- pkg/controller/podautoscaler/metrics/BUILD | 1 + .../podautoscaler/metrics/interfaces.go | 5 +- .../metrics/legacy_metrics_client.go | 16 +- .../metrics/legacy_metrics_client_test.go | 2 +- .../metrics/rest_metrics_client.go | 57 +- .../metrics/rest_metrics_client_test.go | 57 +- .../podautoscaler/replica_calculator.go | 24 +- .../podautoscaler/replica_calculator_test.go | 301 +++++- pkg/features/kube_features.go | 8 + pkg/printers/internalversion/printers.go | 19 + pkg/printers/internalversion/printers_test.go | 155 +++ .../autoscaling/horizontalpodautoscaler/BUILD | 17 + .../horizontalpodautoscaler/strategy.go | 26 + .../horizontalpodautoscaler/strategy_test.go | 110 +++ .../k8s.io/api/autoscaling/v1/generated.pb.go | 905 +++++++++++++++--- .../k8s.io/api/autoscaling/v1/generated.proto | 83 +- .../src/k8s.io/api/autoscaling/v1/types.go | 81 +- .../v1/types_swagger_doc_generated.go | 50 +- .../autoscaling/v1/zz_generated.deepcopy.go | 58 ++ .../api/autoscaling/v2beta1/generated.pb.go | 894 ++++++++++++++--- .../api/autoscaling/v2beta1/generated.proto | 83 +- .../k8s.io/api/autoscaling/v2beta1/types.go | 81 +- .../v2beta1/types_swagger_doc_generated.go | 50 +- .../v2beta1/zz_generated.deepcopy.go | 58 ++ .../api/autoscaling/v2beta2/generated.pb.go | 863 ++++++++++++++--- .../api/autoscaling/v2beta2/generated.proto | 63 +- .../k8s.io/api/autoscaling/v2beta2/types.go | 63 +- .../v2beta2/types_swagger_doc_generated.go | 48 +- .../v2beta2/zz_generated.deepcopy.go | 44 + ...aling.v2beta1.HorizontalPodAutoscaler.json | 100 +- ...scaling.v2beta1.HorizontalPodAutoscaler.pb | Bin 1708 -> 1957 bytes ...aling.v2beta1.HorizontalPodAutoscaler.yaml | 98 +- ...aling.v2beta2.HorizontalPodAutoscaler.json | 140 +-- ...scaling.v2beta2.HorizontalPodAutoscaler.pb | Bin 2336 -> 2125 bytes ...aling.v2beta2.HorizontalPodAutoscaler.yaml | 138 +-- .../generated/openapi/zz_generated.openapi.go | 108 ++- .../k8s.io/kubectl/pkg/describe/describe.go | 20 + .../kubectl/pkg/describe/describe_test.go | 146 +++ 54 files changed, 5526 insertions(+), 806 deletions(-) create mode 100644 pkg/registry/autoscaling/horizontalpodautoscaler/strategy_test.go diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index ab09728432d..60ed4f71de4 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -3024,6 +3024,61 @@ ], "type": "object" }, + "io.k8s.api.autoscaling.v2beta1.ContainerResourceMetricSource": { + "description": "ContainerResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in requests and limits, describing each pod in the current scale target (e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. Only one \"target\" type should be set.", + "properties": { + "container": { + "description": "container is the name of the container in the pods of the scaling target", + "type": "string" + }, + "name": { + "description": "name is the name of the resource in question.", + "type": "string" + }, + "targetAverageUtilization": { + "description": "targetAverageUtilization is the target value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods.", + "format": "int32", + "type": "integer" + }, + "targetAverageValue": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity", + "description": "targetAverageValue is the target value of the average of the resource metric across all relevant pods, as a raw value (instead of as a percentage of the request), similar to the \"pods\" metric source type." + } + }, + "required": [ + "name", + "container" + ], + "type": "object" + }, + "io.k8s.api.autoscaling.v2beta1.ContainerResourceMetricStatus": { + "description": "ContainerResourceMetricStatus indicates the current value of a resource metric known to Kubernetes, as specified in requests and limits, describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "properties": { + "container": { + "description": "container is the name of the container in the pods of the scaling target", + "type": "string" + }, + "currentAverageUtilization": { + "description": "currentAverageUtilization is the current value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods. It will only be present if `targetAverageValue` was set in the corresponding metric specification.", + "format": "int32", + "type": "integer" + }, + "currentAverageValue": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.api.resource.Quantity", + "description": "currentAverageValue is the current value of the average of the resource metric across all relevant pods, as a raw value (instead of as a percentage of the request), similar to the \"pods\" metric source type. It will always be set, regardless of the corresponding metric specification." + }, + "name": { + "description": "name is the name of the resource in question.", + "type": "string" + } + }, + "required": [ + "name", + "currentAverageValue", + "container" + ], + "type": "object" + }, "io.k8s.api.autoscaling.v2beta1.CrossVersionObjectReference": { "description": "CrossVersionObjectReference contains enough information to let you identify the referred resource.", "properties": { @@ -3273,6 +3328,10 @@ "io.k8s.api.autoscaling.v2beta1.MetricSpec": { "description": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", "properties": { + "containerResource": { + "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta1.ContainerResourceMetricSource", + "description": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag." + }, "external": { "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta1.ExternalMetricSource", "description": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster)." @@ -3290,7 +3349,7 @@ "description": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source." }, "type": { - "description": "type is the type of metric source. It should be one of \"Object\", \"Pods\", \"Resource\" or \"External\", each mapping to a matching field in the object.", + "description": "type is the type of metric source. It should be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each mapping to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", "type": "string" } }, @@ -3302,6 +3361,10 @@ "io.k8s.api.autoscaling.v2beta1.MetricStatus": { "description": "MetricStatus describes the last-read state of a single metric.", "properties": { + "containerResource": { + "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta1.ContainerResourceMetricStatus", + "description": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source." + }, "external": { "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta1.ExternalMetricStatus", "description": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster)." @@ -3319,7 +3382,7 @@ "description": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source." }, "type": { - "description": "type is the type of metric source. It will be one of \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object.", + "description": "type is the type of metric source. It will be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", "type": "string" } }, @@ -3479,6 +3542,52 @@ ], "type": "object" }, + "io.k8s.api.autoscaling.v2beta2.ContainerResourceMetricSource": { + "description": "ContainerResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in requests and limits, describing each pod in the current scale target (e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. Only one \"target\" type should be set.", + "properties": { + "container": { + "description": "container is the name of the container in the pods of the scaling target", + "type": "string" + }, + "name": { + "description": "name is the name of the resource in question.", + "type": "string" + }, + "target": { + "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta2.MetricTarget", + "description": "target specifies the target value for the given metric" + } + }, + "required": [ + "name", + "target", + "container" + ], + "type": "object" + }, + "io.k8s.api.autoscaling.v2beta2.ContainerResourceMetricStatus": { + "description": "ContainerResourceMetricStatus indicates the current value of a resource metric known to Kubernetes, as specified in requests and limits, describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "properties": { + "container": { + "description": "Container is the name of the container in the pods of the scaling target", + "type": "string" + }, + "current": { + "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta2.MetricValueStatus", + "description": "current contains the current value for the given metric" + }, + "name": { + "description": "Name is the name of the resource in question.", + "type": "string" + } + }, + "required": [ + "name", + "current", + "container" + ], + "type": "object" + }, "io.k8s.api.autoscaling.v2beta2.CrossVersionObjectReference": { "description": "CrossVersionObjectReference contains enough information to let you identify the referred resource.", "properties": { @@ -3795,6 +3904,10 @@ "io.k8s.api.autoscaling.v2beta2.MetricSpec": { "description": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", "properties": { + "containerResource": { + "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta2.ContainerResourceMetricSource", + "description": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag." + }, "external": { "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta2.ExternalMetricSource", "description": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster)." @@ -3812,7 +3925,7 @@ "description": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source." }, "type": { - "description": "type is the type of metric source. It should be one of \"Object\", \"Pods\", \"Resource\" or \"External\", each mapping to a matching field in the object.", + "description": "type is the type of metric source. It should be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each mapping to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", "type": "string" } }, @@ -3824,6 +3937,10 @@ "io.k8s.api.autoscaling.v2beta2.MetricStatus": { "description": "MetricStatus describes the last-read state of a single metric.", "properties": { + "containerResource": { + "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta2.ContainerResourceMetricStatus", + "description": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source." + }, "external": { "$ref": "#/definitions/io.k8s.api.autoscaling.v2beta2.ExternalMetricStatus", "description": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster)." @@ -3841,7 +3958,7 @@ "description": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source." }, "type": { - "description": "type is the type of metric source. It will be one of \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object.", + "description": "type is the type of metric source. It will be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", "type": "string" } }, diff --git a/pkg/apis/autoscaling/types.go b/pkg/apis/autoscaling/types.go index e2f0f4966db..e0ed0dad1cb 100644 --- a/pkg/apis/autoscaling/types.go +++ b/pkg/apis/autoscaling/types.go @@ -204,6 +204,12 @@ const ( // (for example length of queue in cloud messaging service, or // QPS from loadbalancer running outside of cluster). ExternalMetricSourceType MetricSourceType = "External" + // ContainerResourceMetricSourceType is a resource metric known to Kubernetes, as + // specified in requests and limits, describing a single container in each pod in the current + // scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics (the "pods" source). + ContainerResourceMetricSourceType MetricSourceType = "ContainerResource" ) // MetricSpec specifies how to scale based on a single metric @@ -229,6 +235,13 @@ type MetricSpec struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricSource + // ContainerResource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod of the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricSource // External refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -271,6 +284,22 @@ type ResourceMetricSource struct { Target MetricTarget } +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in the requests and limits, describing a single container in +// each of the pods of the current scale target(e.g. CPU or memory). The values will be +// averaged together before being compared to the target. Such metrics are built into +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +type ContainerResourceMetricSource struct { + // name is the name of the of the resource + Name api.ResourceName + // container is the name of the container in the pods of the scaling target. + Container string + // target specifies the target value for the given metric + Target MetricTarget +} + // ExternalMetricSource indicates how to scale on a metric not associated with // any Kubernetes object (for example length of queue in cloud // messaging service, or QPS from loadbalancer running outside of cluster). @@ -420,6 +449,13 @@ type MetricStatus struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricStatus + // ContainerResource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricStatus // External refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -456,6 +492,18 @@ type ResourceMetricStatus struct { Current MetricValueStatus } +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +type ContainerResourceMetricStatus struct { + // Name is the name of the resource in question. + Name api.ResourceName + Container string + Current MetricValueStatus +} + // ExternalMetricStatus indicates the current value of a global metric // not associated with any Kubernetes object. type ExternalMetricStatus struct { diff --git a/pkg/apis/autoscaling/v1/conversion.go b/pkg/apis/autoscaling/v1/conversion.go index 0b07f4af2c6..31187d6c501 100644 --- a/pkg/apis/autoscaling/v1/conversion.go +++ b/pkg/apis/autoscaling/v1/conversion.go @@ -235,6 +235,28 @@ func Convert_autoscaling_ResourceMetricSource_To_v1_ResourceMetricSource(in *aut return nil } +func Convert_v1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in *autoscalingv1.ContainerResourceMetricStatus, out *autoscaling.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + out.Container = in.Container + utilization := in.CurrentAverageUtilization + averageValue := &in.CurrentAverageValue + out.Current = autoscaling.MetricValueStatus{ + AverageValue: averageValue, + AverageUtilization: utilization, + } + return nil +} + +func Convert_autoscaling_ContainerResourceMetricStatus_To_v1_ContainerResourceMetricStatus(in *autoscaling.ContainerResourceMetricStatus, out *autoscalingv1.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + out.CurrentAverageUtilization = in.Current.AverageUtilization + if in.Current.AverageValue != nil { + out.CurrentAverageValue = *in.Current.AverageValue + } + return nil +} + func Convert_v1_ResourceMetricStatus_To_autoscaling_ResourceMetricStatus(in *autoscalingv1.ResourceMetricStatus, out *autoscaling.ResourceMetricStatus, s conversion.Scope) error { out.Name = core.ResourceName(in.Name) utilization := in.CurrentAverageUtilization @@ -517,3 +539,30 @@ func Convert_v1_HorizontalPodAutoscalerStatus_To_autoscaling_HorizontalPodAutosc } return nil } + +func Convert_v1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in *autoscalingv1.ContainerResourceMetricSource, out *autoscaling.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + out.Container = in.Container + utilization := in.TargetAverageUtilization + averageValue := in.TargetAverageValue + var metricType autoscaling.MetricTargetType + if utilization == nil { + metricType = autoscaling.AverageValueMetricType + } else { + metricType = autoscaling.UtilizationMetricType + } + out.Target = autoscaling.MetricTarget{ + Type: metricType, + AverageValue: averageValue, + AverageUtilization: utilization, + } + return nil +} + +func Convert_autoscaling_ContainerResourceMetricSource_To_v1_ContainerResourceMetricSource(in *autoscaling.ContainerResourceMetricSource, out *autoscalingv1.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + out.TargetAverageUtilization = in.Target.AverageUtilization + out.TargetAverageValue = in.Target.AverageValue + return nil +} diff --git a/pkg/apis/autoscaling/v1/zz_generated.conversion.go b/pkg/apis/autoscaling/v1/zz_generated.conversion.go index fe74c86d314..65374c74cc2 100644 --- a/pkg/apis/autoscaling/v1/zz_generated.conversion.go +++ b/pkg/apis/autoscaling/v1/zz_generated.conversion.go @@ -119,6 +119,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*autoscaling.ContainerResourceMetricSource)(nil), (*v1.ContainerResourceMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_autoscaling_ContainerResourceMetricSource_To_v1_ContainerResourceMetricSource(a.(*autoscaling.ContainerResourceMetricSource), b.(*v1.ContainerResourceMetricSource), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*autoscaling.ContainerResourceMetricStatus)(nil), (*v1.ContainerResourceMetricStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_autoscaling_ContainerResourceMetricStatus_To_v1_ContainerResourceMetricStatus(a.(*autoscaling.ContainerResourceMetricStatus), b.(*v1.ContainerResourceMetricStatus), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*autoscaling.ExternalMetricSource)(nil), (*v1.ExternalMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_autoscaling_ExternalMetricSource_To_v1_ExternalMetricSource(a.(*autoscaling.ExternalMetricSource), b.(*v1.ExternalMetricSource), scope) }); err != nil { @@ -179,6 +189,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1.ContainerResourceMetricSource)(nil), (*autoscaling.ContainerResourceMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(a.(*v1.ContainerResourceMetricSource), b.(*autoscaling.ContainerResourceMetricSource), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.ContainerResourceMetricStatus)(nil), (*autoscaling.ContainerResourceMetricStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(a.(*v1.ContainerResourceMetricStatus), b.(*autoscaling.ContainerResourceMetricStatus), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1.CrossVersionObjectReference)(nil), (*autoscaling.MetricTarget)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1_CrossVersionObjectReference_To_autoscaling_MetricTarget(a.(*v1.CrossVersionObjectReference), b.(*autoscaling.MetricTarget), scope) }); err != nil { @@ -242,6 +262,36 @@ func RegisterConversions(s *runtime.Scheme) error { return nil } +func autoConvert_v1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in *v1.ContainerResourceMetricSource, out *autoscaling.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + // WARNING: in.TargetAverageUtilization requires manual conversion: does not exist in peer-type + // WARNING: in.TargetAverageValue requires manual conversion: does not exist in peer-type + out.Container = in.Container + return nil +} + +func autoConvert_autoscaling_ContainerResourceMetricSource_To_v1_ContainerResourceMetricSource(in *autoscaling.ContainerResourceMetricSource, out *v1.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = corev1.ResourceName(in.Name) + out.Container = in.Container + // WARNING: in.Target requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_v1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in *v1.ContainerResourceMetricStatus, out *autoscaling.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + // WARNING: in.CurrentAverageUtilization requires manual conversion: does not exist in peer-type + // WARNING: in.CurrentAverageValue requires manual conversion: does not exist in peer-type + out.Container = in.Container + return nil +} + +func autoConvert_autoscaling_ContainerResourceMetricStatus_To_v1_ContainerResourceMetricStatus(in *autoscaling.ContainerResourceMetricStatus, out *v1.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = corev1.ResourceName(in.Name) + out.Container = in.Container + // WARNING: in.Current requires manual conversion: does not exist in peer-type + return nil +} + func autoConvert_v1_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference(in *v1.CrossVersionObjectReference, out *autoscaling.CrossVersionObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Name = in.Name @@ -455,6 +505,15 @@ func autoConvert_v1_MetricSpec_To_autoscaling_MetricSpec(in *v1.MetricSpec, out } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(autoscaling.ContainerResourceMetricSource) + if err := Convert_v1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(autoscaling.ExternalMetricSource) @@ -501,6 +560,15 @@ func autoConvert_autoscaling_MetricSpec_To_v1_MetricSpec(in *autoscaling.MetricS } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(v1.ContainerResourceMetricSource) + if err := Convert_autoscaling_ContainerResourceMetricSource_To_v1_ContainerResourceMetricSource(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(v1.ExternalMetricSource) @@ -547,6 +615,15 @@ func autoConvert_v1_MetricStatus_To_autoscaling_MetricStatus(in *v1.MetricStatus } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(autoscaling.ContainerResourceMetricStatus) + if err := Convert_v1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(autoscaling.ExternalMetricStatus) @@ -593,6 +670,15 @@ func autoConvert_autoscaling_MetricStatus_To_v1_MetricStatus(in *autoscaling.Met } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(v1.ContainerResourceMetricStatus) + if err := Convert_autoscaling_ContainerResourceMetricStatus_To_v1_ContainerResourceMetricStatus(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(v1.ExternalMetricStatus) diff --git a/pkg/apis/autoscaling/v2beta1/conversion.go b/pkg/apis/autoscaling/v2beta1/conversion.go index 56b67f7bc5b..171b2af4248 100644 --- a/pkg/apis/autoscaling/v2beta1/conversion.go +++ b/pkg/apis/autoscaling/v2beta1/conversion.go @@ -35,6 +35,28 @@ func Convert_v2beta1_CrossVersionObjectReference_To_autoscaling_MetricTarget(in return nil } +func Convert_v2beta1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in *autoscalingv2beta1.ContainerResourceMetricStatus, out *autoscaling.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + out.Container = in.Container + utilization := in.CurrentAverageUtilization + averageValue := in.CurrentAverageValue + out.Current = autoscaling.MetricValueStatus{ + AverageValue: &averageValue, + AverageUtilization: utilization, + } + return nil +} + +func Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta1_ContainerResourceMetricStatus(in *autoscaling.ContainerResourceMetricStatus, out *autoscalingv2beta1.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + out.CurrentAverageUtilization = in.Current.AverageUtilization + if in.Current.AverageValue != nil { + out.CurrentAverageValue = *in.Current.AverageValue + } + return nil +} + func Convert_v2beta1_ResourceMetricStatus_To_autoscaling_ResourceMetricStatus(in *autoscalingv2beta1.ResourceMetricStatus, out *autoscaling.ResourceMetricStatus, s conversion.Scope) error { out.Name = core.ResourceName(in.Name) utilization := in.CurrentAverageUtilization @@ -309,3 +331,29 @@ func Convert_v2beta1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutosca func Convert_autoscaling_HorizontalPodAutoscalerSpec_To_v2beta1_HorizontalPodAutoscalerSpec(in *autoscaling.HorizontalPodAutoscalerSpec, out *autoscalingv2beta1.HorizontalPodAutoscalerSpec, s conversion.Scope) error { return autoConvert_autoscaling_HorizontalPodAutoscalerSpec_To_v2beta1_HorizontalPodAutoscalerSpec(in, out, s) } + +func Convert_v2beta1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in *autoscalingv2beta1.ContainerResourceMetricSource, out *autoscaling.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + utilization := in.TargetAverageUtilization + averageValue := in.TargetAverageValue + + var metricType autoscaling.MetricTargetType + if utilization == nil { + metricType = autoscaling.AverageValueMetricType + } else { + metricType = autoscaling.UtilizationMetricType + } + out.Target = autoscaling.MetricTarget{ + Type: metricType, + AverageValue: averageValue, + AverageUtilization: utilization, + } + return nil +} + +func Convert_autoscaling_ContainerResourceMetricSource_To_v2beta1_ContainerResourceMetricSource(in *autoscaling.ContainerResourceMetricSource, out *autoscalingv2beta1.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.TargetAverageUtilization = in.Target.AverageUtilization + out.TargetAverageValue = in.Target.AverageValue + return nil +} diff --git a/pkg/apis/autoscaling/v2beta1/zz_generated.conversion.go b/pkg/apis/autoscaling/v2beta1/zz_generated.conversion.go index 06e3a51654b..5a769057231 100644 --- a/pkg/apis/autoscaling/v2beta1/zz_generated.conversion.go +++ b/pkg/apis/autoscaling/v2beta1/zz_generated.conversion.go @@ -104,6 +104,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*autoscaling.ContainerResourceMetricSource)(nil), (*v2beta1.ContainerResourceMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_autoscaling_ContainerResourceMetricSource_To_v2beta1_ContainerResourceMetricSource(a.(*autoscaling.ContainerResourceMetricSource), b.(*v2beta1.ContainerResourceMetricSource), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*autoscaling.ContainerResourceMetricStatus)(nil), (*v2beta1.ContainerResourceMetricStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta1_ContainerResourceMetricStatus(a.(*autoscaling.ContainerResourceMetricStatus), b.(*v2beta1.ContainerResourceMetricStatus), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*autoscaling.ExternalMetricSource)(nil), (*v2beta1.ExternalMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_autoscaling_ExternalMetricSource_To_v2beta1_ExternalMetricSource(a.(*autoscaling.ExternalMetricSource), b.(*v2beta1.ExternalMetricSource), scope) }); err != nil { @@ -159,6 +169,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v2beta1.ContainerResourceMetricSource)(nil), (*autoscaling.ContainerResourceMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v2beta1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(a.(*v2beta1.ContainerResourceMetricSource), b.(*autoscaling.ContainerResourceMetricSource), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v2beta1.ContainerResourceMetricStatus)(nil), (*autoscaling.ContainerResourceMetricStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v2beta1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(a.(*v2beta1.ContainerResourceMetricStatus), b.(*autoscaling.ContainerResourceMetricStatus), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v2beta1.CrossVersionObjectReference)(nil), (*autoscaling.MetricTarget)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v2beta1_CrossVersionObjectReference_To_autoscaling_MetricTarget(a.(*v2beta1.CrossVersionObjectReference), b.(*autoscaling.MetricTarget), scope) }); err != nil { @@ -212,6 +232,36 @@ func RegisterConversions(s *runtime.Scheme) error { return nil } +func autoConvert_v2beta1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in *v2beta1.ContainerResourceMetricSource, out *autoscaling.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + // WARNING: in.TargetAverageUtilization requires manual conversion: does not exist in peer-type + // WARNING: in.TargetAverageValue requires manual conversion: does not exist in peer-type + out.Container = in.Container + return nil +} + +func autoConvert_autoscaling_ContainerResourceMetricSource_To_v2beta1_ContainerResourceMetricSource(in *autoscaling.ContainerResourceMetricSource, out *v2beta1.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + // WARNING: in.Target requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_v2beta1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in *v2beta1.ContainerResourceMetricStatus, out *autoscaling.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + // WARNING: in.CurrentAverageUtilization requires manual conversion: does not exist in peer-type + // WARNING: in.CurrentAverageValue requires manual conversion: does not exist in peer-type + out.Container = in.Container + return nil +} + +func autoConvert_autoscaling_ContainerResourceMetricStatus_To_v2beta1_ContainerResourceMetricStatus(in *autoscaling.ContainerResourceMetricStatus, out *v2beta1.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + // WARNING: in.Current requires manual conversion: does not exist in peer-type + return nil +} + func autoConvert_v2beta1_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference(in *v2beta1.CrossVersionObjectReference, out *autoscaling.CrossVersionObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Name = in.Name @@ -481,6 +531,15 @@ func autoConvert_v2beta1_MetricSpec_To_autoscaling_MetricSpec(in *v2beta1.Metric } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(autoscaling.ContainerResourceMetricSource) + if err := Convert_v2beta1_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(autoscaling.ExternalMetricSource) @@ -527,6 +586,15 @@ func autoConvert_autoscaling_MetricSpec_To_v2beta1_MetricSpec(in *autoscaling.Me } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(v2beta1.ContainerResourceMetricSource) + if err := Convert_autoscaling_ContainerResourceMetricSource_To_v2beta1_ContainerResourceMetricSource(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(v2beta1.ExternalMetricSource) @@ -573,6 +641,15 @@ func autoConvert_v2beta1_MetricStatus_To_autoscaling_MetricStatus(in *v2beta1.Me } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(autoscaling.ContainerResourceMetricStatus) + if err := Convert_v2beta1_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(autoscaling.ExternalMetricStatus) @@ -619,6 +696,15 @@ func autoConvert_autoscaling_MetricStatus_To_v2beta1_MetricStatus(in *autoscalin } else { out.Resource = nil } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(v2beta1.ContainerResourceMetricStatus) + if err := Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta1_ContainerResourceMetricStatus(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } if in.External != nil { in, out := &in.External, &out.External *out = new(v2beta1.ExternalMetricStatus) diff --git a/pkg/apis/autoscaling/v2beta2/zz_generated.conversion.go b/pkg/apis/autoscaling/v2beta2/zz_generated.conversion.go index e579b4221ca..ce94a2e6444 100644 --- a/pkg/apis/autoscaling/v2beta2/zz_generated.conversion.go +++ b/pkg/apis/autoscaling/v2beta2/zz_generated.conversion.go @@ -40,6 +40,26 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v2beta2.ContainerResourceMetricSource)(nil), (*autoscaling.ContainerResourceMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v2beta2_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(a.(*v2beta2.ContainerResourceMetricSource), b.(*autoscaling.ContainerResourceMetricSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*autoscaling.ContainerResourceMetricSource)(nil), (*v2beta2.ContainerResourceMetricSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_autoscaling_ContainerResourceMetricSource_To_v2beta2_ContainerResourceMetricSource(a.(*autoscaling.ContainerResourceMetricSource), b.(*v2beta2.ContainerResourceMetricSource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v2beta2.ContainerResourceMetricStatus)(nil), (*autoscaling.ContainerResourceMetricStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v2beta2_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(a.(*v2beta2.ContainerResourceMetricStatus), b.(*autoscaling.ContainerResourceMetricStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*autoscaling.ContainerResourceMetricStatus)(nil), (*v2beta2.ContainerResourceMetricStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta2_ContainerResourceMetricStatus(a.(*autoscaling.ContainerResourceMetricStatus), b.(*v2beta2.ContainerResourceMetricStatus), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v2beta2.CrossVersionObjectReference)(nil), (*autoscaling.CrossVersionObjectReference)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v2beta2_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference(a.(*v2beta2.CrossVersionObjectReference), b.(*autoscaling.CrossVersionObjectReference), scope) }); err != nil { @@ -263,6 +283,62 @@ func RegisterConversions(s *runtime.Scheme) error { return nil } +func autoConvert_v2beta2_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in *v2beta2.ContainerResourceMetricSource, out *autoscaling.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + if err := Convert_v2beta2_MetricTarget_To_autoscaling_MetricTarget(&in.Target, &out.Target, s); err != nil { + return err + } + out.Container = in.Container + return nil +} + +// Convert_v2beta2_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource is an autogenerated conversion function. +func Convert_v2beta2_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in *v2beta2.ContainerResourceMetricSource, out *autoscaling.ContainerResourceMetricSource, s conversion.Scope) error { + return autoConvert_v2beta2_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(in, out, s) +} + +func autoConvert_autoscaling_ContainerResourceMetricSource_To_v2beta2_ContainerResourceMetricSource(in *autoscaling.ContainerResourceMetricSource, out *v2beta2.ContainerResourceMetricSource, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + if err := Convert_autoscaling_MetricTarget_To_v2beta2_MetricTarget(&in.Target, &out.Target, s); err != nil { + return err + } + return nil +} + +// Convert_autoscaling_ContainerResourceMetricSource_To_v2beta2_ContainerResourceMetricSource is an autogenerated conversion function. +func Convert_autoscaling_ContainerResourceMetricSource_To_v2beta2_ContainerResourceMetricSource(in *autoscaling.ContainerResourceMetricSource, out *v2beta2.ContainerResourceMetricSource, s conversion.Scope) error { + return autoConvert_autoscaling_ContainerResourceMetricSource_To_v2beta2_ContainerResourceMetricSource(in, out, s) +} + +func autoConvert_v2beta2_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in *v2beta2.ContainerResourceMetricStatus, out *autoscaling.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = core.ResourceName(in.Name) + if err := Convert_v2beta2_MetricValueStatus_To_autoscaling_MetricValueStatus(&in.Current, &out.Current, s); err != nil { + return err + } + out.Container = in.Container + return nil +} + +// Convert_v2beta2_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus is an autogenerated conversion function. +func Convert_v2beta2_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in *v2beta2.ContainerResourceMetricStatus, out *autoscaling.ContainerResourceMetricStatus, s conversion.Scope) error { + return autoConvert_v2beta2_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(in, out, s) +} + +func autoConvert_autoscaling_ContainerResourceMetricStatus_To_v2beta2_ContainerResourceMetricStatus(in *autoscaling.ContainerResourceMetricStatus, out *v2beta2.ContainerResourceMetricStatus, s conversion.Scope) error { + out.Name = v1.ResourceName(in.Name) + out.Container = in.Container + if err := Convert_autoscaling_MetricValueStatus_To_v2beta2_MetricValueStatus(&in.Current, &out.Current, s); err != nil { + return err + } + return nil +} + +// Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta2_ContainerResourceMetricStatus is an autogenerated conversion function. +func Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta2_ContainerResourceMetricStatus(in *autoscaling.ContainerResourceMetricStatus, out *v2beta2.ContainerResourceMetricStatus, s conversion.Scope) error { + return autoConvert_autoscaling_ContainerResourceMetricStatus_To_v2beta2_ContainerResourceMetricStatus(in, out, s) +} + func autoConvert_v2beta2_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference(in *v2beta2.CrossVersionObjectReference, out *autoscaling.CrossVersionObjectReference, s conversion.Scope) error { out.Kind = in.Kind out.Name = in.Name @@ -515,7 +591,17 @@ func autoConvert_v2beta2_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPo } out.MinReplicas = (*int32)(unsafe.Pointer(in.MinReplicas)) out.MaxReplicas = in.MaxReplicas - out.Metrics = *(*[]autoscaling.MetricSpec)(unsafe.Pointer(&in.Metrics)) + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = make([]autoscaling.MetricSpec, len(*in)) + for i := range *in { + if err := Convert_v2beta2_MetricSpec_To_autoscaling_MetricSpec(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Metrics = nil + } out.Behavior = (*autoscaling.HorizontalPodAutoscalerBehavior)(unsafe.Pointer(in.Behavior)) return nil } @@ -531,7 +617,17 @@ func autoConvert_autoscaling_HorizontalPodAutoscalerSpec_To_v2beta2_HorizontalPo } out.MinReplicas = (*int32)(unsafe.Pointer(in.MinReplicas)) out.MaxReplicas = in.MaxReplicas - out.Metrics = *(*[]v2beta2.MetricSpec)(unsafe.Pointer(&in.Metrics)) + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = make([]v2beta2.MetricSpec, len(*in)) + for i := range *in { + if err := Convert_autoscaling_MetricSpec_To_v2beta2_MetricSpec(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Metrics = nil + } out.Behavior = (*v2beta2.HorizontalPodAutoscalerBehavior)(unsafe.Pointer(in.Behavior)) return nil } @@ -546,7 +642,17 @@ func autoConvert_v2beta2_HorizontalPodAutoscalerStatus_To_autoscaling_Horizontal out.LastScaleTime = (*metav1.Time)(unsafe.Pointer(in.LastScaleTime)) out.CurrentReplicas = in.CurrentReplicas out.DesiredReplicas = in.DesiredReplicas - out.CurrentMetrics = *(*[]autoscaling.MetricStatus)(unsafe.Pointer(&in.CurrentMetrics)) + if in.CurrentMetrics != nil { + in, out := &in.CurrentMetrics, &out.CurrentMetrics + *out = make([]autoscaling.MetricStatus, len(*in)) + for i := range *in { + if err := Convert_v2beta2_MetricStatus_To_autoscaling_MetricStatus(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.CurrentMetrics = nil + } out.Conditions = *(*[]autoscaling.HorizontalPodAutoscalerCondition)(unsafe.Pointer(&in.Conditions)) return nil } @@ -561,7 +667,17 @@ func autoConvert_autoscaling_HorizontalPodAutoscalerStatus_To_v2beta2_Horizontal out.LastScaleTime = (*metav1.Time)(unsafe.Pointer(in.LastScaleTime)) out.CurrentReplicas = in.CurrentReplicas out.DesiredReplicas = in.DesiredReplicas - out.CurrentMetrics = *(*[]v2beta2.MetricStatus)(unsafe.Pointer(&in.CurrentMetrics)) + if in.CurrentMetrics != nil { + in, out := &in.CurrentMetrics, &out.CurrentMetrics + *out = make([]v2beta2.MetricStatus, len(*in)) + for i := range *in { + if err := Convert_autoscaling_MetricStatus_To_v2beta2_MetricStatus(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.CurrentMetrics = nil + } out.Conditions = *(*[]v2beta2.HorizontalPodAutoscalerCondition)(unsafe.Pointer(&in.Conditions)) return nil } @@ -598,6 +714,15 @@ func autoConvert_v2beta2_MetricSpec_To_autoscaling_MetricSpec(in *v2beta2.Metric out.Object = (*autoscaling.ObjectMetricSource)(unsafe.Pointer(in.Object)) out.Pods = (*autoscaling.PodsMetricSource)(unsafe.Pointer(in.Pods)) out.Resource = (*autoscaling.ResourceMetricSource)(unsafe.Pointer(in.Resource)) + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(autoscaling.ContainerResourceMetricSource) + if err := Convert_v2beta2_ContainerResourceMetricSource_To_autoscaling_ContainerResourceMetricSource(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } out.External = (*autoscaling.ExternalMetricSource)(unsafe.Pointer(in.External)) return nil } @@ -612,6 +737,15 @@ func autoConvert_autoscaling_MetricSpec_To_v2beta2_MetricSpec(in *autoscaling.Me out.Object = (*v2beta2.ObjectMetricSource)(unsafe.Pointer(in.Object)) out.Pods = (*v2beta2.PodsMetricSource)(unsafe.Pointer(in.Pods)) out.Resource = (*v2beta2.ResourceMetricSource)(unsafe.Pointer(in.Resource)) + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(v2beta2.ContainerResourceMetricSource) + if err := Convert_autoscaling_ContainerResourceMetricSource_To_v2beta2_ContainerResourceMetricSource(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } out.External = (*v2beta2.ExternalMetricSource)(unsafe.Pointer(in.External)) return nil } @@ -626,6 +760,15 @@ func autoConvert_v2beta2_MetricStatus_To_autoscaling_MetricStatus(in *v2beta2.Me out.Object = (*autoscaling.ObjectMetricStatus)(unsafe.Pointer(in.Object)) out.Pods = (*autoscaling.PodsMetricStatus)(unsafe.Pointer(in.Pods)) out.Resource = (*autoscaling.ResourceMetricStatus)(unsafe.Pointer(in.Resource)) + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(autoscaling.ContainerResourceMetricStatus) + if err := Convert_v2beta2_ContainerResourceMetricStatus_To_autoscaling_ContainerResourceMetricStatus(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } out.External = (*autoscaling.ExternalMetricStatus)(unsafe.Pointer(in.External)) return nil } @@ -640,6 +783,15 @@ func autoConvert_autoscaling_MetricStatus_To_v2beta2_MetricStatus(in *autoscalin out.Object = (*v2beta2.ObjectMetricStatus)(unsafe.Pointer(in.Object)) out.Pods = (*v2beta2.PodsMetricStatus)(unsafe.Pointer(in.Pods)) out.Resource = (*v2beta2.ResourceMetricStatus)(unsafe.Pointer(in.Resource)) + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(v2beta2.ContainerResourceMetricStatus) + if err := Convert_autoscaling_ContainerResourceMetricStatus_To_v2beta2_ContainerResourceMetricStatus(*in, *out, s); err != nil { + return err + } + } else { + out.ContainerResource = nil + } out.External = (*v2beta2.ExternalMetricStatus)(unsafe.Pointer(in.External)) return nil } diff --git a/pkg/apis/autoscaling/validation/BUILD b/pkg/apis/autoscaling/validation/BUILD index df827ba6762..9ca8db12a9c 100644 --- a/pkg/apis/autoscaling/validation/BUILD +++ b/pkg/apis/autoscaling/validation/BUILD @@ -12,6 +12,7 @@ go_library( importpath = "k8s.io/kubernetes/pkg/apis/autoscaling/validation", deps = [ "//pkg/apis/autoscaling:go_default_library", + "//pkg/apis/core/v1/validation:go_default_library", "//pkg/apis/core/validation:go_default_library", "//pkg/features:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library", diff --git a/pkg/apis/autoscaling/validation/validation.go b/pkg/apis/autoscaling/validation/validation.go index 8e5b457b20f..2e0dea1dda8 100644 --- a/pkg/apis/autoscaling/validation/validation.go +++ b/pkg/apis/autoscaling/validation/validation.go @@ -18,14 +18,13 @@ package validation import ( "fmt" - "strings" - apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation" pathvalidation "k8s.io/apimachinery/pkg/api/validation/path" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/apis/autoscaling" + corevalidation "k8s.io/kubernetes/pkg/apis/core/v1/validation" apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" "k8s.io/kubernetes/pkg/features" ) @@ -239,7 +238,10 @@ func validateScalingPolicy(policy autoscaling.HPAScalingPolicy, fldPath *field.P return allErrs } -var validMetricSourceTypes = sets.NewString(string(autoscaling.ObjectMetricSourceType), string(autoscaling.PodsMetricSourceType), string(autoscaling.ResourceMetricSourceType), string(autoscaling.ExternalMetricSourceType)) +var validMetricSourceTypes = sets.NewString( + string(autoscaling.ObjectMetricSourceType), string(autoscaling.PodsMetricSourceType), + string(autoscaling.ResourceMetricSourceType), string(autoscaling.ExternalMetricSourceType), + string(autoscaling.ContainerResourceMetricSourceType)) var validMetricSourceTypesList = validMetricSourceTypes.List() func validateMetricSpec(spec autoscaling.MetricSpec, fldPath *field.Path) field.ErrorList { @@ -282,10 +284,47 @@ func validateMetricSpec(spec autoscaling.MetricSpec, fldPath *field.Path) field. } } - expectedField := strings.ToLower(string(spec.Type)) + if spec.ContainerResource != nil { + typesPresent.Insert("containerResource") + if typesPresent.Len() == 1 { + allErrs = append(allErrs, validateContainerResourceSource(spec.ContainerResource, fldPath.Child("containerResource"))...) + } + } - if !typesPresent.Has(expectedField) { - allErrs = append(allErrs, field.Required(fldPath.Child(expectedField), "must populate information for the given metric source")) + var expectedField string + switch spec.Type { + + case autoscaling.ObjectMetricSourceType: + if spec.Object == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("object"), "must populate information for the given metric source")) + } + expectedField = "object" + case autoscaling.PodsMetricSourceType: + if spec.Pods == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("pods"), "must populate information for the given metric source")) + } + expectedField = "pods" + case autoscaling.ResourceMetricSourceType: + if spec.Resource == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("resource"), "must populate information for the given metric source")) + } + expectedField = "resource" + case autoscaling.ExternalMetricSourceType: + if spec.External == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("external"), "must populate information for the given metric source")) + } + expectedField = "external" + case autoscaling.ContainerResourceMetricSourceType: + if spec.ContainerResource == nil { + if utilfeature.DefaultFeatureGate.Enabled(features.HPAContainerMetrics) { + allErrs = append(allErrs, field.Required(fldPath.Child("containerResource"), "must populate information for the given metric source")) + } else { + allErrs = append(allErrs, field.Required(fldPath.Child("containerResource"), "must populate information for the given metric source (only allowed when HPAContainerMetrics feature is enabled)")) + } + } + expectedField = "containerResource" + default: + allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), spec.Type, validMetricSourceTypesList)) } if typesPresent.Len() != 1 { @@ -342,6 +381,34 @@ func validatePodsSource(src *autoscaling.PodsMetricSource, fldPath *field.Path) return allErrs } +func validateContainerResourceSource(src *autoscaling.ContainerResourceMetricSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(src.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify a resource name")) + } else { + allErrs = append(allErrs, corevalidation.ValidateContainerResourceName(string(src.Name), fldPath.Child("name"))...) + } + + if len(src.Container) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("container"), "must specify a container")) + } else { + allErrs = append(allErrs, apivalidation.ValidateDNS1123Label(src.Container, fldPath.Child("container"))...) + } + + allErrs = append(allErrs, validateMetricTarget(src.Target, fldPath.Child("target"))...) + + if src.Target.AverageUtilization == nil && src.Target.AverageValue == nil { + allErrs = append(allErrs, field.Required(fldPath.Child("target").Child("averageUtilization"), "must set either a target raw value or a target utilization")) + } + + if src.Target.AverageUtilization != nil && src.Target.AverageValue != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("target").Child("averageValue"), "may not set both a target raw value and a target utilization")) + } + + return allErrs +} + func validateResourceSource(src *autoscaling.ResourceMetricSource, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/apis/autoscaling/validation/validation_test.go b/pkg/apis/autoscaling/validation/validation_test.go index 6a2884268bb..d69554be0b7 100644 --- a/pkg/apis/autoscaling/validation/validation_test.go +++ b/pkg/apis/autoscaling/validation/validation_test.go @@ -565,6 +565,60 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, }, }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "myautoscaler", + Namespace: metav1.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-container", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "myautoscaler", + Namespace: metav1.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-container", + Target: autoscaling.MetricTarget{ + Type: autoscaling.AverageValueMetricType, + AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI), + }, + }, + }, + }, + }, + }, { ObjectMeta: metav1.ObjectMeta{ Name: "myautoscaler", @@ -689,6 +743,30 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "scaleTargetRef.kind: Required", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + msg: "scaleTargetRef.kind: Required", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -712,6 +790,30 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "scaleTargetRef.kind: Invalid", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + msg: "scaleTargetRef.kind: Invalid", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -735,6 +837,30 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "scaleTargetRef.name: Required", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + msg: "scaleTargetRef.name: Required", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -758,6 +884,30 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "scaleTargetRef.name: Invalid", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + msg: "scaleTargetRef.name: Invalid", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ @@ -813,6 +963,34 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "may not set both a target raw value and a target utilization", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myautoscaler", + Namespace: metav1.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI), + }, + }, + }, + }, + }, + }, + msg: "may not set both a target raw value and a target utilization", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -835,6 +1013,53 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "must specify a resource name", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + msg: "must specify a resource name", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: "InvalidResource", + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(70), + }, + }, + }, + }, + }, + }, + msg: "Invalid value: \"InvalidResource\": must be a standard resource type or fully qualified", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -858,6 +1083,77 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "must be greater than 0", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(-10), + }, + }, + }, + }, + }, + }, + msg: "must be greater than 0", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(-10), + }, + }, + }, + }, + }, + }, + msg: "must specify a container", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "---***", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(-10), + }, + }, + }, + }, + }, + }, + msg: "Invalid value: \"---***\"", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -880,6 +1176,29 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, msg: "must set either a target raw value or a target utilization", }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"}, + MinReplicas: utilpointer.Int32Ptr(1), + MaxReplicas: 5, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.ValueMetricType, + }, + }, + }, + }, + }, + }, + msg: "must set either a target raw value or a target utilization", + }, { horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault}, @@ -1321,6 +1640,16 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) { }, }, }, + autoscaling.ContainerResourceMetricSourceType: { + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "test-application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.AverageValueMetricType, + AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, autoscaling.PodsMetricSourceType: { Pods: &autoscaling.PodsMetricSource{ Metric: autoscaling.MetricIdentifier{ diff --git a/pkg/apis/autoscaling/zz_generated.deepcopy.go b/pkg/apis/autoscaling/zz_generated.deepcopy.go index fbb35cd3319..a7467c69045 100644 --- a/pkg/apis/autoscaling/zz_generated.deepcopy.go +++ b/pkg/apis/autoscaling/zz_generated.deepcopy.go @@ -25,6 +25,40 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricSource) DeepCopyInto(out *ContainerResourceMetricSource) { + *out = *in + in.Target.DeepCopyInto(&out.Target) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricSource. +func (in *ContainerResourceMetricSource) DeepCopy() *ContainerResourceMetricSource { + if in == nil { + return nil + } + out := new(ContainerResourceMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricStatus) DeepCopyInto(out *ContainerResourceMetricStatus) { + *out = *in + in.Current.DeepCopyInto(&out.Current) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricStatus. +func (in *ContainerResourceMetricStatus) DeepCopy() *ContainerResourceMetricStatus { + if in == nil { + return nil + } + out := new(ContainerResourceMetricStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { *out = *in @@ -340,6 +374,11 @@ func (in *MetricSpec) DeepCopyInto(out *MetricSpec) { *out = new(ResourceMetricSource) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricSource) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricSource) @@ -376,6 +415,11 @@ func (in *MetricStatus) DeepCopyInto(out *MetricStatus) { *out = new(ResourceMetricStatus) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricStatus) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricStatus) diff --git a/pkg/apis/core/v1/validation/validation.go b/pkg/apis/core/v1/validation/validation.go index b0df5ba2c22..f159fb60f5e 100644 --- a/pkg/apis/core/v1/validation/validation.go +++ b/pkg/apis/core/v1/validation/validation.go @@ -42,7 +42,7 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath for resourceName, quantity := range requirements.Limits { fldPath := limPath.Key(string(resourceName)) // Validate resource name. - allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...) + allErrs = append(allErrs, ValidateContainerResourceName(string(resourceName), fldPath)...) // Validate resource quantity. allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) @@ -51,7 +51,7 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath for resourceName, quantity := range requirements.Requests { fldPath := reqPath.Key(string(resourceName)) // Validate resource name. - allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...) + allErrs = append(allErrs, ValidateContainerResourceName(string(resourceName), fldPath)...) // Validate resource quantity. allErrs = append(allErrs, ValidateResourceQuantityValue(string(resourceName), quantity, fldPath)...) @@ -70,7 +70,8 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath return allErrs } -func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList { +// ValidateContainerResourceName checks the name of resource specified for a container +func ValidateContainerResourceName(value string, fldPath *field.Path) field.ErrorList { allErrs := validateResourceName(value, fldPath) if len(strings.Split(value, "/")) == 1 { if !helper.IsStandardContainerResourceName(value) { diff --git a/pkg/apis/core/v1/validation/validation_test.go b/pkg/apis/core/v1/validation/validation_test.go index 5ff038f3c69..a573e3a8bf9 100644 --- a/pkg/apis/core/v1/validation/validation_test.go +++ b/pkg/apis/core/v1/validation/validation_test.go @@ -129,6 +129,62 @@ func TestValidateResourceRequirements(t *testing.T) { } } +func TestValidateContainerResourceName(t *testing.T) { + successCase := []struct { + Name string + ResourceName string + }{ + { + Name: "CPU resource", + ResourceName: "cpu", + }, + { + Name: "Memory resource", + ResourceName: "memory", + }, + { + Name: "Hugepages resource", + ResourceName: "hugepages-2Mi", + }, + { + Name: "Namespaced resource", + ResourceName: "kubernetes.io/resource-foo", + }, + { + Name: "Extended Resource", + ResourceName: "my.org/resource-bar", + }, + } + for _, tc := range successCase { + if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) != 0 { + t.Errorf("%q unexpected error: %v", tc.Name, errs) + } + } + + errorCase := []struct { + Name string + ResourceName string + }{ + { + Name: "Invalid standard resource", + ResourceName: "cpu-core", + }, + { + Name: "Invalid namespaced resource", + ResourceName: "kubernetes.io/", + }, + { + Name: "Invalid extended resource", + ResourceName: "my.org-foo-resource", + }, + } + for _, tc := range errorCase { + if errs := ValidateContainerResourceName(tc.ResourceName, field.NewPath(tc.ResourceName)); len(errs) == 0 { + t.Errorf("%q expected error", tc.Name) + } + } +} + func TestValidatePodLogOptions(t *testing.T) { var ( diff --git a/pkg/controller/podautoscaler/horizontal.go b/pkg/controller/podautoscaler/horizontal.go index 950f04787f3..22de9dfacc9 100644 --- a/pkg/controller/podautoscaler/horizontal.go +++ b/pkg/controller/podautoscaler/horizontal.go @@ -329,6 +329,11 @@ func (a *HorizontalController) computeReplicasForMetric(hpa *autoscalingv2.Horiz if err != nil { return 0, "", time.Time{}, condition, err } + case autoscalingv2.ContainerResourceMetricSourceType: + replicaCountProposal, timestampProposal, metricNameProposal, condition, err = a.computeStatusForContainerResourceMetric(specReplicas, spec, hpa, selector, status) + if err != nil { + return 0, "", time.Time{}, condition, err + } case autoscalingv2.ExternalMetricSourceType: replicaCountProposal, timestampProposal, metricNameProposal, condition, err = a.computeStatusForExternalMetric(specReplicas, statusReplicas, spec, hpa, selector, status) if err != nil { @@ -435,51 +440,80 @@ func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32, return replicaCountProposal, timestampProposal, fmt.Sprintf("pods metric %s", metricSpec.Pods.Metric.Name), autoscalingv2.HorizontalPodAutoscalerCondition{}, nil } -// computeStatusForResourceMetric computes the desired number of replicas for the specified metric of type ResourceMetricSourceType. -func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, timestampProposal time.Time, metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { - if metricSpec.Resource.Target.AverageValue != nil { +func (a *HorizontalController) computeStatusForResourceMetricGeneric(currentReplicas int32, target autoscalingv2.MetricTarget, + resourceName v1.ResourceName, namespace string, container string, selector labels.Selector) (replicaCountProposal int32, + metricStatus *autoscalingv2.MetricValueStatus, timestampProposal time.Time, metricNameProposal string, + condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { + if target.AverageValue != nil { var rawProposal int64 - replicaCountProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetRawResourceReplicas(currentReplicas, metricSpec.Resource.Target.AverageValue.MilliValue(), metricSpec.Resource.Name, hpa.Namespace, selector) + replicaCountProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetRawResourceReplicas(currentReplicas, target.AverageValue.MilliValue(), resourceName, namespace, selector, container) if err != nil { - condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetResourceMetric", err) - return 0, time.Time{}, "", condition, fmt.Errorf("failed to get %s utilization: %v", metricSpec.Resource.Name, err) + return 0, nil, time.Time{}, "", condition, fmt.Errorf("failed to get %s utilization: %v", resourceName, err) } - metricNameProposal = fmt.Sprintf("%s resource", metricSpec.Resource.Name) - *status = autoscalingv2.MetricStatus{ - Type: autoscalingv2.ResourceMetricSourceType, - Resource: &autoscalingv2.ResourceMetricStatus{ - Name: metricSpec.Resource.Name, - Current: autoscalingv2.MetricValueStatus{ - AverageValue: resource.NewMilliQuantity(rawProposal, resource.DecimalSI), - }, - }, + metricNameProposal = fmt.Sprintf("%s resource", resourceName.String()) + status := autoscalingv2.MetricValueStatus{ + AverageValue: resource.NewMilliQuantity(rawProposal, resource.DecimalSI), } - return replicaCountProposal, timestampProposal, metricNameProposal, autoscalingv2.HorizontalPodAutoscalerCondition{}, nil + return replicaCountProposal, &status, timestampProposal, metricNameProposal, autoscalingv2.HorizontalPodAutoscalerCondition{}, nil } - if metricSpec.Resource.Target.AverageUtilization == nil { + + if target.AverageUtilization == nil { errMsg := "invalid resource metric source: neither a utilization target nor a value target was set" err = fmt.Errorf(errMsg) - condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetResourceMetric", err) - return 0, time.Time{}, "", condition, fmt.Errorf(errMsg) + return 0, nil, time.Time{}, "", condition, fmt.Errorf(errMsg) } - targetUtilization := *metricSpec.Resource.Target.AverageUtilization - replicaCountProposal, percentageProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetResourceReplicas(currentReplicas, targetUtilization, metricSpec.Resource.Name, hpa.Namespace, selector) + + targetUtilization := *target.AverageUtilization + replicaCountProposal, percentageProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetResourceReplicas(currentReplicas, targetUtilization, resourceName, namespace, selector, container) + if err != nil { + return 0, nil, time.Time{}, "", condition, fmt.Errorf("failed to get %s utilization: %v", resourceName, err) + } + + metricNameProposal = fmt.Sprintf("%s resource utilization (percentage of request)", resourceName) + status := autoscalingv2.MetricValueStatus{ + AverageUtilization: &percentageProposal, + AverageValue: resource.NewMilliQuantity(rawProposal, resource.DecimalSI), + } + return replicaCountProposal, &status, timestampProposal, metricNameProposal, autoscalingv2.HorizontalPodAutoscalerCondition{}, nil +} + +// computeStatusForResourceMetric computes the desired number of replicas for the specified metric of type ResourceMetricSourceType. +func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, + selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, timestampProposal time.Time, + metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { + replicaCountProposal, metricValueStatus, timestampProposal, metricNameProposal, condition, err := a.computeStatusForResourceMetricGeneric(currentReplicas, metricSpec.Resource.Target, metricSpec.Resource.Name, hpa.Namespace, "", selector) if err != nil { condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetResourceMetric", err) - return 0, time.Time{}, "", condition, fmt.Errorf("failed to get %s utilization: %v", metricSpec.Resource.Name, err) + return replicaCountProposal, timestampProposal, metricNameProposal, condition, err } - metricNameProposal = fmt.Sprintf("%s resource utilization (percentage of request)", metricSpec.Resource.Name) *status = autoscalingv2.MetricStatus{ Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricStatus{ - Name: metricSpec.Resource.Name, - Current: autoscalingv2.MetricValueStatus{ - AverageUtilization: &percentageProposal, - AverageValue: resource.NewMilliQuantity(rawProposal, resource.DecimalSI), - }, + Name: metricSpec.Resource.Name, + Current: *metricValueStatus, }, } - return replicaCountProposal, timestampProposal, metricNameProposal, autoscalingv2.HorizontalPodAutoscalerCondition{}, nil + return replicaCountProposal, timestampProposal, metricNameProposal, condition, nil +} + +// computeStatusForContainerResourceMetric computes the desired number of replicas for the specified metric of type ResourceMetricSourceType. +func (a *HorizontalController) computeStatusForContainerResourceMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, + selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, timestampProposal time.Time, + metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { + replicaCountProposal, metricValueStatus, timestampProposal, metricNameProposal, condition, err := a.computeStatusForResourceMetricGeneric(currentReplicas, metricSpec.ContainerResource.Target, metricSpec.ContainerResource.Name, hpa.Namespace, metricSpec.ContainerResource.Container, selector) + if err != nil { + condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetContainerResourceMetric", err) + return replicaCountProposal, timestampProposal, metricNameProposal, condition, err + } + *status = autoscalingv2.MetricStatus{ + Type: autoscalingv2.ContainerResourceMetricSourceType, + ContainerResource: &autoscalingv2.ContainerResourceMetricStatus{ + Name: metricSpec.ContainerResource.Name, + Container: metricSpec.ContainerResource.Container, + Current: *metricValueStatus, + }, + } + return replicaCountProposal, timestampProposal, metricNameProposal, condition, nil } // computeStatusForExternalMetric computes the desired number of replicas for the specified metric of type ExternalMetricSourceType. @@ -783,7 +817,7 @@ func getReplicasChangePerPeriod(periodSeconds int32, scaleEvents []timestampedSc } -func (a *HorizontalController) getUnableComputeReplicaCountCondition(hpa *autoscalingv2.HorizontalPodAutoscaler, reason string, err error) (condition autoscalingv2.HorizontalPodAutoscalerCondition) { +func (a *HorizontalController) getUnableComputeReplicaCountCondition(hpa runtime.Object, reason string, err error) (condition autoscalingv2.HorizontalPodAutoscalerCondition) { a.eventRecorder.Event(hpa, v1.EventTypeWarning, reason, err.Error()) return autoscalingv2.HorizontalPodAutoscalerCondition{ Type: autoscalingv2.ScalingActive, diff --git a/pkg/controller/podautoscaler/horizontal_test.go b/pkg/controller/podautoscaler/horizontal_test.go index f55bfa4c9a2..8196da327dc 100644 --- a/pkg/controller/podautoscaler/horizontal_test.go +++ b/pkg/controller/podautoscaler/horizontal_test.go @@ -336,9 +336,18 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa Spec: v1.PodSpec{ Containers: []v1.Container{ { + Name: "container1", Resources: v1.ResourceRequirements{ Requests: v1.ResourceList{ - v1.ResourceCPU: reportedCPURequest, + v1.ResourceCPU: *resource.NewMilliQuantity(reportedCPURequest.MilliValue()/2, resource.DecimalSI), + }, + }, + }, + { + Name: "container2", + Resources: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceCPU: *resource.NewMilliQuantity(reportedCPURequest.MilliValue()/2, resource.DecimalSI), }, }, }, @@ -509,13 +518,24 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa Window: metav1.Duration{Duration: time.Minute}, Containers: []metricsapi.ContainerMetrics{ { - Name: "container", + Name: "container1", Usage: v1.ResourceList{ v1.ResourceCPU: *resource.NewMilliQuantity( - int64(cpu), + int64(cpu/2), resource.DecimalSI), v1.ResourceMemory: *resource.NewQuantity( - int64(1024*1024), + int64(1024*1024/2), + resource.BinarySI), + }, + }, + { + Name: "container2", + Usage: v1.ResourceList{ + v1.ResourceCPU: *resource.NewMilliQuantity( + int64(cpu/2), + resource.DecimalSI), + v1.ResourceMemory: *resource.NewQuantity( + int64(1024*1024/2), resource.BinarySI), }, }, @@ -773,6 +793,31 @@ func TestScaleUp(t *testing.T) { tc.runTest(t) } +func TestScaleUpContainer(t *testing.T) { + tc := testCase{ + minReplicas: 2, + maxReplicas: 6, + specReplicas: 3, + statusReplicas: 3, + expectedDesiredReplicas: 5, + metricsTarget: []autoscalingv2.MetricSpec{{ + Type: autoscalingv2.ContainerResourceMetricSourceType, + ContainerResource: &autoscalingv2.ContainerResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: autoscalingv2.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(30), + }, + Container: "container1", + }, + }}, + reportedLevels: []uint64{300, 500, 700}, + reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + useMetricsAPI: true, + } + tc.runTest(t) +} + func TestScaleUpUnreadyLessScale(t *testing.T) { tc := testCase{ minReplicas: 2, @@ -1269,6 +1314,32 @@ func TestScaleDown(t *testing.T) { tc.runTest(t) } +func TestScaleDownContainerResource(t *testing.T) { + tc := testCase{ + minReplicas: 2, + maxReplicas: 6, + specReplicas: 5, + statusReplicas: 5, + expectedDesiredReplicas: 3, + reportedLevels: []uint64{100, 300, 500, 250, 250}, + reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + metricsTarget: []autoscalingv2.MetricSpec{{ + Type: autoscalingv2.ContainerResourceMetricSourceType, + ContainerResource: &autoscalingv2.ContainerResourceMetricSource{ + Container: "container2", + Name: v1.ResourceCPU, + Target: autoscalingv2.MetricTarget{ + Type: autoscalingv2.UtilizationMetricType, + AverageUtilization: utilpointer.Int32Ptr(50), + }, + }, + }}, + useMetricsAPI: true, + recommendations: []timestampedRecommendation{}, + } + tc.runTest(t) +} + func TestScaleDownWithScalingRules(t *testing.T) { tc := testCase{ minReplicas: 2, @@ -2809,7 +2880,7 @@ func TestScaleDownRCImmediately(t *testing.T) { tc.runTest(t) } -func TestAvoidUncessaryUpdates(t *testing.T) { +func TestAvoidUnnecessaryUpdates(t *testing.T) { now := metav1.Time{Time: time.Now().Add(-time.Hour)} tc := testCase{ minReplicas: 2, diff --git a/pkg/controller/podautoscaler/legacy_replica_calculator_test.go b/pkg/controller/podautoscaler/legacy_replica_calculator_test.go index 0a6276f97f1..f7bacbbcc62 100644 --- a/pkg/controller/podautoscaler/legacy_replica_calculator_test.go +++ b/pkg/controller/podautoscaler/legacy_replica_calculator_test.go @@ -126,14 +126,11 @@ func (tc *legacyReplicaCalcTestCase) prepareTestClient(t *testing.T) *fake.Clien Timestamp: metav1.Time{Time: tc.timestamp}, Containers: make([]metricsapi.ContainerMetrics, numContainersPerPod), } - - for i := 0; i < numContainersPerPod; i++ { + for i, m := range resValue { podMetric.Containers[i] = metricsapi.ContainerMetrics{ Name: fmt.Sprintf("container%v", i), Usage: v1.ResourceList{ - v1.ResourceName(tc.resource.name): *resource.NewMilliQuantity( - int64(resValue), - resource.DecimalSI), + tc.resource.name: *resource.NewMilliQuantity(m, resource.DecimalSI), }, } } @@ -209,7 +206,7 @@ func (tc *legacyReplicaCalcTestCase) runTest(t *testing.T) { } if tc.resource != nil { - outReplicas, outUtilization, outRawValue, outTimestamp, err := replicaCalc.GetResourceReplicas(tc.currentReplicas, tc.resource.targetUtilization, tc.resource.name, testNamespace, selector) + outReplicas, outUtilization, outRawValue, outTimestamp, err := replicaCalc.GetResourceReplicas(tc.currentReplicas, tc.resource.targetUtilization, tc.resource.name, testNamespace, selector, "") if tc.expectedError != nil { require.Error(t, err, "there should be an error calculating the replica count") @@ -244,7 +241,7 @@ func TestLegacyReplicaCalcDisjointResourcesMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0")}, - levels: []int64{100}, + levels: makePodMetricLevels(100), podNames: []string{"an-older-pod-name"}, targetUtilization: 100, @@ -260,7 +257,7 @@ func TestLegacyReplicaCalcScaleUp(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{300, 500, 700}, + levels: makePodMetricLevels(300, 500, 700), targetUtilization: 30, expectedUtilization: 50, @@ -278,7 +275,7 @@ func TestLegacyReplicaCalcScaleUpUnreadyLessScale(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{300, 500, 700}, + levels: makePodMetricLevels(300, 500, 700), targetUtilization: 30, expectedUtilization: 60, @@ -296,7 +293,7 @@ func TestLegacyReplicaCalcScaleUpUnreadyNoScale(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{400, 500, 700}, + levels: makePodMetricLevels(400, 500, 700), targetUtilization: 30, expectedUtilization: 40, @@ -357,7 +354,7 @@ func TestLegacyReplicaCalcScaleDown(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 28, @@ -389,7 +386,7 @@ func TestLegacyReplicaCalcScaleDownIgnoresUnreadyPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 30, @@ -406,7 +403,7 @@ func TestLegacyReplicaCalcTolerance(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")}, - levels: []int64{1010, 1030, 1020}, + levels: makePodMetricLevels(1010, 1030, 1020), targetUtilization: 100, expectedUtilization: 102, @@ -437,7 +434,7 @@ func TestLegacyReplicaCalcSuperfluousMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{4000, 9500, 3000, 7000, 3200, 2000}, + levels: makePodMetricLevels(4000, 9500, 3000, 7000, 3200, 2000), targetUtilization: 100, expectedUtilization: 587, expectedValue: numContainersPerPod * 5875, @@ -453,7 +450,7 @@ func TestLegacyReplicaCalcMissingMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{400, 95}, + levels: makePodMetricLevels(400, 95), targetUtilization: 100, expectedUtilization: 24, @@ -470,7 +467,7 @@ func TestLegacyReplicaCalcEmptyMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{}, + levels: makePodMetricLevels(), targetUtilization: 100, }, @@ -485,7 +482,7 @@ func TestLegacyReplicaCalcEmptyCPURequest(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{}, - levels: []int64{200}, + levels: makePodMetricLevels(200), targetUtilization: 100, }, @@ -500,7 +497,7 @@ func TestLegacyReplicaCalcMissingMetricsNoChangeEq(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{1000}, + levels: makePodMetricLevels(1000), targetUtilization: 100, expectedUtilization: 100, @@ -517,7 +514,7 @@ func TestLegacyReplicaCalcMissingMetricsNoChangeGt(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{1900}, + levels: makePodMetricLevels(1900), targetUtilization: 100, expectedUtilization: 190, @@ -534,7 +531,7 @@ func TestLegacyReplicaCalcMissingMetricsNoChangeLt(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{600}, + levels: makePodMetricLevels(600), targetUtilization: 100, expectedUtilization: 60, @@ -552,7 +549,7 @@ func TestLegacyReplicaCalcMissingMetricsUnreadyNoChange(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 450}, + levels: makePodMetricLevels(100, 450), targetUtilization: 50, expectedUtilization: 45, @@ -570,7 +567,7 @@ func TestLegacyReplicaCalcMissingMetricsUnreadyScaleUp(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 2000}, + levels: makePodMetricLevels(100, 2000), targetUtilization: 50, expectedUtilization: 200, @@ -588,7 +585,7 @@ func TestLegacyReplicaCalcMissingMetricsUnreadyScaleDown(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 100, 100}, + levels: makePodMetricLevels(100, 100, 100), targetUtilization: 50, expectedUtilization: 10, @@ -627,18 +624,18 @@ func TestLegacyReplicaCalcComputedToleranceAlgImplementation(t *testing.T) { expectedReplicas: finalPods, resource: &resourceInfo{ name: v1.ResourceCPU, - levels: []int64{ - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - }, + levels: makePodMetricLevels( + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + ), requests: []resource.Quantity{ resource.MustParse(fmt.Sprint(perPodRequested+100) + "m"), resource.MustParse(fmt.Sprint(perPodRequested-100) + "m"), diff --git a/pkg/controller/podautoscaler/metrics/BUILD b/pkg/controller/podautoscaler/metrics/BUILD index 5dfa54ac939..064461a7e14 100644 --- a/pkg/controller/podautoscaler/metrics/BUILD +++ b/pkg/controller/podautoscaler/metrics/BUILD @@ -20,6 +20,7 @@ go_library( "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/custom_metrics:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/external_metrics:go_default_library", diff --git a/pkg/controller/podautoscaler/metrics/interfaces.go b/pkg/controller/podautoscaler/metrics/interfaces.go index a3733371ffa..94c66b23a9a 100644 --- a/pkg/controller/podautoscaler/metrics/interfaces.go +++ b/pkg/controller/podautoscaler/metrics/interfaces.go @@ -38,8 +38,9 @@ type PodMetricsInfo map[string]PodMetric // resource metrics as well as pod-level arbitrary metrics type MetricsClient interface { // GetResourceMetric gets the given resource metric (and an associated oldest timestamp) - // for all pods matching the specified selector in the given namespace - GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) + // for the specified named container in all pods matching the specified selector in the given namespace and when + // the container is an empty string it returns the sum of all the container metrics. + GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector, container string) (PodMetricsInfo, time.Time, error) // GetRawMetric gets the given metric (and an associated oldest timestamp) // for all pods matching the specified selector in the given namespace diff --git a/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go b/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go index 82886bd3ff1..989cb4b4816 100644 --- a/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go +++ b/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go @@ -63,7 +63,7 @@ func NewHeapsterMetricsClient(client clientset.Interface, namespace, scheme, ser } } -func (h *HeapsterMetricsClient) GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) { +func (h *HeapsterMetricsClient) GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector, container string) (PodMetricsInfo, time.Time, error) { metricPath := fmt.Sprintf("/apis/metrics/v1alpha1/namespaces/%s/pods", namespace) params := map[string]string{"labelSelector": selector.String()} @@ -92,13 +92,15 @@ func (h *HeapsterMetricsClient) GetResourceMetric(resource v1.ResourceName, name podSum := int64(0) missing := len(m.Containers) == 0 for _, c := range m.Containers { - resValue, found := c.Usage[v1.ResourceName(resource)] - if !found { - missing = true - klog.V(2).Infof("missing resource metric %v for container %s in pod %s/%s", resource, c.Name, namespace, m.Name) - continue + if container == "" || container == c.Name { + resValue, found := c.Usage[v1.ResourceName(resource)] + if !found { + missing = true + klog.V(2).Infof("missing resource metric %v for container %s in pod %s/%s", resource, c.Name, namespace, m.Name) + continue + } + podSum += resValue.MilliValue() } - podSum += resValue.MilliValue() } if !missing { diff --git a/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go b/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go index 6ccd51142e8..604752bf2ba 100644 --- a/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go +++ b/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go @@ -222,7 +222,7 @@ func (tc *testCase) runTest(t *testing.T) { metricsClient := NewHeapsterMetricsClient(testClient, DefaultHeapsterNamespace, DefaultHeapsterScheme, DefaultHeapsterService, DefaultHeapsterPort) isResource := len(tc.resourceName) > 0 if isResource { - info, timestamp, err := metricsClient.GetResourceMetric(tc.resourceName, tc.namespace, tc.selector) + info, timestamp, err := metricsClient.GetResourceMetric(tc.resourceName, tc.namespace, tc.selector, "") tc.verifyResults(t, info, timestamp, err) } else { info, timestamp, err := metricsClient.GetRawMetric(tc.metricName, tc.namespace, tc.selector, tc.metricSelector) diff --git a/pkg/controller/podautoscaler/metrics/rest_metrics_client.go b/pkg/controller/podautoscaler/metrics/rest_metrics_client.go index b8ffe6dc4ef..8adba64ec4e 100644 --- a/pkg/controller/podautoscaler/metrics/rest_metrics_client.go +++ b/pkg/controller/podautoscaler/metrics/rest_metrics_client.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" customapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" + metricsapi "k8s.io/metrics/pkg/apis/metrics/v1beta1" resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1" customclient "k8s.io/metrics/pkg/client/custom_metrics" externalclient "k8s.io/metrics/pkg/client/external_metrics" @@ -63,7 +64,7 @@ type resourceMetricsClient struct { // GetResourceMetric gets the given resource metric (and an associated oldest timestamp) // for all pods matching the specified selector in the given namespace -func (c *resourceMetricsClient) GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) { +func (c *resourceMetricsClient) GetResourceMetric(resource v1.ResourceName, namespace string, selector labels.Selector, container string) (PodMetricsInfo, time.Time, error) { metrics, err := c.client.PodMetricses(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()}) if err != nil { return nil, time.Time{}, fmt.Errorf("unable to fetch metrics from resource metrics API: %v", err) @@ -72,34 +73,66 @@ func (c *resourceMetricsClient) GetResourceMetric(resource v1.ResourceName, name if len(metrics.Items) == 0 { return nil, time.Time{}, fmt.Errorf("no metrics returned from resource metrics API") } + var res PodMetricsInfo + if container != "" { + res, err = getContainerMetrics(metrics.Items, resource, container) + if err != nil { + return nil, time.Time{}, fmt.Errorf("failed to get container metrics: %v", err) + } + } else { + res = getPodMetrics(metrics.Items, resource) + } + timestamp := metrics.Items[0].Timestamp.Time + return res, timestamp, nil +} - res := make(PodMetricsInfo, len(metrics.Items)) +func getContainerMetrics(rawMetrics []metricsapi.PodMetrics, resource v1.ResourceName, container string) (PodMetricsInfo, error) { + res := make(PodMetricsInfo, len(rawMetrics)) + for _, m := range rawMetrics { + containerFound := false + for _, c := range m.Containers { + if c.Name == container { + containerFound = true + if val, resFound := c.Usage[resource]; resFound { + res[m.Name] = PodMetric{ + Timestamp: m.Timestamp.Time, + Window: m.Window.Duration, + Value: val.MilliValue(), + } + } + break + } + } + if !containerFound { + return nil, fmt.Errorf("container %s not present in metrics for pod %s/%s", container, m.Namespace, m.Name) + } + } + return res, nil +} - for _, m := range metrics.Items { +func getPodMetrics(rawMetrics []metricsapi.PodMetrics, resource v1.ResourceName) PodMetricsInfo { + res := make(PodMetricsInfo, len(rawMetrics)) + for _, m := range rawMetrics { podSum := int64(0) missing := len(m.Containers) == 0 for _, c := range m.Containers { - resValue, found := c.Usage[v1.ResourceName(resource)] + resValue, found := c.Usage[resource] if !found { missing = true - klog.V(2).Infof("missing resource metric %v for container %s in pod %s/%s", resource, c.Name, namespace, m.Name) - break // containers loop + klog.V(2).Infof("missing resource metric %v for %s/%s", resource, m.Namespace, m.Name) + break } podSum += resValue.MilliValue() } - if !missing { res[m.Name] = PodMetric{ Timestamp: m.Timestamp.Time, Window: m.Window.Duration, - Value: int64(podSum), + Value: podSum, } } } - - timestamp := metrics.Items[0].Timestamp.Time - - return res, timestamp, nil + return res } // customMetricsClient implements the custom-metrics-related parts of MetricsClient, diff --git a/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go b/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go index d7475e65280..9e9bcbb4690 100644 --- a/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go +++ b/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go @@ -50,12 +50,13 @@ type restClientTestCase struct { targetTimestamp int window time.Duration reportedMetricPoints []metricPoint - reportedPodMetrics [][]int64 + reportedPodMetrics []map[string]int64 singleObject *autoscalingapi.CrossVersionObjectReference namespace string selector labels.Selector resourceName v1.ResourceName + container string metricName string metricSelector *metav1.LabelSelector metricLabelSelector labels.Selector @@ -91,9 +92,9 @@ func (tc *restClientTestCase) prepareTestClient(t *testing.T) (*metricsfake.Clie Window: metav1.Duration{Duration: tc.window}, Containers: []metricsapi.ContainerMetrics{}, } - for j, cpu := range containers { + for containerName, cpu := range containers { cm := metricsapi.ContainerMetrics{ - Name: fmt.Sprintf("%s-%d-container-%d", podNamePrefix, i, j), + Name: containerName, Usage: v1.ResourceList{ v1.ResourceCPU: *resource.NewMilliQuantity( cpu, @@ -230,7 +231,7 @@ func (tc *restClientTestCase) runTest(t *testing.T) { isResource := len(tc.resourceName) > 0 isExternal := tc.metricSelector != nil if isResource { - info, timestamp, err := metricsClient.GetResourceMetric(v1.ResourceName(tc.resourceName), tc.namespace, tc.selector) + info, timestamp, err := metricsClient.GetResourceMetric(v1.ResourceName(tc.resourceName), tc.namespace, tc.selector, tc.container) tc.verifyResults(t, info, timestamp, err) } else if isExternal { tc.metricLabelSelector, err = metav1.LabelSelectorAsSelector(tc.metricSelector) @@ -253,7 +254,7 @@ func (tc *restClientTestCase) runTest(t *testing.T) { } } -func TestRESTClientCPU(t *testing.T) { +func TestRESTClientPodCPU(t *testing.T) { targetTimestamp := 1 window := 30 * time.Second tc := restClientTestCase{ @@ -265,7 +266,25 @@ func TestRESTClientCPU(t *testing.T) { resourceName: v1.ResourceCPU, targetTimestamp: targetTimestamp, window: window, - reportedPodMetrics: [][]int64{{5000}, {5000}, {5000}}, + reportedPodMetrics: []map[string]int64{{"test": 5000}, {"test": 5000}, {"test": 5000}}, + } + tc.runTest(t) +} + +func TestRESTClientContainerCPU(t *testing.T) { + targetTimestamp := 1 + window := 30 * time.Second + tc := restClientTestCase{ + desiredMetricValues: PodMetricsInfo{ + "test-pod-0": {Value: 5000, Timestamp: offsetTimestampBy(targetTimestamp), Window: window}, + "test-pod-1": {Value: 5000, Timestamp: offsetTimestampBy(targetTimestamp), Window: window}, + "test-pod-2": {Value: 5000, Timestamp: offsetTimestampBy(targetTimestamp), Window: window}, + }, + container: "test-1", + resourceName: v1.ResourceCPU, + targetTimestamp: targetTimestamp, + window: window, + reportedPodMetrics: []map[string]int64{{"test-1": 5000, "test-2": 500}, {"test-1": 5000, "test-2": 500}, {"test-1": 5000, "test-2": 500}}, } tc.runTest(t) } @@ -362,17 +381,17 @@ func TestRESTClientExternalEmptyMetrics(t *testing.T) { tc.runTest(t) } -func TestRESTClientCPUEmptyMetrics(t *testing.T) { +func TestRESTClientPodCPUEmptyMetrics(t *testing.T) { tc := restClientTestCase{ resourceName: v1.ResourceCPU, desiredError: fmt.Errorf("no metrics returned from resource metrics API"), reportedMetricPoints: []metricPoint{}, - reportedPodMetrics: [][]int64{}, + reportedPodMetrics: []map[string]int64{}, } tc.runTest(t) } -func TestRESTClientCPUEmptyMetricsForOnePod(t *testing.T) { +func TestRESTClientPodCPUEmptyMetricsForOnePod(t *testing.T) { targetTimestamp := 1 window := 30 * time.Second tc := restClientTestCase{ @@ -383,7 +402,25 @@ func TestRESTClientCPUEmptyMetricsForOnePod(t *testing.T) { }, targetTimestamp: targetTimestamp, window: window, - reportedPodMetrics: [][]int64{{100}, {300, 400}, {}}, + reportedPodMetrics: []map[string]int64{{"test-1": 100}, {"test-1": 300, "test-2": 400}, {}}, + } + tc.runTest(t) +} + +func TestRESTClientContainerCPUEmptyMetricsForOnePod(t *testing.T) { + targetTimestamp := 1 + window := 30 * time.Second + tc := restClientTestCase{ + resourceName: v1.ResourceCPU, + desiredMetricValues: PodMetricsInfo{ + "test-pod-0": {Value: 100, Timestamp: offsetTimestampBy(targetTimestamp), Window: window}, + "test-pod-1": {Value: 300, Timestamp: offsetTimestampBy(targetTimestamp), Window: window}, + }, + container: "test-1", + targetTimestamp: targetTimestamp, + window: window, + desiredError: fmt.Errorf("failed to get container metrics"), + reportedPodMetrics: []map[string]int64{{"test-1": 100}, {"test-1": 300, "test-2": 400}, {}}, } tc.runTest(t) } diff --git a/pkg/controller/podautoscaler/replica_calculator.go b/pkg/controller/podautoscaler/replica_calculator.go index 0a083ad98f3..2ee7fefdb68 100644 --- a/pkg/controller/podautoscaler/replica_calculator.go +++ b/pkg/controller/podautoscaler/replica_calculator.go @@ -61,8 +61,8 @@ func NewReplicaCalculator(metricsClient metricsclient.MetricsClient, podLister c // GetResourceReplicas calculates the desired replica count based on a target resource utilization percentage // of the given resource for pods matching the given selector in the given namespace, and the current replica count -func (c *ReplicaCalculator) GetResourceReplicas(currentReplicas int32, targetUtilization int32, resource v1.ResourceName, namespace string, selector labels.Selector) (replicaCount int32, utilization int32, rawUtilization int64, timestamp time.Time, err error) { - metrics, timestamp, err := c.metricsClient.GetResourceMetric(resource, namespace, selector) +func (c *ReplicaCalculator) GetResourceReplicas(currentReplicas int32, targetUtilization int32, resource v1.ResourceName, namespace string, selector labels.Selector, container string) (replicaCount int32, utilization int32, rawUtilization int64, timestamp time.Time, err error) { + metrics, timestamp, err := c.metricsClient.GetResourceMetric(resource, namespace, selector, container) if err != nil { return 0, 0, 0, time.Time{}, fmt.Errorf("unable to get metrics for resource %s: %v", resource, err) } @@ -79,7 +79,7 @@ func (c *ReplicaCalculator) GetResourceReplicas(currentReplicas int32, targetUti readyPodCount, unreadyPods, missingPods, ignoredPods := groupPods(podList, metrics, resource, c.cpuInitializationPeriod, c.delayOfInitialReadinessStatus) removeMetricsForPods(metrics, ignoredPods) removeMetricsForPods(metrics, unreadyPods) - requests, err := calculatePodRequests(podList, resource) + requests, err := calculatePodRequests(podList, container, resource) if err != nil { return 0, 0, 0, time.Time{}, err } @@ -150,8 +150,8 @@ func (c *ReplicaCalculator) GetResourceReplicas(currentReplicas int32, targetUti // GetRawResourceReplicas calculates the desired replica count based on a target resource utilization (as a raw milli-value) // for pods matching the given selector in the given namespace, and the current replica count -func (c *ReplicaCalculator) GetRawResourceReplicas(currentReplicas int32, targetUtilization int64, resource v1.ResourceName, namespace string, selector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { - metrics, timestamp, err := c.metricsClient.GetResourceMetric(resource, namespace, selector) +func (c *ReplicaCalculator) GetRawResourceReplicas(currentReplicas int32, targetUtilization int64, resource v1.ResourceName, namespace string, selector labels.Selector, container string) (replicaCount int32, utilization int64, timestamp time.Time, err error) { + metrics, timestamp, err := c.metricsClient.GetResourceMetric(resource, namespace, selector, container) if err != nil { return 0, 0, time.Time{}, fmt.Errorf("unable to get metrics for resource %s: %v", resource, err) } @@ -414,15 +414,17 @@ func groupPods(pods []*v1.Pod, metrics metricsclient.PodMetricsInfo, resource v1 return } -func calculatePodRequests(pods []*v1.Pod, resource v1.ResourceName) (map[string]int64, error) { +func calculatePodRequests(pods []*v1.Pod, container string, resource v1.ResourceName) (map[string]int64, error) { requests := make(map[string]int64, len(pods)) for _, pod := range pods { podSum := int64(0) - for _, container := range pod.Spec.Containers { - if containerRequest, ok := container.Resources.Requests[resource]; ok { - podSum += containerRequest.MilliValue() - } else { - return nil, fmt.Errorf("missing request for %s", resource) + for _, c := range pod.Spec.Containers { + if container == "" || container == c.Name { + if containerRequest, ok := c.Resources.Requests[resource]; ok { + podSum += containerRequest.MilliValue() + } else { + return nil, fmt.Errorf("missing request for %s", resource) + } } } requests[pod.Name] = podSum diff --git a/pkg/controller/podautoscaler/replica_calculator_test.go b/pkg/controller/podautoscaler/replica_calculator_test.go index e6b3ab15c9e..304054665ad 100644 --- a/pkg/controller/podautoscaler/replica_calculator_test.go +++ b/pkg/controller/podautoscaler/replica_calculator_test.go @@ -52,7 +52,7 @@ import ( type resourceInfo struct { name v1.ResourceName requests []resource.Quantity - levels []int64 + levels [][]int64 // only applies to pod names returned from "heapster" podNames []string @@ -93,6 +93,7 @@ type replicaCalcTestCase struct { resource *resourceInfo metric *metricInfo metricLabelSelector labels.Selector + container string podReadiness []v1.ConditionStatus podStartTime []metav1.Time @@ -152,7 +153,7 @@ func (tc *replicaCalcTestCase) prepareTestClientSet() *fake.Clientset { }, }, Spec: v1.PodSpec{ - Containers: []v1.Container{{}, {}}, + Containers: []v1.Container{{Name: "container1"}, {Name: "container2"}}, }, } if podDeletionTimestamp { @@ -202,13 +203,11 @@ func (tc *replicaCalcTestCase) prepareTestMetricsClient() *metricsfake.Clientset Containers: make([]metricsapi.ContainerMetrics, numContainersPerPod), } - for i := 0; i < numContainersPerPod; i++ { + for i, m := range resValue { podMetric.Containers[i] = metricsapi.ContainerMetrics{ - Name: fmt.Sprintf("container%v", i), + Name: fmt.Sprintf("container%v", i+1), Usage: v1.ResourceList{ - v1.ResourceName(tc.resource.name): *resource.NewMilliQuantity( - int64(resValue), - resource.DecimalSI), + tc.resource.name: *resource.NewMilliQuantity(m, resource.DecimalSI), }, } } @@ -362,7 +361,7 @@ func (tc *replicaCalcTestCase) runTest(t *testing.T) { } if tc.resource != nil { - outReplicas, outUtilization, outRawValue, outTimestamp, err := replicaCalc.GetResourceReplicas(tc.currentReplicas, tc.resource.targetUtilization, tc.resource.name, testNamespace, selector) + outReplicas, outUtilization, outRawValue, outTimestamp, err := replicaCalc.GetResourceReplicas(tc.currentReplicas, tc.resource.targetUtilization, tc.resource.name, testNamespace, selector, tc.container) if tc.expectedError != nil { require.Error(t, err, "there should be an error calculating the replica count") @@ -424,7 +423,16 @@ func (tc *replicaCalcTestCase) runTest(t *testing.T) { assert.Equal(t, tc.metric.expectedUtilization, outUtilization, "utilization should be as expected") assert.True(t, tc.timestamp.Equal(outTimestamp), "timestamp should be as expected") } - +func makePodMetricLevels(containerMetric ...int64) [][]int64 { + metrics := make([][]int64, len(containerMetric)) + for i := 0; i < len(containerMetric); i++ { + metrics[i] = make([]int64, numContainersPerPod) + for j := 0; j < numContainersPerPod; j++ { + metrics[i][j] = containerMetric[i] + } + } + return metrics +} func TestReplicaCalcDisjointResourcesMetrics(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 1, @@ -432,7 +440,7 @@ func TestReplicaCalcDisjointResourcesMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0")}, - levels: []int64{100}, + levels: makePodMetricLevels(100), podNames: []string{"an-older-pod-name"}, targetUtilization: 100, @@ -441,6 +449,20 @@ func TestReplicaCalcDisjointResourcesMetrics(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcMissingContainerMetricError(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 1, + expectedError: fmt.Errorf("container container2 not present in metrics for pod test-namespace/test-pod-0"), + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0")}, + levels: [][]int64{{0}}, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleUp(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 3, @@ -448,7 +470,7 @@ func TestReplicaCalcScaleUp(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{300, 500, 700}, + levels: makePodMetricLevels(300, 500, 700), targetUtilization: 30, expectedUtilization: 50, @@ -458,6 +480,24 @@ func TestReplicaCalcScaleUp(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcContainerScaleUp(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 3, + expectedReplicas: 5, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 300}, {1000, 500}, {1000, 700}}, + + targetUtilization: 30, + expectedUtilization: 50, + expectedValue: 500, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleUpUnreadyLessScale(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 3, @@ -466,7 +506,7 @@ func TestReplicaCalcScaleUpUnreadyLessScale(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{300, 500, 700}, + levels: makePodMetricLevels(300, 500, 700), targetUtilization: 30, expectedUtilization: 60, @@ -476,6 +516,25 @@ func TestReplicaCalcScaleUpUnreadyLessScale(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleUpContainerHotCpuLessScale(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 3, + expectedReplicas: 4, + podStartTime: []metav1.Time{hotCPUCreationTime(), coolCPUCreationTime(), coolCPUCreationTime()}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{0, 300}, {0, 500}, {0, 700}}, + + targetUtilization: 30, + expectedUtilization: 60, + expectedValue: 600, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleUpHotCpuLessScale(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 3, @@ -484,7 +543,7 @@ func TestReplicaCalcScaleUpHotCpuLessScale(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{300, 500, 700}, + levels: makePodMetricLevels(300, 500, 700), targetUtilization: 30, expectedUtilization: 60, @@ -502,7 +561,7 @@ func TestReplicaCalcScaleUpUnreadyNoScale(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{400, 500, 700}, + levels: makePodMetricLevels(400, 500, 700), targetUtilization: 30, expectedUtilization: 40, @@ -521,7 +580,7 @@ func TestReplicaCalcScaleHotCpuNoScale(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{400, 500, 700}, + levels: makePodMetricLevels(400, 500, 700), targetUtilization: 30, expectedUtilization: 40, @@ -540,7 +599,7 @@ func TestReplicaCalcScaleUpIgnoresFailedPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{500, 700}, + levels: makePodMetricLevels(500, 700), targetUtilization: 30, expectedUtilization: 60, @@ -550,6 +609,26 @@ func TestReplicaCalcScaleUpIgnoresFailedPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleUpContainerIgnoresFailedPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 2, + expectedReplicas: 4, + podReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse}, + podPhase: []v1.PodPhase{v1.PodRunning, v1.PodRunning, v1.PodFailed, v1.PodFailed}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 500}, {9000, 700}}, + + targetUtilization: 30, + expectedUtilization: 60, + expectedValue: 600, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleUpIgnoresDeletionPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 2, @@ -560,7 +639,7 @@ func TestReplicaCalcScaleUpIgnoresDeletionPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{500, 700}, + levels: makePodMetricLevels(500, 700), targetUtilization: 30, expectedUtilization: 60, @@ -570,6 +649,27 @@ func TestReplicaCalcScaleUpIgnoresDeletionPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleUpContainerIgnoresDeletionPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 2, + expectedReplicas: 4, + podReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse}, + podPhase: []v1.PodPhase{v1.PodRunning, v1.PodRunning, v1.PodRunning, v1.PodRunning}, + podDeletionTimestamp: []bool{false, false, true, true}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: makePodMetricLevels(500, 700), // TODO: This test is broken and works only because of missing metrics + + targetUtilization: 30, + expectedUtilization: 60, + expectedValue: 600, + }, + container: "container1", + } + tc.runTest(t) +} + func TestReplicaCalcScaleUpCM(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 3, @@ -749,7 +849,7 @@ func TestReplicaCalcScaleDown(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 28, @@ -759,6 +859,24 @@ func TestReplicaCalcScaleDown(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcContainerScaleDown(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 5, + expectedReplicas: 3, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 100}, {1000, 300}, {1000, 500}, {1000, 250}, {1000, 250}}, + + targetUtilization: 50, + expectedUtilization: 28, + expectedValue: 280, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleDownCM(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, @@ -845,7 +963,7 @@ func TestReplicaCalcScaleDownPerPodCMExternal(t *testing.T) { tc.runTest(t) } -func TestReplicaCalcScaleDownIncludeUnreadyPods(t *testing.T) { +func TestReplicaCalcScaleDownExcludeUnreadyPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, expectedReplicas: 2, @@ -853,7 +971,7 @@ func TestReplicaCalcScaleDownIncludeUnreadyPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 30, @@ -863,6 +981,25 @@ func TestReplicaCalcScaleDownIncludeUnreadyPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleDownContainerExcludeUnreadyPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 5, + expectedReplicas: 2, + podReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 100}, {1000, 300}, {1000, 500}, {1000, 250}, {1000, 250}}, + + targetUtilization: 50, + expectedUtilization: 30, + expectedValue: 300, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleDownExcludeUnscheduledPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, @@ -872,7 +1009,7 @@ func TestReplicaCalcScaleDownExcludeUnscheduledPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100}, + levels: makePodMetricLevels(100), targetUtilization: 50, expectedUtilization: 10, @@ -882,6 +1019,26 @@ func TestReplicaCalcScaleDownExcludeUnscheduledPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleDownContainerExcludeUnscheduledPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 5, + expectedReplicas: 1, + podReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse, v1.ConditionFalse, v1.ConditionFalse}, + podPhase: []v1.PodPhase{v1.PodRunning, v1.PodPending, v1.PodPending, v1.PodPending, v1.PodPending}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 100}, {1000, 300}, {1000, 500}, {1000, 250}, {1000, 250}}, + + targetUtilization: 50, + expectedUtilization: 10, + expectedValue: 100, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleDownIgnoreHotCpuPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, @@ -890,7 +1047,7 @@ func TestReplicaCalcScaleDownIgnoreHotCpuPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 30, @@ -900,6 +1057,25 @@ func TestReplicaCalcScaleDownIgnoreHotCpuPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleDownContainerIgnoreHotCpuPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 5, + expectedReplicas: 2, + podStartTime: []metav1.Time{coolCPUCreationTime(), coolCPUCreationTime(), coolCPUCreationTime(), hotCPUCreationTime(), hotCPUCreationTime()}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 100}, {1000, 300}, {1000, 500}, {1000, 1000}, {1000, 1000}}, + + targetUtilization: 50, + expectedUtilization: 30, + expectedValue: 300, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleDownIgnoresFailedPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, @@ -909,7 +1085,7 @@ func TestReplicaCalcScaleDownIgnoresFailedPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 28, @@ -919,6 +1095,26 @@ func TestReplicaCalcScaleDownIgnoresFailedPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleDownContainerIgnoresFailedPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 5, + expectedReplicas: 3, + podReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse}, + podPhase: []v1.PodPhase{v1.PodRunning, v1.PodRunning, v1.PodRunning, v1.PodRunning, v1.PodRunning, v1.PodFailed, v1.PodFailed}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: [][]int64{{1000, 100}, {1000, 300}, {1000, 500}, {1000, 250}, {1000, 250}}, //TODO: Test is broken + + targetUtilization: 50, + expectedUtilization: 28, + expectedValue: 280, + }, + container: "container2", + } + tc.runTest(t) +} + func TestReplicaCalcScaleDownIgnoresDeletionPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, @@ -929,7 +1125,7 @@ func TestReplicaCalcScaleDownIgnoresDeletionPods(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250}, + levels: makePodMetricLevels(100, 300, 500, 250, 250), targetUtilization: 50, expectedUtilization: 28, @@ -950,12 +1146,13 @@ func TestReplicaCalcScaleDownIgnoresDeletionPods_StillRunning(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 300, 500, 250, 250, 0, 0}, + levels: [][]int64{{1000, 100}, {1000, 300}, {1000, 500}, {1000, 250}, {1000, 250}}, targetUtilization: 50, expectedUtilization: 28, - expectedValue: numContainersPerPod * 280, + expectedValue: 280, }, + container: "container2", } tc.runTest(t) } @@ -967,7 +1164,7 @@ func TestReplicaCalcTolerance(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")}, - levels: []int64{1010, 1030, 1020}, + levels: makePodMetricLevels(1010, 1030, 1020), targetUtilization: 100, expectedUtilization: 102, @@ -1070,7 +1267,7 @@ func TestReplicaCalcSuperfluousMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{4000, 9500, 3000, 7000, 3200, 2000}, + levels: makePodMetricLevels(4000, 9500, 3000, 7000, 3200, 2000), targetUtilization: 100, expectedUtilization: 587, expectedValue: numContainersPerPod * 5875, @@ -1086,7 +1283,7 @@ func TestReplicaCalcMissingMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{400, 95}, + levels: makePodMetricLevels(400, 95), targetUtilization: 100, expectedUtilization: 24, @@ -1103,7 +1300,7 @@ func TestReplicaCalcEmptyMetrics(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{}, + levels: makePodMetricLevels(), targetUtilization: 100, }, @@ -1118,7 +1315,7 @@ func TestReplicaCalcEmptyCPURequest(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{}, - levels: []int64{200}, + levels: makePodMetricLevels(200), targetUtilization: 100, }, @@ -1133,7 +1330,7 @@ func TestReplicaCalcMissingMetricsNoChangeEq(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{1000}, + levels: makePodMetricLevels(1000), targetUtilization: 100, expectedUtilization: 100, @@ -1150,7 +1347,7 @@ func TestReplicaCalcMissingMetricsNoChangeGt(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{1900}, + levels: makePodMetricLevels(1900), targetUtilization: 100, expectedUtilization: 190, @@ -1167,7 +1364,7 @@ func TestReplicaCalcMissingMetricsNoChangeLt(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{600}, + levels: makePodMetricLevels(600), targetUtilization: 100, expectedUtilization: 60, @@ -1185,7 +1382,7 @@ func TestReplicaCalcMissingMetricsUnreadyChange(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 450}, + levels: makePodMetricLevels(100, 450), targetUtilization: 50, expectedUtilization: 45, @@ -1203,7 +1400,7 @@ func TestReplicaCalcMissingMetricsHotCpuNoChange(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 450}, + levels: makePodMetricLevels(100, 450), targetUtilization: 50, expectedUtilization: 45, @@ -1221,7 +1418,7 @@ func TestReplicaCalcMissingMetricsUnreadyScaleUp(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 2000}, + levels: makePodMetricLevels(100, 2000), targetUtilization: 50, expectedUtilization: 200, @@ -1240,7 +1437,7 @@ func TestReplicaCalcMissingMetricsHotCpuScaleUp(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 2000}, + levels: makePodMetricLevels(100, 2000), targetUtilization: 50, expectedUtilization: 200, @@ -1258,7 +1455,7 @@ func TestReplicaCalcMissingMetricsUnreadyScaleDown(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 100, 100}, + levels: makePodMetricLevels(100, 100, 100), targetUtilization: 50, expectedUtilization: 10, @@ -1276,7 +1473,7 @@ func TestReplicaCalcDuringRollingUpdateWithMaxSurge(t *testing.T) { resource: &resourceInfo{ name: v1.ResourceCPU, requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, - levels: []int64{100, 100}, + levels: makePodMetricLevels(100, 100), targetUtilization: 50, expectedUtilization: 10, @@ -1315,18 +1512,18 @@ func TestReplicaCalcComputedToleranceAlgImplementation(t *testing.T) { expectedReplicas: finalPods, resource: &resourceInfo{ name: v1.ResourceCPU, - levels: []int64{ - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - totalUsedCPUOfAllPods / 10, - }, + levels: makePodMetricLevels( + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + totalUsedCPUOfAllPods/10, + ), requests: []resource.Quantity{ resource.MustParse(fmt.Sprint(perPodRequested+100) + "m"), resource.MustParse(fmt.Sprint(perPodRequested-100) + "m"), diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 9d1f8b5e152..e8cf9bc65f4 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -642,6 +642,13 @@ const ( // // Disables Accelerator Metrics Collected by Kubelet DisableAcceleratorUsageMetrics featuregate.Feature = "DisableAcceleratorUsageMetrics" + + // owner: @arjunrn @mwielgus @josephburnett + // alpha: v1.20 + // + // Add support for the HPA to scale based on metrics from individual containers + // in target pods + HPAContainerMetrics featuregate.Feature = "HPAContainerMetrics" ) func init() { @@ -739,6 +746,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS WinOverlay: {Default: true, PreRelease: featuregate.Beta}, WinDSR: {Default: false, PreRelease: featuregate.Alpha}, DisableAcceleratorUsageMetrics: {Default: true, PreRelease: featuregate.Beta}, + HPAContainerMetrics: {Default: false, PreRelease: featuregate.Alpha}, // inherited features from generic apiserver, relisted here to get a conflict if it is changed // unintentionally on either side: diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index a5ad60763ae..6a3bb265f1e 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -2042,6 +2042,25 @@ func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.Met } list = append(list, fmt.Sprintf("%s/%s", current, target)) } + case autoscaling.ContainerResourceMetricSourceType: + if spec.ContainerResource.Target.AverageValue != nil { + current := "" + if len(statuses) > i && statuses[i].ContainerResource != nil { + current = statuses[i].ContainerResource.Current.AverageValue.String() + } + list = append(list, fmt.Sprintf("%s/%s", current, spec.ContainerResource.Target.AverageValue.String())) + } else { + current := "" + if len(statuses) > i && statuses[i].ContainerResource != nil && statuses[i].ContainerResource.Current.AverageUtilization != nil { + current = fmt.Sprintf("%d%%", *statuses[i].ContainerResource.Current.AverageUtilization) + } + + target := "" + if spec.ContainerResource.Target.AverageUtilization != nil { + target = fmt.Sprintf("%d%%", *spec.ContainerResource.Target.AverageUtilization) + } + list = append(list, fmt.Sprintf("%s/%s", current, target)) + } default: list = append(list, "") } diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 9765a88599e..6d4796a94e4 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -2813,6 +2813,161 @@ func TestPrintHPA(t *testing.T) { // Columns: Name, Reference, Targets, MinPods, MaxPods, Replicas, Age expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50%/80%", "2", int64(10), int64(4), ""}}}, }, + // container resource source type, targetVal (no current) + { + hpa: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Name: "some-rc", + Kind: "ReplicationController", + }, + MinReplicas: &minReplicasVal, + MaxReplicas: 10, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.AverageValueMetricType, + AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + }, + }, + // Columns: Name, Reference, Targets, MinPods, MaxPods, Replicas, Age + expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "/100m", "2", int64(10), int64(4), ""}}}, + }, + // container resource source type, targetVal + { + hpa: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Name: "some-rc", + Kind: "ReplicationController", + }, + MinReplicas: &minReplicasVal, + MaxReplicas: 10, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Target: autoscaling.MetricTarget{ + Type: autoscaling.AverageValueMetricType, + AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + CurrentMetrics: []autoscaling.MetricStatus{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricStatus{ + Name: api.ResourceCPU, + Container: "application", + Current: autoscaling.MetricValueStatus{ + AverageValue: resource.NewMilliQuantity(50, resource.DecimalSI), + }, + }, + }, + }, + }, + }, + // Columns: Name, Reference, Targets, MinPods, MaxPods, Replicas, Age + expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50m/100m", "2", int64(10), int64(4), ""}}}, + }, + // container resource source type, targetUtil (no current) + { + hpa: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Name: "some-rc", + Kind: "ReplicationController", + }, + MinReplicas: &minReplicasVal, + MaxReplicas: 10, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Container: "application", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: &targetUtilizationVal, + }, + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + }, + }, + // Columns: Name, Reference, Targets, MinPods, MaxPods, Replicas, Age + expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "/80%", "2", int64(10), int64(4), ""}}}, + }, + // container resource source type, targetUtil + { + hpa: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Name: "some-rc", + Kind: "ReplicationController", + }, + MinReplicas: &minReplicasVal, + MaxReplicas: 10, + Metrics: []autoscaling.MetricSpec{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: api.ResourceCPU, + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: &targetUtilizationVal, + }, + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + CurrentMetrics: []autoscaling.MetricStatus{ + { + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricStatus{ + Name: api.ResourceCPU, + Container: "application", + Current: autoscaling.MetricValueStatus{ + AverageUtilization: ¤tUtilizationVal, + AverageValue: resource.NewMilliQuantity(40, resource.DecimalSI), + }, + }, + }, + }, + }, + }, + // Columns: Name, Reference, Targets, MinPods, MaxPods, Replicas, Age + expected: []metav1.TableRow{{Cells: []interface{}{"some-hpa", "ReplicationController/some-rc", "50%/80%", "2", int64(10), int64(4), ""}}}, + }, // multiple specs { hpa: autoscaling.HorizontalPodAutoscaler{ diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/BUILD b/pkg/registry/autoscaling/horizontalpodautoscaler/BUILD index 868fea4a83a..1cd20e7bd79 100644 --- a/pkg/registry/autoscaling/horizontalpodautoscaler/BUILD +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/BUILD @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", + "go_test", ) go_library( @@ -16,9 +17,11 @@ go_library( "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/autoscaling:go_default_library", "//pkg/apis/autoscaling/validation:go_default_library", + "//pkg/features:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) @@ -37,3 +40,17 @@ filegroup( ], tags = ["automanaged"], ) + +go_test( + name = "go_default_test", + srcs = ["strategy_test.go"], + embed = [":go_default_library"], + deps = [ + "//pkg/apis/autoscaling:go_default_library", + "//pkg/apis/core:go_default_library", + "//pkg/features:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", + "//vendor/k8s.io/utils/pointer:go_default_library", + ], +) diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go b/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go index f26088f22ac..75b8e4eccdd 100644 --- a/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go @@ -22,9 +22,11 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/storage/names" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling/validation" + "k8s.io/kubernetes/pkg/features" ) // autoscalerStrategy implements behavior for HorizontalPodAutoscalers @@ -48,6 +50,10 @@ func (autoscalerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Obje // create cannot set status newHPA.Status = autoscaling.HorizontalPodAutoscalerStatus{} + + if !utilfeature.DefaultFeatureGate.Enabled(features.HPAContainerMetrics) { + dropContainerMetricSources(newHPA.Spec.Metrics) + } } // Validate validates a new autoscaler. @@ -69,10 +75,30 @@ func (autoscalerStrategy) AllowCreateOnUpdate() bool { func (autoscalerStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { newHPA := obj.(*autoscaling.HorizontalPodAutoscaler) oldHPA := old.(*autoscaling.HorizontalPodAutoscaler) + if !utilfeature.DefaultFeatureGate.Enabled(features.HPAContainerMetrics) && !hasContainerMetricSources(oldHPA) { + dropContainerMetricSources(newHPA.Spec.Metrics) + } // Update is not allowed to set status newHPA.Status = oldHPA.Status } +// dropContainerMetricSources ensures all container resource metric sources are nil +func dropContainerMetricSources(metrics []autoscaling.MetricSpec) { + for i := range metrics { + metrics[i].ContainerResource = nil + } +} + +// hasContainerMetricSources returns true if the hpa has any container resource metric sources +func hasContainerMetricSources(hpa *autoscaling.HorizontalPodAutoscaler) bool { + for i := range hpa.Spec.Metrics { + if hpa.Spec.Metrics[i].ContainerResource != nil { + return true + } + } + return false +} + // ValidateUpdate is the default update validation for an end user. func (autoscalerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateHorizontalPodAutoscalerUpdate(obj.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler)) diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/strategy_test.go b/pkg/registry/autoscaling/horizontalpodautoscaler/strategy_test.go new file mode 100644 index 00000000000..8bc41be0612 --- /dev/null +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/strategy_test.go @@ -0,0 +1,110 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package horizontalpodautoscaler + +import ( + "context" + "testing" + + utilfeature "k8s.io/apiserver/pkg/util/feature" + featuregatetesting "k8s.io/component-base/featuregate/testing" + "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/features" + "k8s.io/utils/pointer" +) + +func makeTestContainerMetricsHPA(hasContainerMetric bool) *autoscaling.HorizontalPodAutoscaler { + testHPA := &autoscaling.HorizontalPodAutoscaler{ + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + Metrics: []autoscaling.MetricSpec{}, + }, + } + if hasContainerMetric { + testHPA.Spec.Metrics = append(testHPA.Spec.Metrics, autoscaling.MetricSpec{ + Type: autoscaling.ContainerResourceMetricSourceType, + ContainerResource: &autoscaling.ContainerResourceMetricSource{ + Name: core.ResourceCPU, + Container: "test-container", + Target: autoscaling.MetricTarget{ + Type: autoscaling.UtilizationMetricType, + AverageUtilization: pointer.Int32Ptr(30), + }, + }, + }) + } + return testHPA +} + +func TestCreateWithFeatureEnabled(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAContainerMetrics, true)() + testHPA := makeTestContainerMetricsHPA(true) + Strategy.PrepareForCreate(context.Background(), testHPA) + if testHPA.Spec.Metrics[0].ContainerResource == nil { + t.Errorf("container metrics was set to nil") + } +} + +func TestCreateWithFeatureDisabled(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAContainerMetrics, false)() + testHPA := makeTestContainerMetricsHPA(true) + Strategy.PrepareForCreate(context.Background(), testHPA) + if testHPA.Spec.Metrics[0].ContainerResource != nil { + t.Errorf("container metrics is not nil") + } +} + +func TestAutoscalerStatusStrategy_PrepareForUpdate(t *testing.T) { + for _, tc := range []struct { + name string + featureEnabled bool + old bool + expectedNew bool + }{ + { + name: "feature disabled with existing container metrics", + featureEnabled: false, + old: true, + expectedNew: true, + }, + { + name: "feature enabled with no container metrics", + featureEnabled: true, + old: false, + expectedNew: true, + }, + { + name: "feature enabled with existing container metrics", + featureEnabled: true, + old: true, + expectedNew: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAContainerMetrics, tc.featureEnabled)() + oldHPA := makeTestContainerMetricsHPA(tc.old) + newHPA := makeTestContainerMetricsHPA(true) + Strategy.PrepareForUpdate(context.Background(), newHPA, oldHPA) + if tc.expectedNew && newHPA.Spec.Metrics[0].ContainerResource == nil { + t.Errorf("container metric source is nil") + } + if !tc.expectedNew && newHPA.Spec.Metrics[0].ContainerResource != nil { + t.Errorf("container metric source is not nil") + } + }) + } +} diff --git a/staging/src/k8s.io/api/autoscaling/v1/generated.pb.go b/staging/src/k8s.io/api/autoscaling/v1/generated.pb.go index 1e3d89076d5..1de893f7ee4 100644 --- a/staging/src/k8s.io/api/autoscaling/v1/generated.pb.go +++ b/staging/src/k8s.io/api/autoscaling/v1/generated.pb.go @@ -47,10 +47,66 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +func (m *ContainerResourceMetricSource) Reset() { *m = ContainerResourceMetricSource{} } +func (*ContainerResourceMetricSource) ProtoMessage() {} +func (*ContainerResourceMetricSource) Descriptor() ([]byte, []int) { + return fileDescriptor_2bb1f2101a7f10e2, []int{0} +} +func (m *ContainerResourceMetricSource) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerResourceMetricSource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ContainerResourceMetricSource) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerResourceMetricSource.Merge(m, src) +} +func (m *ContainerResourceMetricSource) XXX_Size() int { + return m.Size() +} +func (m *ContainerResourceMetricSource) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerResourceMetricSource.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerResourceMetricSource proto.InternalMessageInfo + +func (m *ContainerResourceMetricStatus) Reset() { *m = ContainerResourceMetricStatus{} } +func (*ContainerResourceMetricStatus) ProtoMessage() {} +func (*ContainerResourceMetricStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_2bb1f2101a7f10e2, []int{1} +} +func (m *ContainerResourceMetricStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerResourceMetricStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ContainerResourceMetricStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerResourceMetricStatus.Merge(m, src) +} +func (m *ContainerResourceMetricStatus) XXX_Size() int { + return m.Size() +} +func (m *ContainerResourceMetricStatus) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerResourceMetricStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerResourceMetricStatus proto.InternalMessageInfo + func (m *CrossVersionObjectReference) Reset() { *m = CrossVersionObjectReference{} } func (*CrossVersionObjectReference) ProtoMessage() {} func (*CrossVersionObjectReference) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{0} + return fileDescriptor_2bb1f2101a7f10e2, []int{2} } func (m *CrossVersionObjectReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -78,7 +134,7 @@ var xxx_messageInfo_CrossVersionObjectReference proto.InternalMessageInfo func (m *ExternalMetricSource) Reset() { *m = ExternalMetricSource{} } func (*ExternalMetricSource) ProtoMessage() {} func (*ExternalMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{1} + return fileDescriptor_2bb1f2101a7f10e2, []int{3} } func (m *ExternalMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +162,7 @@ var xxx_messageInfo_ExternalMetricSource proto.InternalMessageInfo func (m *ExternalMetricStatus) Reset() { *m = ExternalMetricStatus{} } func (*ExternalMetricStatus) ProtoMessage() {} func (*ExternalMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{2} + return fileDescriptor_2bb1f2101a7f10e2, []int{4} } func (m *ExternalMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -134,7 +190,7 @@ var xxx_messageInfo_ExternalMetricStatus proto.InternalMessageInfo func (m *HorizontalPodAutoscaler) Reset() { *m = HorizontalPodAutoscaler{} } func (*HorizontalPodAutoscaler) ProtoMessage() {} func (*HorizontalPodAutoscaler) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{3} + return fileDescriptor_2bb1f2101a7f10e2, []int{5} } func (m *HorizontalPodAutoscaler) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -162,7 +218,7 @@ var xxx_messageInfo_HorizontalPodAutoscaler proto.InternalMessageInfo func (m *HorizontalPodAutoscalerCondition) Reset() { *m = HorizontalPodAutoscalerCondition{} } func (*HorizontalPodAutoscalerCondition) ProtoMessage() {} func (*HorizontalPodAutoscalerCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{4} + return fileDescriptor_2bb1f2101a7f10e2, []int{6} } func (m *HorizontalPodAutoscalerCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -190,7 +246,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerCondition proto.InternalMessageInfo func (m *HorizontalPodAutoscalerList) Reset() { *m = HorizontalPodAutoscalerList{} } func (*HorizontalPodAutoscalerList) ProtoMessage() {} func (*HorizontalPodAutoscalerList) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{5} + return fileDescriptor_2bb1f2101a7f10e2, []int{7} } func (m *HorizontalPodAutoscalerList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -218,7 +274,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerList proto.InternalMessageInfo func (m *HorizontalPodAutoscalerSpec) Reset() { *m = HorizontalPodAutoscalerSpec{} } func (*HorizontalPodAutoscalerSpec) ProtoMessage() {} func (*HorizontalPodAutoscalerSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{6} + return fileDescriptor_2bb1f2101a7f10e2, []int{8} } func (m *HorizontalPodAutoscalerSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -246,7 +302,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerSpec proto.InternalMessageInfo func (m *HorizontalPodAutoscalerStatus) Reset() { *m = HorizontalPodAutoscalerStatus{} } func (*HorizontalPodAutoscalerStatus) ProtoMessage() {} func (*HorizontalPodAutoscalerStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{7} + return fileDescriptor_2bb1f2101a7f10e2, []int{9} } func (m *HorizontalPodAutoscalerStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -274,7 +330,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerStatus proto.InternalMessageInfo func (m *MetricSpec) Reset() { *m = MetricSpec{} } func (*MetricSpec) ProtoMessage() {} func (*MetricSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{8} + return fileDescriptor_2bb1f2101a7f10e2, []int{10} } func (m *MetricSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -302,7 +358,7 @@ var xxx_messageInfo_MetricSpec proto.InternalMessageInfo func (m *MetricStatus) Reset() { *m = MetricStatus{} } func (*MetricStatus) ProtoMessage() {} func (*MetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{9} + return fileDescriptor_2bb1f2101a7f10e2, []int{11} } func (m *MetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -330,7 +386,7 @@ var xxx_messageInfo_MetricStatus proto.InternalMessageInfo func (m *ObjectMetricSource) Reset() { *m = ObjectMetricSource{} } func (*ObjectMetricSource) ProtoMessage() {} func (*ObjectMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{10} + return fileDescriptor_2bb1f2101a7f10e2, []int{12} } func (m *ObjectMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -358,7 +414,7 @@ var xxx_messageInfo_ObjectMetricSource proto.InternalMessageInfo func (m *ObjectMetricStatus) Reset() { *m = ObjectMetricStatus{} } func (*ObjectMetricStatus) ProtoMessage() {} func (*ObjectMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{11} + return fileDescriptor_2bb1f2101a7f10e2, []int{13} } func (m *ObjectMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -386,7 +442,7 @@ var xxx_messageInfo_ObjectMetricStatus proto.InternalMessageInfo func (m *PodsMetricSource) Reset() { *m = PodsMetricSource{} } func (*PodsMetricSource) ProtoMessage() {} func (*PodsMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{12} + return fileDescriptor_2bb1f2101a7f10e2, []int{14} } func (m *PodsMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -414,7 +470,7 @@ var xxx_messageInfo_PodsMetricSource proto.InternalMessageInfo func (m *PodsMetricStatus) Reset() { *m = PodsMetricStatus{} } func (*PodsMetricStatus) ProtoMessage() {} func (*PodsMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{13} + return fileDescriptor_2bb1f2101a7f10e2, []int{15} } func (m *PodsMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -442,7 +498,7 @@ var xxx_messageInfo_PodsMetricStatus proto.InternalMessageInfo func (m *ResourceMetricSource) Reset() { *m = ResourceMetricSource{} } func (*ResourceMetricSource) ProtoMessage() {} func (*ResourceMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{14} + return fileDescriptor_2bb1f2101a7f10e2, []int{16} } func (m *ResourceMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -470,7 +526,7 @@ var xxx_messageInfo_ResourceMetricSource proto.InternalMessageInfo func (m *ResourceMetricStatus) Reset() { *m = ResourceMetricStatus{} } func (*ResourceMetricStatus) ProtoMessage() {} func (*ResourceMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{15} + return fileDescriptor_2bb1f2101a7f10e2, []int{17} } func (m *ResourceMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -498,7 +554,7 @@ var xxx_messageInfo_ResourceMetricStatus proto.InternalMessageInfo func (m *Scale) Reset() { *m = Scale{} } func (*Scale) ProtoMessage() {} func (*Scale) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{16} + return fileDescriptor_2bb1f2101a7f10e2, []int{18} } func (m *Scale) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -526,7 +582,7 @@ var xxx_messageInfo_Scale proto.InternalMessageInfo func (m *ScaleSpec) Reset() { *m = ScaleSpec{} } func (*ScaleSpec) ProtoMessage() {} func (*ScaleSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{17} + return fileDescriptor_2bb1f2101a7f10e2, []int{19} } func (m *ScaleSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -554,7 +610,7 @@ var xxx_messageInfo_ScaleSpec proto.InternalMessageInfo func (m *ScaleStatus) Reset() { *m = ScaleStatus{} } func (*ScaleStatus) ProtoMessage() {} func (*ScaleStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_2bb1f2101a7f10e2, []int{18} + return fileDescriptor_2bb1f2101a7f10e2, []int{20} } func (m *ScaleStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -580,6 +636,8 @@ func (m *ScaleStatus) XXX_DiscardUnknown() { var xxx_messageInfo_ScaleStatus proto.InternalMessageInfo func init() { + proto.RegisterType((*ContainerResourceMetricSource)(nil), "k8s.io.api.autoscaling.v1.ContainerResourceMetricSource") + proto.RegisterType((*ContainerResourceMetricStatus)(nil), "k8s.io.api.autoscaling.v1.ContainerResourceMetricStatus") proto.RegisterType((*CrossVersionObjectReference)(nil), "k8s.io.api.autoscaling.v1.CrossVersionObjectReference") proto.RegisterType((*ExternalMetricSource)(nil), "k8s.io.api.autoscaling.v1.ExternalMetricSource") proto.RegisterType((*ExternalMetricStatus)(nil), "k8s.io.api.autoscaling.v1.ExternalMetricStatus") @@ -606,102 +664,206 @@ func init() { } var fileDescriptor_2bb1f2101a7f10e2 = []byte{ - // 1516 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0xcf, 0x6f, 0x13, 0xc7, - 0x17, 0x8f, 0x7f, 0x24, 0x24, 0xe3, 0x90, 0xe4, 0x3b, 0x20, 0x08, 0xe1, 0x8b, 0x37, 0xda, 0x22, - 0x44, 0x7f, 0xb0, 0x6e, 0x52, 0x8a, 0xe8, 0x31, 0x76, 0x4b, 0x41, 0x8d, 0x21, 0x4c, 0x02, 0xa5, - 0x3f, 0xc5, 0x64, 0x3d, 0x38, 0x43, 0xbc, 0xbb, 0xd6, 0xec, 0xd8, 0x22, 0x48, 0x95, 0xda, 0x43, - 0xef, 0xbd, 0xb4, 0xea, 0xb1, 0x95, 0x7a, 0xed, 0x99, 0x73, 0x6f, 0x1c, 0x39, 0x20, 0x95, 0xd3, - 0xaa, 0x6c, 0x8f, 0xfd, 0x0f, 0x38, 0x55, 0xf3, 0xc3, 0xeb, 0x5d, 0xdb, 0xeb, 0x24, 0x26, 0x44, - 0x6d, 0x6f, 0x3b, 0x33, 0xef, 0x7d, 0xde, 0xec, 0x7b, 0x6f, 0xde, 0x2f, 0x50, 0xde, 0xbe, 0xec, - 0x5b, 0xd4, 0x2b, 0x6d, 0xb7, 0x36, 0x09, 0x73, 0x09, 0x27, 0x7e, 0xa9, 0x4d, 0xdc, 0x9a, 0xc7, - 0x4a, 0xfa, 0x00, 0x37, 0x69, 0x09, 0xb7, 0xb8, 0xe7, 0xdb, 0xb8, 0x41, 0xdd, 0x7a, 0xa9, 0xbd, - 0x54, 0xaa, 0x13, 0x97, 0x30, 0xcc, 0x49, 0xcd, 0x6a, 0x32, 0x8f, 0x7b, 0xf0, 0x94, 0x22, 0xb5, - 0x70, 0x93, 0x5a, 0x31, 0x52, 0xab, 0xbd, 0xb4, 0x70, 0xa1, 0x4e, 0xf9, 0x56, 0x6b, 0xd3, 0xb2, - 0x3d, 0xa7, 0x54, 0xf7, 0xea, 0x5e, 0x49, 0x72, 0x6c, 0xb6, 0xee, 0xc9, 0x95, 0x5c, 0xc8, 0x2f, - 0x85, 0xb4, 0x60, 0xc6, 0x84, 0xda, 0x1e, 0x23, 0x03, 0xa4, 0x2d, 0x5c, 0xec, 0xd2, 0x38, 0xd8, - 0xde, 0xa2, 0x2e, 0x61, 0x3b, 0xa5, 0xe6, 0x76, 0x5d, 0x32, 0x31, 0xe2, 0x7b, 0x2d, 0x66, 0x93, - 0x7d, 0x71, 0xf9, 0x25, 0x87, 0x70, 0x3c, 0x48, 0x56, 0x29, 0x8d, 0x8b, 0xb5, 0x5c, 0x4e, 0x9d, - 0x7e, 0x31, 0x97, 0x76, 0x63, 0xf0, 0xed, 0x2d, 0xe2, 0xe0, 0x5e, 0x3e, 0xf3, 0xfb, 0x0c, 0x38, - 0x5d, 0x61, 0x9e, 0xef, 0xdf, 0x26, 0xcc, 0xa7, 0x9e, 0x7b, 0x63, 0xf3, 0x3e, 0xb1, 0x39, 0x22, - 0xf7, 0x08, 0x23, 0xae, 0x4d, 0xe0, 0x22, 0xc8, 0x6f, 0x53, 0xb7, 0x36, 0x9f, 0x59, 0xcc, 0x9c, - 0x9f, 0x2a, 0x4f, 0x3f, 0x0e, 0x8c, 0xb1, 0x30, 0x30, 0xf2, 0x1f, 0x51, 0xb7, 0x86, 0xe4, 0x89, - 0xa0, 0x70, 0xb1, 0x43, 0xe6, 0xb3, 0x49, 0x8a, 0xeb, 0xd8, 0x21, 0x48, 0x9e, 0xc0, 0x65, 0x00, - 0x70, 0x93, 0x6a, 0x01, 0xf3, 0x39, 0x49, 0x07, 0x35, 0x1d, 0x58, 0x59, 0xbb, 0xa6, 0x4f, 0x50, - 0x8c, 0xca, 0xfc, 0x21, 0x07, 0x8e, 0x7f, 0xf0, 0x80, 0x13, 0xe6, 0xe2, 0x46, 0x95, 0x70, 0x46, - 0xed, 0x75, 0xa9, 0x5f, 0x01, 0xe6, 0xc8, 0xb5, 0x10, 0xa0, 0xaf, 0x15, 0x81, 0x55, 0xa3, 0x13, - 0x14, 0xa3, 0x82, 0x1e, 0x98, 0x51, 0xab, 0x75, 0xd2, 0x20, 0x36, 0xf7, 0x98, 0xbc, 0x6c, 0x61, - 0xf9, 0x1d, 0xab, 0xeb, 0x40, 0x91, 0xd6, 0xac, 0xe6, 0x76, 0x5d, 0x6c, 0xf8, 0x96, 0x30, 0x8e, - 0xd5, 0x5e, 0xb2, 0x56, 0xf1, 0x26, 0x69, 0x74, 0x58, 0xcb, 0x30, 0x0c, 0x8c, 0x99, 0x6a, 0x02, - 0x0e, 0xf5, 0xc0, 0x43, 0x0c, 0x0a, 0x1c, 0xb3, 0x3a, 0xe1, 0xb7, 0x71, 0xa3, 0x45, 0xe4, 0x2f, - 0x17, 0x96, 0xad, 0x61, 0xd2, 0xac, 0x8e, 0x03, 0x59, 0x37, 0x5b, 0xd8, 0xe5, 0x94, 0xef, 0x94, - 0x67, 0xc3, 0xc0, 0x28, 0x6c, 0x74, 0x61, 0x50, 0x1c, 0x13, 0xb6, 0x01, 0x54, 0xcb, 0x95, 0x36, - 0x61, 0xb8, 0x4e, 0x94, 0xa4, 0xfc, 0x48, 0x92, 0x4e, 0x84, 0x81, 0x01, 0x37, 0xfa, 0xd0, 0xd0, - 0x00, 0x09, 0xe6, 0x4f, 0xfd, 0x86, 0xe1, 0x98, 0xb7, 0xfc, 0x7f, 0x87, 0x61, 0xb6, 0xc0, 0xb4, - 0xdd, 0x62, 0x8c, 0xb8, 0x2f, 0x65, 0x99, 0xe3, 0xfa, 0xb7, 0xa6, 0x2b, 0x31, 0x2c, 0x94, 0x40, - 0x86, 0x3b, 0xe0, 0x98, 0x5e, 0x1f, 0x80, 0x81, 0x4e, 0x86, 0x81, 0x71, 0xac, 0xd2, 0x0f, 0x87, - 0x06, 0xc9, 0x30, 0x1f, 0x65, 0xc1, 0xc9, 0xab, 0x1e, 0xa3, 0x0f, 0x3d, 0x97, 0xe3, 0xc6, 0x9a, - 0x57, 0x5b, 0xd1, 0xb1, 0x91, 0x30, 0x78, 0x17, 0x4c, 0x0a, 0xed, 0xd5, 0x30, 0xc7, 0xd2, 0x46, - 0x85, 0xe5, 0xb7, 0xf7, 0xa6, 0x6b, 0x15, 0x18, 0xaa, 0x84, 0xe3, 0xae, 0x55, 0xbb, 0x7b, 0x28, - 0x42, 0x85, 0x77, 0x40, 0xde, 0x6f, 0x12, 0x5b, 0x5b, 0xf2, 0x92, 0x95, 0x1a, 0xa3, 0xad, 0x94, - 0x3b, 0xae, 0x37, 0x89, 0xdd, 0x8d, 0x23, 0x62, 0x85, 0x24, 0x22, 0xbc, 0x0b, 0x26, 0x7c, 0xe9, - 0x6b, 0xda, 0x6c, 0x97, 0x47, 0xc0, 0x96, 0xfc, 0xe5, 0x19, 0x8d, 0x3e, 0xa1, 0xd6, 0x48, 0xe3, - 0x9a, 0xdf, 0xe6, 0xc0, 0x62, 0x0a, 0x67, 0xc5, 0x73, 0x6b, 0x94, 0x53, 0xcf, 0x85, 0x57, 0x41, - 0x9e, 0xef, 0x34, 0x3b, 0x2e, 0x7e, 0xb1, 0x73, 0xd1, 0x8d, 0x9d, 0x26, 0x79, 0x11, 0x18, 0x67, - 0x77, 0xe3, 0x17, 0x74, 0x48, 0x22, 0xc0, 0xd5, 0xe8, 0x87, 0xb2, 0x09, 0x2c, 0x7d, 0xad, 0x17, - 0x81, 0x31, 0x20, 0x2f, 0x59, 0x11, 0x52, 0xf2, 0xf2, 0x22, 0x22, 0x34, 0xb0, 0xcf, 0x37, 0x18, - 0x76, 0x7d, 0x25, 0x89, 0x3a, 0x1d, 0x0f, 0x7f, 0x63, 0x6f, 0x46, 0x16, 0x1c, 0xe5, 0x05, 0x7d, - 0x0b, 0xb8, 0xda, 0x87, 0x86, 0x06, 0x48, 0x80, 0xe7, 0xc0, 0x04, 0x23, 0xd8, 0xf7, 0x5c, 0xe9, - 0xdc, 0x53, 0x5d, 0xe5, 0x22, 0xb9, 0x8b, 0xf4, 0x29, 0x7c, 0x1d, 0x1c, 0x71, 0x88, 0xef, 0xe3, - 0x3a, 0x99, 0x1f, 0x97, 0x84, 0xb3, 0x9a, 0xf0, 0x48, 0x55, 0x6d, 0xa3, 0xce, 0xb9, 0xf9, 0x34, - 0x03, 0x4e, 0xa7, 0xe8, 0x71, 0x95, 0xfa, 0x1c, 0x7e, 0xde, 0xe7, 0xc5, 0xd6, 0x1e, 0x23, 0x06, - 0xf5, 0x95, 0x0f, 0xcf, 0x69, 0xd9, 0x93, 0x9d, 0x9d, 0x98, 0x07, 0x7f, 0x0c, 0xc6, 0x29, 0x27, - 0x8e, 0xb0, 0x4a, 0xee, 0x7c, 0x61, 0x79, 0x79, 0xff, 0x6e, 0x56, 0x3e, 0xaa, 0xe1, 0xc7, 0xaf, - 0x09, 0x20, 0xa4, 0xf0, 0xcc, 0xbf, 0xb2, 0xa9, 0xbf, 0x25, 0xdc, 0x1c, 0xb6, 0xc1, 0x8c, 0x5c, - 0xa9, 0x50, 0x8c, 0xc8, 0x3d, 0xfd, 0x73, 0xc3, 0x1e, 0xd1, 0x90, 0xe4, 0x5d, 0x3e, 0xa1, 0x6f, - 0x31, 0xb3, 0x9e, 0x40, 0x45, 0x3d, 0x52, 0xe0, 0x12, 0x28, 0x38, 0xd4, 0x45, 0xa4, 0xd9, 0xa0, - 0x36, 0x56, 0xce, 0x38, 0xae, 0xd2, 0x4f, 0xb5, 0xbb, 0x8d, 0xe2, 0x34, 0xf0, 0x5d, 0x50, 0x70, - 0xf0, 0x83, 0x88, 0x25, 0x27, 0x59, 0x8e, 0x69, 0x79, 0x85, 0x6a, 0xf7, 0x08, 0xc5, 0xe9, 0xe0, - 0x7d, 0x50, 0x54, 0x39, 0xa5, 0xb2, 0x76, 0xeb, 0x16, 0xa7, 0x0d, 0xfa, 0x10, 0x0b, 0x3f, 0x5a, - 0x23, 0xcc, 0x26, 0x2e, 0x17, 0xae, 0x91, 0x97, 0x48, 0x66, 0x18, 0x18, 0xc5, 0x8d, 0xa1, 0x94, - 0x68, 0x17, 0x24, 0xf3, 0xb7, 0x1c, 0x38, 0x33, 0x34, 0x0c, 0xc0, 0x2b, 0x00, 0x7a, 0x9b, 0x3e, - 0x61, 0x6d, 0x52, 0xfb, 0x50, 0xd5, 0x45, 0xa2, 0x40, 0x11, 0x3a, 0xcf, 0xa9, 0x9c, 0x78, 0xa3, - 0xef, 0x14, 0x0d, 0xe0, 0x80, 0x36, 0x38, 0x2a, 0xde, 0x85, 0xd2, 0x32, 0xd5, 0xb5, 0xd0, 0xfe, - 0x1e, 0xdd, 0xff, 0xc2, 0xc0, 0x38, 0xba, 0x1a, 0x07, 0x41, 0x49, 0x4c, 0xb8, 0x02, 0x66, 0x75, - 0xb0, 0xef, 0xd1, 0xfa, 0x49, 0xad, 0xf5, 0xd9, 0x4a, 0xf2, 0x18, 0xf5, 0xd2, 0x0b, 0x88, 0x1a, - 0xf1, 0x29, 0x23, 0xb5, 0x08, 0x22, 0x9f, 0x84, 0x78, 0x3f, 0x79, 0x8c, 0x7a, 0xe9, 0xa1, 0x03, - 0x0c, 0x8d, 0x9a, 0x6a, 0xc1, 0x71, 0x09, 0xf9, 0x5a, 0x18, 0x18, 0x46, 0x65, 0x38, 0x29, 0xda, - 0x0d, 0x4b, 0x94, 0x81, 0xba, 0x76, 0x90, 0x0f, 0xe4, 0x62, 0x22, 0xf4, 0x2e, 0xf6, 0x84, 0xde, - 0xb9, 0x78, 0xa1, 0x18, 0x0b, 0xb3, 0x37, 0xc1, 0x84, 0x27, 0x5f, 0x86, 0xb6, 0xcb, 0x85, 0x21, - 0xcf, 0x29, 0x4a, 0x69, 0x11, 0x50, 0x19, 0x88, 0x58, 0xa6, 0x9f, 0x96, 0x06, 0x82, 0xd7, 0x40, - 0xbe, 0xe9, 0xd5, 0x3a, 0x89, 0xe8, 0xcd, 0x21, 0x80, 0x6b, 0x5e, 0xcd, 0x4f, 0xc0, 0x4d, 0x8a, - 0x1b, 0x8b, 0x5d, 0x24, 0x21, 0xe0, 0x27, 0x60, 0xb2, 0x93, 0xf0, 0x75, 0x75, 0x50, 0x1a, 0x02, - 0x87, 0x34, 0x69, 0x02, 0x72, 0x5a, 0x04, 0xb2, 0xce, 0x09, 0x8a, 0xe0, 0x04, 0x34, 0xd1, 0xa5, - 0x9a, 0xb4, 0xca, 0x70, 0xe8, 0x41, 0xe5, 0xb6, 0x82, 0xee, 0x9c, 0xa0, 0x08, 0xce, 0xfc, 0x31, - 0x07, 0xa6, 0x13, 0xe5, 0xdf, 0x21, 0x9b, 0x46, 0xe5, 0xf1, 0x03, 0x33, 0x8d, 0x82, 0x3b, 0x50, - 0xd3, 0x28, 0xc8, 0x57, 0x62, 0x9a, 0x18, 0xf4, 0x00, 0xd3, 0x3c, 0xcd, 0x01, 0xd8, 0xef, 0xc6, - 0xf0, 0x4b, 0x30, 0xa1, 0x02, 0xe6, 0x4b, 0x26, 0x95, 0x28, 0xbd, 0xeb, 0xfc, 0xa1, 0x51, 0x7b, - 0xea, 0xff, 0xec, 0x9e, 0xea, 0x7f, 0x72, 0x10, 0x7d, 0x52, 0x94, 0x75, 0x52, 0x7b, 0xa5, 0x2f, - 0xc0, 0xa4, 0xdf, 0x69, 0x30, 0xf2, 0xa3, 0x37, 0x18, 0x52, 0xe1, 0x51, 0x6b, 0x11, 0x41, 0xc2, - 0x1a, 0x98, 0xc6, 0xf1, 0x1a, 0x7f, 0x7c, 0xa4, 0xdf, 0x98, 0x13, 0x0d, 0x45, 0xa2, 0xb8, 0x4f, - 0xa0, 0x9a, 0xbf, 0xf7, 0x9a, 0x55, 0xbd, 0xbb, 0x7f, 0xa2, 0x59, 0x0f, 0xaf, 0xcb, 0xfa, 0x4f, - 0x58, 0xf6, 0xe7, 0x2c, 0x98, 0xeb, 0x4d, 0x13, 0x23, 0xb5, 0xd3, 0x0f, 0x07, 0xce, 0x04, 0xb2, - 0x23, 0x5d, 0x3a, 0xea, 0x02, 0xf6, 0x36, 0x17, 0x48, 0x58, 0x22, 0x77, 0xe0, 0x96, 0x30, 0x7f, - 0x49, 0xea, 0x68, 0xf4, 0x91, 0xc3, 0x57, 0x83, 0xfb, 0xf2, 0xd1, 0x94, 0x74, 0x5a, 0x0b, 0xdb, - 0x73, 0x6f, 0xfe, 0xaa, 0xd5, 0xf4, 0x6b, 0x16, 0x1c, 0x1f, 0x54, 0x22, 0xc0, 0x8a, 0x9e, 0xd2, - 0x29, 0x25, 0x95, 0xe2, 0x53, 0xba, 0x17, 0x81, 0x61, 0x0c, 0x68, 0x33, 0x3b, 0x30, 0xb1, 0x41, - 0xde, 0x1d, 0x30, 0x9f, 0xb0, 0x7c, 0xac, 0x66, 0xd3, 0x4d, 0xc3, 0xff, 0xc3, 0xc0, 0x98, 0xdf, - 0x48, 0xa1, 0x41, 0xa9, 0xdc, 0x29, 0xd3, 0xac, 0xdc, 0x2b, 0x9f, 0x66, 0x3d, 0xea, 0xd7, 0x97, - 0x72, 0xad, 0x03, 0xd1, 0xd7, 0x67, 0xe0, 0x54, 0xd2, 0x07, 0xfa, 0x15, 0x76, 0x26, 0x0c, 0x8c, - 0x53, 0x95, 0x34, 0x22, 0x94, 0xce, 0x9f, 0xe6, 0xc8, 0xb9, 0xc3, 0x71, 0x64, 0xf3, 0x9b, 0x2c, - 0x18, 0x97, 0xcd, 0xc9, 0x21, 0x8c, 0x94, 0xae, 0x24, 0x46, 0x4a, 0x67, 0x87, 0x64, 0x38, 0x79, - 0xa3, 0xd4, 0x01, 0xd2, 0xf5, 0x9e, 0x01, 0xd2, 0xb9, 0x5d, 0x91, 0x86, 0x8f, 0x8b, 0xde, 0x03, - 0x53, 0x91, 0x40, 0xf8, 0x96, 0x28, 0x16, 0x75, 0x57, 0x95, 0x91, 0xb6, 0x8d, 0x66, 0x0c, 0x51, - 0x3b, 0x15, 0x51, 0x98, 0x14, 0x14, 0x62, 0x12, 0xf6, 0xc7, 0x2c, 0xa8, 0xfd, 0xf8, 0xc0, 0x74, - 0xaa, 0x4b, 0xdd, 0x1f, 0x13, 0xca, 0xe7, 0x1f, 0x3f, 0x2f, 0x8e, 0x3d, 0x79, 0x5e, 0x1c, 0x7b, - 0xf6, 0xbc, 0x38, 0xf6, 0x75, 0x58, 0xcc, 0x3c, 0x0e, 0x8b, 0x99, 0x27, 0x61, 0x31, 0xf3, 0x2c, - 0x2c, 0x66, 0xfe, 0x08, 0x8b, 0x99, 0xef, 0xfe, 0x2c, 0x8e, 0x7d, 0x9a, 0x6d, 0x2f, 0xfd, 0x1d, - 0x00, 0x00, 0xff, 0xff, 0x3c, 0x26, 0x41, 0xcb, 0x94, 0x19, 0x00, 0x00, + // 1605 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x58, 0x4d, 0x70, 0xd3, 0xd6, + 0x16, 0x8e, 0x7f, 0x12, 0x92, 0xe3, 0x90, 0x9f, 0x0b, 0x0f, 0x4c, 0x78, 0x58, 0x19, 0x3d, 0x86, + 0xc9, 0x7b, 0xaf, 0x48, 0x8d, 0x4b, 0x19, 0xba, 0x8c, 0xdc, 0x52, 0x98, 0xc6, 0x10, 0x6e, 0x02, + 0xa5, 0xbf, 0xc3, 0x8d, 0x7c, 0x71, 0x44, 0x2c, 0xc9, 0x23, 0xc9, 0x1e, 0xc2, 0x0c, 0x33, 0xed, + 0xa2, 0xfb, 0x6e, 0x68, 0xb7, 0xed, 0x4c, 0xb7, 0x5d, 0xb3, 0xee, 0x8e, 0x25, 0x0b, 0x66, 0xca, + 0xca, 0x53, 0xd4, 0x45, 0x17, 0x5d, 0x75, 0xcb, 0xaa, 0xa3, 0xab, 0x2b, 0x59, 0xb2, 0x2d, 0xc5, + 0x71, 0x42, 0xa6, 0xed, 0xb0, 0xb3, 0x7c, 0xcf, 0xf9, 0xce, 0xbd, 0xe7, 0xff, 0x1c, 0x50, 0xb6, + 0x2f, 0xd9, 0x92, 0x66, 0xca, 0xdb, 0xad, 0x4d, 0x6a, 0x19, 0xd4, 0xa1, 0xb6, 0xdc, 0xa6, 0x46, + 0xcd, 0xb4, 0x64, 0x7e, 0x40, 0x9a, 0x9a, 0x4c, 0x5a, 0x8e, 0x69, 0xab, 0xa4, 0xa1, 0x19, 0x75, + 0xb9, 0xbd, 0x2c, 0xd7, 0xa9, 0x41, 0x2d, 0xe2, 0xd0, 0x9a, 0xd4, 0xb4, 0x4c, 0xc7, 0x44, 0xa7, + 0x7c, 0x52, 0x89, 0x34, 0x35, 0x29, 0x42, 0x2a, 0xb5, 0x97, 0x17, 0xce, 0xd7, 0x35, 0x67, 0xab, + 0xb5, 0x29, 0xa9, 0xa6, 0x2e, 0xd7, 0xcd, 0xba, 0x29, 0x33, 0x8e, 0xcd, 0xd6, 0x5d, 0xf6, 0xc5, + 0x3e, 0xd8, 0x2f, 0x1f, 0x69, 0x41, 0x8c, 0x08, 0x55, 0x4d, 0x8b, 0x0e, 0x90, 0xb6, 0x70, 0xa1, + 0x4b, 0xa3, 0x13, 0x75, 0x4b, 0x33, 0xa8, 0xb5, 0x23, 0x37, 0xb7, 0xeb, 0x8c, 0xc9, 0xa2, 0xb6, + 0xd9, 0xb2, 0x54, 0xba, 0x27, 0x2e, 0x5b, 0xd6, 0xa9, 0x43, 0x06, 0xc9, 0x92, 0x93, 0xb8, 0xac, + 0x96, 0xe1, 0x68, 0x7a, 0xbf, 0x98, 0x8b, 0xbb, 0x31, 0xd8, 0xea, 0x16, 0xd5, 0x49, 0x2f, 0x9f, + 0xf8, 0x5b, 0x16, 0xce, 0x54, 0x4c, 0xc3, 0x21, 0x1e, 0x07, 0xe6, 0x8f, 0xa8, 0x52, 0xc7, 0xd2, + 0xd4, 0x75, 0xf6, 0x1b, 0x55, 0x20, 0x6f, 0x10, 0x9d, 0x16, 0x33, 0x8b, 0x99, 0xa5, 0x29, 0x45, + 0x7e, 0xd2, 0x11, 0xc6, 0xdc, 0x8e, 0x90, 0xbf, 0x46, 0x74, 0xfa, 0xb2, 0x23, 0x08, 0xfd, 0x8a, + 0x93, 0x02, 0x18, 0x8f, 0x04, 0x33, 0x66, 0x74, 0x1b, 0x8a, 0x0e, 0xb1, 0xea, 0xd4, 0x59, 0x69, + 0x53, 0x8b, 0xd4, 0xe9, 0x4d, 0x47, 0x6b, 0x68, 0x0f, 0x88, 0xa3, 0x99, 0x46, 0x31, 0xbb, 0x98, + 0x59, 0x1a, 0x57, 0xfe, 0xed, 0x76, 0x84, 0xe2, 0x46, 0x02, 0x0d, 0x4e, 0xe4, 0x46, 0x6d, 0x40, + 0xb1, 0xb3, 0x5b, 0xa4, 0xd1, 0xa2, 0xc5, 0xdc, 0x62, 0x66, 0xa9, 0x50, 0x96, 0xa4, 0xae, 0x83, + 0x84, 0x5a, 0x91, 0x9a, 0xdb, 0x75, 0xe6, 0x31, 0x81, 0xc9, 0xa4, 0x1b, 0x2d, 0x62, 0x38, 0x9a, + 0xb3, 0xa3, 0x9c, 0x70, 0x3b, 0x02, 0xda, 0xe8, 0x43, 0xc3, 0x03, 0x24, 0x20, 0x19, 0xa6, 0xd4, + 0x40, 0x6f, 0xc5, 0x71, 0xa6, 0x9b, 0x79, 0xae, 0x9b, 0xa9, 0xae, 0x42, 0xbb, 0x34, 0xe2, 0x1f, + 0x29, 0x9a, 0x76, 0x88, 0xd3, 0xb2, 0x0f, 0x46, 0xd3, 0x9f, 0xc0, 0x29, 0xb5, 0x65, 0x59, 0xd4, + 0x48, 0x56, 0xf5, 0x19, 0xb7, 0x23, 0x9c, 0xaa, 0x24, 0x11, 0xe1, 0x64, 0x7e, 0xf4, 0x10, 0x8e, + 0xc5, 0x0f, 0xf7, 0xa3, 0xed, 0xd3, 0xfc, 0x81, 0xc7, 0x2a, 0xfd, 0x90, 0x78, 0x90, 0x9c, 0xb8, + 0xce, 0xf3, 0x43, 0xe8, 0xfc, 0x51, 0x06, 0x4e, 0x57, 0x2c, 0xd3, 0xb6, 0x6f, 0x51, 0xcb, 0xd6, + 0x4c, 0xe3, 0xfa, 0xe6, 0x3d, 0xaa, 0x3a, 0x98, 0xde, 0xa5, 0x16, 0x35, 0x54, 0x8a, 0x16, 0x21, + 0xbf, 0xad, 0x19, 0x35, 0xae, 0xf1, 0xe9, 0x40, 0xe3, 0x1f, 0x68, 0x46, 0x0d, 0xb3, 0x13, 0x8f, + 0x82, 0xd9, 0x24, 0x1b, 0xa7, 0x88, 0x28, 0xbc, 0x0c, 0x40, 0x9a, 0x1a, 0x17, 0xc0, 0x54, 0x31, + 0xa5, 0x20, 0x4e, 0x07, 0x2b, 0x6b, 0x57, 0xf9, 0x09, 0x8e, 0x50, 0x89, 0xdf, 0xe4, 0xe0, 0xf8, + 0x7b, 0xf7, 0x1d, 0x6a, 0x19, 0xa4, 0x11, 0x0b, 0xb6, 0x32, 0x80, 0xce, 0xbe, 0xaf, 0x75, 0x1d, + 0x21, 0x04, 0xab, 0x86, 0x27, 0x38, 0x42, 0x85, 0x4c, 0x98, 0xf1, 0xbf, 0xd6, 0x69, 0x83, 0xaa, + 0x8e, 0x69, 0xb1, 0xcb, 0x16, 0xca, 0x6f, 0xa5, 0xd9, 0xc3, 0x96, 0xbc, 0xd4, 0x23, 0xb5, 0x97, + 0xa5, 0x55, 0xb2, 0x49, 0x1b, 0x01, 0xab, 0x82, 0xdc, 0x8e, 0x30, 0x53, 0x8d, 0xc1, 0xe1, 0x1e, + 0x78, 0x44, 0xa0, 0xe0, 0x07, 0xc4, 0x7e, 0xac, 0x3f, 0xeb, 0x76, 0x84, 0xc2, 0x46, 0x17, 0x06, + 0x47, 0x31, 0x13, 0xa2, 0x3a, 0xff, 0xaa, 0xa3, 0x5a, 0xfc, 0xae, 0xdf, 0x30, 0x7e, 0x6c, 0xfe, + 0x2d, 0x0c, 0xb3, 0x05, 0xd3, 0x3c, 0x6c, 0xf6, 0x63, 0x99, 0xe3, 0xfc, 0x59, 0xd3, 0x95, 0x08, + 0x16, 0x8e, 0x21, 0xa3, 0x9d, 0xc1, 0x89, 0x60, 0x34, 0x03, 0x9d, 0xdc, 0x4b, 0x12, 0x10, 0x1f, + 0x67, 0xe1, 0xe4, 0x15, 0xd3, 0xd2, 0x1e, 0x78, 0x51, 0xde, 0x58, 0x33, 0x6b, 0x2b, 0xbc, 0xf2, + 0x53, 0x0b, 0xdd, 0x81, 0x49, 0x4f, 0x7b, 0x35, 0xe2, 0x10, 0x66, 0xa3, 0x42, 0xf9, 0xcd, 0xe1, + 0x74, 0xed, 0x27, 0x86, 0x2a, 0x75, 0x48, 0xd7, 0xaa, 0xdd, 0xff, 0x70, 0x88, 0x8a, 0x6e, 0x43, + 0xde, 0x6e, 0x52, 0x95, 0x5b, 0xf2, 0xa2, 0x94, 0xd8, 0x81, 0x48, 0x09, 0x77, 0x5c, 0x6f, 0x52, + 0xb5, 0x9b, 0x47, 0xbc, 0x2f, 0xcc, 0x10, 0xd1, 0x1d, 0x98, 0xb0, 0x99, 0xaf, 0x71, 0xb3, 0x5d, + 0x1a, 0x01, 0x9b, 0xf1, 0x2b, 0x33, 0x1c, 0x7d, 0xc2, 0xff, 0xc6, 0x1c, 0x57, 0xfc, 0x2a, 0x07, + 0x8b, 0x09, 0x9c, 0x15, 0xd3, 0xa8, 0x69, 0x2c, 0xc5, 0x5f, 0x81, 0xbc, 0xb3, 0xd3, 0x0c, 0x5c, + 0xfc, 0x42, 0x70, 0xd1, 0x8d, 0x9d, 0xa6, 0x57, 0x84, 0xce, 0xee, 0xc6, 0xef, 0xd1, 0x61, 0x86, + 0x80, 0x56, 0xc3, 0x07, 0x65, 0x63, 0x58, 0xfc, 0x5a, 0x2f, 0x3b, 0xc2, 0x80, 0xae, 0x4b, 0x0a, + 0x91, 0xe2, 0x97, 0xf7, 0x32, 0x42, 0x83, 0xd8, 0xce, 0x86, 0x45, 0x0c, 0xdb, 0x97, 0xa4, 0xe9, + 0x81, 0x87, 0xff, 0x6f, 0x38, 0x23, 0x7b, 0x1c, 0xca, 0x02, 0xbf, 0x05, 0x5a, 0xed, 0x43, 0xc3, + 0x03, 0x24, 0xa0, 0x73, 0x30, 0x61, 0x51, 0x62, 0x9b, 0x06, 0x2f, 0x38, 0xa1, 0x72, 0x31, 0xfb, + 0x17, 0xf3, 0x53, 0xf4, 0x5f, 0x38, 0xa2, 0x53, 0xdb, 0x26, 0x75, 0xca, 0xbb, 0x81, 0x59, 0x4e, + 0x78, 0xa4, 0xea, 0xff, 0x8d, 0x83, 0x73, 0xf1, 0x59, 0x06, 0x4e, 0x27, 0xe8, 0x71, 0x55, 0xb3, + 0x1d, 0xf4, 0x69, 0x9f, 0x17, 0x4b, 0x43, 0x66, 0x0c, 0xcd, 0xf6, 0x7d, 0x78, 0x8e, 0xcb, 0x9e, + 0x0c, 0xfe, 0x89, 0x78, 0xf0, 0x87, 0x30, 0xae, 0x39, 0x54, 0xf7, 0xac, 0x92, 0x5b, 0x2a, 0x94, + 0xcb, 0x7b, 0x77, 0x33, 0xe5, 0x28, 0x87, 0x1f, 0xbf, 0xea, 0x01, 0x61, 0x1f, 0x4f, 0xfc, 0x3d, + 0x9b, 0xf8, 0x2c, 0xcf, 0xcd, 0x51, 0x1b, 0x66, 0xd8, 0x97, 0x9f, 0x8a, 0x31, 0xbd, 0xcb, 0x1f, + 0x97, 0x16, 0x44, 0x29, 0xc5, 0x5b, 0x39, 0xc1, 0x6f, 0x31, 0xb3, 0x1e, 0x43, 0xc5, 0x3d, 0x52, + 0xd0, 0x32, 0x14, 0x74, 0xcd, 0xc0, 0xb4, 0xd9, 0xd0, 0x54, 0x62, 0xf3, 0x1e, 0x88, 0x95, 0x9f, + 0x6a, 0xf7, 0x6f, 0x1c, 0xa5, 0x41, 0x6f, 0x43, 0x41, 0x27, 0xf7, 0x43, 0x96, 0x1c, 0x63, 0x39, + 0xc6, 0xe5, 0x15, 0xaa, 0xdd, 0x23, 0x1c, 0xa5, 0x43, 0xf7, 0xa0, 0xe4, 0xd7, 0x94, 0xca, 0xda, + 0xcd, 0x48, 0xdb, 0xb4, 0x46, 0x2d, 0x95, 0x1a, 0x8e, 0xe7, 0x1a, 0x79, 0x86, 0x24, 0xba, 0x1d, + 0xa1, 0xb4, 0x91, 0x4a, 0x89, 0x77, 0x41, 0x12, 0x7f, 0xca, 0xc1, 0x99, 0xd4, 0x34, 0x80, 0x2e, + 0x03, 0x32, 0x37, 0x6d, 0x6a, 0xb5, 0x69, 0xed, 0x7d, 0xbf, 0xeb, 0xf7, 0x1a, 0x14, 0x4f, 0xe7, + 0x39, 0xbf, 0x26, 0x5e, 0xef, 0x3b, 0xc5, 0x03, 0x38, 0x90, 0x0a, 0x47, 0xbd, 0xb8, 0xf0, 0xb5, + 0xac, 0xf1, 0x5e, 0x68, 0x6f, 0x41, 0x37, 0xef, 0x76, 0x84, 0xa3, 0xab, 0x51, 0x10, 0x1c, 0xc7, + 0x44, 0x2b, 0x30, 0xcb, 0x93, 0x7d, 0x8f, 0xd6, 0x4f, 0x72, 0xad, 0xcf, 0x56, 0xe2, 0xc7, 0xb8, + 0x97, 0xde, 0x83, 0xa8, 0x51, 0x5b, 0xb3, 0x68, 0x2d, 0x84, 0xc8, 0xc7, 0x21, 0xde, 0x8d, 0x1f, + 0xe3, 0x5e, 0x7a, 0xa4, 0x83, 0xc0, 0x51, 0x13, 0x2d, 0x38, 0xce, 0x20, 0xff, 0xe3, 0x76, 0x04, + 0xa1, 0x92, 0x4e, 0x8a, 0x77, 0xc3, 0x12, 0x1f, 0xe5, 0x81, 0xf7, 0x0e, 0x2c, 0x40, 0x2e, 0xc4, + 0x52, 0xef, 0x62, 0x4f, 0xea, 0x9d, 0x8b, 0x36, 0x8a, 0x91, 0x34, 0x7b, 0x03, 0x26, 0x4c, 0x16, + 0x19, 0xdc, 0x2e, 0xe7, 0x53, 0xc2, 0x29, 0x2c, 0x69, 0x21, 0x90, 0x02, 0x5e, 0x2e, 0xe3, 0xa1, + 0xc5, 0x81, 0xd0, 0x55, 0xc8, 0x37, 0xcd, 0x5a, 0x50, 0x88, 0xfe, 0x9f, 0x02, 0xb8, 0x66, 0xd6, + 0xec, 0x18, 0xdc, 0xa4, 0x77, 0x63, 0xef, 0x5f, 0xcc, 0x20, 0xd0, 0x47, 0x30, 0x19, 0x14, 0x7c, + 0xde, 0x1d, 0xc8, 0x29, 0x70, 0x83, 0x06, 0x50, 0x65, 0xda, 0x4b, 0x64, 0xc1, 0x09, 0x0e, 0xe1, + 0xd0, 0x43, 0x98, 0x57, 0x7b, 0xe7, 0xa9, 0xe2, 0x91, 0x5d, 0x6b, 0x67, 0xea, 0xb4, 0xab, 0xfc, + 0xcb, 0xed, 0x08, 0xf3, 0x7d, 0x24, 0xb8, 0x5f, 0x92, 0xf7, 0x32, 0xca, 0x3b, 0x45, 0xe6, 0x14, + 0xe9, 0x2f, 0x1b, 0xd4, 0xed, 0xfb, 0x2f, 0x0b, 0x4e, 0x70, 0x08, 0x27, 0x7e, 0x9b, 0x87, 0xe9, + 0x58, 0xf7, 0x79, 0xc8, 0x9e, 0xe1, 0xb7, 0x11, 0x07, 0xe6, 0x19, 0x3e, 0xdc, 0x81, 0x7a, 0x86, + 0x0f, 0x79, 0x48, 0x9e, 0xe1, 0x0b, 0x3b, 0x24, 0xcf, 0x88, 0xbc, 0x6c, 0x80, 0x67, 0x3c, 0xcb, + 0x01, 0xea, 0x0f, 0x62, 0xf4, 0x39, 0x4c, 0xf8, 0xe5, 0x62, 0x9f, 0x25, 0x35, 0x6c, 0x6e, 0x78, + 0xf5, 0xe4, 0xa8, 0x3d, 0xd3, 0x4f, 0x76, 0xa8, 0xe9, 0x87, 0x1e, 0xc4, 0x94, 0x18, 0xd6, 0xdc, + 0xc4, 0x49, 0xf1, 0x33, 0x98, 0xb4, 0x83, 0xf1, 0x2a, 0x3f, 0xfa, 0x78, 0xc5, 0x14, 0x1e, 0x0e, + 0x56, 0x21, 0x24, 0xaa, 0xc1, 0x34, 0x89, 0x4e, 0x38, 0xe3, 0x23, 0x3d, 0x63, 0xce, 0x1b, 0xa7, + 0x62, 0xa3, 0x4d, 0x0c, 0x55, 0xfc, 0xb9, 0xd7, 0xac, 0x7e, 0xd8, 0xff, 0x15, 0xcd, 0x7a, 0x78, + 0x33, 0xe6, 0x3f, 0xc2, 0xb2, 0xdf, 0x67, 0x61, 0xae, 0xb7, 0x48, 0x8e, 0xb4, 0x4c, 0x78, 0x30, + 0x70, 0x23, 0x92, 0x1d, 0xe9, 0xd2, 0xe1, 0x0c, 0x34, 0xe4, 0xae, 0x33, 0x6a, 0x89, 0xdc, 0x81, + 0x5b, 0x42, 0xfc, 0x21, 0xae, 0xa3, 0xd1, 0x17, 0x2e, 0x09, 0xeb, 0xc9, 0xec, 0x21, 0xad, 0x27, + 0x5f, 0xb1, 0x9a, 0x7e, 0xcc, 0xc2, 0xf1, 0xd7, 0x1b, 0xfa, 0xe1, 0x77, 0x79, 0x8f, 0xfb, 0xf5, + 0xf5, 0x7a, 0xcf, 0x3e, 0xd4, 0x8a, 0xed, 0xcb, 0x2c, 0x8c, 0xb3, 0xd1, 0xec, 0x10, 0x16, 0x6a, + 0x97, 0x63, 0x0b, 0xb5, 0xb3, 0x29, 0x15, 0x8e, 0xdd, 0x28, 0x71, 0x7d, 0x76, 0xad, 0x67, 0x7d, + 0x76, 0x6e, 0x57, 0xa4, 0xf4, 0x65, 0xd9, 0x3b, 0x30, 0x15, 0x0a, 0x44, 0x6f, 0x78, 0xbd, 0x2a, + 0x9f, 0x29, 0x33, 0xcc, 0xb6, 0xe1, 0x86, 0x25, 0x1c, 0x26, 0x43, 0x0a, 0x51, 0x83, 0x42, 0x44, + 0xc2, 0xde, 0x98, 0x3d, 0x6a, 0x3b, 0xba, 0x2e, 0x9e, 0xea, 0x52, 0xf7, 0xe7, 0x04, 0x65, 0xe9, + 0xc9, 0x8b, 0xd2, 0xd8, 0xd3, 0x17, 0xa5, 0xb1, 0xe7, 0x2f, 0x4a, 0x63, 0x5f, 0xb8, 0xa5, 0xcc, + 0x13, 0xb7, 0x94, 0x79, 0xea, 0x96, 0x32, 0xcf, 0xdd, 0x52, 0xe6, 0x17, 0xb7, 0x94, 0xf9, 0xfa, + 0xd7, 0xd2, 0xd8, 0xc7, 0xd9, 0xf6, 0xf2, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc7, 0x83, 0x99, + 0xe1, 0x70, 0x1d, 0x00, 0x00, +} + +func (m *ContainerResourceMetricSource) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContainerResourceMetricSource) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerResourceMetricSource) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Container) + copy(dAtA[i:], m.Container) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Container))) + i-- + dAtA[i] = 0x2a + if m.TargetAverageValue != nil { + { + size, err := m.TargetAverageValue.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.TargetAverageUtilization != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.TargetAverageUtilization)) + i-- + dAtA[i] = 0x10 + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ContainerResourceMetricStatus) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContainerResourceMetricStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerResourceMetricStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Container) + copy(dAtA[i:], m.Container) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Container))) + i-- + dAtA[i] = 0x22 + { + size, err := m.CurrentAverageValue.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.CurrentAverageUtilization != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.CurrentAverageUtilization)) + i-- + dAtA[i] = 0x10 + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *CrossVersionObjectReference) Marshal() (dAtA []byte, err error) { @@ -1138,6 +1300,18 @@ func (m *MetricSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContainerResource != nil { + { + size, err := m.ContainerResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.External != nil { { size, err := m.External.MarshalToSizedBuffer(dAtA[:i]) @@ -1214,6 +1388,18 @@ func (m *MetricStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContainerResource != nil { + { + size, err := m.ContainerResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.External != nil { { size, err := m.External.MarshalToSizedBuffer(dAtA[:i]) @@ -1723,6 +1909,44 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *ContainerResourceMetricSource) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if m.TargetAverageUtilization != nil { + n += 1 + sovGenerated(uint64(*m.TargetAverageUtilization)) + } + if m.TargetAverageValue != nil { + l = m.TargetAverageValue.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + l = len(m.Container) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *ContainerResourceMetricStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if m.CurrentAverageUtilization != nil { + n += 1 + sovGenerated(uint64(*m.CurrentAverageUtilization)) + } + l = m.CurrentAverageValue.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Container) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *CrossVersionObjectReference) Size() (n int) { if m == nil { return 0 @@ -1896,6 +2120,10 @@ func (m *MetricSpec) Size() (n int) { l = m.External.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.ContainerResource != nil { + l = m.ContainerResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -1923,6 +2151,10 @@ func (m *MetricStatus) Size() (n int) { l = m.External.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.ContainerResource != nil { + l = m.ContainerResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -2083,6 +2315,32 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *ContainerResourceMetricSource) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerResourceMetricSource{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `TargetAverageUtilization:` + valueToStringGenerated(this.TargetAverageUtilization) + `,`, + `TargetAverageValue:` + strings.Replace(fmt.Sprintf("%v", this.TargetAverageValue), "Quantity", "resource.Quantity", 1) + `,`, + `Container:` + fmt.Sprintf("%v", this.Container) + `,`, + `}`, + }, "") + return s +} +func (this *ContainerResourceMetricStatus) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerResourceMetricStatus{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `CurrentAverageUtilization:` + valueToStringGenerated(this.CurrentAverageUtilization) + `,`, + `CurrentAverageValue:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CurrentAverageValue), "Quantity", "resource.Quantity", 1), `&`, ``, 1) + `,`, + `Container:` + fmt.Sprintf("%v", this.Container) + `,`, + `}`, + }, "") + return s +} func (this *CrossVersionObjectReference) String() string { if this == nil { return "nil" @@ -2200,6 +2458,7 @@ func (this *MetricSpec) String() string { `Pods:` + strings.Replace(this.Pods.String(), "PodsMetricSource", "PodsMetricSource", 1) + `,`, `Resource:` + strings.Replace(this.Resource.String(), "ResourceMetricSource", "ResourceMetricSource", 1) + `,`, `External:` + strings.Replace(this.External.String(), "ExternalMetricSource", "ExternalMetricSource", 1) + `,`, + `ContainerResource:` + strings.Replace(this.ContainerResource.String(), "ContainerResourceMetricSource", "ContainerResourceMetricSource", 1) + `,`, `}`, }, "") return s @@ -2214,6 +2473,7 @@ func (this *MetricStatus) String() string { `Pods:` + strings.Replace(this.Pods.String(), "PodsMetricStatus", "PodsMetricStatus", 1) + `,`, `Resource:` + strings.Replace(this.Resource.String(), "ResourceMetricStatus", "ResourceMetricStatus", 1) + `,`, `External:` + strings.Replace(this.External.String(), "ExternalMetricStatus", "ExternalMetricStatus", 1) + `,`, + `ContainerResource:` + strings.Replace(this.ContainerResource.String(), "ContainerResourceMetricStatus", "ContainerResourceMetricStatus", 1) + `,`, `}`, }, "") return s @@ -2335,6 +2595,349 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *ContainerResourceMetricSource) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContainerResourceMetricSource: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContainerResourceMetricSource: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = k8s_io_api_core_v1.ResourceName(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetAverageUtilization", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.TargetAverageUtilization = &v + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetAverageValue", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TargetAverageValue == nil { + m.TargetAverageValue = &resource.Quantity{} + } + if err := m.TargetAverageValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Container", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Container = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContainerResourceMetricStatus) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContainerResourceMetricStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContainerResourceMetricStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = k8s_io_api_core_v1.ResourceName(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentAverageUtilization", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CurrentAverageUtilization = &v + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentAverageValue", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CurrentAverageValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Container", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Container = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *CrossVersionObjectReference) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3870,6 +4473,42 @@ func (m *MetricSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContainerResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ContainerResource == nil { + m.ContainerResource = &ContainerResourceMetricSource{} + } + if err := m.ContainerResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -4099,6 +4738,42 @@ func (m *MetricStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContainerResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ContainerResource == nil { + m.ContainerResource = &ContainerResourceMetricStatus{} + } + if err := m.ContainerResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/autoscaling/v1/generated.proto b/staging/src/k8s.io/api/autoscaling/v1/generated.proto index 51ace462371..08b8667c8d5 100644 --- a/staging/src/k8s.io/api/autoscaling/v1/generated.proto +++ b/staging/src/k8s.io/api/autoscaling/v1/generated.proto @@ -30,6 +30,60 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v1"; +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in the requests and limits, describing a single container in +// each of the pods of the current scale target(e.g. CPU or memory). The values will be +// averaged together before being compared to the target. Such metrics are built into +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +message ContainerResourceMetricSource { + // name is the name of the resource in question. + optional string name = 1; + + // targetAverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + optional int32 targetAverageUtilization = 2; + + // targetAverageValue is the target value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 3; + + // container is the name of the container in the pods of the scaling target. + optional string container = 5; +} + +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing a single container in each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +message ContainerResourceMetricStatus { + // name is the name of the resource in question. + optional string name = 1; + + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. It will only be + // present if `targetAverageValue` was set in the corresponding metric + // specification. + // +optional + optional int32 currentAverageUtilization = 2; + + // currentAverageValue is the current value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // It will always be set, regardless of the corresponding metric specification. + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 3; + + // container is the name of the container in the pods of the scaling taget + optional string container = 4; +} + // CrossVersionObjectReference contains enough information to let you identify the referred resource. message CrossVersionObjectReference { // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" @@ -184,8 +238,10 @@ message HorizontalPodAutoscalerStatus { // MetricSpec specifies how to scale based on a single metric // (only `type` and one other matching field should be set at once). message MetricSpec { - // type is the type of metric source. It should be one of "Object", - // "Pods" or "Resource", each mapping to a matching field in the object. + // type is the type of metric source. It should be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each mapping to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled optional string type = 1; // object refers to a metric describing a single kubernetes object @@ -207,6 +263,15 @@ message MetricSpec { // +optional optional ResourceMetricSource resource = 4; + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod of the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. + // +optional + optional ContainerResourceMetricSource containerResource = 7; + // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -218,8 +283,10 @@ message MetricSpec { // MetricStatus describes the last-read state of a single metric. message MetricStatus { - // type is the type of metric source. It will be one of "Object", - // "Pods" or "Resource", each corresponds to a matching field in the object. + // type is the type of metric source. It will be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each corresponds to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled optional string type = 1; // object refers to a metric describing a single kubernetes object @@ -241,6 +308,14 @@ message MetricStatus { // +optional optional ResourceMetricStatus resource = 4; + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ContainerResourceMetricStatus containerResource = 7; + // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster diff --git a/staging/src/k8s.io/api/autoscaling/v1/types.go b/staging/src/k8s.io/api/autoscaling/v1/types.go index 55b2a0d6b68..3343177b2ad 100644 --- a/staging/src/k8s.io/api/autoscaling/v1/types.go +++ b/staging/src/k8s.io/api/autoscaling/v1/types.go @@ -165,6 +165,12 @@ const ( // Kubernetes, and have special scaling options on top of those available // to normal per-pod metrics (the "pods" source). ResourceMetricSourceType MetricSourceType = "Resource" + // ContainerResourceMetricSourceType is a resource metric known to Kubernetes, as + // specified in requests and limits, describing a single container in each pod in the current + // scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics (the "pods" source). + ContainerResourceMetricSourceType MetricSourceType = "ContainerResource" // ExternalMetricSourceType is a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -176,8 +182,10 @@ const ( // MetricSpec specifies how to scale based on a single metric // (only `type` and one other matching field should be set at once). type MetricSpec struct { - // type is the type of metric source. It should be one of "Object", - // "Pods" or "Resource", each mapping to a matching field in the object. + // type is the type of metric source. It should be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each mapping to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"` // object refers to a metric describing a single kubernetes object @@ -196,6 +204,14 @@ type MetricSpec struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricSource `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"` + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod of the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. + // +optional + ContainerResource *ContainerResourceMetricSource `json:"containerResource,omitempty" protobuf:"bytes,7,opt,name=containerResource"` // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -267,6 +283,30 @@ type ResourceMetricSource struct { TargetAverageValue *resource.Quantity `json:"targetAverageValue,omitempty" protobuf:"bytes,3,opt,name=targetAverageValue"` } +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in the requests and limits, describing a single container in +// each of the pods of the current scale target(e.g. CPU or memory). The values will be +// averaged together before being compared to the target. Such metrics are built into +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +type ContainerResourceMetricSource struct { + // name is the name of the resource in question. + Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"` + // targetAverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + TargetAverageUtilization *int32 `json:"targetAverageUtilization,omitempty" protobuf:"varint,2,opt,name=targetAverageUtilization"` + // targetAverageValue is the target value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // +optional + TargetAverageValue *resource.Quantity `json:"targetAverageValue,omitempty" protobuf:"bytes,3,opt,name=targetAverageValue"` + // container is the name of the container in the pods of the scaling target. + Container string `json:"container" protobuf:"bytes,5,opt,name=container"` +} + // ExternalMetricSource indicates how to scale on a metric not associated with // any Kubernetes object (for example length of queue in cloud // messaging service, or QPS from loadbalancer running outside of cluster). @@ -289,8 +329,10 @@ type ExternalMetricSource struct { // MetricStatus describes the last-read state of a single metric. type MetricStatus struct { - // type is the type of metric source. It will be one of "Object", - // "Pods" or "Resource", each corresponds to a matching field in the object. + // type is the type of metric source. It will be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each corresponds to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"` // object refers to a metric describing a single kubernetes object @@ -309,6 +351,13 @@ type MetricStatus struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricStatus `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"` + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricStatus `json:"containerResource,omitempty" protobuf:"bytes,7,opt,name=containerResource"` // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -414,6 +463,30 @@ type ResourceMetricStatus struct { CurrentAverageValue resource.Quantity `json:"currentAverageValue" protobuf:"bytes,3,name=currentAverageValue"` } +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing a single container in each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +type ContainerResourceMetricStatus struct { + // name is the name of the resource in question. + Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"` + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. It will only be + // present if `targetAverageValue` was set in the corresponding metric + // specification. + // +optional + CurrentAverageUtilization *int32 `json:"currentAverageUtilization,omitempty" protobuf:"bytes,2,opt,name=currentAverageUtilization"` + // currentAverageValue is the current value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // It will always be set, regardless of the corresponding metric specification. + CurrentAverageValue resource.Quantity `json:"currentAverageValue" protobuf:"bytes,3,name=currentAverageValue"` + // container is the name of the container in the pods of the scaling taget + Container string `json:"container" protobuf:"bytes,4,opt,name=container"` +} + // ExternalMetricStatus indicates the current value of a global metric // not associated with any Kubernetes object. type ExternalMetricStatus struct { diff --git a/staging/src/k8s.io/api/autoscaling/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/autoscaling/v1/types_swagger_doc_generated.go index 129ce2b484e..192dc5f3985 100644 --- a/staging/src/k8s.io/api/autoscaling/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/autoscaling/v1/types_swagger_doc_generated.go @@ -27,6 +27,30 @@ package v1 // Those methods can be generated by using hack/update-generated-swagger-docs.sh // AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_ContainerResourceMetricSource = map[string]string{ + "": "ContainerResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in the requests and limits, describing a single container in each of the pods of the current scale target(e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built into Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. Only one \"target\" type should be set.", + "name": "name is the name of the resource in question.", + "targetAverageUtilization": "targetAverageUtilization is the target value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods.", + "targetAverageValue": "targetAverageValue is the target value of the average of the resource metric across all relevant pods, as a raw value (instead of as a percentage of the request), similar to the \"pods\" metric source type.", + "container": "container is the name of the container in the pods of the scaling target.", +} + +func (ContainerResourceMetricSource) SwaggerDoc() map[string]string { + return map_ContainerResourceMetricSource +} + +var map_ContainerResourceMetricStatus = map[string]string{ + "": "ContainerResourceMetricStatus indicates the current value of a resource metric known to Kubernetes, as specified in requests and limits, describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "name": "name is the name of the resource in question.", + "currentAverageUtilization": "currentAverageUtilization is the current value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods. It will only be present if `targetAverageValue` was set in the corresponding metric specification.", + "currentAverageValue": "currentAverageValue is the current value of the average of the resource metric across all relevant pods, as a raw value (instead of as a percentage of the request), similar to the \"pods\" metric source type. It will always be set, regardless of the corresponding metric specification.", + "container": "container is the name of the container in the pods of the scaling taget", +} + +func (ContainerResourceMetricStatus) SwaggerDoc() map[string]string { + return map_ContainerResourceMetricStatus +} + var map_CrossVersionObjectReference = map[string]string{ "": "CrossVersionObjectReference contains enough information to let you identify the referred resource.", "kind": "Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\"", @@ -122,12 +146,13 @@ func (HorizontalPodAutoscalerStatus) SwaggerDoc() map[string]string { } var map_MetricSpec = map[string]string{ - "": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", - "type": "type is the type of metric source. It should be one of \"Object\", \"Pods\" or \"Resource\", each mapping to a matching field in the object.", - "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", - "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", - "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", - "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", + "": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", + "type": "type is the type of metric source. It should be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each mapping to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", + "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", + "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", + "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "containerResource": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag.", + "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", } func (MetricSpec) SwaggerDoc() map[string]string { @@ -135,12 +160,13 @@ func (MetricSpec) SwaggerDoc() map[string]string { } var map_MetricStatus = map[string]string{ - "": "MetricStatus describes the last-read state of a single metric.", - "type": "type is the type of metric source. It will be one of \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object.", - "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", - "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", - "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", - "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", + "": "MetricStatus describes the last-read state of a single metric.", + "type": "type is the type of metric source. It will be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", + "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", + "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", + "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "containerResource": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", } func (MetricStatus) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/autoscaling/v1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/autoscaling/v1/zz_generated.deepcopy.go index ddb60112803..05ae6ebda72 100644 --- a/staging/src/k8s.io/api/autoscaling/v1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/autoscaling/v1/zz_generated.deepcopy.go @@ -25,6 +25,54 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricSource) DeepCopyInto(out *ContainerResourceMetricSource) { + *out = *in + if in.TargetAverageUtilization != nil { + in, out := &in.TargetAverageUtilization, &out.TargetAverageUtilization + *out = new(int32) + **out = **in + } + if in.TargetAverageValue != nil { + in, out := &in.TargetAverageValue, &out.TargetAverageValue + x := (*in).DeepCopy() + *out = &x + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricSource. +func (in *ContainerResourceMetricSource) DeepCopy() *ContainerResourceMetricSource { + if in == nil { + return nil + } + out := new(ContainerResourceMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricStatus) DeepCopyInto(out *ContainerResourceMetricStatus) { + *out = *in + if in.CurrentAverageUtilization != nil { + in, out := &in.CurrentAverageUtilization, &out.CurrentAverageUtilization + *out = new(int32) + **out = **in + } + out.CurrentAverageValue = in.CurrentAverageValue.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricStatus. +func (in *ContainerResourceMetricStatus) DeepCopy() *ContainerResourceMetricStatus { + if in == nil { + return nil + } + out := new(ContainerResourceMetricStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { *out = *in @@ -252,6 +300,11 @@ func (in *MetricSpec) DeepCopyInto(out *MetricSpec) { *out = new(ResourceMetricSource) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricSource) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricSource) @@ -288,6 +341,11 @@ func (in *MetricStatus) DeepCopyInto(out *MetricStatus) { *out = new(ResourceMetricStatus) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricStatus) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricStatus) diff --git a/staging/src/k8s.io/api/autoscaling/v2beta1/generated.pb.go b/staging/src/k8s.io/api/autoscaling/v2beta1/generated.pb.go index e129e41b8bf..750808f8d21 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta1/generated.pb.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta1/generated.pb.go @@ -47,10 +47,66 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +func (m *ContainerResourceMetricSource) Reset() { *m = ContainerResourceMetricSource{} } +func (*ContainerResourceMetricSource) ProtoMessage() {} +func (*ContainerResourceMetricSource) Descriptor() ([]byte, []int) { + return fileDescriptor_26c1bfc7a52d0478, []int{0} +} +func (m *ContainerResourceMetricSource) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerResourceMetricSource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ContainerResourceMetricSource) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerResourceMetricSource.Merge(m, src) +} +func (m *ContainerResourceMetricSource) XXX_Size() int { + return m.Size() +} +func (m *ContainerResourceMetricSource) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerResourceMetricSource.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerResourceMetricSource proto.InternalMessageInfo + +func (m *ContainerResourceMetricStatus) Reset() { *m = ContainerResourceMetricStatus{} } +func (*ContainerResourceMetricStatus) ProtoMessage() {} +func (*ContainerResourceMetricStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_26c1bfc7a52d0478, []int{1} +} +func (m *ContainerResourceMetricStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerResourceMetricStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ContainerResourceMetricStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerResourceMetricStatus.Merge(m, src) +} +func (m *ContainerResourceMetricStatus) XXX_Size() int { + return m.Size() +} +func (m *ContainerResourceMetricStatus) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerResourceMetricStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerResourceMetricStatus proto.InternalMessageInfo + func (m *CrossVersionObjectReference) Reset() { *m = CrossVersionObjectReference{} } func (*CrossVersionObjectReference) ProtoMessage() {} func (*CrossVersionObjectReference) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{0} + return fileDescriptor_26c1bfc7a52d0478, []int{2} } func (m *CrossVersionObjectReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -78,7 +134,7 @@ var xxx_messageInfo_CrossVersionObjectReference proto.InternalMessageInfo func (m *ExternalMetricSource) Reset() { *m = ExternalMetricSource{} } func (*ExternalMetricSource) ProtoMessage() {} func (*ExternalMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{1} + return fileDescriptor_26c1bfc7a52d0478, []int{3} } func (m *ExternalMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +162,7 @@ var xxx_messageInfo_ExternalMetricSource proto.InternalMessageInfo func (m *ExternalMetricStatus) Reset() { *m = ExternalMetricStatus{} } func (*ExternalMetricStatus) ProtoMessage() {} func (*ExternalMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{2} + return fileDescriptor_26c1bfc7a52d0478, []int{4} } func (m *ExternalMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -134,7 +190,7 @@ var xxx_messageInfo_ExternalMetricStatus proto.InternalMessageInfo func (m *HorizontalPodAutoscaler) Reset() { *m = HorizontalPodAutoscaler{} } func (*HorizontalPodAutoscaler) ProtoMessage() {} func (*HorizontalPodAutoscaler) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{3} + return fileDescriptor_26c1bfc7a52d0478, []int{5} } func (m *HorizontalPodAutoscaler) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -162,7 +218,7 @@ var xxx_messageInfo_HorizontalPodAutoscaler proto.InternalMessageInfo func (m *HorizontalPodAutoscalerCondition) Reset() { *m = HorizontalPodAutoscalerCondition{} } func (*HorizontalPodAutoscalerCondition) ProtoMessage() {} func (*HorizontalPodAutoscalerCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{4} + return fileDescriptor_26c1bfc7a52d0478, []int{6} } func (m *HorizontalPodAutoscalerCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -190,7 +246,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerCondition proto.InternalMessageInfo func (m *HorizontalPodAutoscalerList) Reset() { *m = HorizontalPodAutoscalerList{} } func (*HorizontalPodAutoscalerList) ProtoMessage() {} func (*HorizontalPodAutoscalerList) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{5} + return fileDescriptor_26c1bfc7a52d0478, []int{7} } func (m *HorizontalPodAutoscalerList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -218,7 +274,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerList proto.InternalMessageInfo func (m *HorizontalPodAutoscalerSpec) Reset() { *m = HorizontalPodAutoscalerSpec{} } func (*HorizontalPodAutoscalerSpec) ProtoMessage() {} func (*HorizontalPodAutoscalerSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{6} + return fileDescriptor_26c1bfc7a52d0478, []int{8} } func (m *HorizontalPodAutoscalerSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -246,7 +302,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerSpec proto.InternalMessageInfo func (m *HorizontalPodAutoscalerStatus) Reset() { *m = HorizontalPodAutoscalerStatus{} } func (*HorizontalPodAutoscalerStatus) ProtoMessage() {} func (*HorizontalPodAutoscalerStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{7} + return fileDescriptor_26c1bfc7a52d0478, []int{9} } func (m *HorizontalPodAutoscalerStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -274,7 +330,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerStatus proto.InternalMessageInfo func (m *MetricSpec) Reset() { *m = MetricSpec{} } func (*MetricSpec) ProtoMessage() {} func (*MetricSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{8} + return fileDescriptor_26c1bfc7a52d0478, []int{10} } func (m *MetricSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -302,7 +358,7 @@ var xxx_messageInfo_MetricSpec proto.InternalMessageInfo func (m *MetricStatus) Reset() { *m = MetricStatus{} } func (*MetricStatus) ProtoMessage() {} func (*MetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{9} + return fileDescriptor_26c1bfc7a52d0478, []int{11} } func (m *MetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -330,7 +386,7 @@ var xxx_messageInfo_MetricStatus proto.InternalMessageInfo func (m *ObjectMetricSource) Reset() { *m = ObjectMetricSource{} } func (*ObjectMetricSource) ProtoMessage() {} func (*ObjectMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{10} + return fileDescriptor_26c1bfc7a52d0478, []int{12} } func (m *ObjectMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -358,7 +414,7 @@ var xxx_messageInfo_ObjectMetricSource proto.InternalMessageInfo func (m *ObjectMetricStatus) Reset() { *m = ObjectMetricStatus{} } func (*ObjectMetricStatus) ProtoMessage() {} func (*ObjectMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{11} + return fileDescriptor_26c1bfc7a52d0478, []int{13} } func (m *ObjectMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -386,7 +442,7 @@ var xxx_messageInfo_ObjectMetricStatus proto.InternalMessageInfo func (m *PodsMetricSource) Reset() { *m = PodsMetricSource{} } func (*PodsMetricSource) ProtoMessage() {} func (*PodsMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{12} + return fileDescriptor_26c1bfc7a52d0478, []int{14} } func (m *PodsMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -414,7 +470,7 @@ var xxx_messageInfo_PodsMetricSource proto.InternalMessageInfo func (m *PodsMetricStatus) Reset() { *m = PodsMetricStatus{} } func (*PodsMetricStatus) ProtoMessage() {} func (*PodsMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{13} + return fileDescriptor_26c1bfc7a52d0478, []int{15} } func (m *PodsMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -442,7 +498,7 @@ var xxx_messageInfo_PodsMetricStatus proto.InternalMessageInfo func (m *ResourceMetricSource) Reset() { *m = ResourceMetricSource{} } func (*ResourceMetricSource) ProtoMessage() {} func (*ResourceMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{14} + return fileDescriptor_26c1bfc7a52d0478, []int{16} } func (m *ResourceMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -470,7 +526,7 @@ var xxx_messageInfo_ResourceMetricSource proto.InternalMessageInfo func (m *ResourceMetricStatus) Reset() { *m = ResourceMetricStatus{} } func (*ResourceMetricStatus) ProtoMessage() {} func (*ResourceMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_26c1bfc7a52d0478, []int{15} + return fileDescriptor_26c1bfc7a52d0478, []int{17} } func (m *ResourceMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -496,6 +552,8 @@ func (m *ResourceMetricStatus) XXX_DiscardUnknown() { var xxx_messageInfo_ResourceMetricStatus proto.InternalMessageInfo func init() { + proto.RegisterType((*ContainerResourceMetricSource)(nil), "k8s.io.api.autoscaling.v2beta1.ContainerResourceMetricSource") + proto.RegisterType((*ContainerResourceMetricStatus)(nil), "k8s.io.api.autoscaling.v2beta1.ContainerResourceMetricStatus") proto.RegisterType((*CrossVersionObjectReference)(nil), "k8s.io.api.autoscaling.v2beta1.CrossVersionObjectReference") proto.RegisterType((*ExternalMetricSource)(nil), "k8s.io.api.autoscaling.v2beta1.ExternalMetricSource") proto.RegisterType((*ExternalMetricStatus)(nil), "k8s.io.api.autoscaling.v2beta1.ExternalMetricStatus") @@ -519,100 +577,203 @@ func init() { } var fileDescriptor_26c1bfc7a52d0478 = []byte{ - // 1475 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0xcb, 0x8f, 0x1b, 0x45, - 0x13, 0x5f, 0x3f, 0x76, 0xb3, 0x69, 0x6f, 0x76, 0xf7, 0xeb, 0x44, 0x89, 0xb3, 0xf9, 0x62, 0xaf, - 0x2c, 0x84, 0x42, 0x44, 0x66, 0x12, 0xb3, 0x3c, 0x24, 0x84, 0xc4, 0xda, 0x40, 0x12, 0xb1, 0x4e, - 0x42, 0xef, 0x26, 0x42, 0x90, 0x20, 0xda, 0x33, 0x1d, 0x6f, 0xb3, 0x9e, 0x19, 0x6b, 0xba, 0x6d, - 0x65, 0x83, 0x90, 0xb8, 0x70, 0xe7, 0x02, 0x67, 0x90, 0x38, 0x21, 0xb8, 0xc2, 0x99, 0x5b, 0x8e, - 0x39, 0x26, 0x02, 0x59, 0x64, 0xf8, 0x2f, 0x72, 0x42, 0xfd, 0x98, 0xf1, 0x8c, 0x1f, 0x6b, 0xc7, - 0x38, 0xe1, 0x71, 0x9b, 0xee, 0xaa, 0xfa, 0x55, 0x4f, 0xfd, 0xaa, 0xab, 0xbb, 0x1a, 0x5c, 0xdc, - 0x7b, 0x8d, 0x19, 0xd4, 0x33, 0xf7, 0xda, 0x75, 0xe2, 0xbb, 0x84, 0x13, 0x66, 0x76, 0x88, 0x6b, - 0x7b, 0xbe, 0xa9, 0x05, 0xb8, 0x45, 0x4d, 0xdc, 0xe6, 0x1e, 0xb3, 0x70, 0x93, 0xba, 0x0d, 0xb3, - 0x53, 0xae, 0x13, 0x8e, 0x2f, 0x98, 0x0d, 0xe2, 0x12, 0x1f, 0x73, 0x62, 0x1b, 0x2d, 0xdf, 0xe3, - 0x1e, 0x2c, 0x28, 0x7d, 0x03, 0xb7, 0xa8, 0x11, 0xd3, 0x37, 0xb4, 0xfe, 0xda, 0xb9, 0x06, 0xe5, - 0xbb, 0xed, 0xba, 0x61, 0x79, 0x8e, 0xd9, 0xf0, 0x1a, 0x9e, 0x29, 0xcd, 0xea, 0xed, 0xdb, 0x72, - 0x24, 0x07, 0xf2, 0x4b, 0xc1, 0xad, 0x95, 0x62, 0xee, 0x2d, 0xcf, 0x27, 0x66, 0x67, 0xc0, 0xe5, - 0xda, 0x46, 0x4f, 0xc7, 0xc1, 0xd6, 0x2e, 0x75, 0x89, 0xbf, 0x6f, 0xb6, 0xf6, 0x1a, 0xd2, 0xc8, - 0x27, 0xcc, 0x6b, 0xfb, 0x16, 0x79, 0x22, 0x2b, 0x66, 0x3a, 0x84, 0xe3, 0x61, 0xbe, 0xcc, 0x51, - 0x56, 0x7e, 0xdb, 0xe5, 0xd4, 0x19, 0x74, 0xf3, 0xca, 0x38, 0x03, 0x66, 0xed, 0x12, 0x07, 0xf7, - 0xdb, 0x95, 0xbe, 0x4a, 0x81, 0x53, 0x55, 0xdf, 0x63, 0xec, 0x06, 0xf1, 0x19, 0xf5, 0xdc, 0xab, - 0xf5, 0x4f, 0x88, 0xc5, 0x11, 0xb9, 0x4d, 0x7c, 0xe2, 0x5a, 0x04, 0xae, 0x83, 0xec, 0x1e, 0x75, - 0xed, 0x7c, 0x6a, 0x3d, 0x75, 0xe6, 0x70, 0x65, 0xe9, 0x5e, 0xb7, 0x38, 0x17, 0x74, 0x8b, 0xd9, - 0x77, 0xa9, 0x6b, 0x23, 0x29, 0x11, 0x1a, 0x2e, 0x76, 0x48, 0x3e, 0x9d, 0xd4, 0xb8, 0x82, 0x1d, - 0x82, 0xa4, 0x04, 0x96, 0x01, 0xc0, 0x2d, 0xaa, 0x1d, 0xe4, 0x33, 0x52, 0x0f, 0x6a, 0x3d, 0xb0, - 0x79, 0xed, 0xb2, 0x96, 0xa0, 0x98, 0x56, 0xe9, 0xeb, 0x0c, 0x38, 0xf6, 0xf6, 0x1d, 0x4e, 0x7c, - 0x17, 0x37, 0x6b, 0x84, 0xfb, 0xd4, 0xda, 0x96, 0xf1, 0x15, 0x60, 0x8e, 0x1c, 0x0b, 0x07, 0x7a, - 0x59, 0x11, 0x58, 0x2d, 0x92, 0xa0, 0x98, 0x16, 0xf4, 0xc0, 0xb2, 0x1a, 0x6d, 0x93, 0x26, 0xb1, - 0xb8, 0xe7, 0xcb, 0xc5, 0xe6, 0xca, 0x2f, 0x19, 0xbd, 0x2c, 0x8a, 0xa2, 0x66, 0xb4, 0xf6, 0x1a, - 0x62, 0x82, 0x19, 0x82, 0x1c, 0xa3, 0x73, 0xc1, 0xd8, 0xc2, 0x75, 0xd2, 0x0c, 0x4d, 0x2b, 0x30, - 0xe8, 0x16, 0x97, 0x6b, 0x09, 0x38, 0xd4, 0x07, 0x0f, 0x31, 0xc8, 0x71, 0xec, 0x37, 0x08, 0xbf, - 0x81, 0x9b, 0x6d, 0x22, 0x7f, 0x39, 0x57, 0x36, 0x0e, 0xf2, 0x66, 0x84, 0x09, 0x64, 0xbc, 0xd7, - 0xc6, 0x2e, 0xa7, 0x7c, 0xbf, 0xb2, 0x12, 0x74, 0x8b, 0xb9, 0x9d, 0x1e, 0x0c, 0x8a, 0x63, 0xc2, - 0x0e, 0x80, 0x6a, 0xb8, 0xd9, 0x21, 0x3e, 0x6e, 0x10, 0xe5, 0x29, 0x3b, 0x95, 0xa7, 0xe3, 0x41, - 0xb7, 0x08, 0x77, 0x06, 0xd0, 0xd0, 0x10, 0x0f, 0xa5, 0x6f, 0x06, 0x89, 0xe1, 0x98, 0xb7, 0xd9, - 0xbf, 0x83, 0x98, 0x5d, 0xb0, 0x64, 0xb5, 0x7d, 0x9f, 0xb8, 0x7f, 0x89, 0x99, 0x63, 0xfa, 0xb7, - 0x96, 0xaa, 0x31, 0x2c, 0x94, 0x40, 0x86, 0xfb, 0xe0, 0xa8, 0x1e, 0xcf, 0x80, 0xa0, 0x13, 0x41, - 0xb7, 0x78, 0xb4, 0x3a, 0x08, 0x87, 0x86, 0xf9, 0x28, 0xfd, 0x92, 0x06, 0x27, 0x2e, 0x79, 0x3e, - 0xbd, 0xeb, 0xb9, 0x1c, 0x37, 0xaf, 0x79, 0xf6, 0xa6, 0x2e, 0x90, 0xc4, 0x87, 0x1f, 0x83, 0x45, - 0x11, 0x3d, 0x1b, 0x73, 0x2c, 0x39, 0xca, 0x95, 0xcf, 0x4f, 0x16, 0x6b, 0x55, 0x18, 0x6a, 0x84, - 0xe3, 0x1e, 0xab, 0xbd, 0x39, 0x14, 0xa1, 0xc2, 0x5b, 0x20, 0xcb, 0x5a, 0xc4, 0xd2, 0x4c, 0xbe, - 0x6e, 0x1c, 0x5c, 0xa8, 0x8d, 0x11, 0x0b, 0xdd, 0x6e, 0x11, 0xab, 0x57, 0x4c, 0xc4, 0x08, 0x49, - 0x58, 0x48, 0xc0, 0x02, 0x93, 0x09, 0xa7, 0xb9, 0x7b, 0x63, 0x5a, 0x07, 0x12, 0xa4, 0xb2, 0xac, - 0x5d, 0x2c, 0xa8, 0x31, 0xd2, 0xe0, 0xa5, 0x2f, 0x32, 0x60, 0x7d, 0x84, 0x65, 0xd5, 0x73, 0x6d, - 0xca, 0xa9, 0xe7, 0xc2, 0x4b, 0x20, 0xcb, 0xf7, 0x5b, 0x61, 0xb2, 0x6f, 0x84, 0xab, 0xdd, 0xd9, - 0x6f, 0x91, 0xc7, 0xdd, 0xe2, 0x73, 0xe3, 0xec, 0x85, 0x1e, 0x92, 0x08, 0x70, 0x2b, 0xfa, 0xab, - 0x74, 0x02, 0x4b, 0x2f, 0xeb, 0x71, 0xb7, 0x38, 0xe4, 0x84, 0x32, 0x22, 0xa4, 0xe4, 0xe2, 0x45, - 0x6d, 0x68, 0x62, 0xc6, 0x77, 0x7c, 0xec, 0x32, 0xe5, 0x89, 0x3a, 0x61, 0xae, 0x9f, 0x9d, 0x8c, - 0x6e, 0x61, 0x51, 0x59, 0xd3, 0xab, 0x80, 0x5b, 0x03, 0x68, 0x68, 0x88, 0x07, 0xf8, 0x3c, 0x58, - 0xf0, 0x09, 0x66, 0x9e, 0x2b, 0xd3, 0xfc, 0x70, 0x2f, 0xb8, 0x48, 0xce, 0x22, 0x2d, 0x85, 0x2f, - 0x80, 0x43, 0x0e, 0x61, 0x0c, 0x37, 0x48, 0x7e, 0x5e, 0x2a, 0xae, 0x68, 0xc5, 0x43, 0x35, 0x35, - 0x8d, 0x42, 0x79, 0xe9, 0x61, 0x0a, 0x9c, 0x1a, 0x11, 0xc7, 0x2d, 0xca, 0x38, 0xbc, 0x39, 0x90, - 0xcf, 0xc6, 0x84, 0xb5, 0x83, 0x32, 0x95, 0xcd, 0xab, 0xda, 0xf7, 0x62, 0x38, 0x13, 0xcb, 0xe5, - 0x9b, 0x60, 0x9e, 0x72, 0xe2, 0x08, 0x56, 0x32, 0x67, 0x72, 0xe5, 0x57, 0xa7, 0xcc, 0xb5, 0xca, - 0x11, 0xed, 0x63, 0xfe, 0xb2, 0x40, 0x43, 0x0a, 0xb4, 0xf4, 0x6b, 0x7a, 0xe4, 0xbf, 0x89, 0x84, - 0x87, 0x9f, 0x82, 0x65, 0x39, 0x52, 0x95, 0x19, 0x91, 0xdb, 0xfa, 0x0f, 0xc7, 0xee, 0xa9, 0x03, - 0x0e, 0xf4, 0xca, 0x71, 0xbd, 0x94, 0xe5, 0xed, 0x04, 0x34, 0xea, 0x73, 0x05, 0x2f, 0x80, 0x9c, - 0x43, 0x5d, 0x44, 0x5a, 0x4d, 0x6a, 0x61, 0x95, 0x96, 0xf3, 0xea, 0x48, 0xaa, 0xf5, 0xa6, 0x51, - 0x5c, 0x07, 0xbe, 0x0c, 0x72, 0x0e, 0xbe, 0x13, 0x99, 0x64, 0xa4, 0xc9, 0x51, 0xed, 0x2f, 0x57, - 0xeb, 0x89, 0x50, 0x5c, 0x0f, 0x5e, 0x17, 0xd9, 0x20, 0xaa, 0x34, 0xcb, 0x67, 0x65, 0x98, 0xcf, - 0x8e, 0xfb, 0x3f, 0x5d, 0xe4, 0x45, 0x89, 0x88, 0x65, 0x8e, 0x84, 0x40, 0x21, 0x56, 0xe9, 0xa7, - 0x2c, 0x38, 0x7d, 0xe0, 0xde, 0x87, 0xef, 0x00, 0xe8, 0xd5, 0x19, 0xf1, 0x3b, 0xc4, 0xbe, 0xa8, - 0xae, 0x45, 0xe2, 0x7e, 0x22, 0x62, 0x9c, 0x51, 0x47, 0xe2, 0xd5, 0x01, 0x29, 0x1a, 0x62, 0x01, - 0x2d, 0x70, 0x44, 0x6c, 0x06, 0x15, 0x50, 0xaa, 0xaf, 0x42, 0x4f, 0xb6, 0xd3, 0xfe, 0x17, 0x74, - 0x8b, 0x47, 0xb6, 0xe2, 0x20, 0x28, 0x89, 0x09, 0x37, 0xc1, 0x8a, 0xae, 0xf5, 0x7d, 0x01, 0x3e, - 0xa1, 0x23, 0xb0, 0x52, 0x4d, 0x8a, 0x51, 0xbf, 0xbe, 0x80, 0xb0, 0x09, 0xa3, 0x3e, 0xb1, 0x23, - 0x88, 0x6c, 0x12, 0xe2, 0xad, 0xa4, 0x18, 0xf5, 0xeb, 0xc3, 0x26, 0x58, 0xd6, 0xa8, 0x3a, 0xde, - 0xf9, 0x79, 0x49, 0xd9, 0x8b, 0x13, 0x52, 0xa6, 0x8a, 0x6e, 0x94, 0x83, 0xd5, 0x04, 0x16, 0xea, - 0xc3, 0x86, 0x1c, 0x00, 0x2b, 0x2c, 0x71, 0x2c, 0xbf, 0x20, 0x3d, 0xbd, 0x39, 0xe5, 0x1e, 0x8c, - 0x6a, 0x65, 0xef, 0xf8, 0x8a, 0xa6, 0x18, 0x8a, 0xf9, 0x29, 0x7d, 0x9f, 0x01, 0xa0, 0x97, 0x61, - 0x70, 0x23, 0x51, 0xe4, 0xd7, 0xfb, 0x8a, 0xfc, 0x6a, 0xfc, 0x72, 0x1a, 0x2b, 0xe8, 0x37, 0xc0, - 0x82, 0x27, 0x77, 0x9e, 0x4e, 0x86, 0xf2, 0xb8, 0x65, 0x47, 0x67, 0x69, 0x84, 0x56, 0x01, 0xa2, - 0x74, 0xea, 0xfd, 0xab, 0xd1, 0xe0, 0x15, 0x90, 0x6d, 0x79, 0x76, 0x78, 0xf8, 0x9d, 0x1f, 0x87, - 0x7a, 0xcd, 0xb3, 0x59, 0x02, 0x73, 0x51, 0xac, 0x5d, 0xcc, 0x22, 0x89, 0x03, 0x3f, 0x02, 0x8b, - 0xe1, 0x75, 0x43, 0xdf, 0x4d, 0x36, 0xc6, 0x61, 0x22, 0xad, 0x9f, 0xc0, 0x5d, 0x12, 0x15, 0x34, - 0x94, 0xa0, 0x08, 0x53, 0xe0, 0x13, 0x7d, 0x5b, 0x94, 0xb5, 0x7e, 0x02, 0xfc, 0x61, 0xd7, 0x7e, - 0x85, 0x1f, 0x4a, 0x50, 0x84, 0x59, 0xfa, 0x21, 0x03, 0x96, 0x12, 0xd7, 0xd0, 0xbf, 0x83, 0x2e, - 0x95, 0xd5, 0xb3, 0xa5, 0x4b, 0x61, 0xce, 0x9e, 0x2e, 0x85, 0xfb, 0xf4, 0xe8, 0x8a, 0xe1, 0x0f, - 0xa1, 0xeb, 0x61, 0x06, 0xc0, 0xc1, 0x4c, 0x87, 0x16, 0x58, 0x50, 0xad, 0xc6, 0x2c, 0x4e, 0xb8, - 0xe8, 0xd6, 0xa1, 0x0f, 0x33, 0x0d, 0xdd, 0xd7, 0xa0, 0xa4, 0x27, 0x6a, 0x50, 0xc8, 0x2c, 0x1a, - 0xb9, 0xe8, 0x08, 0x1c, 0xd9, 0xcc, 0xdd, 0x02, 0x8b, 0x2c, 0xec, 0x80, 0xb2, 0xd3, 0x77, 0x40, - 0x32, 0xea, 0x51, 0xef, 0x13, 0x41, 0x42, 0x1b, 0x2c, 0xe1, 0x78, 0x13, 0x32, 0x3f, 0xd5, 0x6f, - 0xac, 0x8a, 0x8e, 0x27, 0xd1, 0x7d, 0x24, 0x50, 0x4b, 0xbf, 0xf5, 0x73, 0xab, 0x36, 0xe4, 0x3f, - 0x96, 0xdb, 0x67, 0xd7, 0x0b, 0xfe, 0x27, 0xe8, 0xfd, 0x36, 0x0d, 0x56, 0xfb, 0x8f, 0x93, 0xa9, - 0x9a, 0xfe, 0xbb, 0x43, 0x5f, 0x2e, 0xd2, 0x53, 0x2d, 0x3a, 0xea, 0x50, 0x26, 0x7b, 0xbd, 0x48, - 0x30, 0x91, 0x99, 0x39, 0x13, 0xa5, 0xef, 0x92, 0x31, 0x9a, 0xfe, 0x61, 0xe4, 0xb3, 0xe1, 0xaf, - 0x07, 0xd3, 0x05, 0xe9, 0x94, 0x76, 0x36, 0xf1, 0x0b, 0xc2, 0xd3, 0x0e, 0xd3, 0x8f, 0x69, 0x70, - 0x6c, 0xd8, 0x2d, 0x02, 0x56, 0xf5, 0x5b, 0xa2, 0x0a, 0x92, 0x19, 0x7f, 0x4b, 0x7c, 0xdc, 0x2d, - 0x16, 0x87, 0xb4, 0xc0, 0x21, 0x4c, 0xec, 0xb9, 0xf1, 0x7d, 0x90, 0x4f, 0x30, 0x7f, 0x9d, 0xd3, - 0x26, 0xbd, 0xab, 0x2e, 0xf7, 0xaa, 0x8d, 0xf9, 0x7f, 0xd0, 0x2d, 0xe6, 0x77, 0x46, 0xe8, 0xa0, - 0x91, 0xd6, 0x23, 0xde, 0xdc, 0x32, 0x4f, 0xfd, 0xcd, 0xed, 0xe7, 0xc1, 0x78, 0xa9, 0xd4, 0x9a, - 0x49, 0xbc, 0x3e, 0x04, 0x27, 0x93, 0x39, 0x30, 0x18, 0xb0, 0xd3, 0x41, 0xb7, 0x78, 0xb2, 0x3a, - 0x4a, 0x09, 0x8d, 0xb6, 0x1f, 0x95, 0xc8, 0x99, 0x67, 0x93, 0xc8, 0x95, 0x73, 0xf7, 0x1e, 0x15, - 0xe6, 0xee, 0x3f, 0x2a, 0xcc, 0x3d, 0x78, 0x54, 0x98, 0xfb, 0x3c, 0x28, 0xa4, 0xee, 0x05, 0x85, - 0xd4, 0xfd, 0xa0, 0x90, 0x7a, 0x10, 0x14, 0x52, 0xbf, 0x07, 0x85, 0xd4, 0x97, 0x7f, 0x14, 0xe6, - 0x3e, 0x38, 0xa4, 0x8f, 0x9e, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x05, 0x26, 0x31, 0x5d, 0x9f, - 0x18, 0x00, 0x00, + // 1562 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x59, 0x4b, 0x6c, 0x1b, 0xc5, + 0x1b, 0x8f, 0xed, 0xcd, 0xeb, 0x73, 0x9a, 0xc7, 0xb4, 0xff, 0xd6, 0x4d, 0xff, 0xb5, 0xa3, 0x15, + 0x42, 0xa1, 0xa2, 0xbb, 0xad, 0x09, 0x0f, 0x09, 0x21, 0x11, 0x1b, 0x68, 0x2b, 0x92, 0xb6, 0x4c, + 0xd2, 0x0a, 0x41, 0x8b, 0x98, 0xac, 0xa7, 0xce, 0x12, 0x7b, 0xd7, 0xda, 0x19, 0x5b, 0x4d, 0x11, + 0x12, 0x42, 0xe2, 0xce, 0x05, 0xce, 0x20, 0x71, 0x45, 0x88, 0x0b, 0x9c, 0xb9, 0xf5, 0xd8, 0x63, + 0x2b, 0x90, 0x45, 0xcd, 0x81, 0x33, 0xd7, 0x9e, 0xd0, 0xcc, 0xce, 0xae, 0x77, 0xfd, 0x88, 0x1d, + 0x37, 0x0d, 0x0f, 0xf5, 0xe6, 0xdd, 0xf9, 0xbe, 0xdf, 0x37, 0xf3, 0xfb, 0x5e, 0xf3, 0xad, 0xe1, + 0xc2, 0xce, 0x2b, 0xcc, 0xb0, 0x5d, 0x73, 0xa7, 0xbe, 0x45, 0x3d, 0x87, 0x72, 0xca, 0xcc, 0x06, + 0x75, 0x4a, 0xae, 0x67, 0xaa, 0x05, 0x52, 0xb3, 0x4d, 0x52, 0xe7, 0x2e, 0xb3, 0x48, 0xc5, 0x76, + 0xca, 0x66, 0x23, 0xbf, 0x45, 0x39, 0x39, 0x6f, 0x96, 0xa9, 0x43, 0x3d, 0xc2, 0x69, 0xc9, 0xa8, + 0x79, 0x2e, 0x77, 0x51, 0xd6, 0x97, 0x37, 0x48, 0xcd, 0x36, 0x22, 0xf2, 0x86, 0x92, 0x5f, 0x3c, + 0x5b, 0xb6, 0xf9, 0x76, 0x7d, 0xcb, 0xb0, 0xdc, 0xaa, 0x59, 0x76, 0xcb, 0xae, 0x29, 0xd5, 0xb6, + 0xea, 0xb7, 0xe4, 0x93, 0x7c, 0x90, 0xbf, 0x7c, 0xb8, 0x45, 0x3d, 0x62, 0xde, 0x72, 0x3d, 0x6a, + 0x36, 0xba, 0x4c, 0x2e, 0xae, 0xb4, 0x65, 0xaa, 0xc4, 0xda, 0xb6, 0x1d, 0xea, 0xed, 0x9a, 0xb5, + 0x9d, 0xb2, 0x54, 0xf2, 0x28, 0x73, 0xeb, 0x9e, 0x45, 0xf7, 0xa5, 0xc5, 0xcc, 0x2a, 0xe5, 0xa4, + 0x97, 0x2d, 0xb3, 0x9f, 0x96, 0x57, 0x77, 0xb8, 0x5d, 0xed, 0x36, 0xf3, 0xd2, 0x20, 0x05, 0x66, + 0x6d, 0xd3, 0x2a, 0xe9, 0xd4, 0xd3, 0xff, 0x48, 0xc2, 0xe9, 0xa2, 0xeb, 0x70, 0x22, 0x34, 0xb0, + 0x3a, 0xc4, 0x3a, 0xe5, 0x9e, 0x6d, 0x6d, 0xc8, 0xdf, 0xa8, 0x08, 0x9a, 0x43, 0xaa, 0x34, 0x93, + 0x58, 0x4a, 0x2c, 0x4f, 0x17, 0xcc, 0xbb, 0xcd, 0xdc, 0x58, 0xab, 0x99, 0xd3, 0x2e, 0x93, 0x2a, + 0x7d, 0xd4, 0xcc, 0xe5, 0xba, 0x89, 0x33, 0x02, 0x18, 0x21, 0x82, 0xa5, 0x32, 0x7a, 0x17, 0x32, + 0x9c, 0x78, 0x65, 0xca, 0x57, 0x1b, 0xd4, 0x23, 0x65, 0x7a, 0x8d, 0xdb, 0x15, 0xfb, 0x0e, 0xe1, + 0xb6, 0xeb, 0x64, 0x92, 0x4b, 0x89, 0xe5, 0xf1, 0xc2, 0xff, 0x5b, 0xcd, 0x5c, 0x66, 0xb3, 0x8f, + 0x0c, 0xee, 0xab, 0x8d, 0x1a, 0x80, 0x62, 0x6b, 0xd7, 0x49, 0xa5, 0x4e, 0x33, 0xa9, 0xa5, 0xc4, + 0x72, 0x3a, 0x6f, 0x18, 0xed, 0x28, 0x09, 0x59, 0x31, 0x6a, 0x3b, 0x65, 0x19, 0x36, 0x81, 0xcb, + 0x8c, 0x77, 0xea, 0xc4, 0xe1, 0x36, 0xdf, 0x2d, 0x1c, 0x6f, 0x35, 0x73, 0x68, 0xb3, 0x0b, 0x0d, + 0xf7, 0xb0, 0x80, 0x4c, 0x98, 0xb6, 0x02, 0xde, 0x32, 0x9a, 0xe4, 0x66, 0x41, 0x71, 0x33, 0xdd, + 0x26, 0xb4, 0x2d, 0xa3, 0xff, 0xb9, 0x07, 0xd3, 0x9c, 0xf0, 0x3a, 0x3b, 0x18, 0xa6, 0xdf, 0x87, + 0x93, 0x56, 0xdd, 0xf3, 0xa8, 0xd3, 0x9f, 0xea, 0xd3, 0xad, 0x66, 0xee, 0x64, 0xb1, 0x9f, 0x10, + 0xee, 0xaf, 0x8f, 0x3e, 0x81, 0xa3, 0xf1, 0xc5, 0xc7, 0x61, 0xfb, 0x94, 0x3a, 0xe0, 0xd1, 0x62, + 0x37, 0x24, 0xee, 0x65, 0x67, 0xff, 0x9c, 0x7f, 0x99, 0x80, 0x53, 0x45, 0xcf, 0x65, 0xec, 0x3a, + 0xf5, 0x98, 0xed, 0x3a, 0x57, 0xb6, 0x3e, 0xa2, 0x16, 0xc7, 0xf4, 0x16, 0xf5, 0xa8, 0x63, 0x51, + 0xb4, 0x04, 0xda, 0x8e, 0xed, 0x94, 0x14, 0xe3, 0x33, 0x01, 0xe3, 0x6f, 0xdb, 0x4e, 0x09, 0xcb, + 0x15, 0x21, 0x21, 0x7d, 0x92, 0x8c, 0x4b, 0x44, 0x08, 0xcf, 0x03, 0x90, 0x9a, 0xad, 0x0c, 0x48, + 0x2a, 0xa6, 0x0b, 0x48, 0xc9, 0xc1, 0xea, 0xd5, 0x4b, 0x6a, 0x05, 0x47, 0xa4, 0xf4, 0xaf, 0x52, + 0x70, 0xec, 0xcd, 0xdb, 0x9c, 0x7a, 0x0e, 0xa9, 0xc4, 0x92, 0x2d, 0x0f, 0x50, 0x95, 0xcf, 0x97, + 0xdb, 0x81, 0x10, 0x82, 0xad, 0x87, 0x2b, 0x38, 0x22, 0x85, 0x5c, 0x98, 0xf5, 0x9f, 0x36, 0x68, + 0x85, 0x5a, 0xdc, 0xf5, 0xe4, 0x66, 0xd3, 0xf9, 0x17, 0xf6, 0xf2, 0x07, 0x33, 0x44, 0xe9, 0x31, + 0x1a, 0xe7, 0x8d, 0x35, 0xb2, 0x45, 0x2b, 0x81, 0x6a, 0x01, 0xb5, 0x9a, 0xb9, 0xd9, 0xf5, 0x18, + 0x1c, 0xee, 0x80, 0x47, 0x04, 0xd2, 0x7e, 0x42, 0x3c, 0x8e, 0xf7, 0xe7, 0x5a, 0xcd, 0x5c, 0x7a, + 0xb3, 0x0d, 0x83, 0xa3, 0x98, 0x7d, 0xb2, 0x5a, 0x7b, 0xd2, 0x59, 0xad, 0x7f, 0xdd, 0xed, 0x18, + 0x3f, 0x37, 0xff, 0x15, 0x8e, 0xd9, 0x86, 0x19, 0x95, 0x36, 0x8f, 0xe3, 0x99, 0x63, 0xea, 0x58, + 0x33, 0xc5, 0x08, 0x16, 0x8e, 0x21, 0xa3, 0xdd, 0xde, 0x85, 0x60, 0x34, 0x07, 0x9d, 0xd8, 0x4f, + 0x11, 0xd0, 0x7f, 0x4e, 0xc2, 0x89, 0x8b, 0xae, 0x67, 0xdf, 0x11, 0x59, 0x5e, 0xb9, 0xea, 0x96, + 0x56, 0x55, 0xfb, 0xa7, 0x1e, 0xfa, 0x10, 0xa6, 0x04, 0x7b, 0x25, 0xc2, 0x89, 0xf4, 0x51, 0x3a, + 0x7f, 0x6e, 0x38, 0xae, 0xfd, 0xc2, 0xb0, 0x4e, 0x39, 0x69, 0x7b, 0xb5, 0xfd, 0x0e, 0x87, 0xa8, + 0xe8, 0x26, 0x68, 0xac, 0x46, 0x2d, 0xe5, 0xc9, 0x57, 0x8d, 0xbd, 0xaf, 0x21, 0x46, 0x9f, 0x8d, + 0x6e, 0xd4, 0xa8, 0xd5, 0x2e, 0x26, 0xe2, 0x09, 0x4b, 0x58, 0x44, 0x61, 0x82, 0xc9, 0x80, 0x53, + 0xbe, 0x7b, 0x6d, 0x54, 0x03, 0x12, 0xa4, 0x30, 0xab, 0x4c, 0x4c, 0xf8, 0xcf, 0x58, 0x81, 0xeb, + 0x9f, 0xa7, 0x60, 0xa9, 0x8f, 0x66, 0xd1, 0x75, 0x4a, 0xb6, 0x2c, 0xf6, 0x17, 0x41, 0xe3, 0xbb, + 0xb5, 0x20, 0xd8, 0x57, 0x82, 0xdd, 0x6e, 0xee, 0xd6, 0x44, 0x3b, 0x7a, 0x66, 0x90, 0xbe, 0x90, + 0xc3, 0x12, 0x01, 0xad, 0x85, 0xa7, 0x4a, 0xc6, 0xb0, 0xd4, 0xb6, 0x1e, 0x35, 0x73, 0x3d, 0xee, + 0x5f, 0x46, 0x88, 0x14, 0xdf, 0xbc, 0xa8, 0x0d, 0x15, 0xc2, 0xf8, 0xa6, 0x47, 0x1c, 0xe6, 0x5b, + 0xb2, 0xab, 0x41, 0xac, 0x9f, 0x19, 0xce, 0xdd, 0x42, 0xa3, 0xb0, 0xa8, 0x76, 0x81, 0xd6, 0xba, + 0xd0, 0x70, 0x0f, 0x0b, 0xe8, 0x59, 0x98, 0xf0, 0x28, 0x61, 0xae, 0xa3, 0x5a, 0x4f, 0x48, 0x2e, + 0x96, 0x6f, 0xb1, 0x5a, 0x45, 0xcf, 0xc1, 0x64, 0x95, 0x32, 0x46, 0xca, 0x34, 0x33, 0x2e, 0x05, + 0xe7, 0x94, 0xe0, 0xe4, 0xba, 0xff, 0x1a, 0x07, 0xeb, 0xfa, 0x83, 0x04, 0x9c, 0xea, 0xc3, 0xe3, + 0x9a, 0xcd, 0x38, 0xba, 0xd1, 0x15, 0xcf, 0xc6, 0x90, 0xb5, 0xc3, 0x66, 0x7e, 0x34, 0xcf, 0x2b, + 0xdb, 0x53, 0xc1, 0x9b, 0x48, 0x2c, 0xdf, 0x80, 0x71, 0x9b, 0xd3, 0xaa, 0xf0, 0x4a, 0x6a, 0x39, + 0x9d, 0x7f, 0x79, 0xc4, 0x58, 0x2b, 0x1c, 0x51, 0x36, 0xc6, 0x2f, 0x09, 0x34, 0xec, 0x83, 0xea, + 0xbf, 0x24, 0xfb, 0x9e, 0x4d, 0x04, 0x3c, 0xfa, 0x18, 0x66, 0xe5, 0x93, 0x5f, 0x99, 0x31, 0xbd, + 0xa5, 0x4e, 0x38, 0x30, 0xa7, 0xf6, 0x68, 0xe8, 0x85, 0xe3, 0x6a, 0x2b, 0xb3, 0x1b, 0x31, 0x68, + 0xdc, 0x61, 0x0a, 0x9d, 0x87, 0x74, 0xd5, 0x76, 0x30, 0xad, 0x55, 0x6c, 0x8b, 0x30, 0x75, 0x2f, + 0x92, 0x2d, 0x69, 0xbd, 0xfd, 0x1a, 0x47, 0x65, 0xd0, 0x8b, 0x90, 0xae, 0x92, 0xdb, 0xa1, 0x4a, + 0x4a, 0xaa, 0x1c, 0x55, 0xf6, 0xd2, 0xeb, 0xed, 0x25, 0x1c, 0x95, 0x43, 0xd7, 0x44, 0x34, 0x88, + 0x2a, 0xcd, 0x32, 0x9a, 0xa4, 0xf9, 0xcc, 0xa0, 0xf3, 0xa9, 0x22, 0x2f, 0x4a, 0x44, 0x24, 0x72, + 0x24, 0x04, 0x0e, 0xb0, 0xf4, 0x1f, 0x35, 0x38, 0xbd, 0x67, 0xee, 0xa3, 0xb7, 0x00, 0xb9, 0x5b, + 0x8c, 0x7a, 0x0d, 0x5a, 0xba, 0xe0, 0x5f, 0xfa, 0xc5, 0xfd, 0x44, 0x70, 0x9c, 0xf2, 0x5b, 0xe2, + 0x95, 0xae, 0x55, 0xdc, 0x43, 0x03, 0x59, 0x70, 0x44, 0x24, 0x83, 0x4f, 0xa8, 0xad, 0xae, 0x42, + 0xfb, 0xcb, 0xb4, 0x85, 0x56, 0x33, 0x77, 0x64, 0x2d, 0x0a, 0x82, 0xe3, 0x98, 0x68, 0x15, 0xe6, + 0x54, 0xad, 0xef, 0x20, 0xf8, 0x84, 0x62, 0x60, 0xae, 0x18, 0x5f, 0xc6, 0x9d, 0xf2, 0x02, 0xa2, + 0x44, 0x99, 0xed, 0xd1, 0x52, 0x08, 0xa1, 0xc5, 0x21, 0xde, 0x88, 0x2f, 0xe3, 0x4e, 0x79, 0x54, + 0x81, 0x59, 0x85, 0xaa, 0xf8, 0xce, 0x8c, 0x4b, 0x97, 0x3d, 0x3f, 0xa4, 0xcb, 0xfc, 0xa2, 0x1b, + 0xc6, 0x60, 0x31, 0x86, 0x85, 0x3b, 0xb0, 0x11, 0x07, 0xb0, 0x82, 0x12, 0xc7, 0x32, 0x13, 0xd2, + 0xd2, 0xeb, 0x23, 0xe6, 0x60, 0x58, 0x2b, 0xdb, 0xed, 0x2b, 0x7c, 0xc5, 0x70, 0xc4, 0x8e, 0xfe, + 0xbd, 0x06, 0xd0, 0x8e, 0x30, 0xb4, 0x12, 0x2b, 0xf2, 0x4b, 0x1d, 0x45, 0x7e, 0x3e, 0x7a, 0x39, + 0x8d, 0x14, 0xf4, 0xeb, 0x30, 0xe1, 0xca, 0xcc, 0x53, 0xc1, 0x90, 0x1f, 0xb4, 0xed, 0xb0, 0x97, + 0x86, 0x68, 0x05, 0x10, 0xa5, 0x53, 0xe5, 0xaf, 0x42, 0x43, 0x97, 0x41, 0xab, 0xb9, 0xa5, 0xa0, + 0xf9, 0x9d, 0x1b, 0x84, 0x7a, 0xd5, 0x2d, 0xb1, 0x18, 0xe6, 0x94, 0xd8, 0xbb, 0x78, 0x8b, 0x25, + 0x0e, 0xfa, 0x00, 0xa6, 0x82, 0xeb, 0x86, 0xba, 0x9b, 0xac, 0x0c, 0xc2, 0xec, 0x35, 0x03, 0x17, + 0x66, 0x44, 0x05, 0x0d, 0x56, 0x70, 0x88, 0x89, 0x3e, 0x4b, 0xc0, 0x82, 0xd5, 0x39, 0xd3, 0x65, + 0x26, 0x87, 0x6b, 0xdd, 0x7b, 0x8e, 0xdd, 0x85, 0xff, 0xb5, 0x9a, 0xb9, 0x85, 0x2e, 0x11, 0xdc, + 0x6d, 0x4e, 0x1c, 0x92, 0xaa, 0x2b, 0xab, 0x6c, 0x38, 0x43, 0x1c, 0xb2, 0xd7, 0xec, 0xe1, 0x1f, + 0x32, 0x58, 0xc1, 0x21, 0xa6, 0xfe, 0x83, 0x06, 0x33, 0xb1, 0xbb, 0xf0, 0xdf, 0x11, 0x33, 0x7e, + 0x6a, 0x1d, 0x6c, 0xcc, 0xf8, 0x98, 0x07, 0x1f, 0x33, 0x3e, 0xee, 0xa1, 0xc6, 0x8c, 0x6f, 0xf2, + 0x30, 0x63, 0x26, 0x72, 0xc8, 0x1e, 0x31, 0xf3, 0x20, 0x05, 0xa8, 0x3b, 0xe7, 0x91, 0x05, 0x13, + 0xfe, 0xd0, 0x75, 0x10, 0xbd, 0x3e, 0xbc, 0x7f, 0xa9, 0xb6, 0xae, 0xa0, 0x3b, 0x46, 0xb5, 0xe4, + 0x50, 0xa3, 0x1a, 0x3d, 0x88, 0x91, 0x36, 0xbc, 0x0c, 0xf4, 0x1d, 0x6b, 0x6f, 0xc2, 0x14, 0x0b, + 0x66, 0x41, 0x6d, 0xf4, 0x59, 0x50, 0xb2, 0x1e, 0x4e, 0x81, 0x21, 0x24, 0x2a, 0xc1, 0x0c, 0x89, + 0x8e, 0x63, 0xe3, 0x23, 0x1d, 0x63, 0x5e, 0xcc, 0x7e, 0xb1, 0x39, 0x2c, 0x86, 0xaa, 0xff, 0xda, + 0xe9, 0x5b, 0xbf, 0x2a, 0xfc, 0x63, 0x7d, 0x7b, 0x78, 0x53, 0xf1, 0x7f, 0xc2, 0xbd, 0xdf, 0x24, + 0x61, 0xbe, 0xb3, 0xb1, 0x8e, 0xf4, 0xf9, 0xe3, 0x4e, 0xcf, 0x6f, 0x38, 0xc9, 0x91, 0x36, 0x1d, + 0xce, 0x6a, 0x43, 0x7e, 0x9d, 0x8d, 0x7a, 0x22, 0x75, 0xe0, 0x9e, 0xd0, 0xbf, 0x8d, 0x73, 0x34, + 0xfa, 0x27, 0xa2, 0x3e, 0x1f, 0x54, 0x93, 0x87, 0xf4, 0x41, 0xf5, 0x09, 0xd3, 0xf4, 0x5d, 0x12, + 0x8e, 0x3d, 0xfd, 0x4f, 0x61, 0xf8, 0xaf, 0x8f, 0x3f, 0x75, 0xf3, 0xf5, 0xf4, 0x9f, 0x81, 0x61, + 0x02, 0xb9, 0x70, 0xf6, 0xee, 0xc3, 0xec, 0xd8, 0xbd, 0x87, 0xd9, 0xb1, 0xfb, 0x0f, 0xb3, 0x63, + 0x9f, 0xb6, 0xb2, 0x89, 0xbb, 0xad, 0x6c, 0xe2, 0x5e, 0x2b, 0x9b, 0xb8, 0xdf, 0xca, 0x26, 0x7e, + 0x6b, 0x65, 0x13, 0x5f, 0xfc, 0x9e, 0x1d, 0x7b, 0x6f, 0x52, 0xb5, 0x9e, 0xbf, 0x02, 0x00, 0x00, + 0xff, 0xff, 0x4d, 0x4c, 0xa8, 0x42, 0x87, 0x1c, 0x00, 0x00, +} + +func (m *ContainerResourceMetricSource) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContainerResourceMetricSource) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerResourceMetricSource) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Container) + copy(dAtA[i:], m.Container) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Container))) + i-- + dAtA[i] = 0x22 + if m.TargetAverageValue != nil { + { + size, err := m.TargetAverageValue.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.TargetAverageUtilization != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.TargetAverageUtilization)) + i-- + dAtA[i] = 0x10 + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ContainerResourceMetricStatus) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContainerResourceMetricStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerResourceMetricStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Container) + copy(dAtA[i:], m.Container) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Container))) + i-- + dAtA[i] = 0x22 + { + size, err := m.CurrentAverageValue.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.CurrentAverageUtilization != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.CurrentAverageUtilization)) + i-- + dAtA[i] = 0x10 + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *CrossVersionObjectReference) Marshal() (dAtA []byte, err error) { @@ -1081,6 +1242,18 @@ func (m *MetricSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContainerResource != nil { + { + size, err := m.ContainerResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.External != nil { { size, err := m.External.MarshalToSizedBuffer(dAtA[:i]) @@ -1157,6 +1330,18 @@ func (m *MetricStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContainerResource != nil { + { + size, err := m.ContainerResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.External != nil { { size, err := m.External.MarshalToSizedBuffer(dAtA[:i]) @@ -1556,6 +1741,44 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *ContainerResourceMetricSource) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if m.TargetAverageUtilization != nil { + n += 1 + sovGenerated(uint64(*m.TargetAverageUtilization)) + } + if m.TargetAverageValue != nil { + l = m.TargetAverageValue.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + l = len(m.Container) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *ContainerResourceMetricStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if m.CurrentAverageUtilization != nil { + n += 1 + sovGenerated(uint64(*m.CurrentAverageUtilization)) + } + l = m.CurrentAverageValue.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Container) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *CrossVersionObjectReference) Size() (n int) { if m == nil { return 0 @@ -1741,6 +1964,10 @@ func (m *MetricSpec) Size() (n int) { l = m.External.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.ContainerResource != nil { + l = m.ContainerResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -1768,6 +1995,10 @@ func (m *MetricStatus) Size() (n int) { l = m.External.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.ContainerResource != nil { + l = m.ContainerResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -1891,6 +2122,32 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *ContainerResourceMetricSource) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerResourceMetricSource{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `TargetAverageUtilization:` + valueToStringGenerated(this.TargetAverageUtilization) + `,`, + `TargetAverageValue:` + strings.Replace(fmt.Sprintf("%v", this.TargetAverageValue), "Quantity", "resource.Quantity", 1) + `,`, + `Container:` + fmt.Sprintf("%v", this.Container) + `,`, + `}`, + }, "") + return s +} +func (this *ContainerResourceMetricStatus) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerResourceMetricStatus{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `CurrentAverageUtilization:` + valueToStringGenerated(this.CurrentAverageUtilization) + `,`, + `CurrentAverageValue:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.CurrentAverageValue), "Quantity", "resource.Quantity", 1), `&`, ``, 1) + `,`, + `Container:` + fmt.Sprintf("%v", this.Container) + `,`, + `}`, + }, "") + return s +} func (this *CrossVersionObjectReference) String() string { if this == nil { return "nil" @@ -2024,6 +2281,7 @@ func (this *MetricSpec) String() string { `Pods:` + strings.Replace(this.Pods.String(), "PodsMetricSource", "PodsMetricSource", 1) + `,`, `Resource:` + strings.Replace(this.Resource.String(), "ResourceMetricSource", "ResourceMetricSource", 1) + `,`, `External:` + strings.Replace(this.External.String(), "ExternalMetricSource", "ExternalMetricSource", 1) + `,`, + `ContainerResource:` + strings.Replace(this.ContainerResource.String(), "ContainerResourceMetricSource", "ContainerResourceMetricSource", 1) + `,`, `}`, }, "") return s @@ -2038,6 +2296,7 @@ func (this *MetricStatus) String() string { `Pods:` + strings.Replace(this.Pods.String(), "PodsMetricStatus", "PodsMetricStatus", 1) + `,`, `Resource:` + strings.Replace(this.Resource.String(), "ResourceMetricStatus", "ResourceMetricStatus", 1) + `,`, `External:` + strings.Replace(this.External.String(), "ExternalMetricStatus", "ExternalMetricStatus", 1) + `,`, + `ContainerResource:` + strings.Replace(this.ContainerResource.String(), "ContainerResourceMetricStatus", "ContainerResourceMetricStatus", 1) + `,`, `}`, }, "") return s @@ -2126,6 +2385,349 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *ContainerResourceMetricSource) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContainerResourceMetricSource: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContainerResourceMetricSource: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = k8s_io_api_core_v1.ResourceName(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetAverageUtilization", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.TargetAverageUtilization = &v + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetAverageValue", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TargetAverageValue == nil { + m.TargetAverageValue = &resource.Quantity{} + } + if err := m.TargetAverageValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Container", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Container = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContainerResourceMetricStatus) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContainerResourceMetricStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContainerResourceMetricStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = k8s_io_api_core_v1.ResourceName(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentAverageUtilization", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CurrentAverageUtilization = &v + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentAverageValue", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CurrentAverageValue.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Container", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Container = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *CrossVersionObjectReference) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3723,6 +4325,42 @@ func (m *MetricSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContainerResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ContainerResource == nil { + m.ContainerResource = &ContainerResourceMetricSource{} + } + if err := m.ContainerResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -3952,6 +4590,42 @@ func (m *MetricStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContainerResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ContainerResource == nil { + m.ContainerResource = &ContainerResourceMetricStatus{} + } + if err := m.ContainerResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/autoscaling/v2beta1/generated.proto b/staging/src/k8s.io/api/autoscaling/v2beta1/generated.proto index 23d3214d8c1..5ad55fa7277 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta1/generated.proto +++ b/staging/src/k8s.io/api/autoscaling/v2beta1/generated.proto @@ -30,6 +30,60 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v2beta1"; +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +message ContainerResourceMetricSource { + // name is the name of the resource in question. + optional string name = 1; + + // targetAverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + optional int32 targetAverageUtilization = 2; + + // targetAverageValue is the target value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 3; + + // container is the name of the container in the pods of the scaling target + optional string container = 4; +} + +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing a single container in each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +message ContainerResourceMetricStatus { + // name is the name of the resource in question. + optional string name = 1; + + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. It will only be + // present if `targetAverageValue` was set in the corresponding metric + // specification. + // +optional + optional int32 currentAverageUtilization = 2; + + // currentAverageValue is the current value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // It will always be set, regardless of the corresponding metric specification. + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 3; + + // container is the name of the container in the pods of the scaling target + optional string container = 4; +} + // CrossVersionObjectReference contains enough information to let you identify the referred resource. message CrossVersionObjectReference { // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" @@ -200,8 +254,10 @@ message HorizontalPodAutoscalerStatus { // MetricSpec specifies how to scale based on a single metric // (only `type` and one other matching field should be set at once). message MetricSpec { - // type is the type of metric source. It should be one of "Object", - // "Pods", "Resource" or "External", each mapping to a matching field in the object. + // type is the type of metric source. It should be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each mapping to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled optional string type = 1; // object refers to a metric describing a single kubernetes object @@ -223,6 +279,15 @@ message MetricSpec { // +optional optional ResourceMetricSource resource = 4; + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in + // each pod of the current scale target (e.g. CPU or memory). Such metrics are + // built in to Kubernetes, and have special scaling options on top of those + // available to normal per-pod metrics using the "pods" source. + // This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. + // +optional + optional ContainerResourceMetricSource containerResource = 7; + // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -234,8 +299,10 @@ message MetricSpec { // MetricStatus describes the last-read state of a single metric. message MetricStatus { - // type is the type of metric source. It will be one of "Object", - // "Pods" or "Resource", each corresponds to a matching field in the object. + // type is the type of metric source. It will be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each corresponds to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled optional string type = 1; // object refers to a metric describing a single kubernetes object @@ -257,6 +324,14 @@ message MetricStatus { // +optional optional ResourceMetricStatus resource = 4; + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ContainerResourceMetricStatus containerResource = 7; + // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster diff --git a/staging/src/k8s.io/api/autoscaling/v2beta1/types.go b/staging/src/k8s.io/api/autoscaling/v2beta1/types.go index f5fe9f2acfe..05023d9bcf4 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta1/types.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta1/types.go @@ -76,6 +76,12 @@ const ( // Kubernetes, and have special scaling options on top of those available // to normal per-pod metrics (the "pods" source). ResourceMetricSourceType MetricSourceType = "Resource" + // ContainerResourceMetricSourceType is a resource metric known to Kubernetes, as + // specified in requests and limits, describing a single container in each pod in the current + // scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics (the "pods" source). + ContainerResourceMetricSourceType MetricSourceType = "ContainerResource" // ExternalMetricSourceType is a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -87,8 +93,10 @@ const ( // MetricSpec specifies how to scale based on a single metric // (only `type` and one other matching field should be set at once). type MetricSpec struct { - // type is the type of metric source. It should be one of "Object", - // "Pods", "Resource" or "External", each mapping to a matching field in the object. + // type is the type of metric source. It should be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each mapping to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"` // object refers to a metric describing a single kubernetes object @@ -107,6 +115,14 @@ type MetricSpec struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricSource `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"` + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in + // each pod of the current scale target (e.g. CPU or memory). Such metrics are + // built in to Kubernetes, and have special scaling options on top of those + // available to normal per-pod metrics using the "pods" source. + // This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. + // +optional + ContainerResource *ContainerResourceMetricSource `json:"containerResource,omitempty" protobuf:"bytes,7,opt,name=containerResource"` // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -178,6 +194,30 @@ type ResourceMetricSource struct { TargetAverageValue *resource.Quantity `json:"targetAverageValue,omitempty" protobuf:"bytes,3,opt,name=targetAverageValue"` } +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +type ContainerResourceMetricSource struct { + // name is the name of the resource in question. + Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"` + // targetAverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + TargetAverageUtilization *int32 `json:"targetAverageUtilization,omitempty" protobuf:"varint,2,opt,name=targetAverageUtilization"` + // targetAverageValue is the target value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // +optional + TargetAverageValue *resource.Quantity `json:"targetAverageValue,omitempty" protobuf:"bytes,3,opt,name=targetAverageValue"` + // container is the name of the container in the pods of the scaling target + Container string `json:"container" protobuf:"bytes,4,opt,name=container"` +} + // ExternalMetricSource indicates how to scale on a metric not associated with // any Kubernetes object (for example length of queue in cloud // messaging service, or QPS from loadbalancer running outside of cluster). @@ -265,8 +305,10 @@ type HorizontalPodAutoscalerCondition struct { // MetricStatus describes the last-read state of a single metric. type MetricStatus struct { - // type is the type of metric source. It will be one of "Object", - // "Pods" or "Resource", each corresponds to a matching field in the object. + // type is the type of metric source. It will be one of "ContainerResource", + // "External", "Object", "Pods" or "Resource", each corresponds to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"` // object refers to a metric describing a single kubernetes object @@ -285,6 +327,13 @@ type MetricStatus struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricStatus `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"` + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricStatus `json:"containerResource,omitempty" protobuf:"bytes,7,opt,name=containerResource"` // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -354,6 +403,30 @@ type ResourceMetricStatus struct { CurrentAverageValue resource.Quantity `json:"currentAverageValue" protobuf:"bytes,3,name=currentAverageValue"` } +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing a single container in each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +type ContainerResourceMetricStatus struct { + // name is the name of the resource in question. + Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"` + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. It will only be + // present if `targetAverageValue` was set in the corresponding metric + // specification. + // +optional + CurrentAverageUtilization *int32 `json:"currentAverageUtilization,omitempty" protobuf:"bytes,2,opt,name=currentAverageUtilization"` + // currentAverageValue is the current value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // It will always be set, regardless of the corresponding metric specification. + CurrentAverageValue resource.Quantity `json:"currentAverageValue" protobuf:"bytes,3,name=currentAverageValue"` + // container is the name of the container in the pods of the scaling target + Container string `json:"container" protobuf:"bytes,4,opt,name=container"` +} + // ExternalMetricStatus indicates the current value of a global metric // not associated with any Kubernetes object. type ExternalMetricStatus struct { diff --git a/staging/src/k8s.io/api/autoscaling/v2beta1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/autoscaling/v2beta1/types_swagger_doc_generated.go index d945a9f08ae..08a54621f8f 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta1/types_swagger_doc_generated.go @@ -27,6 +27,30 @@ package v2beta1 // Those methods can be generated by using hack/update-generated-swagger-docs.sh // AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_ContainerResourceMetricSource = map[string]string{ + "": "ContainerResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in requests and limits, describing each pod in the current scale target (e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. Only one \"target\" type should be set.", + "name": "name is the name of the resource in question.", + "targetAverageUtilization": "targetAverageUtilization is the target value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods.", + "targetAverageValue": "targetAverageValue is the target value of the average of the resource metric across all relevant pods, as a raw value (instead of as a percentage of the request), similar to the \"pods\" metric source type.", + "container": "container is the name of the container in the pods of the scaling target", +} + +func (ContainerResourceMetricSource) SwaggerDoc() map[string]string { + return map_ContainerResourceMetricSource +} + +var map_ContainerResourceMetricStatus = map[string]string{ + "": "ContainerResourceMetricStatus indicates the current value of a resource metric known to Kubernetes, as specified in requests and limits, describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "name": "name is the name of the resource in question.", + "currentAverageUtilization": "currentAverageUtilization is the current value of the average of the resource metric across all relevant pods, represented as a percentage of the requested value of the resource for the pods. It will only be present if `targetAverageValue` was set in the corresponding metric specification.", + "currentAverageValue": "currentAverageValue is the current value of the average of the resource metric across all relevant pods, as a raw value (instead of as a percentage of the request), similar to the \"pods\" metric source type. It will always be set, regardless of the corresponding metric specification.", + "container": "container is the name of the container in the pods of the scaling target", +} + +func (ContainerResourceMetricStatus) SwaggerDoc() map[string]string { + return map_ContainerResourceMetricStatus +} + var map_CrossVersionObjectReference = map[string]string{ "": "CrossVersionObjectReference contains enough information to let you identify the referred resource.", "kind": "Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\"", @@ -123,12 +147,13 @@ func (HorizontalPodAutoscalerStatus) SwaggerDoc() map[string]string { } var map_MetricSpec = map[string]string{ - "": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", - "type": "type is the type of metric source. It should be one of \"Object\", \"Pods\", \"Resource\" or \"External\", each mapping to a matching field in the object.", - "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", - "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", - "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", - "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", + "": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", + "type": "type is the type of metric source. It should be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each mapping to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", + "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", + "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", + "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "containerResource": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag.", + "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", } func (MetricSpec) SwaggerDoc() map[string]string { @@ -136,12 +161,13 @@ func (MetricSpec) SwaggerDoc() map[string]string { } var map_MetricStatus = map[string]string{ - "": "MetricStatus describes the last-read state of a single metric.", - "type": "type is the type of metric source. It will be one of \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object.", - "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", - "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", - "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", - "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", + "": "MetricStatus describes the last-read state of a single metric.", + "type": "type is the type of metric source. It will be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", + "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", + "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", + "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "containerResource": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", } func (MetricStatus) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/autoscaling/v2beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/autoscaling/v2beta1/zz_generated.deepcopy.go index c51e05b8f09..f10c7884d0d 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta1/zz_generated.deepcopy.go @@ -25,6 +25,54 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricSource) DeepCopyInto(out *ContainerResourceMetricSource) { + *out = *in + if in.TargetAverageUtilization != nil { + in, out := &in.TargetAverageUtilization, &out.TargetAverageUtilization + *out = new(int32) + **out = **in + } + if in.TargetAverageValue != nil { + in, out := &in.TargetAverageValue, &out.TargetAverageValue + x := (*in).DeepCopy() + *out = &x + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricSource. +func (in *ContainerResourceMetricSource) DeepCopy() *ContainerResourceMetricSource { + if in == nil { + return nil + } + out := new(ContainerResourceMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricStatus) DeepCopyInto(out *ContainerResourceMetricStatus) { + *out = *in + if in.CurrentAverageUtilization != nil { + in, out := &in.CurrentAverageUtilization, &out.CurrentAverageUtilization + *out = new(int32) + **out = **in + } + out.CurrentAverageValue = in.CurrentAverageValue.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricStatus. +func (in *ContainerResourceMetricStatus) DeepCopy() *ContainerResourceMetricStatus { + if in == nil { + return nil + } + out := new(ContainerResourceMetricStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { *out = *in @@ -263,6 +311,11 @@ func (in *MetricSpec) DeepCopyInto(out *MetricSpec) { *out = new(ResourceMetricSource) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricSource) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricSource) @@ -299,6 +352,11 @@ func (in *MetricStatus) DeepCopyInto(out *MetricStatus) { *out = new(ResourceMetricStatus) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricStatus) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricStatus) diff --git a/staging/src/k8s.io/api/autoscaling/v2beta2/generated.pb.go b/staging/src/k8s.io/api/autoscaling/v2beta2/generated.pb.go index c69d6cb9e7a..43e06f9eb1f 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta2/generated.pb.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta2/generated.pb.go @@ -47,10 +47,66 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +func (m *ContainerResourceMetricSource) Reset() { *m = ContainerResourceMetricSource{} } +func (*ContainerResourceMetricSource) ProtoMessage() {} +func (*ContainerResourceMetricSource) Descriptor() ([]byte, []int) { + return fileDescriptor_592ad94d7d6be24f, []int{0} +} +func (m *ContainerResourceMetricSource) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerResourceMetricSource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ContainerResourceMetricSource) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerResourceMetricSource.Merge(m, src) +} +func (m *ContainerResourceMetricSource) XXX_Size() int { + return m.Size() +} +func (m *ContainerResourceMetricSource) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerResourceMetricSource.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerResourceMetricSource proto.InternalMessageInfo + +func (m *ContainerResourceMetricStatus) Reset() { *m = ContainerResourceMetricStatus{} } +func (*ContainerResourceMetricStatus) ProtoMessage() {} +func (*ContainerResourceMetricStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_592ad94d7d6be24f, []int{1} +} +func (m *ContainerResourceMetricStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContainerResourceMetricStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ContainerResourceMetricStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContainerResourceMetricStatus.Merge(m, src) +} +func (m *ContainerResourceMetricStatus) XXX_Size() int { + return m.Size() +} +func (m *ContainerResourceMetricStatus) XXX_DiscardUnknown() { + xxx_messageInfo_ContainerResourceMetricStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_ContainerResourceMetricStatus proto.InternalMessageInfo + func (m *CrossVersionObjectReference) Reset() { *m = CrossVersionObjectReference{} } func (*CrossVersionObjectReference) ProtoMessage() {} func (*CrossVersionObjectReference) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{0} + return fileDescriptor_592ad94d7d6be24f, []int{2} } func (m *CrossVersionObjectReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -78,7 +134,7 @@ var xxx_messageInfo_CrossVersionObjectReference proto.InternalMessageInfo func (m *ExternalMetricSource) Reset() { *m = ExternalMetricSource{} } func (*ExternalMetricSource) ProtoMessage() {} func (*ExternalMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{1} + return fileDescriptor_592ad94d7d6be24f, []int{3} } func (m *ExternalMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +162,7 @@ var xxx_messageInfo_ExternalMetricSource proto.InternalMessageInfo func (m *ExternalMetricStatus) Reset() { *m = ExternalMetricStatus{} } func (*ExternalMetricStatus) ProtoMessage() {} func (*ExternalMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{2} + return fileDescriptor_592ad94d7d6be24f, []int{4} } func (m *ExternalMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -134,7 +190,7 @@ var xxx_messageInfo_ExternalMetricStatus proto.InternalMessageInfo func (m *HPAScalingPolicy) Reset() { *m = HPAScalingPolicy{} } func (*HPAScalingPolicy) ProtoMessage() {} func (*HPAScalingPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{3} + return fileDescriptor_592ad94d7d6be24f, []int{5} } func (m *HPAScalingPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -162,7 +218,7 @@ var xxx_messageInfo_HPAScalingPolicy proto.InternalMessageInfo func (m *HPAScalingRules) Reset() { *m = HPAScalingRules{} } func (*HPAScalingRules) ProtoMessage() {} func (*HPAScalingRules) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{4} + return fileDescriptor_592ad94d7d6be24f, []int{6} } func (m *HPAScalingRules) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -190,7 +246,7 @@ var xxx_messageInfo_HPAScalingRules proto.InternalMessageInfo func (m *HorizontalPodAutoscaler) Reset() { *m = HorizontalPodAutoscaler{} } func (*HorizontalPodAutoscaler) ProtoMessage() {} func (*HorizontalPodAutoscaler) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{5} + return fileDescriptor_592ad94d7d6be24f, []int{7} } func (m *HorizontalPodAutoscaler) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -218,7 +274,7 @@ var xxx_messageInfo_HorizontalPodAutoscaler proto.InternalMessageInfo func (m *HorizontalPodAutoscalerBehavior) Reset() { *m = HorizontalPodAutoscalerBehavior{} } func (*HorizontalPodAutoscalerBehavior) ProtoMessage() {} func (*HorizontalPodAutoscalerBehavior) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{6} + return fileDescriptor_592ad94d7d6be24f, []int{8} } func (m *HorizontalPodAutoscalerBehavior) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -246,7 +302,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerBehavior proto.InternalMessageInfo func (m *HorizontalPodAutoscalerCondition) Reset() { *m = HorizontalPodAutoscalerCondition{} } func (*HorizontalPodAutoscalerCondition) ProtoMessage() {} func (*HorizontalPodAutoscalerCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{7} + return fileDescriptor_592ad94d7d6be24f, []int{9} } func (m *HorizontalPodAutoscalerCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -274,7 +330,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerCondition proto.InternalMessageInfo func (m *HorizontalPodAutoscalerList) Reset() { *m = HorizontalPodAutoscalerList{} } func (*HorizontalPodAutoscalerList) ProtoMessage() {} func (*HorizontalPodAutoscalerList) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{8} + return fileDescriptor_592ad94d7d6be24f, []int{10} } func (m *HorizontalPodAutoscalerList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -302,7 +358,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerList proto.InternalMessageInfo func (m *HorizontalPodAutoscalerSpec) Reset() { *m = HorizontalPodAutoscalerSpec{} } func (*HorizontalPodAutoscalerSpec) ProtoMessage() {} func (*HorizontalPodAutoscalerSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{9} + return fileDescriptor_592ad94d7d6be24f, []int{11} } func (m *HorizontalPodAutoscalerSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -330,7 +386,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerSpec proto.InternalMessageInfo func (m *HorizontalPodAutoscalerStatus) Reset() { *m = HorizontalPodAutoscalerStatus{} } func (*HorizontalPodAutoscalerStatus) ProtoMessage() {} func (*HorizontalPodAutoscalerStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{10} + return fileDescriptor_592ad94d7d6be24f, []int{12} } func (m *HorizontalPodAutoscalerStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -358,7 +414,7 @@ var xxx_messageInfo_HorizontalPodAutoscalerStatus proto.InternalMessageInfo func (m *MetricIdentifier) Reset() { *m = MetricIdentifier{} } func (*MetricIdentifier) ProtoMessage() {} func (*MetricIdentifier) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{11} + return fileDescriptor_592ad94d7d6be24f, []int{13} } func (m *MetricIdentifier) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -386,7 +442,7 @@ var xxx_messageInfo_MetricIdentifier proto.InternalMessageInfo func (m *MetricSpec) Reset() { *m = MetricSpec{} } func (*MetricSpec) ProtoMessage() {} func (*MetricSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{12} + return fileDescriptor_592ad94d7d6be24f, []int{14} } func (m *MetricSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -414,7 +470,7 @@ var xxx_messageInfo_MetricSpec proto.InternalMessageInfo func (m *MetricStatus) Reset() { *m = MetricStatus{} } func (*MetricStatus) ProtoMessage() {} func (*MetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{13} + return fileDescriptor_592ad94d7d6be24f, []int{15} } func (m *MetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -442,7 +498,7 @@ var xxx_messageInfo_MetricStatus proto.InternalMessageInfo func (m *MetricTarget) Reset() { *m = MetricTarget{} } func (*MetricTarget) ProtoMessage() {} func (*MetricTarget) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{14} + return fileDescriptor_592ad94d7d6be24f, []int{16} } func (m *MetricTarget) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -470,7 +526,7 @@ var xxx_messageInfo_MetricTarget proto.InternalMessageInfo func (m *MetricValueStatus) Reset() { *m = MetricValueStatus{} } func (*MetricValueStatus) ProtoMessage() {} func (*MetricValueStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{15} + return fileDescriptor_592ad94d7d6be24f, []int{17} } func (m *MetricValueStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -498,7 +554,7 @@ var xxx_messageInfo_MetricValueStatus proto.InternalMessageInfo func (m *ObjectMetricSource) Reset() { *m = ObjectMetricSource{} } func (*ObjectMetricSource) ProtoMessage() {} func (*ObjectMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{16} + return fileDescriptor_592ad94d7d6be24f, []int{18} } func (m *ObjectMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -526,7 +582,7 @@ var xxx_messageInfo_ObjectMetricSource proto.InternalMessageInfo func (m *ObjectMetricStatus) Reset() { *m = ObjectMetricStatus{} } func (*ObjectMetricStatus) ProtoMessage() {} func (*ObjectMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{17} + return fileDescriptor_592ad94d7d6be24f, []int{19} } func (m *ObjectMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -554,7 +610,7 @@ var xxx_messageInfo_ObjectMetricStatus proto.InternalMessageInfo func (m *PodsMetricSource) Reset() { *m = PodsMetricSource{} } func (*PodsMetricSource) ProtoMessage() {} func (*PodsMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{18} + return fileDescriptor_592ad94d7d6be24f, []int{20} } func (m *PodsMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -582,7 +638,7 @@ var xxx_messageInfo_PodsMetricSource proto.InternalMessageInfo func (m *PodsMetricStatus) Reset() { *m = PodsMetricStatus{} } func (*PodsMetricStatus) ProtoMessage() {} func (*PodsMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{19} + return fileDescriptor_592ad94d7d6be24f, []int{21} } func (m *PodsMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -610,7 +666,7 @@ var xxx_messageInfo_PodsMetricStatus proto.InternalMessageInfo func (m *ResourceMetricSource) Reset() { *m = ResourceMetricSource{} } func (*ResourceMetricSource) ProtoMessage() {} func (*ResourceMetricSource) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{20} + return fileDescriptor_592ad94d7d6be24f, []int{22} } func (m *ResourceMetricSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -638,7 +694,7 @@ var xxx_messageInfo_ResourceMetricSource proto.InternalMessageInfo func (m *ResourceMetricStatus) Reset() { *m = ResourceMetricStatus{} } func (*ResourceMetricStatus) ProtoMessage() {} func (*ResourceMetricStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_592ad94d7d6be24f, []int{21} + return fileDescriptor_592ad94d7d6be24f, []int{23} } func (m *ResourceMetricStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -664,6 +720,8 @@ func (m *ResourceMetricStatus) XXX_DiscardUnknown() { var xxx_messageInfo_ResourceMetricStatus proto.InternalMessageInfo func init() { + proto.RegisterType((*ContainerResourceMetricSource)(nil), "k8s.io.api.autoscaling.v2beta2.ContainerResourceMetricSource") + proto.RegisterType((*ContainerResourceMetricStatus)(nil), "k8s.io.api.autoscaling.v2beta2.ContainerResourceMetricStatus") proto.RegisterType((*CrossVersionObjectReference)(nil), "k8s.io.api.autoscaling.v2beta2.CrossVersionObjectReference") proto.RegisterType((*ExternalMetricSource)(nil), "k8s.io.api.autoscaling.v2beta2.ExternalMetricSource") proto.RegisterType((*ExternalMetricStatus)(nil), "k8s.io.api.autoscaling.v2beta2.ExternalMetricStatus") @@ -693,111 +751,202 @@ func init() { } var fileDescriptor_592ad94d7d6be24f = []byte{ - // 1657 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0xdb, 0x6f, 0x1b, 0x45, - 0x17, 0xcf, 0xda, 0xce, 0x6d, 0x9c, 0x5b, 0xa7, 0xfd, 0x5a, 0x2b, 0xd5, 0x67, 0x47, 0xfb, 0x55, - 0x1f, 0x50, 0xd1, 0x35, 0x31, 0x01, 0x2a, 0x55, 0x08, 0xe2, 0x14, 0xda, 0xaa, 0x49, 0x1b, 0xc6, - 0x69, 0x40, 0x28, 0xad, 0x18, 0xef, 0x4e, 0x9c, 0x21, 0xf6, 0xae, 0xb5, 0xb3, 0x76, 0x9b, 0x22, - 0x21, 0x5e, 0x78, 0x47, 0x20, 0x5e, 0xf9, 0x03, 0x10, 0x42, 0xe2, 0x05, 0x89, 0x47, 0x2e, 0xaa, - 0x2a, 0x84, 0x50, 0xdf, 0x28, 0x2f, 0x16, 0x35, 0xff, 0x45, 0x9e, 0xd0, 0x5c, 0x76, 0xbd, 0xbb, - 0x76, 0x62, 0x27, 0x4a, 0x8a, 0xfa, 0xb6, 0x33, 0xe7, 0x9c, 0xdf, 0x99, 0x39, 0xf7, 0x59, 0x70, - 0x65, 0xfb, 0x22, 0x33, 0xa8, 0x93, 0xdf, 0x6e, 0x94, 0x89, 0x6b, 0x13, 0x8f, 0xb0, 0x7c, 0x93, - 0xd8, 0x96, 0xe3, 0xe6, 0x15, 0x01, 0xd7, 0x69, 0x1e, 0x37, 0x3c, 0x87, 0x99, 0xb8, 0x4a, 0xed, - 0x4a, 0xbe, 0x59, 0x28, 0x13, 0x0f, 0x17, 0xf2, 0x15, 0x62, 0x13, 0x17, 0x7b, 0xc4, 0x32, 0xea, - 0xae, 0xe3, 0x39, 0x30, 0x2b, 0xf9, 0x0d, 0x5c, 0xa7, 0x46, 0x88, 0xdf, 0x50, 0xfc, 0xb3, 0x17, - 0x2a, 0xd4, 0xdb, 0x6a, 0x94, 0x0d, 0xd3, 0xa9, 0xe5, 0x2b, 0x4e, 0xc5, 0xc9, 0x0b, 0xb1, 0x72, - 0x63, 0x53, 0xac, 0xc4, 0x42, 0x7c, 0x49, 0xb8, 0x59, 0x3d, 0xa4, 0xde, 0x74, 0x5c, 0x92, 0x6f, - 0xce, 0xc7, 0x55, 0xce, 0x2e, 0x74, 0x78, 0x6a, 0xd8, 0xdc, 0xa2, 0x36, 0x71, 0x77, 0xf2, 0xf5, - 0xed, 0x8a, 0x10, 0x72, 0x09, 0x73, 0x1a, 0xae, 0x49, 0x0e, 0x24, 0xc5, 0xf2, 0x35, 0xe2, 0xe1, - 0x5e, 0xba, 0xf2, 0x7b, 0x49, 0xb9, 0x0d, 0xdb, 0xa3, 0xb5, 0x6e, 0x35, 0xaf, 0xf6, 0x13, 0x60, - 0xe6, 0x16, 0xa9, 0xe1, 0xb8, 0x9c, 0xfe, 0xa5, 0x06, 0xce, 0x2e, 0xb9, 0x0e, 0x63, 0xeb, 0xc4, - 0x65, 0xd4, 0xb1, 0x6f, 0x96, 0x3f, 0x24, 0xa6, 0x87, 0xc8, 0x26, 0x71, 0x89, 0x6d, 0x12, 0x38, - 0x07, 0x52, 0xdb, 0xd4, 0xb6, 0x32, 0xda, 0x9c, 0xf6, 0xfc, 0x78, 0x71, 0xe2, 0x61, 0x2b, 0x37, - 0xd4, 0x6e, 0xe5, 0x52, 0xd7, 0xa9, 0x6d, 0x21, 0x41, 0xe1, 0x1c, 0x36, 0xae, 0x91, 0x4c, 0x22, - 0xca, 0x71, 0x03, 0xd7, 0x08, 0x12, 0x14, 0x58, 0x00, 0x00, 0xd7, 0xa9, 0x52, 0x90, 0x49, 0x0a, - 0x3e, 0xa8, 0xf8, 0xc0, 0xe2, 0xea, 0x35, 0x45, 0x41, 0x21, 0x2e, 0xfd, 0x81, 0x06, 0x4e, 0xbd, - 0x75, 0xcf, 0x23, 0xae, 0x8d, 0xab, 0x2b, 0xc4, 0x73, 0xa9, 0x59, 0x12, 0xf6, 0x85, 0xef, 0x81, - 0x91, 0x9a, 0x58, 0x8b, 0x23, 0xa5, 0x0b, 0x2f, 0x19, 0xfb, 0x47, 0x82, 0x21, 0xa5, 0xaf, 0x59, - 0xc4, 0xf6, 0xe8, 0x26, 0x25, 0x6e, 0x71, 0x4a, 0xa9, 0x1e, 0x91, 0x14, 0xa4, 0xf0, 0xe0, 0x1a, - 0x18, 0xf1, 0xb0, 0x5b, 0x21, 0x9e, 0xb8, 0x4a, 0xba, 0xf0, 0xe2, 0x60, 0xc8, 0x6b, 0x42, 0xa6, - 0x83, 0x2a, 0xd7, 0x48, 0x61, 0xe9, 0xbf, 0x77, 0x5f, 0xc4, 0xc3, 0x5e, 0x83, 0x1d, 0xe3, 0x45, - 0x36, 0xc0, 0xa8, 0xd9, 0x70, 0x5d, 0x62, 0xfb, 0x37, 0x99, 0x1f, 0x0c, 0x7a, 0x1d, 0x57, 0x1b, - 0x44, 0x9e, 0xae, 0x38, 0xad, 0xb0, 0x47, 0x97, 0x24, 0x12, 0xf2, 0x21, 0xf5, 0x6f, 0x35, 0x30, - 0x73, 0x75, 0x75, 0xb1, 0x24, 0x21, 0x56, 0x9d, 0x2a, 0x35, 0x77, 0xe0, 0x45, 0x90, 0xf2, 0x76, - 0xea, 0x44, 0x85, 0xc9, 0x39, 0x3f, 0x08, 0xd6, 0x76, 0xea, 0x64, 0xb7, 0x95, 0x3b, 0x15, 0xe7, - 0xe7, 0xfb, 0x48, 0x48, 0xc0, 0xff, 0x81, 0xe1, 0x26, 0xd7, 0x2b, 0x8e, 0x3a, 0x5c, 0x9c, 0x54, - 0xa2, 0xc3, 0xe2, 0x30, 0x48, 0xd2, 0xe0, 0x25, 0x30, 0x59, 0x27, 0x2e, 0x75, 0xac, 0x12, 0x31, - 0x1d, 0xdb, 0x62, 0x22, 0x88, 0x86, 0x8b, 0xff, 0x51, 0xcc, 0x93, 0xab, 0x61, 0x22, 0x8a, 0xf2, - 0xea, 0x5f, 0x25, 0xc0, 0x74, 0xe7, 0x00, 0xa8, 0x51, 0x25, 0x0c, 0xde, 0x01, 0xb3, 0xcc, 0xc3, - 0x65, 0x5a, 0xa5, 0xf7, 0xb1, 0x47, 0x1d, 0xfb, 0x5d, 0x6a, 0x5b, 0xce, 0xdd, 0x28, 0x7a, 0xb6, - 0xdd, 0xca, 0xcd, 0x96, 0xf6, 0xe4, 0x42, 0xfb, 0x20, 0xc0, 0xeb, 0x60, 0x82, 0x91, 0x2a, 0x31, - 0x3d, 0x79, 0x5f, 0x65, 0x97, 0xe7, 0xda, 0xad, 0xdc, 0x44, 0x29, 0xb4, 0xbf, 0xdb, 0xca, 0x9d, - 0x8c, 0x18, 0x46, 0x12, 0x51, 0x44, 0x18, 0xde, 0x01, 0x63, 0x75, 0xfe, 0x45, 0x09, 0xcb, 0x24, - 0xe6, 0x92, 0x83, 0xc4, 0x4a, 0xdc, 0xe0, 0xc5, 0x19, 0x65, 0xaa, 0xb1, 0x55, 0x85, 0x84, 0x02, - 0x4c, 0xfd, 0xc7, 0x04, 0x38, 0x73, 0xd5, 0x71, 0xe9, 0x7d, 0xc7, 0xf6, 0x70, 0x75, 0xd5, 0xb1, - 0x16, 0x15, 0x22, 0x71, 0xe1, 0x07, 0x60, 0x8c, 0xd7, 0x28, 0x0b, 0x7b, 0xb8, 0x47, 0x9c, 0x06, - 0xa5, 0xc6, 0xa8, 0x6f, 0x57, 0xf8, 0x06, 0x33, 0x38, 0xb7, 0xd1, 0x9c, 0x37, 0x64, 0x21, 0x59, - 0x21, 0x1e, 0xee, 0xe4, 0x7a, 0x67, 0x0f, 0x05, 0xa8, 0xf0, 0x36, 0x48, 0xb1, 0x3a, 0x31, 0x55, - 0xa8, 0x5e, 0xea, 0x7b, 0xb3, 0xde, 0x07, 0x2d, 0xd5, 0x89, 0xd9, 0x29, 0x3e, 0x7c, 0x85, 0x04, - 0x2c, 0x24, 0x60, 0x84, 0x89, 0x90, 0x16, 0x5e, 0x4d, 0x17, 0x5e, 0x3f, 0xac, 0x02, 0x99, 0x17, - 0x41, 0xce, 0xc9, 0x35, 0x52, 0xe0, 0xfa, 0x1f, 0x1a, 0xc8, 0xed, 0x21, 0x59, 0x24, 0x5b, 0xb8, - 0x49, 0x1d, 0x17, 0xae, 0x83, 0x51, 0xb1, 0x73, 0xab, 0xae, 0x4c, 0x99, 0x1f, 0xdc, 0x8d, 0x22, - 0x6c, 0x8b, 0x69, 0x9e, 0x91, 0x25, 0x89, 0x81, 0x7c, 0x30, 0xb8, 0x01, 0xc6, 0xc5, 0xe7, 0x65, - 0xe7, 0xae, 0xad, 0xcc, 0x78, 0x60, 0xe4, 0xc9, 0x76, 0x2b, 0x37, 0x5e, 0xf2, 0x51, 0x50, 0x07, - 0x50, 0xff, 0x34, 0x09, 0xe6, 0xf6, 0xb8, 0xd9, 0x92, 0x63, 0x5b, 0x94, 0x07, 0x3f, 0xbc, 0x1a, - 0xc9, 0xff, 0x85, 0x58, 0xfe, 0x9f, 0xeb, 0x27, 0x1f, 0xaa, 0x07, 0xcb, 0x81, 0xbf, 0x12, 0x11, - 0x2c, 0x65, 0xf0, 0xdd, 0x56, 0xae, 0x47, 0xaf, 0x36, 0x02, 0xa4, 0xa8, 0x5b, 0x60, 0x13, 0xc0, - 0x2a, 0x66, 0xde, 0x9a, 0x8b, 0x6d, 0x26, 0x35, 0xd1, 0x1a, 0x51, 0x91, 0x70, 0x7e, 0xb0, 0x40, - 0xe6, 0x12, 0xc5, 0x59, 0x75, 0x0a, 0xb8, 0xdc, 0x85, 0x86, 0x7a, 0x68, 0x80, 0xff, 0x07, 0x23, - 0x2e, 0xc1, 0xcc, 0xb1, 0x33, 0x29, 0x71, 0x8b, 0x20, 0x6c, 0x90, 0xd8, 0x45, 0x8a, 0x0a, 0x5f, - 0x00, 0xa3, 0x35, 0xc2, 0x18, 0xae, 0x90, 0xcc, 0xb0, 0x60, 0x0c, 0xea, 0xee, 0x8a, 0xdc, 0x46, - 0x3e, 0x5d, 0xff, 0x53, 0x03, 0x67, 0xf7, 0xb0, 0xe3, 0x32, 0x65, 0x1e, 0xdc, 0xe8, 0xca, 0x54, - 0x63, 0xb0, 0x0b, 0x72, 0x69, 0x91, 0xa7, 0x41, 0x8d, 0xf0, 0x77, 0x42, 0x59, 0xba, 0x01, 0x86, - 0xa9, 0x47, 0x6a, 0x7e, 0x01, 0x7a, 0xed, 0x90, 0x59, 0xd4, 0xa9, 0xef, 0xd7, 0x38, 0x1a, 0x92, - 0xa0, 0xfa, 0x83, 0xe4, 0x9e, 0x77, 0xe3, 0xa9, 0x0c, 0x3f, 0x02, 0x53, 0x62, 0xa5, 0x7a, 0x2b, - 0xd9, 0x54, 0x37, 0xec, 0x5b, 0x2d, 0xf6, 0x19, 0x6d, 0x8a, 0xa7, 0xd5, 0x51, 0xa6, 0x4a, 0x11, - 0x68, 0x14, 0x53, 0x05, 0xe7, 0x41, 0xba, 0x46, 0x6d, 0x44, 0xea, 0x55, 0x6a, 0x62, 0xa6, 0xfa, - 0xd4, 0x74, 0xbb, 0x95, 0x4b, 0xaf, 0x74, 0xb6, 0x51, 0x98, 0x07, 0xbe, 0x02, 0xd2, 0x35, 0x7c, - 0x2f, 0x10, 0x91, 0xfd, 0xe4, 0xa4, 0xd2, 0x97, 0x5e, 0xe9, 0x90, 0x50, 0x98, 0x0f, 0xde, 0xe2, - 0xd1, 0xc0, 0x3b, 0x31, 0xcb, 0xa4, 0x84, 0x99, 0xcf, 0x0f, 0xd6, 0xb8, 0x45, 0xf1, 0x0b, 0x45, - 0x8e, 0x80, 0x40, 0x3e, 0x16, 0xa4, 0x60, 0xac, 0xac, 0x6a, 0x90, 0x88, 0xb2, 0x74, 0xe1, 0x8d, - 0xc3, 0xba, 0x4f, 0xc1, 0x14, 0x27, 0x78, 0x98, 0xf8, 0x2b, 0x14, 0xc0, 0xeb, 0xdf, 0xa7, 0xc0, - 0x7f, 0xf7, 0x2d, 0xa0, 0xf0, 0x6d, 0x00, 0x9d, 0x32, 0x23, 0x6e, 0x93, 0x58, 0x57, 0xe4, 0x2c, - 0xca, 0x87, 0x42, 0xee, 0xce, 0x64, 0xf1, 0x34, 0xcf, 0xb0, 0x9b, 0x5d, 0x54, 0xd4, 0x43, 0x02, - 0x9a, 0x60, 0x92, 0xe7, 0x9d, 0xf4, 0x1d, 0x55, 0xf3, 0xe7, 0xc1, 0x92, 0xfa, 0x04, 0x1f, 0x1d, - 0x96, 0xc3, 0x20, 0x28, 0x8a, 0x09, 0x17, 0xc1, 0xb4, 0x1a, 0x7b, 0x62, 0xbe, 0x3c, 0xa3, 0x8c, - 0x3d, 0xbd, 0x14, 0x25, 0xa3, 0x38, 0x3f, 0x87, 0xb0, 0x08, 0xa3, 0x2e, 0xb1, 0x02, 0x88, 0x54, - 0x14, 0xe2, 0x72, 0x94, 0x8c, 0xe2, 0xfc, 0xb0, 0x0a, 0xa6, 0x14, 0xaa, 0x72, 0x6d, 0x66, 0x58, - 0x44, 0xc7, 0x80, 0x03, 0xaa, 0xea, 0x5c, 0x41, 0xb8, 0x2f, 0x45, 0xb0, 0x50, 0x0c, 0x1b, 0x7a, - 0x00, 0x98, 0x7e, 0x35, 0x65, 0x99, 0x11, 0xa1, 0xe9, 0xcd, 0x43, 0xc6, 0x4b, 0x50, 0x96, 0x3b, - 0x33, 0x40, 0xb0, 0xc5, 0x50, 0x48, 0x8f, 0xfe, 0x85, 0x06, 0x66, 0xe2, 0x03, 0x6e, 0xf0, 0xb4, - 0xd0, 0xf6, 0x7c, 0x5a, 0xdc, 0x06, 0x63, 0x72, 0x54, 0x72, 0x5c, 0x15, 0x00, 0x2f, 0x0f, 0x58, - 0xf4, 0x70, 0x99, 0x54, 0x4b, 0x4a, 0x54, 0x86, 0xb3, 0xbf, 0x42, 0x01, 0xa4, 0xfe, 0x75, 0x12, - 0x80, 0x4e, 0x8a, 0xc1, 0x85, 0x48, 0x97, 0x9b, 0x8b, 0x75, 0xb9, 0x99, 0xf0, 0x3b, 0x25, 0xd4, - 0xd1, 0xd6, 0xc1, 0x88, 0x23, 0x4a, 0x8f, 0x3a, 0x61, 0xa1, 0x9f, 0x31, 0x83, 0x31, 0x29, 0x40, - 0x2b, 0x02, 0xde, 0x3b, 0x54, 0x01, 0x53, 0x68, 0xf0, 0x06, 0x48, 0xd5, 0x1d, 0xcb, 0x9f, 0x6b, - 0xfa, 0x8e, 0x84, 0xab, 0x8e, 0xc5, 0x22, 0x98, 0x63, 0xfc, 0xec, 0x7c, 0x17, 0x09, 0x1c, 0x3e, - 0x66, 0xfa, 0xaf, 0x58, 0x11, 0xa2, 0xe9, 0xc2, 0x42, 0x3f, 0x4c, 0xa4, 0xf8, 0x23, 0xb8, 0xc2, - 0x98, 0x3e, 0x05, 0x05, 0x98, 0x1c, 0x9f, 0xa8, 0x87, 0x90, 0x2a, 0x43, 0x7d, 0xf1, 0x7b, 0xbd, - 0x00, 0x25, 0xbe, 0x4f, 0x41, 0x01, 0xa6, 0xfe, 0x4d, 0x12, 0x4c, 0x44, 0x5e, 0x58, 0xff, 0x86, - 0xbb, 0x64, 0xae, 0x1d, 0xad, 0xbb, 0x24, 0xe6, 0xd1, 0xbb, 0x4b, 0xe2, 0x1e, 0x9f, 0xbb, 0x42, - 0xf8, 0x3d, 0xdc, 0xf5, 0x73, 0xc2, 0x77, 0x97, 0x6c, 0xb5, 0x83, 0xb9, 0x4b, 0xf2, 0x86, 0xdc, - 0x75, 0x33, 0xfc, 0x7e, 0xec, 0x33, 0xf3, 0x18, 0xfe, 0xe5, 0x8c, 0x77, 0x1a, 0xd8, 0xf6, 0xa8, - 0xb7, 0x53, 0x1c, 0xef, 0x7a, 0x6b, 0x5a, 0x60, 0x02, 0x37, 0x89, 0x8b, 0x2b, 0x44, 0x6c, 0x2b, - 0x7f, 0x1d, 0x14, 0x77, 0x86, 0x3f, 0xf5, 0x16, 0x43, 0x38, 0x28, 0x82, 0xca, 0xdb, 0xa0, 0x5a, - 0xdf, 0xf2, 0x82, 0x37, 0xa4, 0xea, 0x0c, 0xa2, 0x0d, 0x2e, 0x76, 0x51, 0x51, 0x0f, 0x09, 0xfd, - 0xf3, 0x04, 0x38, 0xd1, 0xf5, 0x7a, 0xef, 0x18, 0x45, 0x3b, 0x26, 0xa3, 0x24, 0x9e, 0xa2, 0x51, - 0x92, 0x07, 0x36, 0xca, 0x2f, 0x09, 0x00, 0xbb, 0x8b, 0x28, 0xfc, 0x58, 0xb4, 0x62, 0xd3, 0xa5, - 0x65, 0x62, 0x49, 0xf2, 0x51, 0x8c, 0x91, 0xe1, 0x3e, 0x1e, 0xc6, 0x46, 0x71, 0x65, 0xc7, 0xf3, - 0x83, 0x29, 0xf4, 0x1f, 0x29, 0x79, 0xb4, 0xff, 0x91, 0xf4, 0xdf, 0xe2, 0x66, 0x7c, 0xa6, 0x7f, - 0x5c, 0xf5, 0x72, 0x7f, 0xf2, 0x29, 0xba, 0x5f, 0xff, 0x49, 0x03, 0x33, 0xf1, 0x26, 0xfc, 0xcc, - 0xfd, 0xce, 0xfc, 0x35, 0x7a, 0x89, 0x67, 0xfb, 0x57, 0xe6, 0x77, 0x1a, 0x38, 0xd5, 0x6b, 0x84, - 0x81, 0x4b, 0x91, 0xc1, 0x33, 0x1f, 0x1e, 0x3c, 0x77, 0x5b, 0xb9, 0x5c, 0x8f, 0x1f, 0x10, 0x3e, - 0x4c, 0x68, 0x36, 0x3d, 0x1e, 0x07, 0xfc, 0xd0, 0x7d, 0x66, 0xe9, 0x84, 0x23, 0x39, 0xf3, 0xb1, - 0xda, 0xbb, 0x78, 0xe1, 0xe1, 0x93, 0xec, 0xd0, 0xa3, 0x27, 0xd9, 0xa1, 0xc7, 0x4f, 0xb2, 0x43, - 0x9f, 0xb4, 0xb3, 0xda, 0xc3, 0x76, 0x56, 0x7b, 0xd4, 0xce, 0x6a, 0x8f, 0xdb, 0x59, 0xed, 0xaf, - 0x76, 0x56, 0xfb, 0xec, 0xef, 0xec, 0xd0, 0xfb, 0xa3, 0x0a, 0xfa, 0x9f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x79, 0xae, 0x08, 0x04, 0x2d, 0x1a, 0x00, 0x00, + // 1741 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xcd, 0x6f, 0x1b, 0xc7, + 0x15, 0xd7, 0x92, 0xd4, 0xd7, 0x50, 0x9f, 0xe3, 0x2f, 0x42, 0x86, 0x49, 0x61, 0x6b, 0xb4, 0xae, + 0x51, 0x2f, 0x2b, 0x56, 0x6d, 0x0d, 0x18, 0x45, 0xab, 0x95, 0x5b, 0xdb, 0xb0, 0x64, 0xab, 0x43, + 0x59, 0x2d, 0x0a, 0xd9, 0xe8, 0x70, 0x77, 0x44, 0x4d, 0x45, 0xee, 0x12, 0xbb, 0x4b, 0xda, 0x72, + 0x81, 0xa2, 0x08, 0x90, 0x7b, 0x90, 0x20, 0xd7, 0xfc, 0x09, 0x09, 0x7c, 0x09, 0x90, 0x63, 0x3e, + 0x60, 0x18, 0x41, 0x10, 0xf8, 0x16, 0xe7, 0x42, 0xc4, 0xcc, 0x31, 0xc7, 0xdc, 0x7c, 0x0a, 0xe6, + 0x63, 0x3f, 0x49, 0x89, 0x94, 0x20, 0x29, 0xd0, 0x8d, 0x3b, 0xf3, 0xde, 0xef, 0xcd, 0x7b, 0xf3, + 0x7b, 0x6f, 0xde, 0x0c, 0xc1, 0xad, 0x9d, 0xeb, 0xae, 0x46, 0xed, 0xe2, 0x4e, 0xb3, 0x42, 0x1c, + 0x8b, 0x78, 0xc4, 0x2d, 0xb6, 0x88, 0x65, 0xda, 0x4e, 0x51, 0x4e, 0xe0, 0x06, 0x2d, 0xe2, 0xa6, + 0x67, 0xbb, 0x06, 0xae, 0x51, 0xab, 0x5a, 0x6c, 0x95, 0x2a, 0xc4, 0xc3, 0xa5, 0x62, 0x95, 0x58, + 0xc4, 0xc1, 0x1e, 0x31, 0xb5, 0x86, 0x63, 0x7b, 0x36, 0xcc, 0x0b, 0x79, 0x0d, 0x37, 0xa8, 0x16, + 0x91, 0xd7, 0xa4, 0xfc, 0xdc, 0xb5, 0x2a, 0xf5, 0xb6, 0x9b, 0x15, 0xcd, 0xb0, 0xeb, 0xc5, 0xaa, + 0x5d, 0xb5, 0x8b, 0x5c, 0xad, 0xd2, 0xdc, 0xe2, 0x5f, 0xfc, 0x83, 0xff, 0x12, 0x70, 0x73, 0x6a, + 0xc4, 0xbc, 0x61, 0x3b, 0xa4, 0xd8, 0x5a, 0x48, 0x9a, 0x9c, 0x5b, 0x0c, 0x65, 0xea, 0xd8, 0xd8, + 0xa6, 0x16, 0x71, 0x76, 0x8b, 0x8d, 0x9d, 0x2a, 0x57, 0x72, 0x88, 0x6b, 0x37, 0x1d, 0x83, 0x1c, + 0x48, 0xcb, 0x2d, 0xd6, 0x89, 0x87, 0x7b, 0xd9, 0x2a, 0xee, 0xa5, 0xe5, 0x34, 0x2d, 0x8f, 0xd6, + 0xbb, 0xcd, 0xfc, 0xa1, 0x9f, 0x82, 0x6b, 0x6c, 0x93, 0x3a, 0x4e, 0xea, 0xa9, 0x3f, 0x28, 0xe0, + 0xd2, 0xb2, 0x6d, 0x79, 0x98, 0x69, 0x20, 0xe9, 0xc4, 0x2a, 0xf1, 0x1c, 0x6a, 0x94, 0xf9, 0x6f, + 0xb8, 0x0c, 0x32, 0x16, 0xae, 0x93, 0x9c, 0x32, 0xaf, 0x5c, 0x19, 0xd7, 0x8b, 0x2f, 0xda, 0x85, + 0xa1, 0x4e, 0xbb, 0x90, 0xb9, 0x87, 0xeb, 0xe4, 0x4d, 0xbb, 0x50, 0xe8, 0x0e, 0x9c, 0xe6, 0xc3, + 0x30, 0x11, 0xc4, 0x95, 0xe1, 0x3a, 0x18, 0xf1, 0xb0, 0x53, 0x25, 0x5e, 0x2e, 0x35, 0xaf, 0x5c, + 0xc9, 0x96, 0x7e, 0xa3, 0xed, 0xbf, 0x7f, 0x9a, 0x58, 0xc2, 0x3a, 0xd7, 0xd1, 0xa7, 0xa4, 0xd1, + 0x11, 0xf1, 0x8d, 0x24, 0x16, 0x2c, 0x82, 0x71, 0xc3, 0x5f, 0x7b, 0x2e, 0xcd, 0xd7, 0x37, 0x2b, + 0x45, 0xc7, 0x43, 0xa7, 0x42, 0x19, 0xf5, 0xc7, 0x7d, 0xbc, 0xf5, 0xb0, 0xd7, 0x74, 0x8f, 0xc6, + 0xdb, 0x4d, 0x30, 0x6a, 0x34, 0x1d, 0x87, 0x58, 0xbe, 0xbb, 0x0b, 0x83, 0xb9, 0xbb, 0x81, 0x6b, + 0x4d, 0x22, 0x16, 0xa2, 0x4f, 0x4b, 0xd3, 0xa3, 0xcb, 0x02, 0x09, 0xf9, 0x90, 0x07, 0xf7, 0xfa, + 0x7d, 0x05, 0x5c, 0x5c, 0x76, 0x6c, 0xd7, 0xdd, 0x20, 0x8e, 0x4b, 0x6d, 0xeb, 0x7e, 0xe5, 0x3f, + 0xc4, 0xf0, 0x10, 0xd9, 0x22, 0x0e, 0xb1, 0x0c, 0x02, 0xe7, 0x41, 0x66, 0x87, 0x5a, 0xa6, 0xf4, + 0x79, 0xc2, 0xf7, 0xf9, 0x2e, 0xb5, 0x4c, 0xc4, 0x67, 0x98, 0x04, 0x8f, 0x4a, 0x2a, 0x2e, 0x11, + 0x71, 0xb9, 0x04, 0x00, 0x6e, 0x50, 0x69, 0x40, 0xae, 0x0a, 0x4a, 0x39, 0xb0, 0xb4, 0x76, 0x47, + 0xce, 0xa0, 0x88, 0x94, 0xfa, 0x5c, 0x01, 0x67, 0xff, 0xfa, 0xc4, 0x23, 0x8e, 0x85, 0x6b, 0x31, + 0xca, 0xfd, 0x13, 0x8c, 0xd4, 0xf9, 0x37, 0x5f, 0x52, 0xb6, 0xf4, 0xdb, 0xc1, 0xc2, 0x77, 0xc7, + 0x24, 0x96, 0x47, 0xb7, 0x28, 0x71, 0x42, 0xc6, 0x88, 0x19, 0x24, 0xf1, 0x8e, 0x87, 0x87, 0xea, + 0xd7, 0xdd, 0x8e, 0x08, 0x36, 0x1d, 0x9f, 0x23, 0xc7, 0x4a, 0x31, 0xf5, 0x43, 0x05, 0xcc, 0xdc, + 0x5e, 0x5b, 0x2a, 0x0b, 0x88, 0x35, 0xbb, 0x46, 0x8d, 0x5d, 0x78, 0x1d, 0x64, 0xbc, 0xdd, 0x86, + 0x9f, 0x1a, 0x97, 0x7d, 0x12, 0xac, 0xef, 0x36, 0x58, 0x6a, 0x9c, 0x4d, 0xca, 0xb3, 0x71, 0xc4, + 0x35, 0xe0, 0x2f, 0xc0, 0x70, 0x8b, 0xd9, 0xe5, 0x4b, 0x1d, 0xd6, 0x27, 0xa5, 0xea, 0x30, 0x5f, + 0x0c, 0x12, 0x73, 0xf0, 0x06, 0x98, 0x6c, 0x10, 0x87, 0xda, 0x66, 0x99, 0x18, 0xb6, 0x65, 0xba, + 0x9c, 0x44, 0xc3, 0xfa, 0x39, 0x29, 0x3c, 0xb9, 0x16, 0x9d, 0x44, 0x71, 0x59, 0xf5, 0x83, 0x14, + 0x98, 0x0e, 0x17, 0x80, 0x9a, 0x35, 0xe2, 0xc2, 0x47, 0x60, 0xce, 0xf5, 0x70, 0x85, 0xd6, 0xe8, + 0x53, 0xec, 0x51, 0xdb, 0xfa, 0x07, 0xb5, 0x4c, 0xfb, 0x71, 0x1c, 0x3d, 0xdf, 0x69, 0x17, 0xe6, + 0xca, 0x7b, 0x4a, 0xa1, 0x7d, 0x10, 0xe0, 0x5d, 0x30, 0xe1, 0x92, 0x1a, 0x31, 0x3c, 0xe1, 0xaf, + 0x8c, 0xcb, 0xaf, 0x3a, 0xed, 0xc2, 0x44, 0x39, 0x32, 0xfe, 0xa6, 0x5d, 0x38, 0x13, 0x0b, 0x8c, + 0x98, 0x44, 0x31, 0x65, 0xf8, 0x08, 0x8c, 0x35, 0xd8, 0x2f, 0x4a, 0xdc, 0x5c, 0x6a, 0x3e, 0x3d, + 0x08, 0x57, 0x92, 0x01, 0xd7, 0x67, 0x64, 0xa8, 0xc6, 0xd6, 0x24, 0x12, 0x0a, 0x30, 0xd5, 0x4f, + 0x53, 0xe0, 0xc2, 0x6d, 0xdb, 0xa1, 0x4f, 0x59, 0x55, 0xa8, 0xad, 0xd9, 0xe6, 0x92, 0x44, 0x24, + 0x0e, 0xfc, 0x37, 0x18, 0x63, 0xe7, 0x90, 0x89, 0x3d, 0xdc, 0x83, 0xa7, 0xc1, 0x71, 0xa2, 0x35, + 0x76, 0xaa, 0x6c, 0xc0, 0xd5, 0x98, 0xb4, 0xd6, 0x5a, 0xd0, 0x44, 0x21, 0x59, 0x25, 0x1e, 0x0e, + 0x73, 0x3d, 0x1c, 0x43, 0x01, 0x2a, 0x7c, 0x08, 0x32, 0x6e, 0x83, 0x18, 0x92, 0xaa, 0x37, 0xfa, + 0x7a, 0xd6, 0x7b, 0xa1, 0xe5, 0x06, 0x31, 0xc2, 0xe2, 0xc3, 0xbe, 0x10, 0x87, 0x85, 0x04, 0x8c, + 0xb8, 0x9c, 0xd2, 0x7c, 0x57, 0xb3, 0xa5, 0x3f, 0x1d, 0xd6, 0x80, 0xc8, 0x8b, 0x20, 0xe7, 0xc4, + 0x37, 0x92, 0xe0, 0xea, 0x37, 0x0a, 0x28, 0xec, 0xa1, 0xa9, 0x93, 0x6d, 0xdc, 0xa2, 0xb6, 0x03, + 0x37, 0xc0, 0x28, 0x1f, 0x79, 0xd0, 0x90, 0xa1, 0x2c, 0x0e, 0xbe, 0x8d, 0x9c, 0xb6, 0x7a, 0x96, + 0x65, 0x64, 0x59, 0x60, 0x20, 0x1f, 0x0c, 0x6e, 0x82, 0x71, 0xfe, 0xf3, 0xa6, 0xfd, 0xd8, 0x92, + 0x61, 0x3c, 0x30, 0xf2, 0x24, 0x3b, 0x21, 0xca, 0x3e, 0x0a, 0x0a, 0x01, 0xd5, 0xb7, 0xd3, 0x60, + 0x7e, 0x0f, 0xcf, 0x96, 0x6d, 0xcb, 0xa4, 0x8c, 0xfc, 0xf0, 0x76, 0x2c, 0xff, 0x17, 0x13, 0xf9, + 0x7f, 0xb9, 0x9f, 0x7e, 0xa4, 0x1e, 0xac, 0x04, 0xfb, 0x95, 0x8a, 0x61, 0xc9, 0x80, 0xbf, 0x69, + 0x17, 0x7a, 0xf4, 0x63, 0x5a, 0x80, 0x14, 0xdf, 0x16, 0xd8, 0x02, 0xb0, 0x86, 0x5d, 0x6f, 0xdd, + 0xc1, 0x96, 0x2b, 0x2c, 0xd1, 0x3a, 0x91, 0x4c, 0xb8, 0x3a, 0x18, 0x91, 0x99, 0x86, 0x3e, 0x27, + 0x57, 0x01, 0x57, 0xba, 0xd0, 0x50, 0x0f, 0x0b, 0xf0, 0x97, 0x60, 0xc4, 0x21, 0xd8, 0xb5, 0xad, + 0x5c, 0x86, 0x7b, 0x11, 0xd0, 0x06, 0xf1, 0x51, 0x24, 0x67, 0xe1, 0xaf, 0xc1, 0x68, 0x9d, 0xb8, + 0x2e, 0xae, 0x92, 0xdc, 0x30, 0x17, 0x0c, 0xea, 0xee, 0xaa, 0x18, 0x46, 0xfe, 0xbc, 0xfa, 0xad, + 0x02, 0x2e, 0xee, 0x11, 0xc7, 0x15, 0xea, 0x7a, 0x70, 0xb3, 0x2b, 0x53, 0xb5, 0xc1, 0x1c, 0x64, + 0xda, 0x3c, 0x4f, 0x83, 0x1a, 0xe1, 0x8f, 0x44, 0xb2, 0x74, 0x13, 0x0c, 0x53, 0x8f, 0xd4, 0xfd, + 0x02, 0xf4, 0xc7, 0x43, 0x66, 0x51, 0x58, 0xdf, 0xef, 0x30, 0x34, 0x24, 0x40, 0xd5, 0xe7, 0xe9, + 0x3d, 0x7d, 0x63, 0xa9, 0x0c, 0xff, 0x0b, 0xa6, 0xf8, 0x97, 0x3c, 0x5b, 0xc9, 0x96, 0xf4, 0xb0, + 0x6f, 0xb5, 0xd8, 0xa7, 0xb5, 0xd1, 0xcf, 0xcb, 0xa5, 0x4c, 0x95, 0x63, 0xd0, 0x28, 0x61, 0x0a, + 0x2e, 0x80, 0x6c, 0x9d, 0x5a, 0x88, 0x34, 0x6a, 0xd4, 0xc0, 0xae, 0x3c, 0xa7, 0xa6, 0x3b, 0xed, + 0x42, 0x76, 0x35, 0x1c, 0x46, 0x51, 0x19, 0xf8, 0x7b, 0x90, 0xad, 0xe3, 0x27, 0x81, 0x8a, 0x38, + 0x4f, 0xce, 0x48, 0x7b, 0xd9, 0xd5, 0x70, 0x0a, 0x45, 0xe5, 0xe0, 0x03, 0xc6, 0x06, 0x76, 0x12, + 0xbb, 0xb9, 0x0c, 0x0f, 0xf3, 0xd5, 0xc1, 0x0e, 0x6e, 0x5e, 0xfc, 0x22, 0xcc, 0xe1, 0x10, 0xc8, + 0xc7, 0x82, 0x14, 0x8c, 0x55, 0x64, 0x0d, 0xe2, 0x2c, 0xcb, 0x96, 0xfe, 0x7c, 0xd8, 0xed, 0x93, + 0x30, 0xfa, 0x04, 0xa3, 0x89, 0xff, 0x85, 0x02, 0x78, 0xf5, 0xe3, 0x0c, 0xb8, 0xb4, 0x6f, 0x01, + 0x85, 0x7f, 0x03, 0xd0, 0xae, 0xb8, 0xc4, 0x69, 0x11, 0xf3, 0x96, 0xb8, 0x6f, 0xb0, 0xa6, 0x90, + 0x6d, 0x67, 0x5a, 0x3f, 0xcf, 0x32, 0xec, 0x7e, 0xd7, 0x2c, 0xea, 0xa1, 0x01, 0x0d, 0x30, 0xc9, + 0xf2, 0x4e, 0xec, 0x1d, 0x95, 0xfd, 0xe7, 0xc1, 0x92, 0x7a, 0x96, 0xb5, 0x0e, 0x2b, 0x51, 0x10, + 0x14, 0xc7, 0x84, 0x4b, 0x60, 0x5a, 0xb6, 0x3d, 0x89, 0xbd, 0xbc, 0x20, 0x83, 0x3d, 0xbd, 0x1c, + 0x9f, 0x46, 0x49, 0x79, 0x06, 0x61, 0x12, 0x97, 0x3a, 0xc4, 0x0c, 0x20, 0x32, 0x71, 0x88, 0x9b, + 0xf1, 0x69, 0x94, 0x94, 0x87, 0x35, 0x30, 0x25, 0x51, 0xe5, 0xd6, 0xe6, 0x86, 0x39, 0x3b, 0x06, + 0x6c, 0x50, 0xe5, 0xc9, 0x15, 0xd0, 0x7d, 0x39, 0x86, 0x85, 0x12, 0xd8, 0xd0, 0x03, 0xc0, 0xf0, + 0xab, 0xa9, 0x9b, 0x1b, 0xe1, 0x96, 0xfe, 0x72, 0x48, 0xbe, 0x04, 0x65, 0x39, 0xec, 0x01, 0x82, + 0x21, 0x17, 0x45, 0xec, 0xa8, 0xef, 0x29, 0x60, 0x26, 0xd9, 0xe0, 0x06, 0x57, 0x0b, 0x65, 0xcf, + 0xab, 0xc5, 0x43, 0x30, 0x26, 0x5a, 0x25, 0xdb, 0x91, 0x04, 0xf8, 0xdd, 0x80, 0x45, 0x0f, 0x57, + 0x48, 0xad, 0x2c, 0x55, 0x05, 0x9d, 0xfd, 0x2f, 0x14, 0x40, 0xaa, 0x1f, 0x65, 0x00, 0x08, 0x53, + 0x0c, 0x2e, 0xc6, 0x4e, 0xb9, 0xf9, 0xc4, 0x29, 0x37, 0x13, 0xbd, 0xa7, 0x44, 0x4e, 0xb4, 0x0d, + 0x30, 0x62, 0xf3, 0xd2, 0x23, 0x57, 0x58, 0xea, 0x17, 0xcc, 0xa0, 0x4d, 0x0a, 0xd0, 0x74, 0xc0, + 0xce, 0x0e, 0x59, 0xc0, 0x24, 0x1a, 0xbc, 0x07, 0x32, 0x0d, 0xdb, 0xf4, 0xfb, 0x9a, 0xbe, 0x2d, + 0xe1, 0x9a, 0x6d, 0xba, 0x31, 0xcc, 0x31, 0xb6, 0x76, 0x36, 0x8a, 0x38, 0x0e, 0x6b, 0x33, 0xfd, + 0x97, 0x0a, 0x4e, 0xd1, 0x6c, 0x69, 0xb1, 0x1f, 0x66, 0xaf, 0x47, 0x01, 0x11, 0x4c, 0x7f, 0x06, + 0x05, 0x98, 0xf0, 0x2d, 0x05, 0xcc, 0x1a, 0xc9, 0x0b, 0x76, 0x6e, 0x74, 0xb0, 0xae, 0x6c, 0xdf, + 0x77, 0x08, 0xfd, 0x5c, 0xa7, 0x5d, 0x98, 0xed, 0x12, 0x41, 0xdd, 0xe6, 0x98, 0x93, 0x44, 0xde, + 0xc6, 0x64, 0x2d, 0xec, 0xeb, 0x64, 0xaf, 0x6b, 0xa8, 0x70, 0xd2, 0x9f, 0x41, 0x01, 0xa6, 0xfa, + 0x2c, 0x03, 0x26, 0x62, 0xd7, 0xbc, 0x9f, 0x83, 0x33, 0x22, 0xe1, 0x8f, 0x96, 0x33, 0x02, 0xf3, + 0xe8, 0x39, 0x23, 0x70, 0x4f, 0x94, 0x33, 0xc2, 0xe4, 0x49, 0x72, 0x26, 0xe2, 0x64, 0x0f, 0xce, + 0x7c, 0x9e, 0xf2, 0x39, 0x23, 0x9a, 0x8e, 0xc1, 0x38, 0x23, 0x64, 0x23, 0x9c, 0xb9, 0x1f, 0xbd, + 0x49, 0xf7, 0xe9, 0xfe, 0x34, 0x3f, 0xc2, 0xda, 0xdf, 0x9b, 0xd8, 0xf2, 0xa8, 0xb7, 0xab, 0x8f, + 0x77, 0xdd, 0xba, 0x4d, 0x30, 0x81, 0x5b, 0xc4, 0xc1, 0x55, 0xc2, 0x87, 0x25, 0x69, 0x0e, 0x8a, + 0x3b, 0xc3, 0x2e, 0xbd, 0x4b, 0x11, 0x1c, 0x14, 0x43, 0x65, 0x0d, 0x81, 0xfc, 0x7e, 0xe0, 0x05, + 0xb7, 0x69, 0x79, 0x46, 0xf2, 0x86, 0x60, 0xa9, 0x6b, 0x16, 0xf5, 0xd0, 0x50, 0xdf, 0x4d, 0x81, + 0xd9, 0xae, 0x77, 0x8c, 0x30, 0x28, 0xca, 0x31, 0x05, 0x25, 0x75, 0x82, 0x41, 0x49, 0x1f, 0x38, + 0x28, 0x5f, 0xa4, 0x00, 0xec, 0x3e, 0x4e, 0xe0, 0xff, 0x78, 0x53, 0x62, 0x38, 0xb4, 0x42, 0x4c, + 0x31, 0x7d, 0x14, 0x0d, 0x75, 0xb4, 0xa3, 0x89, 0x62, 0xa3, 0xa4, 0xb1, 0x63, 0x7a, 0xf2, 0x0d, + 0x5f, 0xd4, 0xd2, 0x47, 0xfb, 0xa2, 0xa6, 0x7e, 0x95, 0x0c, 0xe3, 0xa9, 0x7e, 0xc2, 0xeb, 0xb5, + 0xfd, 0xe9, 0x13, 0xdc, 0x7e, 0xf5, 0x33, 0x05, 0xcc, 0x24, 0xdb, 0x91, 0x53, 0xf7, 0xb0, 0xfb, + 0x65, 0xdc, 0x89, 0xd3, 0xfd, 0xa8, 0xfb, 0x4c, 0x01, 0x67, 0x4f, 0xd9, 0x3f, 0x3c, 0xea, 0x27, + 0xdd, 0x6b, 0x3e, 0x2d, 0xff, 0xd3, 0xe8, 0xd7, 0x5e, 0xbc, 0xce, 0x0f, 0xbd, 0x7c, 0x9d, 0x1f, + 0x7a, 0xf5, 0x3a, 0x3f, 0xf4, 0xff, 0x4e, 0x5e, 0x79, 0xd1, 0xc9, 0x2b, 0x2f, 0x3b, 0x79, 0xe5, + 0x55, 0x27, 0xaf, 0x7c, 0xd7, 0xc9, 0x2b, 0xef, 0x7c, 0x9f, 0x1f, 0xfa, 0xd7, 0xa8, 0x84, 0xfe, + 0x29, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x79, 0x7e, 0xc9, 0x1b, 0x1d, 0x00, 0x00, +} + +func (m *ContainerResourceMetricSource) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContainerResourceMetricSource) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerResourceMetricSource) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Container) + copy(dAtA[i:], m.Container) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Container))) + i-- + dAtA[i] = 0x1a + { + size, err := m.Target.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ContainerResourceMetricStatus) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContainerResourceMetricStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContainerResourceMetricStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Container) + copy(dAtA[i:], m.Container) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Container))) + i-- + dAtA[i] = 0x1a + { + size, err := m.Current.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *CrossVersionObjectReference) Marshal() (dAtA []byte, err error) { @@ -1408,6 +1557,18 @@ func (m *MetricSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContainerResource != nil { + { + size, err := m.ContainerResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.External != nil { { size, err := m.External.MarshalToSizedBuffer(dAtA[:i]) @@ -1484,6 +1645,18 @@ func (m *MetricStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ContainerResource != nil { + { + size, err := m.ContainerResource.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.External != nil { { size, err := m.External.MarshalToSizedBuffer(dAtA[:i]) @@ -1928,6 +2101,36 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *ContainerResourceMetricSource) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = m.Target.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Container) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *ContainerResourceMetricStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = m.Current.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Container) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *CrossVersionObjectReference) Size() (n int) { if m == nil { return 0 @@ -2166,6 +2369,10 @@ func (m *MetricSpec) Size() (n int) { l = m.External.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.ContainerResource != nil { + l = m.ContainerResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -2193,6 +2400,10 @@ func (m *MetricStatus) Size() (n int) { l = m.External.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.ContainerResource != nil { + l = m.ContainerResource.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -2326,6 +2537,30 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *ContainerResourceMetricSource) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerResourceMetricSource{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Target:` + strings.Replace(strings.Replace(this.Target.String(), "MetricTarget", "MetricTarget", 1), `&`, ``, 1) + `,`, + `Container:` + fmt.Sprintf("%v", this.Container) + `,`, + `}`, + }, "") + return s +} +func (this *ContainerResourceMetricStatus) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerResourceMetricStatus{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Current:` + strings.Replace(strings.Replace(this.Current.String(), "MetricValueStatus", "MetricValueStatus", 1), `&`, ``, 1) + `,`, + `Container:` + fmt.Sprintf("%v", this.Container) + `,`, + `}`, + }, "") + return s +} func (this *CrossVersionObjectReference) String() string { if this == nil { return "nil" @@ -2507,6 +2742,7 @@ func (this *MetricSpec) String() string { `Pods:` + strings.Replace(this.Pods.String(), "PodsMetricSource", "PodsMetricSource", 1) + `,`, `Resource:` + strings.Replace(this.Resource.String(), "ResourceMetricSource", "ResourceMetricSource", 1) + `,`, `External:` + strings.Replace(this.External.String(), "ExternalMetricSource", "ExternalMetricSource", 1) + `,`, + `ContainerResource:` + strings.Replace(this.ContainerResource.String(), "ContainerResourceMetricSource", "ContainerResourceMetricSource", 1) + `,`, `}`, }, "") return s @@ -2521,6 +2757,7 @@ func (this *MetricStatus) String() string { `Pods:` + strings.Replace(this.Pods.String(), "PodsMetricStatus", "PodsMetricStatus", 1) + `,`, `Resource:` + strings.Replace(this.Resource.String(), "ResourceMetricStatus", "ResourceMetricStatus", 1) + `,`, `External:` + strings.Replace(this.External.String(), "ExternalMetricStatus", "ExternalMetricStatus", 1) + `,`, + `ContainerResource:` + strings.Replace(this.ContainerResource.String(), "ContainerResourceMetricStatus", "ContainerResourceMetricStatus", 1) + `,`, `}`, }, "") return s @@ -2626,6 +2863,306 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *ContainerResourceMetricSource) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContainerResourceMetricSource: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContainerResourceMetricSource: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = k8s_io_api_core_v1.ResourceName(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Target", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Target.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Container", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Container = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContainerResourceMetricStatus) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContainerResourceMetricStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContainerResourceMetricStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = k8s_io_api_core_v1.ResourceName(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Current", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Current.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Container", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Container = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *CrossVersionObjectReference) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -4623,6 +5160,42 @@ func (m *MetricSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContainerResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ContainerResource == nil { + m.ContainerResource = &ContainerResourceMetricSource{} + } + if err := m.ContainerResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -4852,6 +5425,42 @@ func (m *MetricStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContainerResource", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ContainerResource == nil { + m.ContainerResource = &ContainerResourceMetricStatus{} + } + if err := m.ContainerResource.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/autoscaling/v2beta2/generated.proto b/staging/src/k8s.io/api/autoscaling/v2beta2/generated.proto index de2a9c23c22..77a6cb379ee 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta2/generated.proto +++ b/staging/src/k8s.io/api/autoscaling/v2beta2/generated.proto @@ -30,6 +30,40 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v2beta2"; +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +message ContainerResourceMetricSource { + // name is the name of the resource in question. + optional string name = 1; + + // target specifies the target value for the given metric + optional MetricTarget target = 2; + + // container is the name of the container in the pods of the scaling target + optional string container = 3; +} + +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing a single container in each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +message ContainerResourceMetricStatus { + // Name is the name of the resource in question. + optional string name = 1; + + // current contains the current value for the given metric + optional MetricValueStatus current = 2; + + // Container is the name of the container in the pods of the scaling target + optional string container = 3; +} + // CrossVersionObjectReference contains enough information to let you identify the referred resource. message CrossVersionObjectReference { // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" @@ -256,8 +290,10 @@ message MetricIdentifier { // MetricSpec specifies how to scale based on a single metric // (only `type` and one other matching field should be set at once). message MetricSpec { - // type is the type of metric source. It should be one of "Object", - // "Pods", "Resource" or "External", each mapping to a matching field in the object. + // type is the type of metric source. It should be one of "ContainerResource", "External", + // "Object", "Pods" or "Resource", each mapping to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled optional string type = 1; // object refers to a metric describing a single kubernetes object @@ -279,6 +315,15 @@ message MetricSpec { // +optional optional ResourceMetricSource resource = 4; + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in + // each pod of the current scale target (e.g. CPU or memory). Such metrics are + // built in to Kubernetes, and have special scaling options on top of those + // available to normal per-pod metrics using the "pods" source. + // This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. + // +optional + optional ContainerResourceMetricSource containerResource = 7; + // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -290,8 +335,10 @@ message MetricSpec { // MetricStatus describes the last-read state of a single metric. message MetricStatus { - // type is the type of metric source. It will be one of "Object", - // "Pods" or "Resource", each corresponds to a matching field in the object. + // type is the type of metric source. It will be one of "ContainerResource", "External", + // "Object", "Pods" or "Resource", each corresponds to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled optional string type = 1; // object refers to a metric describing a single kubernetes object @@ -313,6 +360,14 @@ message MetricStatus { // +optional optional ResourceMetricStatus resource = 4; + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ContainerResourceMetricStatus containerResource = 7; + // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster diff --git a/staging/src/k8s.io/api/autoscaling/v2beta2/types.go b/staging/src/k8s.io/api/autoscaling/v2beta2/types.go index da2733d2f36..ac6cb676903 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta2/types.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta2/types.go @@ -96,8 +96,10 @@ type CrossVersionObjectReference struct { // MetricSpec specifies how to scale based on a single metric // (only `type` and one other matching field should be set at once). type MetricSpec struct { - // type is the type of metric source. It should be one of "Object", - // "Pods", "Resource" or "External", each mapping to a matching field in the object. + // type is the type of metric source. It should be one of "ContainerResource", "External", + // "Object", "Pods" or "Resource", each mapping to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"` // object refers to a metric describing a single kubernetes object @@ -116,6 +118,14 @@ type MetricSpec struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricSource `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"` + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in + // each pod of the current scale target (e.g. CPU or memory). Such metrics are + // built in to Kubernetes, and have special scaling options on top of those + // available to normal per-pod metrics using the "pods" source. + // This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag. + // +optional + ContainerResource *ContainerResourceMetricSource `json:"containerResource,omitempty" protobuf:"bytes,7,opt,name=containerResource"` // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -220,6 +230,12 @@ const ( // Kubernetes, and have special scaling options on top of those available // to normal per-pod metrics (the "pods" source). ResourceMetricSourceType MetricSourceType = "Resource" + // ContainerResourceMetricSourceType is a resource metric known to Kubernetes, as + // specified in requests and limits, describing a single container in each pod in the current + // scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics (the "pods" source). + ContainerResourceMetricSourceType MetricSourceType = "ContainerResource" // ExternalMetricSourceType is a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -263,6 +279,22 @@ type ResourceMetricSource struct { Target MetricTarget `json:"target" protobuf:"bytes,2,name=target"` } +// ContainerResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +type ContainerResourceMetricSource struct { + // name is the name of the resource in question. + Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"` + // target specifies the target value for the given metric + Target MetricTarget `json:"target" protobuf:"bytes,2,name=target"` + // container is the name of the container in the pods of the scaling target + Container string `json:"container" protobuf:"bytes,3,opt,name=container"` +} + // ExternalMetricSource indicates how to scale on a metric not associated with // any Kubernetes object (for example length of queue in cloud // messaging service, or QPS from loadbalancer running outside of cluster). @@ -382,8 +414,10 @@ type HorizontalPodAutoscalerCondition struct { // MetricStatus describes the last-read state of a single metric. type MetricStatus struct { - // type is the type of metric source. It will be one of "Object", - // "Pods" or "Resource", each corresponds to a matching field in the object. + // type is the type of metric source. It will be one of "ContainerResource", "External", + // "Object", "Pods" or "Resource", each corresponds to a matching field in the object. + // Note: "ContainerResource" type is available on when the feature-gate + // HPAContainerMetrics is enabled Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"` // object refers to a metric describing a single kubernetes object @@ -402,6 +436,13 @@ type MetricStatus struct { // to normal per-pod metrics using the "pods" source. // +optional Resource *ResourceMetricStatus `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"` + // container resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing a single container in each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + ContainerResource *ContainerResourceMetricStatus `json:"containerResource,omitempty" protobuf:"bytes,7,opt,name=containerResource"` // external refers to a global metric that is not associated // with any Kubernetes object. It allows autoscaling based on information // coming from components running outside of cluster @@ -443,6 +484,20 @@ type ResourceMetricStatus struct { Current MetricValueStatus `json:"current" protobuf:"bytes,2,name=current"` } +// ContainerResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing a single container in each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +type ContainerResourceMetricStatus struct { + // Name is the name of the resource in question. + Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"` + // current contains the current value for the given metric + Current MetricValueStatus `json:"current" protobuf:"bytes,2,name=current"` + // Container is the name of the container in the pods of the scaling target + Container string `json:"container" protobuf:"bytes,3,opt,name=container"` +} + // ExternalMetricStatus indicates the current value of a global metric // not associated with any Kubernetes object. type ExternalMetricStatus struct { diff --git a/staging/src/k8s.io/api/autoscaling/v2beta2/types_swagger_doc_generated.go b/staging/src/k8s.io/api/autoscaling/v2beta2/types_swagger_doc_generated.go index 1c1b229f873..e3ea3002bdd 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta2/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta2/types_swagger_doc_generated.go @@ -27,6 +27,28 @@ package v2beta2 // Those methods can be generated by using hack/update-generated-swagger-docs.sh // AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_ContainerResourceMetricSource = map[string]string{ + "": "ContainerResourceMetricSource indicates how to scale on a resource metric known to Kubernetes, as specified in requests and limits, describing each pod in the current scale target (e.g. CPU or memory). The values will be averaged together before being compared to the target. Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. Only one \"target\" type should be set.", + "name": "name is the name of the resource in question.", + "target": "target specifies the target value for the given metric", + "container": "container is the name of the container in the pods of the scaling target", +} + +func (ContainerResourceMetricSource) SwaggerDoc() map[string]string { + return map_ContainerResourceMetricSource +} + +var map_ContainerResourceMetricStatus = map[string]string{ + "": "ContainerResourceMetricStatus indicates the current value of a resource metric known to Kubernetes, as specified in requests and limits, describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "name": "Name is the name of the resource in question.", + "current": "current contains the current value for the given metric", + "container": "Container is the name of the container in the pods of the scaling target", +} + +func (ContainerResourceMetricStatus) SwaggerDoc() map[string]string { + return map_ContainerResourceMetricStatus +} + var map_CrossVersionObjectReference = map[string]string{ "": "CrossVersionObjectReference contains enough information to let you identify the referred resource.", "kind": "Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\"", @@ -162,12 +184,13 @@ func (MetricIdentifier) SwaggerDoc() map[string]string { } var map_MetricSpec = map[string]string{ - "": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", - "type": "type is the type of metric source. It should be one of \"Object\", \"Pods\", \"Resource\" or \"External\", each mapping to a matching field in the object.", - "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", - "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", - "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", - "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", + "": "MetricSpec specifies how to scale based on a single metric (only `type` and one other matching field should be set at once).", + "type": "type is the type of metric source. It should be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each mapping to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", + "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", + "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", + "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "containerResource": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod of the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source. This is an alpha feature and can be enabled by the HPAContainerMetrics feature flag.", + "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", } func (MetricSpec) SwaggerDoc() map[string]string { @@ -175,12 +198,13 @@ func (MetricSpec) SwaggerDoc() map[string]string { } var map_MetricStatus = map[string]string{ - "": "MetricStatus describes the last-read state of a single metric.", - "type": "type is the type of metric source. It will be one of \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object.", - "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", - "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", - "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", - "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", + "": "MetricStatus describes the last-read state of a single metric.", + "type": "type is the type of metric source. It will be one of \"ContainerResource\", \"External\", \"Object\", \"Pods\" or \"Resource\", each corresponds to a matching field in the object. Note: \"ContainerResource\" type is available on when the feature-gate HPAContainerMetrics is enabled", + "object": "object refers to a metric describing a single kubernetes object (for example, hits-per-second on an Ingress object).", + "pods": "pods refers to a metric describing each pod in the current scale target (for example, transactions-processed-per-second). The values will be averaged together before being compared to the target value.", + "resource": "resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "containerResource": "container resource refers to a resource metric (such as those specified in requests and limits) known to Kubernetes describing a single container in each pod in the current scale target (e.g. CPU or memory). Such metrics are built in to Kubernetes, and have special scaling options on top of those available to normal per-pod metrics using the \"pods\" source.", + "external": "external refers to a global metric that is not associated with any Kubernetes object. It allows autoscaling based on information coming from components running outside of cluster (for example length of queue in cloud messaging service, or QPS from loadbalancer running outside of cluster).", } func (MetricStatus) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/autoscaling/v2beta2/zz_generated.deepcopy.go b/staging/src/k8s.io/api/autoscaling/v2beta2/zz_generated.deepcopy.go index ca26fe92065..81642822a6a 100644 --- a/staging/src/k8s.io/api/autoscaling/v2beta2/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/autoscaling/v2beta2/zz_generated.deepcopy.go @@ -25,6 +25,40 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricSource) DeepCopyInto(out *ContainerResourceMetricSource) { + *out = *in + in.Target.DeepCopyInto(&out.Target) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricSource. +func (in *ContainerResourceMetricSource) DeepCopy() *ContainerResourceMetricSource { + if in == nil { + return nil + } + out := new(ContainerResourceMetricSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerResourceMetricStatus) DeepCopyInto(out *ContainerResourceMetricStatus) { + *out = *in + in.Current.DeepCopyInto(&out.Current) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerResourceMetricStatus. +func (in *ContainerResourceMetricStatus) DeepCopy() *ContainerResourceMetricStatus { + if in == nil { + return nil + } + out := new(ContainerResourceMetricStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CrossVersionObjectReference) DeepCopyInto(out *CrossVersionObjectReference) { *out = *in @@ -340,6 +374,11 @@ func (in *MetricSpec) DeepCopyInto(out *MetricSpec) { *out = new(ResourceMetricSource) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricSource) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricSource) @@ -376,6 +415,11 @@ func (in *MetricStatus) DeepCopyInto(out *MetricStatus) { *out = new(ResourceMetricStatus) (*in).DeepCopyInto(*out) } + if in.ContainerResource != nil { + in, out := &in.ContainerResource, &out.ContainerResource + *out = new(ContainerResourceMetricStatus) + (*in).DeepCopyInto(*out) + } if in.External != nil { in, out := &in.External, &out.External *out = new(ExternalMetricStatus) diff --git a/staging/src/k8s.io/api/testdata/HEAD/autoscaling.v2beta1.HorizontalPodAutoscaler.json b/staging/src/k8s.io/api/testdata/HEAD/autoscaling.v2beta1.HorizontalPodAutoscaler.json index d31f07a9c58..260e3141229 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/autoscaling.v2beta1.HorizontalPodAutoscaler.json +++ b/staging/src/k8s.io/api/testdata/HEAD/autoscaling.v2beta1.HorizontalPodAutoscaler.json @@ -98,98 +98,122 @@ "targetAverageUtilization": 1253093074, "targetAverageValue": "8" }, + "containerResource": { + "name": "w垁鷌辪虽U珝Żwʮ馜üNșƶ4ĩ", + "targetAverageUtilization": 1463207240, + "targetAverageValue": "84", + "container": "39" + }, "external": { - "metricName": "39", + "metricName": "40", "metricSelector": { "matchLabels": { - "4kh6oqu-or---40--87-1wpl6-2-310e5hz/B._z": "G6t-2.-_-8w6" + "bigm-h8-3q768km-0--03-t-0-035--5b95w------4-n4f-h/u-5.-Z3P__D__6t-2.-_-8wE._._3.-.83_iq_-1": "1-_Y33--.8U.-.5--_zm-.-_RJt2pX_2_28.-.7_8B.HF-U-_ik_--DSX0" }, "matchExpressions": [ { - "key": "1295at-o7qff7-x--r7v66bm71u-n4f9wk-3--652x01--p--n4-4-t--2gk-0/d.83_iq_-y.-25C.A-j..9dfn3Y8d_0_.---M_4FpF_W-1._-vL_i.-_-a--GI", - "operator": "DoesNotExist" + "key": "680---z-6-t2z-w-fg98-r--v53nyx5u-o-k-md--381d-7.3di292f--90-17-hg1-o-p665--4-j8---t6-r7r/Y-H-Mqpt._.-_..05c.---qy-_5_S.d5a37", + "operator": "NotIn", + "values": [ + "dY_um-_8r--684._-_18_...E.-2o_-.5" + ] } ] }, - "targetValue": "570", - "targetAverageValue": "829" + "targetValue": "865", + "targetAverageValue": "379" } } ] }, "status": { - "observedGeneration": -7224326297454280417, - "currentReplicas": 596942561, - "desiredReplicas": -1880980172, + "observedGeneration": 61436896663269868, + "currentReplicas": -1462219068, + "desiredReplicas": -370386363, "currentMetrics": [ { - "type": " ïì«丯Ƙ枛牐ɺ皚|懥", + "type": "", "object": { "target": { - "kind": "46", - "name": "47", - "apiVersion": "48" + "kind": "47", + "name": "48", + "apiVersion": "49" }, - "metricName": "49", - "currentValue": "55", + "metricName": "50", + "currentValue": "856", "selector": { "matchLabels": { - "8._Wxpe..J7rs6.0_OHz_.B-.-_w_--.8_r_N-.3n-xu": "o_-Nm-_X8" + "vL7": "L_0N_N.O30-_u._-2hT.-z-._7-5lL..-_--.VEa-_gn.8-c.C3_F._oX-FT" }, "matchExpressions": [ { - "key": "665--4-j8---t6-r7--9.9dy/XvSA..1", - "operator": "Exists" + "key": "4_.-N_g-.._5", + "operator": "In", + "values": [ + "2qz.W..4....-h._.GgT7_7B_D-..-.k4u-zA_--_.-.6GA26C-s.Nj-d-4_t" + ] } ] }, - "averageValue": "14" + "averageValue": "817" }, "pods": { - "metricName": "56", - "currentAverageValue": "878", + "metricName": "57", + "currentAverageValue": "400", "selector": { "matchLabels": { - "6fv--m-8--72-bca4m56au3f-j/0-_1-F.h-__k_K5._..O_.J_-G_--V-42E_--o90G_A4..-L..-__0N_N.O3i": "r_gn.8-c.C3_F._oX-F9_.v" + "mj_9.M.134-5-.q6H_.--_---.M.U_-m.-P.yP9S--858LI__.8U": "KrO-S-P_-...0c.-.p_3_J_SA995IKCR.s--f.-f.-zv._._.5-HT" }, "matchExpressions": [ { - "key": "g-..__._____K_g1cXfr.4_.B", - "operator": "DoesNotExist" + "key": "26-k8-c2---2etfh41ca-z-5g2wco280.ka-6-31g--z-o-3bz6-8-0-1-z--271s-p9-8--m-cbck561-7n/VC..7o_x3..-.8J", + "operator": "NotIn", + "values": [ + "8._Q.6.I--2_9.v.--_.--4QQ.-s.H.Hf" + ] } ] } }, "resource": { - "name": "šeSvEȤƏ埮pɵ{WOŭW灬pȭ", - "currentAverageUtilization": -1607821167, - "currentAverageValue": "832" + "name": "ƻ遲njlȘ鹾KƂʼnç", + "currentAverageUtilization": 769521729, + "currentAverageValue": "727" + }, + "containerResource": { + "name": "!@@)Zq=", + "currentAverageUtilization": -861915578, + "currentAverageValue": "111", + "container": "64" }, "external": { - "metricName": "63", + "metricName": "65", "metricSelector": { "matchLabels": { - "4_4--.-_Z4.LA3HVG93_._.I3.__-.0-z_z0sn_.hx_-a__0-8-.M-.-.-8vJ": "zET_..3dCv3j._.-_pP__up.2L_s-o779._-k-5___-Qq4" + "2y3-4-3/AO": "r..6W.V0" }, "matchExpressions": [ { - "key": "FC-rtSY.g._2F7.-_e..OP", - "operator": "Exists" + "key": "v55039780bdw0-1-47rrw8-7/U_--56-.7D.3_KPg___Kp", + "operator": "In", + "values": [ + "N7_-Zp_._w" + ] } ] }, - "currentValue": "229", - "currentAverageValue": "606" + "currentValue": "200", + "currentAverageValue": "288" } } ], "conditions": [ { - "type": "鯶縆", - "status": "aTGÒ鵌Ē3", - "lastTransitionTime": "2416-12-01T11:47:49Z", - "reason": "70", - "message": "71" + "type": "", + "status": "", + "lastTransitionTime": "1995-10-31T09:59:43Z", + "reason": "72", + "message": "73" } ] } diff --git a/staging/src/k8s.io/api/testdata/HEAD/autoscaling.v2beta1.HorizontalPodAutoscaler.pb b/staging/src/k8s.io/api/testdata/HEAD/autoscaling.v2beta1.HorizontalPodAutoscaler.pb index 601b4af04b2e8c7c7eb6fbac5fde18983de757db..d6276db2cd23cc6057d257264bdb3460a1b53966 100644 GIT binary patch delta 1153 zcmX|ATWB0r7)~aJgrRB}q{zP5Zl4VNe`d~^Gv`dOm^7DeF5M)}rAc0XlB~O%Z1Teju9PSdh)wAzcytC>7x4al+%OfC;D zfGeTOyDJrdS`JkWj+PGvKMmQQ4NwS+a*}9}D5!!!ATYHdBqWJ|M$&4Tz;k*%pam&` zO|xw0Y*f!fgWb=MRz+!^1PQ|jn#>tY48ttYYK{N~r{`Vgy;l3>z;HKEhXAUg4mC(; zLIV|mO(hFkm(&InAqV*sfHYnTG|JSf2t^tobivb*&3Nol3IeX|!|Cil#B8mZWytlf~*tA$BsgKpS}=!-WImBLR7aV{iyT6p81G zwcBkbP;uU*4tte-s`lWm%ZFcFdvy1MM>oHkeR%!W{%-Btj}PB@bMMP!K?>f$&? zqyf$iEdgZ;XkY~gBn=}K=V5rpnX-@h3{8?UfJn-*7>LuNT*nKDKF^MjW$4akW;E$D zG{{bXIe!D{{hXBpF*w^Vf&o~^H45<@ zdeR34SPl}LBI*y=I7^U6n8dBga2miUGd@DZigMIgWdf#Qk||&YnLsR&q*0pg4?{IF zHgF!-0n!*f_033}tiZ&K)7WmcQzC#I&n&ovc&VDs`rgVCqoXpSwo(+v#oQ9BPI{S0 zenpVW^#Bat36Fn4Xm1@#AsZkME6Xc66?mWvJ#zzyx=5E~goYXYUqA+F3IiPBNFKAX z8O_G8KQ)C6Py!R__$m9D=I-I;Prtc#@!-bcox5YrEBjaX-tGGO_dkELB6hXV-38kU zl(T3bw{5W{S<q@0&K=&|;paQ;YgK3mB zHkl!!vClN4o$3 delta 902 zcmY*X&1+m$6wiCc5U(jMZ{f%2VwjEX;5m8k-TUr)Zy}PVnQ7B>rjpW3-5jP#W|EAV zH<_%pE z>&D)-Jr_Om&!JU+-Ml@px)V3A4g54{ylr+K8^V;K^}rB;*sn@+I$CN#R0RNK0|Y)e z%a!*uxF8*S)|+b&A4FKy>LSOR-^1_Md+O9W>STyGRdU;#0lDU{`@V1{f$Ms$o+ zs*<89aFC!mLGwKTd4Tj0Yv@okTgycCvDSR89(!Iq=lOPmOW=mFfBFZnp56KU>mSZO zzGA%c`)`lFG~+*CxX}Hp+wFF`Msl-XycXZu*jl^&{U5hB?tZcJ)s@|kF5drj_wwZr zcFy0h&KqJ#m`Yow@?)k7xQ4NQVR~MoC_?dOfHc*r%p#8a)tW||vWMG*2Z7No695KO zr3|1fL#tuE5D{b+fpUSB6mi|r9xDwC0n@8%77ZX|+GmDy&B+l&#~S#TQ7y^y92L9C zZh6}35%YuCHAB=yP8XU0i@-nlE}Wjut3^-e8?pck!#0ouDVzhM5*_uB5VM5i1Zl=~ z5|lgE;Y$?SX&O<8Fu{k&&QJ!ka^8BmO2sk;FpZ;$!R80H-RwQik`u6qN$>!L-Z|;8j^A|CK@GX3llvp|M{KVdy;d{`Q6{+ zJ7f4(;(3)HN*vUt_)WuLFp0Z9XW;hnt{*t`0f%_Sgx}-Pqv&C0`SJP!a6(~~O7le= zD^ksbyE)_(L4+2u4eFFrHD+65GuWB{KrsPWG!UH)W}>OO9b~r1%Ir8TX-)8|#R+E6 zK~^hdiww1mU~LuKB$aJDU8l(vX|7V@0H7v9*xTG%Y|?-dN@;aIRFK*e)^sP{onfoA z=h+;YEwy$Bej4o!jJJko`j7bAL)WHKH{474tCw*cim}KhBbzi`Pnzsq{FOgkh@SBG zu6Cvc-QE5P&(-kjqxluFRA0P*(&@ z*YyaPsESE^)D;V$jf?4KZmjr_AP|RM?>!UjqWqv-a~ck%e{=*(x4bbvkhpYx>kEVM`&i$Xal&_h1@3I`u=*`N z;p6W|E=n?lR%t1t zN7?QI(GJB#C+rhLE2qsixxh+kJ!I5k8#X_ZQ z&=dY}G0+trKI^{{JU=J;rh?0Zq3OxMB;FUbK$IgOW>prvx9%>)rp$3@l<76A*v%m; zde)t8NOsW^1X^fQI?IJpFw;{c52WX4aV0)bRilt{Yf&2|)x-%lVxcFCAeYD#M5ZK@ z-H!eBGz%h%3C*yOqC%+4CZ%?oYip1dmc{>WW|WnpM1#?EP5AWBnUelru=!)?6Z2#K5o&0#SB0YuT6eaY|Fy7;xS?PH3#!_%$F*wj} aOi1|oo7-QbnEYK-MY09 z3pyE!qPT1pE9d63E4Y<>`g@+7=LxS^!Wo{tLv~wn2m?SOWQtS+ zJqe=G3JU&dhk(~#nPSl01oe7@WH4%0Mck~GdVw-eZ`<}r9rQwjPh+)R)Gsk3Mfbf9 zlrpcdL1LQ0*p7PY0V%Z;Q~*5+ur&(lYQ`vStfvN(AS9gP$bpCgrWZueI=hpArZIHh zBk9na06#TVh^RgQNwGk-w3cp&8l66$0et{nMnczH!-mvj+lZAiQzQx$k|{im#nf;L zfYvad9t^}&V1#;`peb!B(5JWh+rtdA=oI*xh;!90g*8zPx6(Qm+t!Q=lyx&E2Zc@K zIfW)*e(J*9yH^UCD|beP62hCZa~WBxh*EjxudfE4JjKCP9OcM%vQ{jfIpn^ZDUMvL zc{BFL^o98JSpG!b_y2aQ)<-vdPB-U;MMM*YVxsZzuj;{QUjF z(4FPNX7WO1ejHqBvvXIEEKmmfVNQ760v-$E+r78F2F(nn4pM$=!sTZ+o~4?e?{)tO(BIk8=!@D zQgnfp+Usfo)*hiIw9zVsRim>;sJ0l@5+04pTFbsZ+9IqXD1BO!bphX|E;`2EziB6i zc{!gYyru}eraE~|b3Wq9eI#Aeg*!aC#F4|CS3{}|e2{L_?3IIR4}t;V0GLr(2f*18 z*C4Rp8&^T?PFa1RQa^+wsZ&EHgBn^|DwxvX!R2exR;7ov+q@$!_HeUysjbo1r3xEd zyHOm)Ta{1($P%(x$5>B{$~##c`86!cAP62|m?K9y#gxMs48&5FSM@{KjxK1*3VJkA zQBwi66)cc~RPup_^h!y40V?b!#b$|lBLD#uA8?v>5dt7V93UD~dMnYWSsHY&SfAdr zApNo=HJK@_v{lp%$re#J6~}McKOQb!_Zlg`J&+r#m_PB!=8bp94$cnd2Iq#3)aH-o zJ}EDr{&@c4dxC>t16Yc^QNoQ+vVTth-vCcJ@++dFE5ZYgB*}hVHb7pyNieuH#7w{f zm=HGon4uWJVst^$h=gL6fwX{>G%96eiYnNA5JD>Gw(ZD}LhVE;QyFWljrdrzXMvY4 z>S7E`q0CJo?BAjG0TY=9%n;rpYubQTYpjpDJyjy!2w^6s@tV^cV$1^#ltve{(A$Bj zyYP?%I_$BlSi_J+#lHTuMyaa<+**=tN!4!MN3E#KVmd~WFcuM%O~cl}&@9I(ojG2dJm)HYaH()(WPbFD{_4vIXNPk)h1K(uqq+Xu=l0Bw7c!sC o3{`8