Align autoscaling annotations in tests (#1531)

* Align autoscaling annotations in unit tests

* Fix code style

* Fix e2e tests
This commit is contained in:
David Simansky 2021-11-26 14:34:51 +01:00 committed by GitHub
parent 0e89cfccbe
commit 2b1e77de20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 324 additions and 191 deletions

8
go.mod
View File

@ -18,10 +18,10 @@ require (
k8s.io/cli-runtime v0.21.4
k8s.io/client-go v0.21.4
k8s.io/code-generator v0.21.4
knative.dev/eventing v0.27.1-0.20211123070249-2cda8f40b5d9
knative.dev/eventing v0.27.1-0.20211123205351-820db20be4b2
knative.dev/hack v0.0.0-20211122162614-813559cefdda
knative.dev/networking v0.0.0-20211123024050-aa82452902be
knative.dev/pkg v0.0.0-20211123074649-0fae0afc10ad
knative.dev/serving v0.27.1-0.20211123120750-26c7dc6ccc53
knative.dev/networking v0.0.0-20211124064027-ea794f17c1bf
knative.dev/pkg v0.0.0-20211123135150-787aec59e70a
knative.dev/serving v0.27.1-0.20211124064027-e6f8e414ac9e
sigs.k8s.io/yaml v1.3.0
)

19
go.sum
View File

@ -1735,25 +1735,24 @@ k8s.io/legacy-cloud-providers v0.21.0/go.mod h1:bNxo7gDg+PGkBmT/MFZswLTWdSWK9kAl
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ=
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
knative.dev/caching v0.0.0-20211122134815-4f6b1e562337/go.mod h1:awOzz1AtzphZ5YbuMa3ZfRTN2IqRcLaiknYYuCZPZOA=
knative.dev/eventing v0.27.1-0.20211123070249-2cda8f40b5d9 h1:8GhioMgKtYTPbcEjzBsMd2g+KfUMiMurqnuD1EU9KNE=
knative.dev/eventing v0.27.1-0.20211123070249-2cda8f40b5d9/go.mod h1:fnBpTKtPOxC7WOaQY6WUiUAVBXTb44njuhTi7LXHGVc=
knative.dev/caching v0.0.0-20211123074749-2c27e22a9971/go.mod h1:/5cq0Jmn8O7zOptuBNUh/iHgy3yS7ZJ1hyEf/8Eof08=
knative.dev/eventing v0.27.1-0.20211123205351-820db20be4b2 h1:QwyD6phsrqx5hDplMkFZ6NJPLMSnxN3YjAw+Qnnrbpg=
knative.dev/eventing v0.27.1-0.20211123205351-820db20be4b2/go.mod h1:fnBpTKtPOxC7WOaQY6WUiUAVBXTb44njuhTi7LXHGVc=
knative.dev/hack v0.0.0-20211101195839-11d193bf617b/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
knative.dev/hack v0.0.0-20211112192837-128cf0150a69/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
knative.dev/hack v0.0.0-20211117134436-69a2295d54ce/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
knative.dev/hack v0.0.0-20211122162614-813559cefdda h1:WBfGcmu5pN+RCxDotKVYtWlJVI2V4Hvah+XD9mcSR/o=
knative.dev/hack v0.0.0-20211122162614-813559cefdda/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
knative.dev/hack/schema v0.0.0-20211122162614-813559cefdda/go.mod h1:ffjwmdcrH5vN3mPhO8RrF2KfNnbHeCE2C60A+2cv3U0=
knative.dev/networking v0.0.0-20211122065314-75d86c5d4128/go.mod h1:UCDjE4GxZJat8RJohbAwwxe+U3LjRJOU2Hb2LNiNMY0=
knative.dev/networking v0.0.0-20211123024050-aa82452902be h1:E9JdH2VCkl+pfCGExsTtwW158HrSCuCCoOfYHGn+mf0=
knative.dev/networking v0.0.0-20211123024050-aa82452902be/go.mod h1:u/Biwu9curBfc1GvZE293SwEfLo84sZ6df7cymgwLvw=
knative.dev/networking v0.0.0-20211124064027-ea794f17c1bf h1:qoRaPCrq3ymaBxK7XV0JOm0Pu+sAgFlTNYQh+pBwS8k=
knative.dev/networking v0.0.0-20211124064027-ea794f17c1bf/go.mod h1:ZYtIxKNhCdg8lle16ADEyy/C0ANH9rhJokx5C9dzjDE=
knative.dev/pkg v0.0.0-20211101212339-96c0204a70dc/go.mod h1:SkfDk9bWIiNZD7XtILGkG7AKVyF/M6M0bGxLgl0SYL8=
knative.dev/pkg v0.0.0-20211120133512-d016976f2567/go.mod h1:VqUp1KWJqpTDNoiSI/heaX3uMdubImslJE2tBkP+Bbw=
knative.dev/pkg v0.0.0-20211123074649-0fae0afc10ad h1:d5EVnV0T5JX403WUx2scfr1tE/MY9xIY92qJoxCcm1I=
knative.dev/pkg v0.0.0-20211123074649-0fae0afc10ad/go.mod h1:fZUlVceKtVNyFU6LokWGk2a9QFQXeSTtnbKOjjkQ690=
knative.dev/pkg v0.0.0-20211123135150-787aec59e70a h1:mgE9GdkjfPJc7KpgBox52dSy1GsQmsFTWXy+1HjEn9I=
knative.dev/pkg v0.0.0-20211123135150-787aec59e70a/go.mod h1:fZUlVceKtVNyFU6LokWGk2a9QFQXeSTtnbKOjjkQ690=
knative.dev/reconciler-test v0.0.0-20211112132636-ae9e2e21972f/go.mod h1:gTsbLk496j/M9xqMpx/liyCQ0X3bwDpRtcs2Zzws364=
knative.dev/serving v0.27.1-0.20211123120750-26c7dc6ccc53 h1:Sw0cdAMaOpGZ9iY2kzmoOBv9oe/mUh1ubdW+U6S7b2M=
knative.dev/serving v0.27.1-0.20211123120750-26c7dc6ccc53/go.mod h1:lVEraTokiW04QvfhBaZh4BPn9DAeqL4Gs9yaRbVV4ks=
knative.dev/serving v0.27.1-0.20211124064027-e6f8e414ac9e h1:/Mhn3Z9tM2T+uT/D9sSCtT7QNzwUtofmW24vGUuc9wA=
knative.dev/serving v0.27.1-0.20211124064027-e6f8e414ac9e/go.mod h1:VgFSdL4RDG+HAnRod0mtlhwrYJnVAkfuR5m/sH03/c8=
pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

View File

@ -507,9 +507,9 @@ func TestServiceCreateWithBothAnnotationAndInitScaleAsOption(t *testing.T) {
r := client.Recorder()
output, err := executeServiceCommand(client, "create", "foo", "--image", "gcr.io/foo/bar:baz", "--annotation", "autoscaling.knative.dev/initialScale=0", "--scale-init", "0")
output, err := executeServiceCommand(client, "create", "foo", "--image", "gcr.io/foo/bar:baz", "--annotation", autoscaling.InitialScaleAnnotationKey+"=0", "--scale-init", "0")
assert.Assert(t, err != nil)
assert.Assert(t, util.ContainsAll(output, "only one of the", "--scale-init", "--annotation", "autoscaling.knative.dev/initialScale", "can be specified"))
assert.Assert(t, util.ContainsAll(output, "only one of the", "--scale-init", "--annotation", autoscaling.InitialScaleAnnotationKey, "can be specified"))
r.Validate()
}
@ -641,7 +641,7 @@ func TestServiceCreateWithScaleServiceAnnotationsError(t *testing.T) {
"--annotation-service", autoscaling.InitialScaleAnnotationKey+"=1",
"--no-wait")
assert.Assert(t, err != nil)
assert.Assert(t, util.ContainsAll(output, "service can not have auto-scaling related annotation", "autoscaling.knative.dev/initialScale"))
assert.Assert(t, util.ContainsAll(output, "service can not have auto-scaling related annotation", autoscaling.InitialScaleAnnotationKey))
r.Validate()
}

View File

@ -24,6 +24,8 @@ import (
"strings"
"testing"
"knative.dev/serving/pkg/apis/autoscaling"
"gotest.tools/v3/assert"
api_errors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -406,11 +408,11 @@ func TestServiceCreateMaxMinScale(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
"autoscaling.knative.dev/target", "10",
"autoscaling.knative.dev/targetUtilizationPercentage", "50",
"autoscaling.knative.dev/window", "10s",
autoscaling.MinScaleAnnotationKey, "1",
autoscaling.MaxScaleAnnotationKey, "5",
autoscaling.TargetAnnotationKey, "10",
autoscaling.TargetUtilizationPercentageKey, "50",
autoscaling.WindowAnnotationKey, "10s",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -441,8 +443,8 @@ func TestServiceCreateScale(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "5",
"autoscaling.knative.dev/maxScale", "5",
autoscaling.MinScaleAnnotationKey, "5",
autoscaling.MaxScaleAnnotationKey, "5",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -461,7 +463,7 @@ func TestServiceCreateScaleWithNegativeValue(t *testing.T) {
if err == nil {
t.Fatal(err)
}
expectedErrMsg := "expected 0 <= -1 <= 2147483647: autoscaling.knative.dev/maxScale"
expectedErrMsg := "expected 0 <= -1 <= 2147483647: " + autoscaling.MaxScaleAnnotationKey
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
}
@ -522,8 +524,8 @@ func TestServiceCreateScaleRange(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
autoscaling.MinScaleAnnotationKey, "1",
autoscaling.MaxScaleAnnotationKey, "5",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -551,7 +553,7 @@ func TestServiceCreateScaleRangeOnlyMin(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
autoscaling.MinScaleAnnotationKey, "1",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -570,7 +572,7 @@ func TestServiceCreateScaleRangeOnlyMinNegative(t *testing.T) {
if err == nil {
t.Fatal(err)
}
expectedErrMsg := "expected 0 <= -1 <= 2147483647: autoscaling.knative.dev/minScale"
expectedErrMsg := "expected 0 <= -1 <= 2147483647: " + autoscaling.MinScaleAnnotationKey
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
}
@ -592,7 +594,7 @@ func TestServiceCreateScaleRangeOnlyMax(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/maxScale", "5",
autoscaling.MaxScaleAnnotationKey, "5",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -611,7 +613,7 @@ func TestServiceCreateScaleRangeOnlyMaxNegative(t *testing.T) {
if err == nil {
t.Fatal(err)
}
expectedErrMsg := "expected 0 <= -5 <= 2147483647: autoscaling.knative.dev/maxScale"
expectedErrMsg := "expected 0 <= -5 <= 2147483647: " + autoscaling.MaxScaleAnnotationKey
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
}
@ -1080,5 +1082,5 @@ func TestServiceCreateFromYAMLWithOverrideError(t *testing.T) {
_, _, _, err = fakeServiceCreate([]string{
"service", "create", "foo", "--filename", tempFile, "--scale", "-1"}, false)
assert.Assert(t, err != nil)
assert.Assert(t, util.ContainsAll(err.Error(), "expected", "0", "<=", "2147483647", "autoscaling.knative.dev/maxScale"))
assert.Assert(t, util.ContainsAll(err.Error(), "expected", "0", "<=", "2147483647", autoscaling.MaxScaleAnnotationKey))
}

View File

@ -1500,16 +1500,16 @@ func TestServiceUpdateInitialScaleMock(t *testing.T) {
template := &newService.Spec.Template
template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
template.ObjectMeta.Annotations = map[string]string{
"autoscaling.knative.dev/initialScale": "1",
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
autoscaling.InitialScaleAnnotationKey: "1",
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
}
updatedService := getService(svcName)
template = &updatedService.Spec.Template
template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
template.ObjectMeta.Annotations = map[string]string{
"autoscaling.knative.dev/initialScale": "2",
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
autoscaling.InitialScaleAnnotationKey: "2",
clientserving.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
}
r := client.Recorder()

View File

@ -23,6 +23,8 @@ import (
"testing"
"time"
"knative.dev/serving/pkg/apis/autoscaling"
"gotest.tools/v3/assert"
"gotest.tools/v3/assert/cmp"
@ -387,10 +389,10 @@ func TestServiceUpdateMaxMinScale(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
"autoscaling.knative.dev/target", "10",
"autoscaling.knative.dev/targetUtilizationPercentage", "50",
autoscaling.MinScaleAnnotationKey, "1",
autoscaling.MaxScaleAnnotationKey, "5",
autoscaling.TargetAnnotationKey, "10",
autoscaling.TargetUtilizationPercentageKey, "50",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -424,8 +426,8 @@ func TestServiceUpdateScale(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "5",
"autoscaling.knative.dev/maxScale", "5",
autoscaling.MinScaleAnnotationKey, "5",
autoscaling.MaxScaleAnnotationKey, "5",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -449,7 +451,7 @@ func TestServiceUpdateScaleWithNegativeValue(t *testing.T) {
t.Fatal("Expected error, got nil")
}
expectedErrMsg := "expected 0 <= -1 <= 2147483647: autoscaling.knative.dev/maxScale"
expectedErrMsg := "expected 0 <= -1 <= 2147483647: " + autoscaling.MaxScaleAnnotationKey
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
@ -512,8 +514,8 @@ func TestServiceUpdateScaleWithRange(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
"autoscaling.knative.dev/maxScale", "5",
autoscaling.MinScaleAnnotationKey, "1",
autoscaling.MaxScaleAnnotationKey, "5",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -543,7 +545,7 @@ func TestServiceUpdateScaleMinWithRange(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/minScale", "1",
autoscaling.MinScaleAnnotationKey, "1",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -567,7 +569,7 @@ func TestServiceUpdateScaleMinWithRangeNegative(t *testing.T) {
t.Fatal("Expected error, got nil")
}
expectedErrMsg := "expected 0 <= -1 <= 2147483647: autoscaling.knative.dev/minScale"
expectedErrMsg := "expected 0 <= -1 <= 2147483647: " + autoscaling.MinScaleAnnotationKey
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)
@ -592,7 +594,7 @@ func TestServiceUpdateScaleMaxWithRange(t *testing.T) {
actualAnnos := template.Annotations
expectedAnnos := []string{
"autoscaling.knative.dev/maxScale", "5",
autoscaling.MaxScaleAnnotationKey, "5",
}
for i := 0; i < len(expectedAnnos); i += 2 {
@ -616,7 +618,7 @@ func TestServiceUpdateScaleMaxWithRangeNegative(t *testing.T) {
t.Fatal("Expected error, got nil")
}
expectedErrMsg := "expected 0 <= -5 <= 2147483647: autoscaling.knative.dev/maxScale"
expectedErrMsg := "expected 0 <= -5 <= 2147483647: " + autoscaling.MaxScaleAnnotationKey
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Errorf("Invalid error output, expected: %s, got : '%s'", expectedErrMsg, err)

View File

@ -155,7 +155,7 @@ func TestUpdateMinScale(t *testing.T) {
checkAnnotationValueInt(t, template, autoscaling.MinScaleAnnotationKey, 10)
// Update with invalid value
err = UpdateMinScale(template, -1)
assert.ErrorContains(t, err, "minScale")
assert.ErrorContains(t, err, "min-scale")
}
func TestUpdateMaxScale(t *testing.T) {
@ -166,7 +166,7 @@ func TestUpdateMaxScale(t *testing.T) {
checkAnnotationValueInt(t, template, autoscaling.MaxScaleAnnotationKey, 10)
// Update with invalid value
err = UpdateMaxScale(template, -1)
assert.ErrorContains(t, err, "maxScale")
assert.ErrorContains(t, err, "max-scale")
}
func TestScaleWindow(t *testing.T) {

View File

@ -268,7 +268,7 @@ func validateServiceConcurrencyTarget(r *test.KnRunResultCollector, serviceName,
}
func validateServiceConcurrencyUtilization(r *test.KnRunResultCollector, serviceName, concurrencyUtilization string) {
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/targetUtilizationPercentage}"
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/target-utilization-percentage}"
out := r.KnTest().Kn().Run("service", "list", serviceName, "-o", jsonpath)
assert.Equal(r.T(), out.Stdout, concurrencyUtilization)
r.AssertNoError(out)
@ -282,21 +282,21 @@ func validateScaleWindow(r *test.KnRunResultCollector, serviceName, window strin
}
func validateServiceMinScale(r *test.KnRunResultCollector, serviceName, minScale string) {
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/minScale}"
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/min-scale}"
out := r.KnTest().Kn().Run("service", "list", serviceName, "-o", jsonpath)
assert.Equal(r.T(), out.Stdout, minScale)
r.AssertNoError(out)
}
func validateServiceMaxScale(r *test.KnRunResultCollector, serviceName, maxScale string) {
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/maxScale}"
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/max-scale}"
out := r.KnTest().Kn().Run("service", "list", serviceName, "-o", jsonpath)
assert.Equal(r.T(), out.Stdout, maxScale)
r.AssertNoError(out)
}
func validateServiceInitScale(r *test.KnRunResultCollector, serviceName, initScale string) {
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/initialScale}"
jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/initial-scale}"
out := r.KnTest().Kn().Run("service", "list", serviceName, "-o", jsonpath)
assert.Equal(r.T(), out.Stdout, initScale)
r.AssertNoError(out)

View File

@ -20,9 +20,10 @@ import (
"context"
"github.com/rickb777/date/period"
"knative.dev/eventing/pkg/apis/feature"
"knative.dev/pkg/apis"
duckv1 "knative.dev/pkg/apis/duck/v1"
"knative.dev/eventing/pkg/apis/feature"
)
// DeliverySpec contains the delivery options for event senders,
@ -60,6 +61,26 @@ type DeliverySpec struct {
// For exponential policy, backoff delay is backoffDelay*2^<numberOfRetries>.
// +optional
BackoffDelay *string `json:"backoffDelay,omitempty"`
// RetryAfterMax provides an optional upper bound on the duration specified in a "Retry-After" header
// when calculating backoff times for retrying 429 and 503 response codes. Setting the value to
// zero ("PT0S") can be used to opt-out of respecting "Retry-After" header values altogether. This
// value only takes effect if "Retry" is configured, and also depends on specific implementations
// (Channels, Sources, etc.) choosing to provide this capability.
//
// Note: This API is EXPERIMENTAL and might be changed at anytime. While this experimental
// feature is in the Alpha/Beta stage, you must provide a valid value to opt-in for
// supporting "Retry-After" headers. When the feature becomes Stable/GA "Retry-After"
// headers will be respected by default, and you can choose to specify "PT0S" to
// opt-out of supporting "Retry-After" headers.
// For more details: https://github.com/knative/eventing/issues/5811
//
// More information on Duration format:
// - https://www.iso.org/iso-8601-date-and-time-format.html
// - https://en.wikipedia.org/wiki/ISO_8601
//
// +optional
RetryAfterMax *string `json:"retryAfterMax,omitempty"`
}
func (ds *DeliverySpec) Validate(ctx context.Context) *apis.FieldError {
@ -101,6 +122,18 @@ func (ds *DeliverySpec) Validate(ctx context.Context) *apis.FieldError {
errs = errs.Also(apis.ErrInvalidValue(*ds.BackoffDelay, "backoffDelay"))
}
}
if ds.RetryAfterMax != nil {
if feature.FromContext(ctx).IsEnabled(feature.DeliveryRetryAfter) {
p, me := period.Parse(*ds.RetryAfterMax)
if me != nil || p.IsNegative() {
errs = errs.Also(apis.ErrInvalidValue(*ds.RetryAfterMax, "retryAfterMax"))
}
} else {
errs = errs.Also(apis.ErrDisallowedFields("retryAfterMax"))
}
}
return errs
}

View File

@ -163,6 +163,11 @@ func (in *DeliverySpec) DeepCopyInto(out *DeliverySpec) {
*out = new(string)
**out = **in
}
if in.RetryAfterMax != nil {
in, out := &in.RetryAfterMax, &out.RetryAfterMax
*out = new(string)
**out = **in
}
return
}

View File

@ -17,9 +17,10 @@ limitations under the License.
package feature
const (
KReferenceGroup = "kreference-group"
DeliveryTimeout = "delivery-timeout"
KReferenceMapping = "kreference-mapping"
StrictSubscriber = "strict-subscriber"
NewTriggerFilters = "new-trigger-filters"
KReferenceGroup = "kreference-group"
DeliveryRetryAfter = "delivery-retryafter"
DeliveryTimeout = "delivery-timeout"
KReferenceMapping = "kreference-mapping"
StrictSubscriber = "strict-subscriber"
NewTriggerFilters = "new-trigger-filters"
)

View File

@ -84,10 +84,6 @@ type metricsConfig struct {
// If duration is less than or equal to zero, it enables the default behavior.
reportingPeriod time.Duration
// recorder provides a hook for performing custom transformations before
// writing the metrics to the stats.RecordWithOptions interface.
recorder func(context.Context, []stats.Measurement, ...stats.Options) error
// secret contains credentials for an exporter to use for authentication.
secret *corev1.Secret
@ -117,16 +113,13 @@ func (mc *metricsConfig) record(ctx context.Context, mss []stats.Measurement, ro
return nil
}
if mc.recorder == nil {
opt, err := optionForResource(metricskey.GetResource(ctx))
if err != nil {
return err
}
ros = append(ros, opt)
return stats.RecordWithOptions(ctx, append(ros, stats.WithMeasurements(mss...))...)
opt, err := optionForResource(metricskey.GetResource(ctx))
if err != nil {
return err
}
return mc.recorder(ctx, mss, ros...)
ros = append(ros, opt)
return stats.RecordWithOptions(ctx, append(ros, stats.WithMeasurements(mss...))...)
}
func createMetricsConfig(_ context.Context, ops ExporterOptions) (*metricsConfig, error) {

View File

@ -26,11 +26,12 @@ import (
"time"
"knative.dev/pkg/apis"
"knative.dev/pkg/kmap"
"knative.dev/serving/pkg/autoscaler/config/autoscalerconfig"
)
func getIntGE0(m map[string]string, k string) (int32, *apis.FieldError) {
v, ok := m[k]
func getIntGE0(m map[string]string, key kmap.KeyPriority) (int32, *apis.FieldError) {
k, v, ok := key.Get(m)
if !ok {
return 0, nil
}
@ -62,107 +63,109 @@ func ValidateAnnotations(ctx context.Context, config *autoscalerconfig.Config, a
Also(validateInitialScale(config, anns))
}
func validateClass(annotations map[string]string) *apis.FieldError {
if c, ok := annotations[ClassAnnotationKey]; ok {
if strings.HasSuffix(c, domain) && c != KPA && c != HPA {
return apis.ErrInvalidValue(c, ClassAnnotationKey)
func validateClass(m map[string]string) *apis.FieldError {
if k, v, ok := ClassAnnotation.Get(m); ok {
if strings.HasSuffix(v, domain) && v != KPA && v != HPA {
return apis.ErrInvalidValue(v, k)
}
}
return nil
}
func validateAlgorithm(annotations map[string]string) *apis.FieldError {
func validateAlgorithm(m map[string]string) *apis.FieldError {
// Not a KPA? Don't validate, custom autoscalers might have custom values.
if c := annotations[ClassAnnotationKey]; c != KPA {
if _, v, _ := ClassAnnotation.Get(m); v != KPA {
return nil
}
if a := annotations[MetricAggregationAlgorithmKey]; a != "" {
switch a {
case MetricAggregationAlgorithmLinear, MetricAggregationAlgorithmWeightedExponential:
if k, v, _ := MetricAggregationAlgorithmAnnotation.Get(m); v != "" {
switch v {
case MetricAggregationAlgorithmLinear,
MetricAggregationAlgorithmWeightedExponential,
MetricAggregationAlgorithmWeightedExponentialAlt:
return nil
default:
return apis.ErrInvalidValue(a, MetricAggregationAlgorithmKey)
return apis.ErrInvalidValue(v, k)
}
}
return nil
}
func validateFloats(annotations map[string]string) (errs *apis.FieldError) {
if v, ok := annotations[PanicWindowPercentageAnnotationKey]; ok {
func validateFloats(m map[string]string) (errs *apis.FieldError) {
if k, v, ok := PanicWindowPercentageAnnotation.Get(m); ok {
if fv, err := strconv.ParseFloat(v, 64); err != nil {
errs = errs.Also(apis.ErrInvalidValue(v, PanicWindowPercentageAnnotationKey))
errs = errs.Also(apis.ErrInvalidValue(v, k))
} else if fv < PanicWindowPercentageMin || fv > PanicWindowPercentageMax {
errs = apis.ErrOutOfBoundsValue(v, PanicWindowPercentageMin,
PanicWindowPercentageMax, PanicWindowPercentageAnnotationKey)
PanicWindowPercentageMax, k)
}
}
if v, ok := annotations[PanicThresholdPercentageAnnotationKey]; ok {
if k, v, ok := PanicThresholdPercentageAnnotation.Get(m); ok {
if fv, err := strconv.ParseFloat(v, 64); err != nil {
errs = errs.Also(apis.ErrInvalidValue(v, PanicThresholdPercentageAnnotationKey))
errs = errs.Also(apis.ErrInvalidValue(v, k))
} else if fv < PanicThresholdPercentageMin || fv > PanicThresholdPercentageMax {
errs = errs.Also(apis.ErrOutOfBoundsValue(v, PanicThresholdPercentageMin,
PanicThresholdPercentageMax, PanicThresholdPercentageAnnotationKey))
PanicThresholdPercentageMax, k))
}
}
if v, ok := annotations[TargetAnnotationKey]; ok {
if k, v, ok := TargetAnnotation.Get(m); ok {
if fv, err := strconv.ParseFloat(v, 64); err != nil || fv < TargetMin {
errs = errs.Also(apis.ErrGeneric(fmt.Sprintf("target %s should be at least %g", v, TargetMin), TargetAnnotationKey))
errs = errs.Also(apis.ErrGeneric(fmt.Sprintf("target %s should be at least %g", v, TargetMin), k))
}
}
if v, ok := annotations[TargetUtilizationPercentageKey]; ok {
if k, v, ok := TargetUtilizationPercentageAnnotation.Get(m); ok {
if fv, err := strconv.ParseFloat(v, 64); err != nil {
errs = errs.Also(apis.ErrInvalidValue(v, TargetUtilizationPercentageKey))
errs = errs.Also(apis.ErrInvalidValue(v, k))
} else if fv < 1 || fv > 100 {
errs = errs.Also(apis.ErrOutOfBoundsValue(v, 1, 100, TargetUtilizationPercentageKey))
errs = errs.Also(apis.ErrOutOfBoundsValue(v, 1, 100, k))
}
}
if v, ok := annotations[TargetBurstCapacityKey]; ok {
if k, v, ok := TargetBurstCapacityAnnotation.Get(m); ok {
if fv, err := strconv.ParseFloat(v, 64); err != nil || fv < 0 && fv != -1 {
errs = errs.Also(apis.ErrInvalidValue(v, TargetBurstCapacityKey))
errs = errs.Also(apis.ErrInvalidValue(v, k))
}
}
return errs
}
func validateScaleDownDelay(annotations map[string]string) *apis.FieldError {
func validateScaleDownDelay(m map[string]string) *apis.FieldError {
var errs *apis.FieldError
if w, ok := annotations[ScaleDownDelayAnnotationKey]; ok {
if d, err := time.ParseDuration(w); err != nil {
errs = apis.ErrInvalidValue(w, ScaleDownDelayAnnotationKey)
if k, v, ok := ScaleDownDelayAnnotation.Get(m); ok {
if d, err := time.ParseDuration(v); err != nil {
errs = apis.ErrInvalidValue(v, k)
} else if d < 0 || d > WindowMax {
// Since we disallow windows longer than WindowMax, so we should limit this
// as well.
errs = apis.ErrOutOfBoundsValue(w, 0*time.Second, WindowMax, ScaleDownDelayAnnotationKey)
errs = apis.ErrOutOfBoundsValue(v, 0*time.Second, WindowMax, k)
} else if d.Round(time.Second) != d {
errs = apis.ErrGeneric("must be specified with at most second precision", ScaleDownDelayAnnotationKey)
errs = apis.ErrGeneric("must be specified with at most second precision", k)
}
}
return errs
}
func validateLastPodRetention(annotations map[string]string) *apis.FieldError {
if w, ok := annotations[ScaleToZeroPodRetentionPeriodKey]; ok {
if d, err := time.ParseDuration(w); err != nil {
return apis.ErrInvalidValue(w, ScaleToZeroPodRetentionPeriodKey)
func validateLastPodRetention(m map[string]string) *apis.FieldError {
if k, v, ok := ScaleToZeroPodRetentionPeriodAnnotation.Get(m); ok {
if d, err := time.ParseDuration(v); err != nil {
return apis.ErrInvalidValue(v, k)
} else if d < 0 || d > WindowMax {
// Since we disallow windows longer than WindowMax, so we should limit this
// as well.
return apis.ErrOutOfBoundsValue(w, time.Duration(0), WindowMax, ScaleToZeroPodRetentionPeriodKey)
return apis.ErrOutOfBoundsValue(v, time.Duration(0), WindowMax, k)
}
}
return nil
}
func validateWindow(annotations map[string]string) *apis.FieldError {
if w, ok := annotations[WindowAnnotationKey]; ok {
switch d, err := time.ParseDuration(w); {
func validateWindow(m map[string]string) *apis.FieldError {
if _, v, ok := WindowAnnotation.Get(m); ok {
switch d, err := time.ParseDuration(v); {
case err != nil:
return apis.ErrInvalidValue(w, WindowAnnotationKey)
return apis.ErrInvalidValue(v, WindowAnnotationKey)
case d < WindowMin || d > WindowMax:
return apis.ErrOutOfBoundsValue(w, WindowMin, WindowMax, WindowAnnotationKey)
return apis.ErrOutOfBoundsValue(v, WindowMin, WindowMax, WindowAnnotationKey)
case d.Truncate(time.Second) != d:
return apis.ErrGeneric("must be specified with at most second precision", WindowAnnotationKey)
}
@ -170,48 +173,48 @@ func validateWindow(annotations map[string]string) *apis.FieldError {
return nil
}
func validateMinMaxScale(config *autoscalerconfig.Config, annotations map[string]string) *apis.FieldError {
min, errs := getIntGE0(annotations, MinScaleAnnotationKey)
max, err := getIntGE0(annotations, MaxScaleAnnotationKey)
func validateMinMaxScale(config *autoscalerconfig.Config, m map[string]string) *apis.FieldError {
min, errs := getIntGE0(m, MinScaleAnnotation)
max, err := getIntGE0(m, MaxScaleAnnotation)
errs = errs.Also(err)
if max != 0 && max < min {
errs = errs.Also(&apis.FieldError{
Message: fmt.Sprintf("maxScale=%d is less than minScale=%d", max, min),
Message: fmt.Sprintf("max-scale=%d is less than min-scale=%d", max, min),
Paths: []string{MaxScaleAnnotationKey, MinScaleAnnotationKey},
})
}
if _, hasMaxScaleAnnotation := annotations[MaxScaleAnnotationKey]; hasMaxScaleAnnotation {
errs = errs.Also(validateMaxScaleWithinLimit(max, config.MaxScaleLimit))
if k, _, ok := MaxScaleAnnotation.Get(m); ok {
errs = errs.Also(validateMaxScaleWithinLimit(k, max, config.MaxScaleLimit))
}
return errs
}
func validateMaxScaleWithinLimit(maxScale, maxScaleLimit int32) (errs *apis.FieldError) {
func validateMaxScaleWithinLimit(key string, maxScale, maxScaleLimit int32) (errs *apis.FieldError) {
if maxScaleLimit == 0 {
return nil
}
if maxScale > maxScaleLimit {
errs = errs.Also(apis.ErrOutOfBoundsValue(maxScale, 1, maxScaleLimit, MaxScaleAnnotationKey))
errs = errs.Also(apis.ErrOutOfBoundsValue(maxScale, 1, maxScaleLimit, key))
}
if maxScale == 0 {
errs = errs.Also(&apis.FieldError{
Message: fmt.Sprint("maxScale=0 (unlimited), must be less than ", maxScaleLimit),
Paths: []string{MaxScaleAnnotationKey},
Message: fmt.Sprint("max-scale=0 (unlimited), must be less than ", maxScaleLimit),
Paths: []string{key},
})
}
return errs
}
func validateMetric(annotations map[string]string) *apis.FieldError {
if metric, ok := annotations[MetricAnnotationKey]; ok {
func validateMetric(m map[string]string) *apis.FieldError {
if _, metric, ok := MetricAnnotation.Get(m); ok {
classValue := KPA
if c, ok := annotations[ClassAnnotationKey]; ok {
if _, c, ok := ClassAnnotation.Get(m); ok {
classValue = c
}
switch classValue {
@ -234,11 +237,11 @@ func validateMetric(annotations map[string]string) *apis.FieldError {
return nil
}
func validateInitialScale(config *autoscalerconfig.Config, annotations map[string]string) *apis.FieldError {
if initialScale, ok := annotations[InitialScaleAnnotationKey]; ok {
initScaleInt, err := strconv.Atoi(initialScale)
func validateInitialScale(config *autoscalerconfig.Config, m map[string]string) *apis.FieldError {
if k, v, ok := InitialScaleAnnotation.Get(m); ok {
initScaleInt, err := strconv.Atoi(v)
if err != nil || initScaleInt < 0 || (!config.AllowZeroInitialScale && initScaleInt == 0) {
return apis.ErrInvalidValue(initialScale, InitialScaleAnnotationKey)
return apis.ErrInvalidValue(v, k)
}
}
return nil

View File

@ -16,7 +16,11 @@ limitations under the License.
package autoscaling
import "time"
import (
"time"
"knative.dev/pkg/kmap"
)
const (
domain = ".knative.dev"
@ -39,20 +43,21 @@ const (
// MinScaleAnnotationKey is the annotation to specify the minimum number of Pods
// the PodAutoscaler should provision. For example,
// autoscaling.knative.dev/minScale: "1"
MinScaleAnnotationKey = GroupName + "/minScale"
// autoscaling.knative.dev/min-scale: "1"
MinScaleAnnotationKey = GroupName + "/min-scale"
// MaxScaleAnnotationKey is the annotation to specify the maximum number of Pods
// the PodAutoscaler should provision. For example,
// autoscaling.knative.dev/maxScale: "10"
MaxScaleAnnotationKey = GroupName + "/maxScale"
// autoscaling.knative.dev/max-scale: "10"
MaxScaleAnnotationKey = GroupName + "/max-scale"
// InitialScaleAnnotationKey is the annotation to specify the initial scale of
// a revision when a service is initially deployed. This number can be set to 0 iff
// allow-zero-initial-scale of config-autoscaler is true.
InitialScaleAnnotationKey = GroupName + "/initialScale"
InitialScaleAnnotationKey = GroupName + "/initial-scale"
// ScaleDownDelayAnnotationKey is the annotation to specify a scale down delay.
ScaleDownDelayAnnotationKey = GroupName + "/scaleDownDelay"
ScaleDownDelayAnnotationKey = GroupName + "/scale-down-delay"
// MetricAnnotationKey is the annotation to specify what metric the PodAutoscaler
// should be scaled on. For example,
@ -86,7 +91,7 @@ const (
// made the decision to scale to 0.
// This is the per-revision setting compliment to the
// scale-to-zero-pod-retention-period global setting.
ScaleToZeroPodRetentionPeriodKey = GroupName + "/scaleToZeroPodRetentionPeriod"
ScaleToZeroPodRetentionPeriodKey = GroupName + "/scale-to-zero-pod-retention-period"
// MetricAggregationAlgorithmKey is the annotation that can be used for selection
// of the algorithm to use for averaging metric data in the Autoscaler.
@ -102,13 +107,21 @@ const (
// KPA will compute the decay multiplier automatically based on the window size
// and it is at least 0.2. This algorithm might not utilize all the values
// in the window, due to their coefficients being infinitesimal.
MetricAggregationAlgorithmKey = GroupName + "/metricAggregationAlgorithm"
MetricAggregationAlgorithmKey = GroupName + "/metric-aggregation-algorithm"
// MetricAggregationAlgorithmLinear is the linear aggregation algorithm with all weights
// equal to 1.
MetricAggregationAlgorithmLinear = "linear"
// MetricAggregationAlgorithmWeightedExponential is the weighted aggregation algorithm
// with exponentially decaying weights.
MetricAggregationAlgorithmWeightedExponential = "weightedExponential"
MetricAggregationAlgorithmWeightedExponential = "weighted-exponential"
// MetricAggregationAlgorithmWeightedExponentialAlt is the alternate casing for MetricAggregationAlgorithmWeightedExponential
// Note: use the Metric.AggregationAlgorithm() method as it will normalize the casing
// and return MetricAggregationAlgorithmWeightedExponential
MetricAggregationAlgorithmWeightedExponentialAlt = "weightedExponential"
// WindowAnnotationKey is the annotation to specify the time
// interval over which to calculate the average metric. Larger
@ -136,7 +149,7 @@ const (
// desired target resource utilization for the revision.
// TargetUtilization is a percentage in the 1 <= TU <= 100 range.
// This annotation takes precedence over the config map value.
TargetUtilizationPercentageKey = GroupName + "/targetUtilizationPercentage"
TargetUtilizationPercentageKey = GroupName + "/target-utilization-percentage"
// TargetBurstCapacityKey specifies the desired burst capacity for the
// revision. Possible values are:
@ -144,7 +157,7 @@ const (
// 0 -- no TBC;
// >0 -- actual TBC.
// <0 && != -1 -- an error.
TargetBurstCapacityKey = GroupName + "/targetBurstCapacity"
TargetBurstCapacityKey = GroupName + "/target-burst-capacity"
// PanicWindowPercentageAnnotationKey is the annotation to
// specify the time interval over which to calculate the average
@ -153,15 +166,16 @@ const (
// mode). Lower values make panic mode more sensitive. Note:
// Panic threshold can be overridden with the
// PanicThresholdPercentageAnnotationKey. For example,
// autoscaling.knative.dev/panicWindowPercentage: "5.0"
// autoscaling.knative.dev/panicThresholdPercentage: "150.0"
// autoscaling.knative.dev/panic-window-percentage: "5.0"
// autoscaling.knative.dev/panic-threshold-percentage: "150.0"
// Only the kpa.autoscaling.knative.dev class autoscaler supports
// the panicWindowPercentage annotation.
// the panic-window-percentage annotation.
// Panic window is specified as a percentage to maintain the
// autoscaler's algorithm behavior when only the stable window is
// specified. The panic window will change along with the stable
// window at the default percentage.
PanicWindowPercentageAnnotationKey = GroupName + "/panicWindowPercentage"
PanicWindowPercentageAnnotationKey = GroupName + "/panic-window-percentage"
// PanicWindowPercentageMin is the minimum allowable panic window
// percentage. The autoscaler calculates desired replicas every 2
// seconds (tick-interval in config-autoscaler), so a panic
@ -182,11 +196,12 @@ const (
// in the panic window. The level is defined as a percentage of
// the metric target. Lower values make panic mode more
// sensitive. For example,
// autoscaling.knative.dev/panicWindowPercentage: "5.0"
// autoscaling.knative.dev/panicThresholdPercentage: "150.0"
// autoscaling.knative.dev/panic-window-percentage: "5.0"
// autoscaling.knative.dev/panic-threshold-percentage: "150.0"
// Only the kpa.autoscaling.knative.dev class autoscaler supports
// the panicThresholdPercentage annotation
PanicThresholdPercentageAnnotationKey = GroupName + "/panicThresholdPercentage"
PanicThresholdPercentageAnnotationKey = GroupName + "/panic-threshold-percentage"
// PanicThresholdPercentageMin is the minimum allowable panic
// threshold percentage. The KPA autoscaler's panic feature
// allows the autoscaler to be more responsive over a smaller
@ -202,3 +217,58 @@ const (
// but bounding from above.
PanicThresholdPercentageMax = 1000.0
)
var (
ClassAnnotation = kmap.KeyPriority{
ClassAnnotationKey,
}
InitialScaleAnnotation = kmap.KeyPriority{
InitialScaleAnnotationKey,
GroupName + "/initialScale",
}
MaxScaleAnnotation = kmap.KeyPriority{
MaxScaleAnnotationKey,
GroupName + "/maxScale",
}
MetricAnnotation = kmap.KeyPriority{
MetricAnnotationKey,
}
MetricAggregationAlgorithmAnnotation = kmap.KeyPriority{
MetricAggregationAlgorithmKey,
GroupName + "/metricAggregationAlgorithm",
}
MinScaleAnnotation = kmap.KeyPriority{
MinScaleAnnotationKey,
GroupName + "/minScale",
}
PanicThresholdPercentageAnnotation = kmap.KeyPriority{
PanicThresholdPercentageAnnotationKey,
GroupName + "/panicThresholdPercentage",
}
PanicWindowPercentageAnnotation = kmap.KeyPriority{
PanicWindowPercentageAnnotationKey,
GroupName + "/panicWindowPercentage",
}
ScaleDownDelayAnnotation = kmap.KeyPriority{
ScaleDownDelayAnnotationKey,
GroupName + "/scaleDownDelay",
}
ScaleToZeroPodRetentionPeriodAnnotation = kmap.KeyPriority{
ScaleToZeroPodRetentionPeriodKey,
GroupName + "/scaleToZeroPodRetentionPeriod",
}
TargetAnnotation = kmap.KeyPriority{
TargetAnnotationKey,
}
TargetBurstCapacityAnnotation = kmap.KeyPriority{
TargetBurstCapacityKey,
GroupName + "/targetBurstCapacity",
}
TargetUtilizationPercentageAnnotation = kmap.KeyPriority{
TargetUtilizationPercentageKey,
GroupName + "/targetUtilizationPercentage",
}
WindowAnnotation = kmap.KeyPriority{
WindowAnnotationKey,
}
)

View File

@ -19,6 +19,7 @@ package v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
"knative.dev/serving/pkg/apis/autoscaling"
)
const (
@ -74,3 +75,14 @@ func (m *Metric) IsReady() bool {
return ms.ObservedGeneration == m.Generation &&
ms.GetCondition(MetricConditionReady).IsTrue()
}
func (m *Metric) AggregationAlgorithm() string {
if _, s, ok := autoscaling.MetricAggregationAlgorithmAnnotation.Get(m.Annotations); ok {
// Normalize and use the regular casing
if s == autoscaling.MetricAggregationAlgorithmWeightedExponentialAlt {
return autoscaling.MetricAggregationAlgorithmWeightedExponential
}
return s
}
return ""
}

View File

@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/apis"
"knative.dev/pkg/kmap"
"knative.dev/serving/pkg/apis/autoscaling"
"knative.dev/serving/pkg/autoscaler/config/autoscalerconfig"
)
@ -63,16 +64,16 @@ func (pa *PodAutoscaler) Metric() string {
return defaultMetric(pa.Class())
}
func (pa *PodAutoscaler) annotationInt32(key string) (int32, bool) {
if s, ok := pa.Annotations[key]; ok {
func (pa *PodAutoscaler) annotationInt32(k kmap.KeyPriority) (int32, bool) {
if _, s, ok := k.Get(pa.Annotations); ok {
i, err := strconv.ParseInt(s, 10, 32)
return int32(i), err == nil
}
return 0, false
}
func (pa *PodAutoscaler) annotationFloat64(key string) (float64, bool) {
if s, ok := pa.Annotations[key]; ok {
func (pa *PodAutoscaler) annotationFloat64(k kmap.KeyPriority) (float64, bool) {
if _, s, ok := k.Get(pa.Annotations); ok {
f, err := strconv.ParseFloat(s, 64)
return f, err == nil
}
@ -87,13 +88,13 @@ func (pa *PodAutoscaler) ScaleBounds(asConfig *autoscalerconfig.Config) (int32,
var min int32
if pa.Spec.Reachability != ReachabilityUnreachable {
min = asConfig.MinScale
if paMin, ok := pa.annotationInt32(autoscaling.MinScaleAnnotationKey); ok {
if paMin, ok := pa.annotationInt32(autoscaling.MinScaleAnnotation); ok {
min = paMin
}
}
max := asConfig.MaxScale
if paMax, ok := pa.annotationInt32(autoscaling.MaxScaleAnnotationKey); ok {
if paMax, ok := pa.annotationInt32(autoscaling.MaxScaleAnnotation); ok {
max = paMax
}
@ -102,13 +103,13 @@ func (pa *PodAutoscaler) ScaleBounds(asConfig *autoscalerconfig.Config) (int32,
// Target returns the target annotation value or false if not present, or invalid.
func (pa *PodAutoscaler) Target() (float64, bool) {
return pa.annotationFloat64(autoscaling.TargetAnnotationKey)
return pa.annotationFloat64(autoscaling.TargetAnnotation)
}
// TargetUtilization returns the target utilization percentage as a fraction, if
// the corresponding annotation is set.
func (pa *PodAutoscaler) TargetUtilization() (float64, bool) {
if tu, ok := pa.annotationFloat64(autoscaling.TargetUtilizationPercentageKey); ok {
if tu, ok := pa.annotationFloat64(autoscaling.TargetUtilizationPercentageAnnotation); ok {
return tu / 100, true
}
return 0, false
@ -117,11 +118,11 @@ func (pa *PodAutoscaler) TargetUtilization() (float64, bool) {
// TargetBC returns the target burst capacity, if the corresponding annotation is set.
func (pa *PodAutoscaler) TargetBC() (float64, bool) {
// The value is validated in the webhook.
return pa.annotationFloat64(autoscaling.TargetBurstCapacityKey)
return pa.annotationFloat64(autoscaling.TargetBurstCapacityAnnotation)
}
func (pa *PodAutoscaler) annotationDuration(key string) (time.Duration, bool) {
if s, ok := pa.Annotations[key]; ok {
func (pa *PodAutoscaler) annotationDuration(k kmap.KeyPriority) (time.Duration, bool) {
if _, s, ok := k.Get(pa.Annotations); ok {
d, err := time.ParseDuration(s)
return d, err == nil
}
@ -132,37 +133,37 @@ func (pa *PodAutoscaler) annotationDuration(key string) (time.Duration, bool) {
// or false if not present.
func (pa *PodAutoscaler) ScaleToZeroPodRetention() (time.Duration, bool) {
// The value is validated in the webhook.
return pa.annotationDuration(autoscaling.ScaleToZeroPodRetentionPeriodKey)
return pa.annotationDuration(autoscaling.ScaleToZeroPodRetentionPeriodAnnotation)
}
// Window returns the window annotation value, or false if not present.
func (pa *PodAutoscaler) Window() (time.Duration, bool) {
// The value is validated in the webhook.
return pa.annotationDuration(autoscaling.WindowAnnotationKey)
return pa.annotationDuration(autoscaling.WindowAnnotation)
}
// ScaleDownDelay returns the scale down delay annotation, or false if not present.
func (pa *PodAutoscaler) ScaleDownDelay() (time.Duration, bool) {
// The value is validated in the webhook.
return pa.annotationDuration(autoscaling.ScaleDownDelayAnnotationKey)
return pa.annotationDuration(autoscaling.ScaleDownDelayAnnotation)
}
// PanicWindowPercentage returns the panic window annotation value, or false if not present.
func (pa *PodAutoscaler) PanicWindowPercentage() (percentage float64, ok bool) {
// The value is validated in the webhook.
return pa.annotationFloat64(autoscaling.PanicWindowPercentageAnnotationKey)
return pa.annotationFloat64(autoscaling.PanicWindowPercentageAnnotation)
}
// PanicThresholdPercentage returns the panic threshold annotation value, or false if not present.
func (pa *PodAutoscaler) PanicThresholdPercentage() (percentage float64, ok bool) {
// The value is validated in the webhook.
return pa.annotationFloat64(autoscaling.PanicThresholdPercentageAnnotationKey)
return pa.annotationFloat64(autoscaling.PanicThresholdPercentageAnnotation)
}
// InitialScale returns the initial scale on the revision if present, or false if not present.
func (pa *PodAutoscaler) InitialScale() (int32, bool) {
// The value is validated in the webhook.
return pa.annotationInt32(autoscaling.InitialScaleAnnotationKey)
return pa.annotationInt32(autoscaling.InitialScaleAnnotation)
}
// IsReady returns true if the Status condition PodAutoscalerConditionReady

View File

@ -50,25 +50,25 @@ func ValidateObjectMetadata(ctx context.Context, meta metav1.Object, allowAutosc
// ValidateRolloutDurationAnnotation validates the rollout duration annotation.
// This annotation can be set on either service or route objects.
func ValidateRolloutDurationAnnotation(annos map[string]string) (errs *apis.FieldError) {
if v := annos[RolloutDurationKey]; v != "" {
if k, v, _ := RolloutDurationAnnotation.Get(annos); v != "" {
// Parse as duration.
d, err := time.ParseDuration(v)
if err != nil {
return errs.Also(apis.ErrInvalidValue(v, RolloutDurationKey))
return errs.Also(apis.ErrInvalidValue(v, k))
}
// Validate that it has second precision.
if d.Round(time.Second) != d {
return errs.Also(&apis.FieldError{
// Even if tempting %v won't work here, since it might output the value spelled differently.
Message: fmt.Sprintf("rolloutDuration=%s is not at second precision", v),
Paths: []string{RolloutDurationKey},
Message: fmt.Sprintf("rollout-duration=%s is not at second precision", v),
Paths: []string{k},
})
}
// And positive.
if d < 0 {
return errs.Also(&apis.FieldError{
Message: fmt.Sprintf("rolloutDuration=%s must be positive", v),
Paths: []string{RolloutDurationKey},
Message: fmt.Sprintf("rollout-duration=%s must be positive", v),
Paths: []string{k},
})
}
}

View File

@ -16,7 +16,10 @@ limitations under the License.
package serving
import "k8s.io/apimachinery/pkg/runtime/schema"
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"knative.dev/pkg/kmap"
)
const (
// GroupName is the group name for knative labels and annotations
@ -55,7 +58,7 @@ const (
// of the rollout of the latest revision. The value must be a valid positive
// Golang time.Duration value serialized to string.
// The value can be specified with at most with a second precision.
RolloutDurationKey = GroupName + "/rolloutDuration"
RolloutDurationKey = GroupName + "/rollout-duration"
// RoutingStateLabelKey is the label attached to a Revision indicating
// its state in relation to serving a Route.
@ -111,9 +114,9 @@ const (
// last updated the resource.
UpdaterAnnotation = GroupName + "/lastModifier"
// QueueSideCarResourcePercentageAnnotation is the percentage of user container resources to be used for queue-proxy
// QueueSidecarResourcePercentageAnnotationKey is the percentage of user container resources to be used for queue-proxy
// It has to be in [0.1,100]
QueueSideCarResourcePercentageAnnotation = "queue.sidecar." + GroupName + "/resourcePercentage"
QueueSidecarResourcePercentageAnnotationKey = "queue.sidecar." + GroupName + "/resource-percentage"
// VisibilityClusterLocal is the label value for VisibilityLabelKey
// that will result to the Route/KService getting a cluster local
@ -146,3 +149,14 @@ var (
Resource: "routes",
}
)
var (
RolloutDurationAnnotation = kmap.KeyPriority{
RolloutDurationKey,
GroupName + "/rolloutDuration",
}
QueueSidecarResourcePercentageAnnotation = kmap.KeyPriority{
QueueSidecarResourcePercentageAnnotationKey,
"queue.sidecar." + GroupName + "/resourcePercentage",
}
)

View File

@ -178,22 +178,20 @@ func validateTimeoutSeconds(ctx context.Context, timeoutSeconds int64) *apis.Fie
}
// validateQueueSidecarAnnotation validates QueueSideCarResourcePercentageAnnotation
func validateQueueSidecarAnnotation(annotations map[string]string) *apis.FieldError {
if len(annotations) == 0 {
func validateQueueSidecarAnnotation(m map[string]string) *apis.FieldError {
if len(m) == 0 {
return nil
}
v, ok := annotations[serving.QueueSideCarResourcePercentageAnnotation]
k, v, ok := serving.QueueSidecarResourcePercentageAnnotation.Get(m)
if !ok {
return nil
}
value, err := strconv.ParseFloat(v, 64)
if err != nil {
return apis.ErrInvalidValue(v, apis.CurrentField).
ViaKey(serving.QueueSideCarResourcePercentageAnnotation)
return apis.ErrInvalidValue(v, apis.CurrentField).ViaKey(k)
}
if value < 0.1 || value > 100 {
return apis.ErrOutOfBoundsValue(value, 0.1, 100.0, apis.CurrentField).
ViaKey(serving.QueueSideCarResourcePercentageAnnotation)
return apis.ErrOutOfBoundsValue(value, 0.1, 100.0, apis.CurrentField).ViaKey(k)
}
return nil
}

View File

@ -64,7 +64,7 @@ func (r *Route) IsFailed() bool {
// annotation.
// 0 is returned if missing or cannot be parsed.
func (r *Route) RolloutDuration() time.Duration {
if v, ok := r.Annotations[serving.RolloutDurationKey]; ok && v != "" {
if _, v, ok := serving.RolloutDurationAnnotation.Get(r.Annotations); ok && v != "" {
// WH should've declined all the invalid values for this annotation.
if d, err := time.ParseDuration(v); err == nil {
return d

8
vendor/modules.txt vendored
View File

@ -731,7 +731,7 @@ k8s.io/utils/buffer
k8s.io/utils/integer
k8s.io/utils/pointer
k8s.io/utils/trace
# knative.dev/eventing v0.27.1-0.20211123070249-2cda8f40b5d9
# knative.dev/eventing v0.27.1-0.20211123205351-820db20be4b2
## explicit
knative.dev/eventing/pkg/apis/config
knative.dev/eventing/pkg/apis/duck
@ -760,7 +760,7 @@ knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1beta2/fake
# knative.dev/hack v0.0.0-20211122162614-813559cefdda
## explicit
knative.dev/hack
# knative.dev/networking v0.0.0-20211123024050-aa82452902be
# knative.dev/networking v0.0.0-20211124064027-ea794f17c1bf
## explicit
knative.dev/networking/pkg
knative.dev/networking/pkg/apis/networking
@ -768,7 +768,7 @@ knative.dev/networking/pkg/apis/networking/v1alpha1
knative.dev/networking/pkg/client/clientset/versioned
knative.dev/networking/pkg/client/clientset/versioned/scheme
knative.dev/networking/pkg/client/clientset/versioned/typed/networking/v1alpha1
# knative.dev/pkg v0.0.0-20211123074649-0fae0afc10ad
# knative.dev/pkg v0.0.0-20211123135150-787aec59e70a
## explicit
knative.dev/pkg/apis
knative.dev/pkg/apis/duck
@ -818,7 +818,7 @@ knative.dev/pkg/tracing/config
knative.dev/pkg/tracing/propagation
knative.dev/pkg/tracing/propagation/tracecontextb3
knative.dev/pkg/tracker
# knative.dev/serving v0.27.1-0.20211123120750-26c7dc6ccc53
# knative.dev/serving v0.27.1-0.20211124064027-e6f8e414ac9e
## explicit
knative.dev/serving/pkg/apis/autoscaling
knative.dev/serving/pkg/apis/autoscaling/v1alpha1