Repository: knative/serving
Pull request #12290 (2021-11-16 20:58:29)

Add default cluster-side min-scale
based on a slack conversation: https://knative.slack.com/archives/C94SPR60H/p1637002245043400

<!-- Please include the 'why' behind your changes if no issue exists -->
## Proposed Changes

* add a cluster-wide config value for min-scale

**Release Note**

<!-- Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". -->

```release-note
Add cluster wide default min-scale
```


knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/12290#" title="Author self-approved">nader-ziada</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **vagababov** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @vagababov` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fserving).

<details open>
Needs approval from an approver in each of these files:

- **[config/OWNERS](https://github.com/knative/serving/blob/main/config/OWNERS)**
- **[pkg/apis/autoscaling/OWNERS](https://github.com/knative/serving/blob/main/pkg/apis/autoscaling/OWNERS)**
- **[pkg/autoscaler/OWNERS](https://github.com/knative/serving/blob/main/pkg/autoscaler/OWNERS)**
- **[pkg/reconciler/autoscaling/OWNERS](https://github.com/knative/serving/blob/main/pkg/reconciler/autoscaling/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["vagababov"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) Report
> Merging [#12290](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) (aaa1dff) into [main](https://codecov.io/gh/knative/serving/commit/3a20c13c0a9787542c9204980c38f3052b8004f1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) (3a20c13) will **increase** coverage by `0.02%`.
> The diff coverage is `71.42%`.

[![Impacted file tree graph](https://codecov.io/gh/knative/serving/pull/12290/graphs/tree.svg?width=650&height=150&src=pr&token=MPpDfAj4Ui&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)

```diff
@@            Coverage Diff             @@
##             main   #12290      +/-   ##
==========================================
+ Coverage   87.29%   87.32%   +0.02%     
==========================================
  Files         195      195              
  Lines        9610     9615       +5     
==========================================
+ Hits         8389     8396       +7     
+ Misses        940      938       -2     
  Partials      281      281              
```


| [Impacted Files](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) | Coverage Δ | |
|---|---|---|
| [pkg/autoscaler/config/config.go](https://codecov.io/gh/knative/serving/pull/12290/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2F1dG9zY2FsZXIvY29uZmlnL2NvbmZpZy5nbw==) | `97.87% <50.00%> (-2.13%)` | :arrow_down: |
| [pkg/apis/autoscaling/v1alpha1/pa\_lifecycle.go](https://codecov.io/gh/knative/serving/pull/12290/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2FwaXMvYXV0b3NjYWxpbmcvdjFhbHBoYTEvcGFfbGlmZWN5Y2xlLmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/reconciler/configuration/configuration.go](https://codecov.io/gh/knative/serving/pull/12290/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL3JlY29uY2lsZXIvY29uZmlndXJhdGlvbi9jb25maWd1cmF0aW9uLmdv) | `86.15% <0.00%> (+1.53%)` | :arrow_up: |
| [pkg/autoscaler/statserver/server.go](https://codecov.io/gh/knative/serving/pull/12290/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2F1dG9zY2FsZXIvc3RhdHNlcnZlci9zZXJ2ZXIuZ28=) | `79.61% <0.00%> (+1.94%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative). Last update [3a20c13...aaa1dff](https://codecov.io/gh/knative/serving/pull/12290?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative).


Patch:
diff --git a/config/core/configmaps/autoscaler.yaml b/config/core/configmaps/autoscaler.yaml
index 3fc53df28..620bcaa26 100644
--- a/config/core/configmaps/autoscaler.yaml
+++ b/config/core/configmaps/autoscaler.yaml
@@ -23,7 +23,7 @@ metadata:
     app.kubernetes.io/version: devel
     serving.knative.dev/release: devel
   annotations:
-    knative.dev/example-checksum: "604cb513"
+    knative.dev/example-checksum: "b4401cf4"
 data:
   _example: |
     ################################
@@ -187,6 +187,10 @@ data:
     # or the "autoscaling.knative.dev/initialScale" annotation, can be set to 0.
     allow-zero-initial-scale: "false"
 
+    # min-scale is the cluster-wide default value for the min scale of a revision,
+    # unless overridden by the "autoscaling.knative.dev/minScale" annotation.
+    min-scale: "0"
+
     # max-scale is the cluster-wide default value for the max scale of a revision,
     # unless overridden by the "autoscaling.knative.dev/maxScale" annotation.
     # If set to 0, the revision has no maximum scale.
diff --git a/go.mod b/go.mod
index 902503c7e..faf113308 100644
--- a/go.mod
+++ b/go.mod
@@ -43,9 +43,9 @@ require (
 	k8s.io/code-generator v0.21.4
 	k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7
 	k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 // indirect
-	knative.dev/caching v0.0.0-20211117091234-89a3cb9bc119
-	knative.dev/hack v0.0.0-20211112192837-128cf0150a69
-	knative.dev/networking v0.0.0-20211117091734-66e47364eb5c
-	knative.dev/pkg v0.0.0-20211117100634-54071addcdb8
+	knative.dev/caching v0.0.0-20211117134235-da260af2ab4d
+	knative.dev/hack v0.0.0-20211117134436-69a2295d54ce
+	knative.dev/networking v0.0.0-20211117141434-4d634effa7b7
+	knative.dev/pkg v0.0.0-20211117215328-5708c4c44232
 	sigs.k8s.io/yaml v1.3.0
 )
diff --git a/go.sum b/go.sum
index ff8d932b8..6afe01cb7 100644
--- a/go.sum
+++ b/go.sum
@@ -1604,15 +1604,17 @@ 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-20211117091234-89a3cb9bc119 h1:YFpgPAdKrOxzRm2OYyqvbQpFsXFHSz2xjNLWepO4RAY=
-knative.dev/caching v0.0.0-20211117091234-89a3cb9bc119/go.mod h1:FSLPsqZioiPjIP1UvxjEY2VKnBfctQoQzH/skySdAqM=
-knative.dev/hack v0.0.0-20211112192837-128cf0150a69 h1:/3NW6B9VeqAwpW0ZAS+8xLfwgVMIqH+CPmesDATovhk=
+knative.dev/caching v0.0.0-20211117134235-da260af2ab4d h1:Q3r6eJiA4/mCLLP0FBNGcZSemXa+KDT9Rr7Wg1T++bk=
+knative.dev/caching v0.0.0-20211117134235-da260af2ab4d/go.mod h1:FSLPsqZioiPjIP1UvxjEY2VKnBfctQoQzH/skySdAqM=
 knative.dev/hack v0.0.0-20211112192837-128cf0150a69/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/networking v0.0.0-20211117091734-66e47364eb5c h1:quPRCst/2oQYU9zzrt/J726gJElyfXWUZ/vUzuf5oJ8=
-knative.dev/networking v0.0.0-20211117091734-66e47364eb5c/go.mod h1:gEz/FkP2zpbXS1Pg/+oUjA3eUMgVFTmIG5pDBBiUzQM=
+knative.dev/hack v0.0.0-20211117134436-69a2295d54ce h1:dPARWsX/9nmWg9g09MtGnsn7nZUwjA0UWpKSUozgS6g=
+knative.dev/hack v0.0.0-20211117134436-69a2295d54ce/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/networking v0.0.0-20211117141434-4d634effa7b7 h1:teeoQe15N0VpxIdQ45tfXK786rPs1tIfuyS20rGdcCM=
+knative.dev/networking v0.0.0-20211117141434-4d634effa7b7/go.mod h1:llkl8XkuVxcdm/FJvPfOSscb6IrOyATQ1fpCQ/uFwuE=
 knative.dev/pkg v0.0.0-20211116213053-d82be484e4c3/go.mod h1:VqUp1KWJqpTDNoiSI/heaX3uMdubImslJE2tBkP+Bbw=
-knative.dev/pkg v0.0.0-20211117100634-54071addcdb8 h1:wpZDf2oNNPqhgGCvfBMyroXtAXoxyovRswXu0emmN8Q=
 knative.dev/pkg v0.0.0-20211117100634-54071addcdb8/go.mod h1:VqUp1KWJqpTDNoiSI/heaX3uMdubImslJE2tBkP+Bbw=
+knative.dev/pkg v0.0.0-20211117215328-5708c4c44232 h1:mye0h0gL0sI2YraL1X5FjyfQZoYVaaaRemTJq+uw+/8=
+knative.dev/pkg v0.0.0-20211117215328-5708c4c44232/go.mod h1:VqUp1KWJqpTDNoiSI/heaX3uMdubImslJE2tBkP+Bbw=
 pgregory.net/rapid v0.3.3 h1:jCjBsY4ln4Atz78QoBWxUEvAHaFyNDQg9+WU62aCn1U=
 pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go b/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go
index e2fee67ff..2318a5f36 100644
--- a/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go
+++ b/pkg/apis/autoscaling/v1alpha1/pa_lifecycle.go
@@ -86,7 +86,10 @@ func (pa *PodAutoscaler) annotationFloat64(key string) (float64, bool) {
 func (pa *PodAutoscaler) ScaleBounds(asConfig *autoscalerconfig.Config) (int32, int32) {
 	var min int32
 	if pa.Spec.Reachability != ReachabilityUnreachable {
-		min, _ = pa.annotationInt32(autoscaling.MinScaleAnnotationKey)
+		min = asConfig.MinScale
+		if paMin, ok := pa.annotationInt32(autoscaling.MinScaleAnnotationKey); ok {
+			min = paMin
+		}
 	}
 
 	max := asConfig.MaxScale
diff --git a/pkg/autoscaler/config/autoscalerconfig/autoscalerconfig.go b/pkg/autoscaler/config/autoscalerconfig/autoscalerconfig.go
index 6ab3b8508..cd3788d88 100644
--- a/pkg/autoscaler/config/autoscalerconfig/autoscalerconfig.go
+++ b/pkg/autoscaler/config/autoscalerconfig/autoscalerconfig.go
@@ -50,6 +50,10 @@ type Config struct {
 	// services. This can be set to 0 iff AllowZeroInitialScale is true.
 	InitialScale int32
 
+	// MinScale is the default min scale for any revision created without an
+	// autoscaling.knative.dev/minScale annotation
+	MinScale int32
+
 	// MaxScale is the default max scale for any revision created without an
 	// autoscaling.knative.dev/maxScale annotation
 	MaxScale int32
diff --git a/pkg/autoscaler/config/config.go b/pkg/autoscaler/config/config.go
index e4f1d8541..b3eff7b2e 100644
--- a/pkg/autoscaler/config/config.go
+++ b/pkg/autoscaler/config/config.go
@@ -60,6 +60,7 @@ func defaultConfig() *autoscalerconfig.Config {
 		PodAutoscalerClass:            autoscaling.KPA,
 		AllowZeroInitialScale:         false,
 		InitialScale:                  1,
+		MinScale:                      0,
 		MaxScale:                      0,
 		MaxScaleLimit:                 0,
 	}
@@ -86,6 +87,7 @@ func NewConfigFromMap(data map[string]string) (*autoscalerconfig.Config, error)
 		cm.AsFloat64("panic-threshold-percentage", &lc.PanicThresholdPercentage),
 
 		cm.AsInt32("initial-scale", &lc.InitialScale),
+		cm.AsInt32("min-scale", &lc.MinScale),
 		cm.AsInt32("max-scale", &lc.MaxScale),
 		cm.AsInt32("max-scale-limit", &lc.MaxScaleLimit),
 
@@ -176,6 +178,10 @@ func validate(lc *autoscalerconfig.Config) (*autoscalerconfig.Config, error) {
 		return nil, fmt.Errorf("initial-scale = %v, must be at least 0 (or at least 1 when allow-zero-initial-scale is false)", lc.InitialScale)
 	}
 
+	if lc.MinScale < 0 {
+		return nil, fmt.Errorf("min-scale = %v, must be at least 0", lc.MinScale)
+	}
+
 	var minMaxScale int32
 	if lc.MaxScaleLimit > 0 {
 		// Default maxScale must be set if maxScaleLimit is set.
@@ -191,6 +197,10 @@ func validate(lc *autoscalerconfig.Config) (*autoscalerconfig.Config, error) {
 		return nil, fmt.Errorf("max-scale-limit = %v, must be at least 0", lc.MaxScaleLimit)
 	}
 
+	if lc.MinScale > lc.MaxScale && lc.MaxScale > 0 {
+		return nil, fmt.Errorf("min-scale (%d) must be less than max-scale (%d)", lc.MinScale, lc.MaxScale)
+	}
+
 	return lc, nil
 }
 
diff --git a/pkg/reconciler/domainmapping/reconciler.go b/pkg/reconciler/domainmapping/reconciler.go
index 67d2971d6..8708358e9 100644
--- a/pkg/reconciler/domainmapping/reconciler.go
+++ b/pkg/reconciler/domainmapping/reconciler.go
@@ -99,7 +99,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, dm *v1alpha1.DomainMappi
 	dm.Status.Address = &duckv1.Addressable{URL: url}
 
 	// IngressClass can be set via annotations or in the config map.
-	ingressClass := dm.Annotations[networking.IngressClassAnnotationKey]
+	ingressClass := networking.GetIngressClass(dm.Annotations)
 	if ingressClass == "" {
 		ingressClass = config.FromContext(ctx).Network.DefaultIngressClass
 	}
@@ -181,7 +181,7 @@ func autoTLSEnabled(ctx context.Context, dm *v1alpha1.DomainMapping) bool {
 	if !config.FromContext(ctx).Network.AutoTLS {
 		return false
 	}
-	annotationValue := dm.Annotations[networking.DisableAutoTLSAnnotationKey]
+	annotationValue := networking.GetDisableAutoTLS(dm.Annotations)
 	disabledByAnnotation, err := strconv.ParseBool(annotationValue)
 	if annotationValue != "" && err != nil {
 		logger := logging.FromContext(ctx)
diff --git a/pkg/reconciler/nscert/nscert.go b/pkg/reconciler/nscert/nscert.go
index e1644deac..6f4d13c7a 100644
--- a/pkg/reconciler/nscert/nscert.go
+++ b/pkg/reconciler/nscert/nscert.go
@@ -56,7 +56,7 @@ var _ namespacereconciler.Interface = (*reconciler)(nil)
 var domainTemplateRegex = regexp.MustCompile(`^\*\..+$`)
 
 func certClass(ctx context.Context, r *corev1.Namespace) string {
-	if class := r.Annotations[networking.CertificateClassAnnotationKey]; class != "" {
+	if class := networking.GetCertificateClass(r.Annotations); class != "" {
 		return class
 	}
 	return config.FromContext(ctx).Network.DefaultCertificateClass
diff --git a/pkg/reconciler/route/resources/ingress.go b/pkg/reconciler/route/resources/ingress.go
index e081b3f69..a17f56a41 100644
--- a/pkg/reconciler/route/resources/ingress.go
+++ b/pkg/reconciler/route/resources/ingress.go
@@ -195,7 +195,7 @@ func makeIngressSpec(
 		}
 	}
 
-	httpOption, err := getHTTPOption(ctx, r.Annotations)
+	httpProtocol, err := getHTTPProtocol(ctx, r.Annotations)
 	if err != nil {
 		return netv1alpha1.IngressSpec{}, err
 	}
@@ -203,20 +203,20 @@ func makeIngressSpec(
 	return netv1alpha1.IngressSpec{
 		Rules:      rules,
 		TLS:        tls,
-		HTTPOption: httpOption,
+		HTTPOption: httpProtocol,
 	}, nil
 }
 
-func getHTTPOption(ctx context.Context, annotations map[string]string) (netv1alpha1.HTTPOption, error) {
-	if len(annotations) != 0 && annotations[networking.HTTPOptionAnnotationKey] != "" {
-		annotation := annotations[networking.HTTPOptionAnnotationKey]
-		switch strings.ToLower(annotation) {
-		case "enabled":
+func getHTTPProtocol(ctx context.Context, annotations map[string]string) (netv1alpha1.HTTPOption, error) {
+	if len(annotations) != 0 && networking.GetHTTPProtocol(annotations) != "" {
+		protocol := strings.ToLower(networking.GetHTTPProtocol(annotations))
+		switch network.HTTPProtocol(protocol) {
+		case network.HTTPEnabled:
 			return netv1alpha1.HTTPOptionEnabled, nil
-		case "redirected":
+		case network.HTTPRedirected:
 			return netv1alpha1.HTTPOptionRedirected, nil
 		default:
-			return "", fmt.Errorf("incorrect HTTPOption annotation:" + annotation)
+			return "", fmt.Errorf("incorrect http-protocol annotation:" + protocol)
 		}
 	}
 
diff --git a/pkg/reconciler/route/route.go b/pkg/reconciler/route/route.go
index f522e5b49..0cfb0816e 100644
--- a/pkg/reconciler/route/route.go
+++ b/pkg/reconciler/route/route.go
@@ -83,14 +83,14 @@ type Reconciler struct {
 var _ routereconciler.Interface = (*Reconciler)(nil)
 
 func ingressClassForRoute(ctx context.Context, r *v1.Route) string {
-	if ingressClass := r.Annotations[networking.IngressClassAnnotationKey]; ingressClass != "" {
+	if ingressClass := networking.GetIngressClass(r.Annotations); ingressClass != "" {
 		return ingressClass
 	}
 	return config.FromContext(ctx).Network.DefaultIngressClass
 }
 
 func certClass(ctx context.Context, r *v1.Route) string {
-	if class := r.Annotations[networking.CertificateClassAnnotationKey]; class != "" {
+	if class := networking.GetCertificateClass(r.Annotations); class != "" {
 		return class
 	}
 	return config.FromContext(ctx).Network.DefaultCertificateClass
@@ -476,7 +476,7 @@ func autoTLSEnabled(ctx context.Context, r *v1.Route) bool {
 	}
 
 	logger := logging.FromContext(ctx)
-	annotationValue := r.Annotations[networking.DisableAutoTLSAnnotationKey]
+	annotationValue := networking.GetDisableAutoTLS(r.Annotations)
 
 	disabledByAnnotation, err := strconv.ParseBool(annotationValue)
 	if annotationValue != "" && err != nil {
diff --git a/support/COMMUNITY_CONTACTS.md b/support/COMMUNITY_CONTACTS.md
index 9c389316c..a98b357a5 100644
--- a/support/COMMUNITY_CONTACTS.md
+++ b/support/COMMUNITY_CONTACTS.md
@@ -68,7 +68,6 @@ rotation, feel free to send a PR to remove yourself.
 - [carlisia](https://github.com/carlisia)
 - [dprotaso](https://github.com/dprotaso)
 - [julz](https://github.com/julz)
-- [markusthoemmes](https://github.com/markusthoemmes)
 - [nader-ziada](https://github.com/nader-ziada)
 - [nak3](https://github.com/nak3)
 - [shinigambit](https://github.com/shinigambit)
diff --git a/support/support.rotation b/support/support.rotation
index e895d0020..a64fce334 100644
--- a/support/support.rotation
+++ b/support/support.rotation
@@ -19,9 +19,9 @@
 2021-12-13T01:00:00Z | julz
 2021-12-20T01:00:00Z | N/A - break
 2021-12-27T01:00:00Z | N/A - break
-2022-01-03T01:00:00Z | markusthoemmes
+2022-01-03T01:00:00Z | TBD
 2022-01-10T01:00:00Z | nader-ziada
 2022-01-11T01:00:00Z | yanweiguo
-2022-01-17T01:00:00Z | nak3s
+2022-01-17T01:00:00Z | nak3
 2022-01-24T01:00:00Z | shinigambit
 2022-02-07T01:00:00Z | ZhiminXiang
diff --git a/vendor/knative.dev/networking/pkg/apis/networking/register.go b/vendor/knative.dev/networking/pkg/apis/networking/register.go
index aac6a5edd..204e72d73 100644
--- a/vendor/knative.dev/networking/pkg/apis/networking/register.go
+++ b/vendor/knative.dev/networking/pkg/apis/networking/register.go
@@ -84,3 +84,19 @@ var (
 	// DefaultRetryCount will be set if Attempts not specified.
 	DefaultRetryCount = 3
 )
+
+func GetIngressClass(annotations map[string]string) (val string) {
+	return annotations[IngressClassAnnotationKey]
+}
+
+func GetCertificateClass(annotations map[string]string) (val string) {
+	return annotations[CertificateClassAnnotationKey]
+}
+
+func GetHTTPProtocol(annotations map[string]string) (val string) {
+	return annotations[HTTPOptionAnnotationKey]
+}
+
+func GetDisableAutoTLS(annotations map[string]string) (val string) {
+	return annotations[DisableAutoTLSAnnotationKey]
+}
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go
index ada0dff3e..68ac8b4cb 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/comment_parser.go
@@ -19,25 +19,41 @@ import "strings"
 
 // Adapted from the k8s.io comment parser https://github.com/kubernetes/gengo/blob/master/types/comments.go
 
+// CommentsTags maps marker prefixes to a set of tags containing keys and values
+type CommentTags map[string]CommentTag
+
+// CommentTags maps keys to a list of values
+type CommentTag map[string][]string
+
 // ExtractCommentTags parses comments for lines of the form:
 //
-//   'marker' + ':' "key=value,key2=value2".
+//   "marker" + "prefix" + ':' + "key=value,key2=value2".
 //
-// Values are optional; empty map is the default.  A tag can be specified more than
+//  In the following example the marker is '+' and the prefix is 'foo':
+//   +foo:key=value1,key2=value2,key=value3
+//
+// Values are optional; empty map is the default. A tag can be specified more than
 // one time and all values are returned.  If the resulting map has an entry for
 // a key, the value (a slice) is guaranteed to have at least 1 element.
 //
 // Example: if you pass "+" for 'marker', and the following lines are in
 // the comments:
-//   +foo:key=value1,key2=value2
+//   +foo:key=value1,key2=value2,key=value3
 //   +bar
 //
 // Then this function will return:
-//   map[string]map[string]string{"foo":{"key":value1","key2":"value2"}, "bar": nil}
+//   map[string]map[string]string{
+//     "foo":{
+//      "key":  []string{"value1", "value3"},
+//      "key2": []string{"value2"}
+//     },
+//     "bar": {},
+//  }
 //
 // Users are not expected to repeat values.
-func ExtractCommentTags(marker string, lines []string) map[string]map[string]string {
-	out := map[string]map[string]string{}
+func ExtractCommentTags(marker string, lines []string) CommentTags {
+	out := CommentTags{}
+
 	for _, line := range lines {
 		line = strings.TrimSpace(line)
 		if len(line) == 0 || !strings.HasPrefix(line, marker) {
@@ -45,29 +61,32 @@ func ExtractCommentTags(marker string, lines []string) map[string]map[string]str
 		}
 
 		options := strings.SplitN(line[len(marker):], ":", 2)
+		prefix := options[0]
+
 		if len(options) == 2 {
 			vals := strings.Split(options[1], ",")
 
-			opts := out[options[0]]
+			opts := out[prefix]
 			if opts == nil {
-				opts = make(map[string]string, len(vals))
+				opts = make(CommentTag, len(vals))
+				out[prefix] = opts
 			}
 
 			for _, pair := range vals {
-				if kv := strings.SplitN(pair, "=", 2); len(kv) == 2 {
-					opts[kv[0]] = kv[1]
-				} else if kv[0] != "" {
-					opts[kv[0]] = ""
+				kv := strings.SplitN(pair, "=", 2)
+				if len(kv) == 1 && kv[0] == "" {
+					continue
+				}
+				if _, ok := opts[kv[0]]; !ok {
+					opts[kv[0]] = []string{}
+				}
+				if len(kv) == 2 {
+					opts[kv[0]] = append(opts[kv[0]], kv[1])
 				}
-			}
-			if len(opts) == 0 {
-				out[options[0]] = nil
-			} else {
-				out[options[0]] = opts
 			}
 		} else if len(options) == 1 && options[0] != "" {
-			if _, has := out[options[0]]; !has {
-				out[options[0]] = nil
+			if _, has := out[prefix]; !has {
+				out[prefix] = CommentTag{}
 			}
 		}
 	}
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go
index 1900802fa..f79339824 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go
@@ -193,29 +193,36 @@ func MustParseClientGenTags(lines []string) Tags {
 	return ret
 }
 
-func extractCommentTags(t *types.Type) map[string]map[string]string {
+func extractCommentTags(t *types.Type) CommentTags {
 	comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
 	return ExtractCommentTags("+", comments)
 }
 
-func extractReconcilerClassTag(tags map[string]map[string]string) (string, bool) {
+func extractReconcilerClassesTag(tags CommentTags) ([]string, bool) {
 	vals, ok := tags["genreconciler"]
 	if !ok {
-		return "", false
+		return nil, false
 	}
-	classname, has := vals["class"]
-	return classname, has
+	classnames, has := vals["class"]
+	if has && len(classnames) == 0 {
+		return nil, false
+	}
+	return classnames, has
 }
 
-func isKRShaped(tags map[string]map[string]string) bool {
+func isKRShaped(tags CommentTags) bool {
 	vals, has := tags["genreconciler"]
 	if !has {
 		return false
 	}
-	return vals["krshapedlogic"] != "false"
+	stringVals, has := vals["krshapedlogic"]
+	if !has || len(vals) == 0 {
+		return true // Default is true
+	}
+	return stringVals[0] != "false"
 }
 
-func isNonNamespaced(tags map[string]map[string]string) bool {
+func isNonNamespaced(tags CommentTags) bool {
 	vals, has := tags["genclient"]
 	if !has {
 		return false
@@ -224,7 +231,7 @@ func isNonNamespaced(tags map[string]map[string]string) bool {
 	return has
 }
 
-func stubs(tags map[string]map[string]string) bool {
+func stubs(tags CommentTags) bool {
 	vals, has := tags["genreconciler"]
 	if !has {
 		return false
@@ -545,7 +552,7 @@ func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentyp
 		// Fix for golang iterator bug.
 		t := t
 		extracted := extractCommentTags(t)
-		reconcilerClass, hasReconcilerClass := extractReconcilerClassTag(extracted)
+		reconcilerClasses, hasReconcilerClass := extractReconcilerClassesTag(extracted)
 		nonNamespaced := isNonNamespaced(extracted)
 		isKRShaped := isKRShaped(extracted)
 		stubs := stubs(extracted)
@@ -573,7 +580,7 @@ func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentyp
 					clientPkg:           clientPackagePath,
 					informerPackagePath: informerPackagePath,
 					schemePkg:           filepath.Join(customArgs.VersionedClientSetPackage, "scheme"),
-					reconcilerClass:     reconcilerClass,
+					reconcilerClasses:   reconcilerClasses,
 					hasReconcilerClass:  hasReconcilerClass,
 					hasStatus:           hasStatus(t),
 				})
@@ -602,7 +609,7 @@ func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentyp
 						outputPackage:       filepath.Join(packagePath, "stub"),
 						imports:             generator.NewImportTracker(),
 						informerPackagePath: informerPackagePath,
-						reconcilerClass:     reconcilerClass,
+						reconcilerClasses:   reconcilerClasses,
 						hasReconcilerClass:  hasReconcilerClass,
 					})
 					return generators
@@ -633,7 +640,7 @@ func reconcilerPackages(basePackage string, groupPkgName string, gv clientgentyp
 					listerPkg:          listerPackagePath,
 					groupGoName:        groupGoName,
 					groupVersion:       gv,
-					reconcilerClass:    reconcilerClass,
+					reconcilerClasses:  reconcilerClasses,
 					hasReconcilerClass: hasReconcilerClass,
 					nonNamespaced:      nonNamespaced,
 					isKRShaped:         isKRShaped,
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go
index a624275a5..63556dec6 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller.go
@@ -38,7 +38,7 @@ type reconcilerControllerGenerator struct {
 	schemePkg           string
 	informerPackagePath string
 
-	reconcilerClass    string
+	reconcilerClasses  []string
 	hasReconcilerClass bool
 	hasStatus          bool
 }
@@ -69,7 +69,7 @@ func (g *reconcilerControllerGenerator) GenerateType(c *generator.Context, t *ty
 	m := map[string]interface{}{
 		"type":      t,
 		"group":     g.groupName,
-		"class":     g.reconcilerClass,
+		"classes":   g.reconcilerClasses,
 		"hasClass":  g.hasReconcilerClass,
 		"hasStatus": g.hasStatus,
 		"controllerImpl": c.Universe.Type(types.Name{
@@ -195,12 +195,24 @@ var reconcilerControllerNewImpl = `
 const (
 	defaultControllerAgentName = "{{.type|lowercaseSingular}}-controller"
 	defaultFinalizerName       = "{{.type|allLowercasePlural}}.{{.group}}"
-	{{if .hasClass}}
+	{{if .hasClass }}
 	// ClassAnnotationKey points to the annotation for the class of this resource.
-	ClassAnnotationKey = "{{ .class }}"
+	{{if gt (.classes | len) 1 }}// Deprecated: Use ClassAnnotationKeys given multiple keys exist
+	{{end -}}
+	ClassAnnotationKey = "{{ index .classes 0 }}"
 	{{end}}
 )
 
+{{if gt (.classes | len) 1 }}
+var (
+	// ClassAnnotationKeys points to the annotation for the class of this resource.
+	ClassAnnotationKeys = []string{
+		{{range $class := .classes}}"{{$class}}",
+		{{end}}
+	}
+)
+{{end}}
+
 // NewImpl returns a {{.controllerImpl|raw}} that handles queuing and feeding work from
 // the queue through an implementation of {{.controllerReconciler|raw}}, delegating to
 // the provided Interface and optional Finalizer methods. OptionsFn is used to return
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go
index 37db246c3..13dff4d51 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_controller_stub.go
@@ -35,7 +35,7 @@ type reconcilerControllerStubGenerator struct {
 
 	reconcilerPkg       string
 	informerPackagePath string
-	reconcilerClass     string
+	reconcilerClasses   []string
 	hasReconcilerClass  bool
 }
 
@@ -64,7 +64,7 @@ func (g *reconcilerControllerStubGenerator) GenerateType(c *generator.Context, t
 
 	m := map[string]interface{}{
 		"type":     t,
-		"class":    g.reconcilerClass,
+		"classes":  g.reconcilerClasses,
 		"hasClass": g.hasReconcilerClass,
 		"informerGet": c.Universe.Function(types.Name{
 			Package: g.informerPackagePath,
@@ -91,10 +91,18 @@ func (g *reconcilerControllerStubGenerator) GenerateType(c *generator.Context, t
 			Package: g.reconcilerPkg,
 			Name:    "ClassAnnotationKey",
 		}),
+		"classAnnotationKeys": c.Universe.Variable(types.Name{
+			Package: g.reconcilerPkg,
+			Name:    "ClassAnnotationKeys",
+		}),
 		"annotationFilterFunc": c.Universe.Function(types.Name{
 			Package: "knative.dev/pkg/reconciler",
 			Name:    "AnnotationFilterFunc",
 		}),
+		"orFilterFunc": c.Universe.Function(types.Name{
+			Package: "knative.dev/pkg/reconciler",
+			Name:    "Or",
+		}),
 		"filterHandler": c.Universe.Type(types.Name{
 			Package: "k8s.io/client-go/tools/cache",
 			Name:    "FilteringResourceEventHandler",
@@ -120,7 +128,17 @@ func NewController(
 
 	{{if .hasClass}}
 	classValue := "default" // TODO: update this to the appropriate value.
+	{{if len .classes | eq 1 }}
 	classFilter := {{.annotationFilterFunc|raw}}({{.classAnnotationKey|raw}}, classValue, false /*allowUnset*/)
+	{{else if gt (len .classes) 1 }}
+	filterFuncs := make([]func(interface{}) bool, 0, len({{.classAnnotationKeys|raw}}))
+
+	for _, key := range {{.classAnnotationKeys|raw}} {
+		filterFuncs = append(filterFuncs, {{.annotationFilterFunc|raw}}(key, classValue, false /*allowUnset*/))
+	}
+
+	classFilter := {{.orFilterFunc|raw}}(filterFuncs...)
+	{{end}}
 	{{end}}
 
 	// TODO: setup additional informers here.
diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go
index e787096b3..5e3f23faf 100644
--- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go
+++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go
@@ -37,7 +37,7 @@ type reconcilerReconcilerGenerator struct {
 	listerName     string
 	listerPkg      string
 
-	reconcilerClass    string
+	reconcilerClasses  []string
 	hasReconcilerClass bool
 	nonNamespaced      bool
 	isKRShaped         bool
@@ -74,7 +74,7 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty
 		"type":          t,
 		"group":         namer.IC(g.groupGoName),
 		"version":       namer.IC(g.groupVersion.Version.String()),
-		"class":         g.reconcilerClass,
+		"classes":       g.reconcilerClasses,
 		"hasClass":      g.hasReconcilerClass,
 		"isKRShaped":    g.isKRShaped,
 		"hasStatus":     g.hasStatus,
@@ -219,6 +219,9 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty
 	sw.Do(reconcilerInterfaceFactory, m)
 	sw.Do(reconcilerNewReconciler, m)
 	sw.Do(reconcilerImplFactory, m)
+	if len(g.reconcilerClasses) > 1 {
+		sw.Do(reconcilerLookupClass, m)
+	}
 	if g.hasStatus {
 		sw.Do(reconcilerStatusFactory, m)
 	}
@@ -227,6 +230,17 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty
 	return sw.Error()
 }
 
+var reconcilerLookupClass = `
+func lookupClass(annotations map[string]string) (string, bool) {
+	for _, key := range ClassAnnotationKeys {
+		 if val, ok := annotations[key]; ok {
+		   return val, true
+		 }
+	}
+	return "", false
+}
+`
+
 var reconcilerInterfaceFactory = `
 // Interface defines the strongly typed interfaces to be implemented by a
 // controller reconciling {{.type|raw}}.
@@ -293,8 +307,15 @@ type reconcilerImpl struct {
 	skipStatusUpdates bool
 	{{end}}
 
-	{{if .hasClass}}
-	// classValue is the resource annotation[{{ .class }}] instance value this reconciler instance filters on.
+	{{if len .classes | eq 1 }}
+	// classValue is the resource annotation[{{ index .classes 0 }}] instance value this reconciler instance filters on.
+	classValue string
+	{{else if gt (len .classes) 1 }}
+	// classValue is the resource annotation instance value this reconciler instance filters on.
+	// The annotations key are:
+	{{- range $class := .classes}}
+	//   {{$class}}
+	{{- end}}
 	classValue string
 	{{end}}
 }
@@ -416,14 +437,22 @@ func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) erro
 	} else if err != nil {
 		return err
 	}
-	{{if .hasClass}}
+
+{{if len .classes | eq 1 }}
 	if classValue, found := original.GetAnnotations()[ClassAnnotationKey]; !found || classValue != r.classValue {
 		logger.Debugw("Skip reconciling resource, class annotation value does not match reconciler instance value.",
 			zap.String("classKey", ClassAnnotationKey),
 			zap.String("issue", classValue+"!="+r.classValue))
 		return nil
 	}
-	{{end}}
+{{else if gt (len .classes) 1 }}
+	if classValue, found := lookupClass(original.GetAnnotations()); !found || classValue != r.classValue {
+		logger.Debugw("Skip reconciling resource, class annotation value does not match reconciler instance value.",
+			zap.Strings("classKeys", ClassAnnotationKeys),
+			zap.String("issue", classValue+"!="+r.classValue))
+		return nil
+	}
+{{end}}
 
 	// Don't modify the informers copy.
 	resource := original.DeepCopy()
diff --git a/vendor/knative.dev/pkg/reconciler/filter.go b/vendor/knative.dev/pkg/reconciler/filter.go
index 36c86c4d3..9f7d2fa36 100644
--- a/vendor/knative.dev/pkg/reconciler/filter.go
+++ b/vendor/knative.dev/pkg/reconciler/filter.go
@@ -77,6 +77,18 @@ func Not(f func(interface{}) bool) func(interface{}) bool {
 	}
 }
 
+// Or creates a FilterFunc which performs an OR of the passed in FilterFuncs
+func Or(funcs ...func(interface{}) bool) func(interface{}) bool {
+	return func(obj interface{}) bool {
+		for _, f := range funcs {
+			if f(obj) {
+				return true
+			}
+		}
+		return false
+	}
+}
+
 // ChainFilterFuncs creates a FilterFunc which performs an AND of the passed FilterFuncs.
 func ChainFilterFuncs(funcs ...func(interface{}) bool) func(interface{}) bool {
 	return func(obj interface{}) bool {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4867e872a..f81d98baa 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -991,7 +991,7 @@ k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/caching v0.0.0-20211117091234-89a3cb9bc119
+# knative.dev/caching v0.0.0-20211117134235-da260af2ab4d
 ## explicit
 knative.dev/caching/config
 knative.dev/caching/pkg/apis/caching
@@ -1012,11 +1012,11 @@ knative.dev/caching/pkg/client/injection/informers/caching/v1alpha1/image/fake
 knative.dev/caching/pkg/client/injection/informers/factory
 knative.dev/caching/pkg/client/injection/informers/factory/fake
 knative.dev/caching/pkg/client/listers/caching/v1alpha1
-# knative.dev/hack v0.0.0-20211112192837-128cf0150a69
+# knative.dev/hack v0.0.0-20211117134436-69a2295d54ce
 ## explicit
 knative.dev/hack
 knative.dev/hack/shell
-# knative.dev/networking v0.0.0-20211117091734-66e47364eb5c
+# knative.dev/networking v0.0.0-20211117141434-4d634effa7b7
 ## explicit
 knative.dev/networking/config
 knative.dev/networking/pkg
@@ -1046,7 +1046,7 @@ knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serve
 knative.dev/networking/pkg/client/listers/networking/v1alpha1
 knative.dev/networking/pkg/ingress
 knative.dev/networking/pkg/prober
-# knative.dev/pkg v0.0.0-20211117100634-54071addcdb8
+# knative.dev/pkg v0.0.0-20211117215328-5708c4c44232
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate


Test patch:
diff --git a/pkg/apis/autoscaling/v1alpha1/pa_lifecycle_test.go b/pkg/apis/autoscaling/v1alpha1/pa_lifecycle_test.go
index 50a4c452a..6ef7b3b1c 100644
--- a/pkg/apis/autoscaling/v1alpha1/pa_lifecycle_test.go
+++ b/pkg/apis/autoscaling/v1alpha1/pa_lifecycle_test.go
@@ -596,6 +596,13 @@ func TestScaleBounds(t *testing.T) {
 		max:     "sandwich",
 		wantMin: 0,
 		wantMax: 0,
+	}, {
+		name: "min-scale set but unreachable",
+		config: autoscalerconfig.Config{
+			MinScale: 2,
+		},
+		reachability: ReachabilityUnreachable,
+		wantMin:      0,
 	}}
 
 	for _, tc := range cases {
diff --git a/pkg/autoscaler/config/config_test.go b/pkg/autoscaler/config/config_test.go
index 871ecb3a2..831950cb0 100644
--- a/pkg/autoscaler/config/config_test.go
+++ b/pkg/autoscaler/config/config_test.go
@@ -133,10 +133,14 @@ func TestNewConfig(t *testing.T) {
 		name: "with toggles explicitly flipped",
 		input: map[string]string{
 			"enable-scale-to-zero": "false",
+			"min-scale":            "1",
+			"max-scale":            "2",
 		},
 		want: func() *autoscalerconfig.Config {
 			c := defaultConfig()
 			c.EnableScaleToZero = false
+			c.MinScale = 1
+			c.MaxScale = 2
 			return c
 		}(),
 	}, {
@@ -144,11 +148,15 @@ func TestNewConfig(t *testing.T) {
 		input: map[string]string{
 			"enable-scale-to-zero":       "false",
 			"scale-to-zero-grace-period": "33s",
+			"min-scale":                  "1",
+			"max-scale":                  "2",
 		},
 		want: func() *autoscalerconfig.Config {
 			c := defaultConfig()
 			c.EnableScaleToZero = false
 			c.ScaleToZeroGracePeriod = 33 * time.Second
+			c.MinScale = 1
+			c.MaxScale = 2
 			return c
 		}(),
 	}, {
@@ -350,6 +358,23 @@ func TestNewConfig(t *testing.T) {
 			"max-scale-limit": "11",
 		},
 		wantErr: true,
+	}, {
+		name: "with max scale less than min-scale",
+		input: map[string]string{
+			"min-scale": "4",
+			"max-scale": "3",
+		},
+		wantErr: true,
+	}, {
+		name: "with min scale set but max-scale not set",
+		input: map[string]string{
+			"min-scale": "4",
+		},
+		want: func() *autoscalerconfig.Config {
+			c := defaultConfig()
+			c.MinScale = 4
+			return c
+		}(),
 	}, {
 		name: "with valid default max scale and max scale limit",
 		input: map[string]string{
diff --git a/pkg/reconciler/autoscaling/kpa/kpa_test.go b/pkg/reconciler/autoscaling/kpa/kpa_test.go
index 0cf6890e5..e0e088700 100644
--- a/pkg/reconciler/autoscaling/kpa/kpa_test.go
+++ b/pkg/reconciler/autoscaling/kpa/kpa_test.go
@@ -111,6 +111,7 @@ func defaultConfigMapData() map[string]string {
 		"panic-window":                            "10s",
 		"scale-to-zero-grace-period":              gracePeriod.String(),
 		"tick-interval":                           "2s",
+		"min-scale":                               "0",
 	}
 }
 
@@ -118,6 +119,7 @@ func initialScaleZeroASConfig() *autoscalerconfig.Config {
 	ac, _ := asconfig.NewConfigFromMap(defaultConfigMapData())
 	ac.AllowZeroInitialScale = true
 	ac.InitialScale = 0
+	ac.MinScale = 0
 	ac.EnableScaleToZero = true
 	return ac
 }
diff --git a/pkg/reconciler/route/reconcile_resources_test.go b/pkg/reconciler/route/reconcile_resources_test.go
index 521df64ee..7e8335bfb 100644
--- a/pkg/reconciler/route/reconcile_resources_test.go
+++ b/pkg/reconciler/route/reconcile_resources_test.go
@@ -608,7 +608,7 @@ func TestReconcileIngressClassAnnotation(t *testing.T) {
 	}
 
 	updated = getRouteIngressFromClient(ctx, t, r)
-	updatedClass := updated.Annotations[networking.IngressClassAnnotationKey]
+	updatedClass := networking.GetIngressClass(updated.Annotations)
 	if expClass != updatedClass {
 		t.Errorf("Unexpected annotation got %q want %q", expClass, updatedClass)
 	}
diff --git a/test/config/ytt/ingress/ambassador/ambassador-ingress-class.yaml b/test/config/ytt/ingress/ambassador/ambassador-ingress-class.yaml
deleted file mode 100644
index 7544ae23e..000000000
--- a/test/config/ytt/ingress/ambassador/ambassador-ingress-class.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-#@ load("@ytt:overlay", "overlay")
-
-#@data/values
----
-serving:
-  ingress_class: ambassador.ingress.networking.knative.dev
diff --git a/test/config/ytt/ingress/ambassador/ambassador-replicas.yaml b/test/config/ytt/ingress/ambassador/ambassador-replicas.yaml
deleted file mode 100644
index c28335313..000000000
--- a/test/config/ytt/ingress/ambassador/ambassador-replicas.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-#@ load("@ytt:overlay", "overlay")
-#@ load("helpers.lib.yaml", "subset")
-
-#@overlay/match by=subset(kind="Deployment", name="ambassador")
----
-spec:
-  #@overlay/match missing_ok=True
-  replicas: 6
diff --git a/test/config/ytt/ingress/kong/kong-ingress-class.yaml b/test/config/ytt/ingress/kong/kong-ingress-class.yaml
deleted file mode 100644
index c69698874..000000000
--- a/test/config/ytt/ingress/kong/kong-ingress-class.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-#@ load("@ytt:overlay", "overlay")
-
-#@data/values
----
-serving:
-  ingress_class: kong
diff --git a/test/config/ytt/ingress/kong/kong-replicas.yaml b/test/config/ytt/ingress/kong/kong-replicas.yaml
deleted file mode 100644
index 22e5df51b..000000000
--- a/test/config/ytt/ingress/kong/kong-replicas.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-#@ load("@ytt:overlay", "overlay")
-#@ load("helpers.lib.yaml", "subset")
-
-#@overlay/match by=subset(kind="Deployment", name="ingress-kong")
----
-spec:
-  #@overlay/match missing_ok=True
-  replicas: 6
diff --git a/test/config/ytt/kind/ingress/ambassador-kind.yaml b/test/config/ytt/kind/ingress/ambassador-kind.yaml
deleted file mode 100644
index 501ef81f1..000000000
--- a/test/config/ytt/kind/ingress/ambassador-kind.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-#@ load("@ytt:overlay", "overlay")
-#@ load("helpers.lib.yaml", "subset")
-
-#@overlay/match by=subset(kind="Deployment", name="ambassador")
----
-spec:
-  #@overlay/match missing_ok=True
-  replicas: 1
diff --git a/test/config/ytt/kind/ingress/kong-kind.yaml b/test/config/ytt/kind/ingress/kong-kind.yaml
deleted file mode 100644
index 03c2b1717..000000000
--- a/test/config/ytt/kind/ingress/kong-kind.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-#@ load("@ytt:overlay", "overlay")
-#@ load("helpers.lib.yaml", "subset")
-
-#@overlay/match by=subset(kind="Deployment", name="ingress-kong")
----
-spec:
-  #@overlay/match missing_ok=True
-  replicas: 1
diff --git a/test/e2e-common.sh b/test/e2e-common.sh
index 7f564936c..f872e5038 100644
--- a/test/e2e-common.sh
+++ b/test/e2e-common.sh
@@ -24,7 +24,6 @@ export CERT_MANAGER_VERSION="latest"
 export INGRESS_CLASS=${INGRESS_CLASS:-istio.ingress.networking.knative.dev}
 export ISTIO_VERSION="latest"
 export KOURIER_VERSION=""
-export AMBASSADOR_VERSION=""
 export CONTOUR_VERSION=""
 export CERTIFICATE_CLASS=""
 # Only build linux/amd64 bit images
@@ -143,13 +142,6 @@ function parse_flags() {
       readonly INGRESS_CLASS="kourier.ingress.networking.knative.dev"
       return 2
       ;;
-    --ambassador-version)
-      # currently, the value of --ambassador-version is ignored
-      # latest version of Ambassador pinned in third_party will be installed
-      readonly AMBASSADOR_VERSION=$2
-      readonly INGRESS_CLASS="ambassador.ingress.networking.knative.dev"
-      return 2
-      ;;
     --contour-version)
       # currently, the value of --contour-version is ignored
       # latest version of Contour pinned in third_party will be installed
@@ -157,13 +149,6 @@ function parse_flags() {
       readonly INGRESS_CLASS="contour.ingress.networking.knative.dev"
       return 2
       ;;
-    --kong-version)
-      # currently, the value of --kong-version is ignored
-      # latest version of Kong pinned in third_party will be installed
-      readonly KONG_VERSION=$2
-      readonly INGRESS_CLASS="kong"
-      return 2
-      ;;
     --system-namespace)
       [[ -z "$2" ]] || [[ $2 = --* ]] && fail_test "Missing argument to --system-namespace"
       export SYSTEM_NAMESPACE=$2
diff --git a/test/e2e-networking-library.sh b/test/e2e-networking-library.sh
index b0fc6efd6..35e0ecaca 100644
--- a/test/e2e-networking-library.sh
+++ b/test/e2e-networking-library.sh
@@ -101,17 +101,9 @@ function setup_ingress_env_vars() {
     export GATEWAY_OVERRIDE=kourier
     export GATEWAY_NAMESPACE_OVERRIDE=kourier-system
   fi
-  if is_ingress_class ambassador; then
-    export GATEWAY_OVERRIDE=ambassador
-    export GATEWAY_NAMESPACE_OVERRIDE=ambassador
-  fi
   if is_ingress_class contour; then
     export GATEWAY_OVERRIDE=envoy
     export GATEWAY_NAMESPACE_OVERRIDE=contour-external
   fi
-  if is_ingress_class kong; then
-    export GATEWAY_OVERRIDE=kong-proxy
-    export GATEWAY_NAMESPACE_OVERRIDE=kong
-  fi
 }
 
diff --git a/third_party/ambassador-latest/README.md b/third_party/ambassador-latest/README.md
deleted file mode 100644
index 231d690d7..000000000
--- a/third_party/ambassador-latest/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-### Ambassador
-
-`ambassador-rbac.yaml` and `ambassador-service.yaml` are required to install
-Ambassador. These need to be updated every time Ambassador's version is bumped.
-Detailed instructions on installing Ambassador are available
-[here](https://www.getambassador.io/user-guide/getting-started/).
-
-These files are hosted at:
-
-- https://www.getambassador.io/yaml/ambassador/ambassador-crds.yaml
-- https://www.getambassador.io/yaml/ambassador/ambassador-rbac.yaml
-
-After updating the files, make sure any other modifications required to run
-Knative with Ambassador are made as well. For instance:
-
-- Set the environment variable `AMBASSADOR_KNATIVE_SUPPORT` to `true` in the
-  deployment `ambassador`.
-- Update the namespace in the ClusterRoleBinding `ambassador` to `ambassador`.
-  It should look like:
-
-```yaml
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: ambassador
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: ambassador
-subjects:
-  - kind: ServiceAccount
-    name: ambassador
-    namespace: ambassador
-```
-
-Make sure the modifications are done as per the
-[installation documentation](https://knative.dev/docs/install/).
diff --git a/third_party/ambassador-latest/ambassador-crds.yaml b/third_party/ambassador-latest/ambassador-crds.yaml
deleted file mode 100644
index ee1df7316..000000000
--- a/third_party/ambassador-latest/ambassador-crds.yaml
+++ /dev/null
@@ -1,293 +0,0 @@
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: authservices.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: AuthService
-    plural: authservices
-    singular: authservice
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: consulresolvers.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: ConsulResolver
-    plural: consulresolvers
-    singular: consulresolver
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: hosts.getambassador.io
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .spec.hostname
-    name: Hostname
-    type: string
-  - JSONPath: .status.state
-    name: State
-    type: string
-  - JSONPath: .status.phaseCompleted
-    name: Phase Completed
-    type: string
-  - JSONPath: .status.phasePending
-    name: Phase Pending
-    type: string
-  - JSONPath: .metadata.creationTimestamp
-    name: Age
-    type: date
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: Host
-    plural: hosts
-    singular: host
-  scope: Namespaced
-  subresources:
-    status: {}
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kubernetesendpointresolvers.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: KubernetesEndpointResolver
-    plural: kubernetesendpointresolvers
-    singular: kubernetesendpointresolver
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kubernetesserviceresolvers.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: KubernetesServiceResolver
-    plural: kubernetesserviceresolvers
-    singular: kubernetesserviceresolver
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: logservices.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: LogService
-    plural: logservices
-    singular: logservice
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: mappings.getambassador.io
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .spec.prefix
-    name: Prefix
-    type: string
-  - JSONPath: .spec.service
-    name: Service
-    type: string
-  - JSONPath: .status.state
-    name: State
-    type: string
-  - JSONPath: .status.reason
-    name: Reason
-    type: string
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: Mapping
-    plural: mappings
-    singular: mapping
-  scope: Namespaced
-  subresources:
-    status: {}
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: modules.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: Module
-    plural: modules
-    singular: module
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: ratelimitservices.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: RateLimitService
-    plural: ratelimitservices
-    singular: ratelimitservice
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tcpmappings.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: TCPMapping
-    plural: tcpmappings
-    singular: tcpmapping
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tlscontexts.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: TLSContext
-    plural: tlscontexts
-    singular: tlscontext
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tracingservices.getambassador.io
-spec:
-  group: getambassador.io
-  names:
-    categories:
-    - ambassador-crds
-    kind: TracingService
-    plural: tracingservices
-    singular: tracingservice
-  scope: Namespaced
-  version: v2
-  versions:
-  - name: v2
-    served: true
-    storage: true
-  - name: v1
-    served: true
-    storage: false
diff --git a/third_party/ambassador-latest/ambassador-namespace.yaml b/third_party/ambassador-latest/ambassador-namespace.yaml
deleted file mode 100644
index ece11b279..000000000
--- a/third_party/ambassador-latest/ambassador-namespace.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-apiVersion: v1
-kind: Namespace
-metadata:
-  name: ambassador
diff --git a/third_party/ambassador-latest/ambassador-rbac.yaml b/third_party/ambassador-latest/ambassador-rbac.yaml
deleted file mode 100644
index 8f112fc7e..000000000
--- a/third_party/ambassador-latest/ambassador-rbac.yaml
+++ /dev/null
@@ -1,145 +0,0 @@
----
-apiVersion: v1
-kind: Service
-metadata:
-  labels:
-    service: ambassador-admin
-    app.kubernetes.io/managed-by: getambassador.io
-  name: ambassador-admin
-  namespace: ambassador
-spec:
-  type: NodePort
-  ports:
-  - name: ambassador-admin
-    port: 8877
-    targetPort: 8877
-  selector:
-    service: ambassador
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRole
-metadata:
-  name: ambassador
-rules:
-- apiGroups: [""]
-  resources: [ "endpoints", "namespaces", "secrets", "services" ]
-  verbs: ["get", "list", "watch"]
-- apiGroups: [ "getambassador.io" ]
-  resources: [ "*" ]
-  verbs: ["get", "list", "watch"]
-- apiGroups: [ "getambassador.io" ]
-  resources: [ "mappings/status" ]
-  verbs: ["update"]
-- apiGroups: [ "apiextensions.k8s.io" ]
-  resources: [ "customresourcedefinitions" ]
-  verbs: ["get", "list", "watch"]
-- apiGroups: [ "networking.internal.knative.dev" ]
-  resources: [ "clusteringresses", "ingresses" ]
-  verbs: ["get", "list", "watch"]
-- apiGroups: [ "networking.internal.knative.dev" ]
-  resources: [ "ingresses/status", "clusteringresses/status" ]
-  verbs: ["update"]
-- apiGroups: [ "extensions", "networking.k8s.io" ]
-  resources: [ "ingresses", "ingressclasses" ]
-  verbs: ["get", "list", "watch"]
-- apiGroups: [ "extensions", "networking.k8s.io" ]
-  resources: [ "ingresses/status" ]
-  verbs: ["update"]
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: ambassador
-  namespace: ambassador
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: ambassador
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: ambassador
-subjects:
-- kind: ServiceAccount
-  name: ambassador
-  namespace: ambassador
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: ambassador
-  namespace: ambassador
-spec:
-  replicas: 3
-  selector:
-    matchLabels:
-      service: ambassador
-  template:
-    metadata:
-      annotations:
-        consul.hashicorp.com/connect-inject: 'false'
-        sidecar.istio.io/inject: 'false'
-      labels:
-        service: ambassador
-        app.kubernetes.io/managed-by: getambassador.io
-    spec:
-      affinity:
-        podAntiAffinity:
-          preferredDuringSchedulingIgnoredDuringExecution:
-          - podAffinityTerm:
-              labelSelector:
-                matchLabels:
-                  service: ambassador
-              topologyKey: kubernetes.io/hostname
-            weight: 100
-      containers:
-      - env:
-        - name: AMBASSADOR_KNATIVE_SUPPORT
-          value: "true"
-        - name: AMBASSADOR_NAMESPACE
-          valueFrom:
-            fieldRef:
-              fieldPath: metadata.namespace
-        image: quay.io/datawire/ambassador:1.4.2
-        livenessProbe:
-          httpGet:
-            path: /ambassador/v0/check_alive
-            port: 8877
-          initialDelaySeconds: 30
-          periodSeconds: 3
-        name: ambassador
-        ports:
-        - containerPort: 8080
-          name: http
-        - containerPort: 8443
-          name: https
-        - containerPort: 8877
-          name: admin
-        readinessProbe:
-          httpGet:
-            path: /ambassador/v0/check_ready
-            port: 8877
-          initialDelaySeconds: 30
-          periodSeconds: 3
-        resources:
-          limits:
-            cpu: 1
-            memory: 400Mi
-          requests:
-            cpu: 200m
-            memory: 100Mi
-        volumeMounts:
-        - mountPath: /tmp/ambassador-pod-info
-          name: ambassador-pod-info
-      restartPolicy: Always
-      securityContext:
-        runAsUser: 8888
-      serviceAccountName: ambassador
-      volumes:
-      - downwardAPI:
-          items:
-          - fieldRef:
-              fieldPath: metadata.labels
-            path: labels
-        name: ambassador-pod-info
diff --git a/third_party/ambassador-latest/ambassador-service.yaml b/third_party/ambassador-latest/ambassador-service.yaml
deleted file mode 100644
index 21550677e..000000000
--- a/third_party/ambassador-latest/ambassador-service.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: ambassador
-  namespace: ambassador
-  labels:
-    app.kubernetes.io/component: ambassador-service
-spec:
-  type: LoadBalancer
-  externalTrafficPolicy: Local
-  ports:
-   - port: 80
-     targetPort: 8080
-     name: http
-   - port: 443
-     targetPort: 8443
-     name: https
-  selector:
-    service: ambassador
diff --git a/third_party/kong-latest/README.md b/third_party/kong-latest/README.md
deleted file mode 100644
index d2852885e..000000000
--- a/third_party/kong-latest/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-The kong.yaml file is generated by running
-
-```
-./download-kong.sh
-```
diff --git a/third_party/kong-latest/download-kong.sh b/third_party/kong-latest/download-kong.sh
deleted file mode 100755
index 42e685f37..000000000
--- a/third_party/kong-latest/download-kong.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2019 The Knative 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.
-
-set -ex
-
-# Download Kong
-KONG_VERSION=0.9.x
-KONG_YAML=all-in-one-dbless.yaml
-DOWNLOAD_URL=https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/${KONG_VERSION}/deploy/single/${KONG_YAML}
-
-wget -O kong.yaml ${DOWNLOAD_URL}
diff --git a/third_party/kong-latest/kong.yaml b/third_party/kong-latest/kong.yaml
deleted file mode 100644
index ab54e2e3c..000000000
--- a/third_party/kong-latest/kong.yaml
+++ /dev/null
@@ -1,750 +0,0 @@
-apiVersion: v1
-kind: Namespace
-metadata:
-  name: kong
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kongclusterplugins.configuration.konghq.com
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .plugin
-    description: Name of the plugin
-    name: Plugin-Type
-    type: string
-  - JSONPath: .metadata.creationTimestamp
-    description: Age
-    name: Age
-    type: date
-  - JSONPath: .disabled
-    description: Indicates if the plugin is disabled
-    name: Disabled
-    priority: 1
-    type: boolean
-  - JSONPath: .config
-    description: Configuration of the plugin
-    name: Config
-    priority: 1
-    type: string
-  group: configuration.konghq.com
-  names:
-    kind: KongClusterPlugin
-    plural: kongclusterplugins
-    shortNames:
-    - kcp
-  scope: Cluster
-  validation:
-    openAPIV3Schema:
-      properties:
-        config:
-          type: object
-        configFrom:
-          properties:
-            secretKeyRef:
-              properties:
-                key:
-                  type: string
-                name:
-                  type: string
-                namespace:
-                  type: string
-              required:
-              - name
-              - namespace
-              - key
-              type: object
-          type: object
-        disabled:
-          type: boolean
-        plugin:
-          type: string
-        protocols:
-          items:
-            enum:
-            - http
-            - https
-            - grpc
-            - grpcs
-            - tcp
-            - tls
-            type: string
-          type: array
-        run_on:
-          enum:
-          - first
-          - second
-          - all
-          type: string
-      required:
-      - plugin
-  version: v1
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kongconsumers.configuration.konghq.com
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .username
-    description: Username of a Kong Consumer
-    name: Username
-    type: string
-  - JSONPath: .metadata.creationTimestamp
-    description: Age
-    name: Age
-    type: date
-  group: configuration.konghq.com
-  names:
-    kind: KongConsumer
-    plural: kongconsumers
-    shortNames:
-    - kc
-  scope: Namespaced
-  validation:
-    openAPIV3Schema:
-      properties:
-        credentials:
-          items:
-            type: string
-          type: array
-        custom_id:
-          type: string
-        username:
-          type: string
-  version: v1
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kongcredentials.configuration.konghq.com
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .type
-    description: Type of credential
-    name: Credential-type
-    type: string
-  - JSONPath: .metadata.creationTimestamp
-    description: Age
-    name: Age
-    type: date
-  - JSONPath: .consumerRef
-    description: Owner of the credential
-    name: Consumer-Ref
-    type: string
-  group: configuration.konghq.com
-  names:
-    kind: KongCredential
-    plural: kongcredentials
-  scope: Namespaced
-  validation:
-    openAPIV3Schema:
-      properties:
-        consumerRef:
-          type: string
-        type:
-          type: string
-      required:
-      - consumerRef
-      - type
-  version: v1
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kongingresses.configuration.konghq.com
-spec:
-  group: configuration.konghq.com
-  names:
-    kind: KongIngress
-    plural: kongingresses
-    shortNames:
-    - ki
-  scope: Namespaced
-  validation:
-    openAPIV3Schema:
-      properties:
-        proxy:
-          properties:
-            connect_timeout:
-              minimum: 0
-              type: integer
-            path:
-              pattern: ^/.*$
-              type: string
-            protocol:
-              enum:
-              - http
-              - https
-              - grpc
-              - grpcs
-              - tcp
-              - tls
-              type: string
-            read_timeout:
-              minimum: 0
-              type: integer
-            retries:
-              minimum: 0
-              type: integer
-            write_timeout:
-              minimum: 0
-              type: integer
-          type: object
-        route:
-          properties:
-            headers:
-              additionalProperties:
-                items:
-                  type: string
-                type: array
-              type: object
-            https_redirect_status_code:
-              type: integer
-            methods:
-              items:
-                type: string
-              type: array
-            path_handling:
-              enum:
-              - v0
-              - v1
-              type: string
-            preserve_host:
-              type: boolean
-            protocols:
-              items:
-                enum:
-                - http
-                - https
-                - grpc
-                - grpcs
-                - tcp
-                - tls
-                type: string
-              type: array
-            regex_priority:
-              type: integer
-            strip_path:
-              type: boolean
-        upstream:
-          properties:
-            algorithm:
-              enum:
-              - round-robin
-              - consistent-hashing
-              - least-connections
-              type: string
-            hash_fallback:
-              type: string
-            hash_fallback_header:
-              type: string
-            hash_on:
-              type: string
-            hash_on_cookie:
-              type: string
-            hash_on_cookie_path:
-              type: string
-            hash_on_header:
-              type: string
-            healthchecks:
-              properties:
-                active:
-                  properties:
-                    concurrency:
-                      minimum: 1
-                      type: integer
-                    healthy:
-                      properties:
-                        http_statuses:
-                          items:
-                            type: integer
-                          type: array
-                        interval:
-                          minimum: 0
-                          type: integer
-                        successes:
-                          minimum: 0
-                          type: integer
-                      type: object
-                    http_path:
-                      pattern: ^/.*$
-                      type: string
-                    timeout:
-                      minimum: 0
-                      type: integer
-                    unhealthy:
-                      properties:
-                        http_failures:
-                          minimum: 0
-                          type: integer
-                        http_statuses:
-                          items:
-                            type: integer
-                          type: array
-                        interval:
-                          minimum: 0
-                          type: integer
-                        tcp_failures:
-                          minimum: 0
-                          type: integer
-                        timeout:
-                          minimum: 0
-                          type: integer
-                      type: object
-                  type: object
-                passive:
-                  properties:
-                    healthy:
-                      properties:
-                        http_statuses:
-                          items:
-                            type: integer
-                          type: array
-                        interval:
-                          minimum: 0
-                          type: integer
-                        successes:
-                          minimum: 0
-                          type: integer
-                      type: object
-                    unhealthy:
-                      properties:
-                        http_failures:
-                          minimum: 0
-                          type: integer
-                        http_statuses:
-                          items:
-                            type: integer
-                          type: array
-                        interval:
-                          minimum: 0
-                          type: integer
-                        tcp_failures:
-                          minimum: 0
-                          type: integer
-                        timeout:
-                          minimum: 0
-                          type: integer
-                      type: object
-                  type: object
-                threshold:
-                  type: integer
-              type: object
-            host_header:
-              type: string
-            slots:
-              minimum: 10
-              type: integer
-          type: object
-  version: v1
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: kongplugins.configuration.konghq.com
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .plugin
-    description: Name of the plugin
-    name: Plugin-Type
-    type: string
-  - JSONPath: .metadata.creationTimestamp
-    description: Age
-    name: Age
-    type: date
-  - JSONPath: .disabled
-    description: Indicates if the plugin is disabled
-    name: Disabled
-    priority: 1
-    type: boolean
-  - JSONPath: .config
-    description: Configuration of the plugin
-    name: Config
-    priority: 1
-    type: string
-  group: configuration.konghq.com
-  names:
-    kind: KongPlugin
-    plural: kongplugins
-    shortNames:
-    - kp
-  scope: Namespaced
-  validation:
-    openAPIV3Schema:
-      properties:
-        config:
-          type: object
-        configFrom:
-          properties:
-            secretKeyRef:
-              properties:
-                key:
-                  type: string
-                name:
-                  type: string
-              required:
-              - name
-              - key
-              type: object
-          type: object
-        disabled:
-          type: boolean
-        plugin:
-          type: string
-        protocols:
-          items:
-            enum:
-            - http
-            - https
-            - grpc
-            - grpcs
-            - tcp
-            - tls
-            type: string
-          type: array
-        run_on:
-          enum:
-          - first
-          - second
-          - all
-          type: string
-      required:
-      - plugin
-  version: v1
----
-apiVersion: apiextensions.k8s.io/v1beta1
-kind: CustomResourceDefinition
-metadata:
-  name: tcpingresses.configuration.konghq.com
-spec:
-  additionalPrinterColumns:
-  - JSONPath: .status.loadBalancer.ingress[*].ip
-    description: Address of the load balancer
-    name: Address
-    type: string
-  - JSONPath: .metadata.creationTimestamp
-    description: Age
-    name: Age
-    type: date
-  group: configuration.konghq.com
-  names:
-    kind: TCPIngress
-    plural: tcpingresses
-  scope: Namespaced
-  subresources:
-    status: {}
-  validation:
-    openAPIV3Schema:
-      properties:
-        apiVersion:
-          type: string
-        kind:
-          type: string
-        metadata:
-          type: object
-        spec:
-          properties:
-            rules:
-              items:
-                properties:
-                  backend:
-                    properties:
-                      serviceName:
-                        type: string
-                      servicePort:
-                        format: int32
-                        type: integer
-                    type: object
-                  host:
-                    type: string
-                  port:
-                    format: int32
-                    type: integer
-                type: object
-              type: array
-            tls:
-              items:
-                properties:
-                  hosts:
-                    items:
-                      type: string
-                    type: array
-                  secretName:
-                    type: string
-                type: object
-              type: array
-          type: object
-        status:
-          type: object
-  version: v1beta1
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: kong-serviceaccount
-  namespace: kong
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRole
-metadata:
-  name: kong-ingress-clusterrole
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - endpoints
-  - nodes
-  - pods
-  - secrets
-  verbs:
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - nodes
-  verbs:
-  - get
-- apiGroups:
-  - ""
-  resources:
-  - services
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - networking.k8s.io
-  - extensions
-  - networking.internal.knative.dev
-  resources:
-  - ingresses
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - events
-  verbs:
-  - create
-  - patch
-- apiGroups:
-  - networking.k8s.io
-  - extensions
-  - networking.internal.knative.dev
-  resources:
-  - ingresses/status
-  verbs:
-  - update
-- apiGroups:
-  - configuration.konghq.com
-  resources:
-  - tcpingresses/status
-  verbs:
-  - update
-- apiGroups:
-  - configuration.konghq.com
-  resources:
-  - kongplugins
-  - kongclusterplugins
-  - kongcredentials
-  - kongconsumers
-  - kongingresses
-  - tcpingresses
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - configmaps
-  verbs:
-  - create
-  - get
-  - update
----
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: kong-ingress-clusterrole-nisa-binding
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: kong-ingress-clusterrole
-subjects:
-- kind: ServiceAccount
-  name: kong-serviceaccount
-  namespace: kong
----
-apiVersion: v1
-kind: Service
-metadata:
-  annotations:
-    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
-    service.beta.kubernetes.io/aws-load-balancer-type: nlb
-  name: kong-proxy
-  namespace: kong
-spec:
-  ports:
-  - name: proxy
-    port: 80
-    protocol: TCP
-    targetPort: 8000
-  - name: proxy-ssl
-    port: 443
-    protocol: TCP
-    targetPort: 8443
-  selector:
-    app: ingress-kong
-  type: LoadBalancer
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: kong-validation-webhook
-  namespace: kong
-spec:
-  ports:
-  - name: webhook
-    port: 443
-    protocol: TCP
-    targetPort: 8080
-  selector:
-    app: ingress-kong
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  labels:
-    app: ingress-kong
-  name: ingress-kong
-  namespace: kong
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      app: ingress-kong
-  template:
-    metadata:
-      annotations:
-        kuma.io/gateway: enabled
-        prometheus.io/port: "8100"
-        prometheus.io/scrape: "true"
-        traffic.sidecar.istio.io/includeInboundPorts: ""
-      labels:
-        app: ingress-kong
-    spec:
-      containers:
-      - env:
-        - name: KONG_PROXY_LISTEN
-          value: 0.0.0.0:8000, 0.0.0.0:8443 ssl http2
-        - name: KONG_ADMIN_LISTEN
-          value: 127.0.0.1:8444 ssl
-        - name: KONG_STATUS_LISTEN
-          value: 0.0.0.0:8100
-        - name: KONG_DATABASE
-          value: "off"
-        - name: KONG_NGINX_WORKER_PROCESSES
-          value: "1"
-        - name: KONG_ADMIN_ACCESS_LOG
-          value: /dev/stdout
-        - name: KONG_ADMIN_ERROR_LOG
-          value: /dev/stderr
-        - name: KONG_PROXY_ERROR_LOG
-          value: /dev/stderr
-        image: kong:2.0
-        lifecycle:
-          preStop:
-            exec:
-              command:
-              - /bin/sh
-              - -c
-              - kong quit
-        livenessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /status
-            port: 8100
-            scheme: HTTP
-          initialDelaySeconds: 5
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        name: proxy
-        ports:
-        - containerPort: 8000
-          name: proxy
-          protocol: TCP
-        - containerPort: 8443
-          name: proxy-ssl
-          protocol: TCP
-        - containerPort: 8100
-          name: metrics
-          protocol: TCP
-        readinessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /status
-            port: 8100
-            scheme: HTTP
-          initialDelaySeconds: 5
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        securityContext:
-          runAsUser: 1000
-      - env:
-        - name: CONTROLLER_KONG_ADMIN_URL
-          value: https://127.0.0.1:8444
-        - name: CONTROLLER_KONG_ADMIN_TLS_SKIP_VERIFY
-          value: "true"
-        - name: CONTROLLER_PUBLISH_SERVICE
-          value: kong/kong-proxy
-        - name: POD_NAME
-          valueFrom:
-            fieldRef:
-              apiVersion: v1
-              fieldPath: metadata.name
-        - name: POD_NAMESPACE
-          valueFrom:
-            fieldRef:
-              apiVersion: v1
-              fieldPath: metadata.namespace
-        image: kong-docker-kubernetes-ingress-controller.bintray.io/kong-ingress-controller:0.9.1
-        imagePullPolicy: IfNotPresent
-        livenessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /healthz
-            port: 10254
-            scheme: HTTP
-          initialDelaySeconds: 5
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        name: ingress-controller
-        ports:
-        - containerPort: 8080
-          name: webhook
-          protocol: TCP
-        readinessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /healthz
-            port: 10254
-            scheme: HTTP
-          initialDelaySeconds: 5
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-      serviceAccountName: kong-serviceaccount