Repository: knative/serving
Pull request #8043 (2020-05-22 15:13:18)

Call MarkTLSNotEnabled for private cluster-local service
## Proposed Changes

https://github.com/knative/serving/pull/7163 propagates the status from KCert to Route when autoTLS is
enabled, but it introduced an issue.

When `serving.knative.dev/visibility: cluster-local` is configured,
KCert is not created and Route's cert status is not updated (=becomes
`Unknwon` status.)

To fix it, this patch calls `MarkTLSNotEnabled` when the service is
cluster-local.

/lint

**Release Note**

```release-note
NONE
```


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

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/8043#" title="Author self-approved">nak3</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign 
You can assign the PR to them by writing `/assign ` 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:

- **[pkg/apis/OWNERS](https://github.com/knative/serving/blob/master/pkg/apis/OWNERS)**
- ~~[pkg/reconciler/route/OWNERS](https://github.com/knative/serving/blob/master/pkg/reconciler/route/OWNERS)~~ [nak3]
- ~~[pkg/testing/OWNERS](https://github.com/knative/serving/blob/master/pkg/testing/OWNERS)~~ [nak3]

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":[]} -->
knative-prow-robot: @nak3: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-go-coverage | 7068b0eb1d88b39616e324906183ca3b08ba0940 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8043/pull-knative-serving-go-coverage/1263850542631751682) | `/test pull-knative-serving-go-coverage`

[Full PR test history](https://gubernator.knative.dev/pr/knative_serving/8043). [Your PR dashboard](https://gubernator.knative.dev/pr/nak3).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
nak3: /test pull-knative-serving-https

I hope this fixes broken https test grid https://testgrid.knative.dev/serving#https 
knative-prow-robot: @nak3: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-go-coverage | 7068b0eb1d88b39616e324906183ca3b08ba0940 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8043/pull-knative-serving-go-coverage/1263850542631751682) | `/test pull-knative-serving-go-coverage`
pull-knative-serving-integration-tests | 7068b0eb1d88b39616e324906183ca3b08ba0940 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8043/pull-knative-serving-integration-tests/1263850542631751680) | `/test pull-knative-serving-integration-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_serving/8043). [Your PR dashboard](https://gubernator.knative.dev/pr/nak3).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-test-reporter-robot: <!--[AUTOMATED-FLAKY-RETRYER]7068b0eb1d88b39616e324906183ca3b08ba0940[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-integration-tests | [pull-knative-serving-integration-tests](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8043/pull-knative-serving-integration-tests/1263850542631751680) | 1/3

Automatically retrying due to test flakiness...
/test pull-knative-serving-integration-tests

Patch:
diff --git a/cmd/autoscaler/main.go b/cmd/autoscaler/main.go
index 4df2d744c..2f2ac4e8c 100644
--- a/cmd/autoscaler/main.go
+++ b/cmd/autoscaler/main.go
@@ -225,15 +225,18 @@ func uniScalerFactoryFunc(endpointsInformer corev1informers.EndpointsInformer,
 func statsScraperFactoryFunc(endpointsLister corev1listers.EndpointsLister,
 	podLister corev1listers.PodLister) asmetrics.StatsScraperFactory {
 	return func(metric *av1alpha1.Metric, logger *zap.SugaredLogger) (asmetrics.StatsScraper, error) {
-		if metric.Spec.ScrapeTarget != "" {
-			podCounter := resources.NewScopedEndpointsCounter(
-				endpointsLister, metric.Namespace, metric.Spec.ScrapeTarget)
-			// TODO(vagababov): while metric name == revision name, we should utilize the proper
-			// values from the labels.
-			podAccessor := resources.NewPodAccessor(podLister, metric.Namespace, metric.Name)
-			return asmetrics.NewStatsScraper(metric, podCounter, podAccessor, logger)
+		if metric.Spec.ScrapeTarget == "" {
+			return nil, nil
 		}
-		return nil, nil
+
+		revisionName := metric.Labels[serving.RevisionLabelKey]
+		if revisionName == "" {
+			return nil, fmt.Errorf("label %q not found or empty in Metric %s", serving.RevisionLabelKey, metric.Name)
+		}
+
+		podCounter := resources.NewScopedEndpointsCounter(endpointsLister, metric.Namespace, metric.Spec.ScrapeTarget)
+		podAccessor := resources.NewPodAccessor(podLister, metric.Namespace, revisionName)
+		return asmetrics.NewStatsScraper(metric, podCounter, podAccessor, logger)
 	}
 }
 
diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go
index fdf3a6007..1c59a288f 100644
--- a/cmd/webhook/main.go
+++ b/cmd/webhook/main.go
@@ -225,10 +225,11 @@ func NewConversionController(ctx context.Context, cmw configmap.Watcher) *contro
 }
 
 func main() {
+
 	// Set up a signal context with our webhook options
 	ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{
 		ServiceName: "webhook",
-		Port:        8443,
+		Port:        webhook.PortFromEnv(8443),
 		SecretName:  "webhook-certs",
 	})
 
diff --git a/config/core/configmaps/features.yaml b/config/core/configmaps/features.yaml
new file mode 100644
index 000000000..6336e627b
--- /dev/null
+++ b/config/core/configmaps/features.yaml
@@ -0,0 +1,41 @@
+# Copyright 2020 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
+#
+#     https://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.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: config-features
+  namespace: knative-serving
+  labels:
+    serving.knative.dev/release: devel
+
+data:
+  _example: |
+    ################################
+    #                              #
+    #    EXAMPLE CONFIGURATION     #
+    #                              #
+    ################################
+
+    # This block is not actually functional configuration,
+    # but serves to illustrate the available configuration
+    # options and document them in a way that is accessible
+    # to users that `kubectl edit` this config map.
+    #
+    # These sample configuration options may be copied out of
+    # this example block and unindented to be in the data block
+    # to actually change the configuration.
+
+    # Indicates whether multi container support is enabled
+    multi-container: "disabled"
diff --git a/config/core/deployments/webhook.yaml b/config/core/deployments/webhook.yaml
index 663ab019e..eb361b147 100644
--- a/config/core/deployments/webhook.yaml
+++ b/config/core/deployments/webhook.yaml
@@ -42,11 +42,11 @@ spec:
 
         resources:
           requests:
-            cpu: 20m
-            memory: 20Mi
+            cpu: 100m
+            memory: 100Mi
           limits:
-            cpu: 200m
-            memory: 200Mi
+            cpu: 500m
+            memory: 500Mi
 
         env:
         - name: SYSTEM_NAMESPACE
@@ -57,6 +57,8 @@ spec:
           value: config-logging
         - name: CONFIG_OBSERVABILITY_NAME
           value: config-observability
+        - name: WEBHOOK_PORT
+          value: "8443"
 
         # TODO(https://github.com/knative/pkg/pull/953): Remove stackdriver specific config
         - name: METRICS_DOMAIN
diff --git a/go.mod b/go.mod
index ba61ed64f..aab2a0681 100644
--- a/go.mod
+++ b/go.mod
@@ -43,7 +43,7 @@ require (
 	k8s.io/code-generator v0.18.0
 	k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
 	k8s.io/metrics v0.17.2
-	knative.dev/caching v0.0.0-20200519161457-43a93f35737e
+	knative.dev/caching v0.0.0-20200521155757-e78d17bc250e
 	knative.dev/pkg v0.0.0-20200519155757-14eb3ae3a5a7
 	knative.dev/test-infra v0.0.0-20200519161858-554a95a37986
 )
diff --git a/go.sum b/go.sum
index 1f75b8f71..42ce87121 100644
--- a/go.sum
+++ b/go.sum
@@ -1430,26 +1430,21 @@ k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl
 k8s.io/utils v0.0.0-20200124190032-861946025e34 h1:HjlUD6M0K3P8nRXmr2B9o4F9dUy9TCj/aEpReeyi6+k=
 k8s.io/utils v0.0.0-20200124190032-861946025e34/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
 knative.dev/caching v0.0.0-20190719140829-2032732871ff/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg=
-knative.dev/caching v0.0.0-20200519161457-43a93f35737e h1:+tN8oODHsfGHUs01Z9Jg056wm/fa66ZDUqI380mwhKQ=
-knative.dev/caching v0.0.0-20200519161457-43a93f35737e/go.mod h1:MX8oysHHDn6GTy+WWIgR80p78RIHV5p14xsXvrqvkbw=
+knative.dev/caching v0.0.0-20200521155757-e78d17bc250e h1:LN2scNClE8G4a9XzM0AGZkK/rT56A0ZlweaMjNzPMD0=
+knative.dev/caching v0.0.0-20200521155757-e78d17bc250e/go.mod h1:bsKPIG2XZFYL8uw5BAxg7EMBLp0vNpu9jZIGus8HUPU=
 knative.dev/eventing-contrib v0.6.1-0.20190723221543-5ce18048c08b/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g=
 knative.dev/pkg v0.0.0-20191101194912-56c2594e4f11/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
 knative.dev/pkg v0.0.0-20191111150521-6d806b998379/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
 knative.dev/pkg v0.0.0-20200428194351-90fc61bae7f7/go.mod h1:o+e8OVEJKIuvXPsGVPIautjXgs05xbos7G+QMRjuUps=
 knative.dev/pkg v0.0.0-20200505191044-3da93ebb24c2 h1:Qu2NlOHb9p3g+CSL/ok9+FySowN60URFEKRSXfWtDv4=
 knative.dev/pkg v0.0.0-20200505191044-3da93ebb24c2/go.mod h1:Q6sL35DdGs8hIQZKdaCXJGgY8f90BmNBKSb8z6d/BTM=
-knative.dev/pkg v0.0.0-20200514052058-c75d324f8b8b h1:lM0uwBgNcS9S4cWLqIS6Fvjt3kR/6oAPXgbXfEzBJwU=
-knative.dev/pkg v0.0.0-20200514052058-c75d324f8b8b/go.mod h1:tMOHGbxtRz8zYFGEGpV/bpoTEM1o89MwYFC4YJXl3GY=
 knative.dev/pkg v0.0.0-20200515002500-16d7b963416f/go.mod h1:tMOHGbxtRz8zYFGEGpV/bpoTEM1o89MwYFC4YJXl3GY=
-knative.dev/pkg v0.0.0-20200518174206-60f4ae1dbe6f h1:f2eK5+z0/l2S431UCezMG9W4FzktuNbD0OB1gezSoMs=
-knative.dev/pkg v0.0.0-20200518174206-60f4ae1dbe6f/go.mod h1:GinFtW8LEi9rzCkzCMHAIlAnZjP1RzauxwhRAI3rimI=
 knative.dev/pkg v0.0.0-20200519155757-14eb3ae3a5a7 h1:9S2r59HZJF9nKvoRLg5zJzx6XpVlVyvVRqz/C/h6h2s=
 knative.dev/pkg v0.0.0-20200519155757-14eb3ae3a5a7/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA=
 knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ=
 knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU=
 knative.dev/test-infra v0.0.0-20200513011557-d03429a76034 h1:JxqONCZVS7or+Fv3ebVQoipuIBH7Ig3Qbx170hgIF+A=
 knative.dev/test-infra v0.0.0-20200513011557-d03429a76034/go.mod h1:aMif0KXL4g19YCYwsy4Ocjjz5xgPlseYV+B95Oo4JGE=
-knative.dev/test-infra v0.0.0-20200514223200-ef4fd3ad398f/go.mod h1:+uml4upluwrnWHRSezi4WVcKJ0OJHynF16Ot7fu0ky4=
 knative.dev/test-infra v0.0.0-20200519015156-82551620b0a9 h1:kKfV3QWsxugwXsqgjFd72MjZeAHJ381dWqAxH2KMknc=
 knative.dev/test-infra v0.0.0-20200519015156-82551620b0a9/go.mod h1:A5b2OAXTOeHT3hHhVQm3dmtbuWvIDP7qzgtqxA3/2pE=
 knative.dev/test-infra v0.0.0-20200519161858-554a95a37986 h1:ZDy43jkWPQ75d4l4DGy+ENQIXlNcnHIh4tB6XxgovNc=
diff --git a/hack/update-deps.sh b/hack/update-deps.sh
index 39f9447d9..1774b9386 100755
--- a/hack/update-deps.sh
+++ b/hack/update-deps.sh
@@ -27,13 +27,13 @@ cd ${ROOT_DIR}
 export GO111MODULE=on
 
 # This controls the release branch we track.
-VERSION="master"
+VERSION="release-0.15"
 
 # The list of dependencies that we track at HEAD and periodically
 # float forward in this repository.
 FLOATING_DEPS=(
-  "knative.dev/test-infra@release-0.15"
-  "knative.dev/pkg@release-0.15"
+  "knative.dev/test-infra@${VERSION}"
+  "knative.dev/pkg@${VERSION}"
   "knative.dev/caching@${VERSION}"
 )
 
diff --git a/pkg/apis/config/defaults.go b/pkg/apis/config/defaults.go
index 75b5db4e1..a458e71fd 100644
--- a/pkg/apis/config/defaults.go
+++ b/pkg/apis/config/defaults.go
@@ -58,7 +58,7 @@ const (
 	DefaultAllowContainerConcurrencyZero bool = true
 )
 
-func defaultConfig() *Defaults {
+func defaultDefaultsConfig() *Defaults {
 	return &Defaults{
 		RevisionTimeoutSeconds:        DefaultRevisionTimeoutSeconds,
 		MaxRevisionTimeoutSeconds:     DefaultMaxRevisionTimeoutSeconds,
@@ -71,12 +71,11 @@ func defaultConfig() *Defaults {
 
 // NewDefaultsConfigFromMap creates a Defaults from the supplied Map.
 func NewDefaultsConfigFromMap(data map[string]string) (*Defaults, error) {
-	nc := defaultConfig()
+	nc := defaultDefaultsConfig()
 
 	if err := cm.Parse(data,
 		cm.AsString("container-name-template", &nc.UserContainerNameTemplate),
 
-		cm.AsBool("enable-multi-container", &nc.EnableMultiContainer),
 		cm.AsBool("allow-container-concurrency-zero", &nc.AllowContainerConcurrencyZero),
 
 		cm.AsInt64("revision-timeout-seconds", &nc.RevisionTimeoutSeconds),
@@ -123,9 +122,6 @@ func NewDefaultsConfigFromConfigMap(config *corev1.ConfigMap) (*Defaults, error)
 
 // Defaults includes the default values to be populated by the webhook.
 type Defaults struct {
-	// Feature flag to enable multi container support.
-	EnableMultiContainer bool
-
 	RevisionTimeoutSeconds int64
 	// This is the timeout set for ingress.
 	// RevisionTimeoutSeconds must be less than this value.
diff --git a/pkg/apis/config/features.go b/pkg/apis/config/features.go
new file mode 100644
index 000000000..b81fb6796
--- /dev/null
+++ b/pkg/apis/config/features.go
@@ -0,0 +1,76 @@
+/*
+Copyright 2020 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
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+	"strings"
+
+	corev1 "k8s.io/api/core/v1"
+	cm "knative.dev/pkg/configmap"
+)
+
+type Flag string
+
+const (
+	// FeaturesConfigName is the name of the ConfigMap for the features.
+	FeaturesConfigName = "config-features"
+
+	Enabled  Flag = "Enabled"
+	Allowed  Flag = "Allowed"
+	Disabled Flag = "Disabled"
+)
+
+func defaultFeaturesConfig() *Features {
+	return &Features{
+		MultiContainer: Disabled,
+	}
+}
+
+// NewFeaturesConfigFromMap creates a Features from the supplied Map
+func NewFeaturesConfigFromMap(data map[string]string) (*Features, error) {
+	nc := defaultFeaturesConfig()
+
+	if err := cm.Parse(data, AsFlag("multi-container", &nc.MultiContainer)); err != nil {
+		return nil, err
+	}
+	return nc, nil
+}
+
+// NewFeaturesConfigFromConfigMap creates a Features from the supplied ConfigMap
+func NewFeaturesConfigFromConfigMap(config *corev1.ConfigMap) (*Features, error) {
+	return NewFeaturesConfigFromMap(config.Data)
+}
+
+// Features specifies which features are allowed by the webhook.
+type Features struct {
+	MultiContainer Flag
+}
+
+// AsFlag parses the value at key as a Flag into the target, if it exists.
+func AsFlag(key string, target *Flag) cm.ParseFunc {
+	return func(data map[string]string) error {
+		if raw, ok := data[key]; ok {
+			for _, flag := range []Flag{Enabled, Allowed, Disabled} {
+				if strings.EqualFold(raw, string(flag)) {
+					*target = flag
+					return nil
+				}
+			}
+		}
+		return nil
+	}
+}
diff --git a/pkg/apis/config/store.go b/pkg/apis/config/store.go
index 2d28d2090..5288d0b05 100644
--- a/pkg/apis/config/store.go
+++ b/pkg/apis/config/store.go
@@ -29,6 +29,7 @@ type cfgKey struct{}
 // +k8s:deepcopy-gen=false
 type Config struct {
 	Defaults   *Defaults
+	Features   *Features
 	Autoscaler *autoscalerconfig.Config
 }
 
@@ -48,9 +49,11 @@ func FromContextOrDefaults(ctx context.Context) *Config {
 		return cfg
 	}
 	defaults, _ := NewDefaultsConfigFromMap(map[string]string{})
+	features, _ := NewFeaturesConfigFromMap(map[string]string{})
 	autoscaler, _ := autoscalerconfig.NewConfigFromMap(map[string]string{})
 	return &Config{
 		Defaults:   defaults,
+		Features:   features,
 		Autoscaler: autoscaler,
 	}
 }
@@ -71,10 +74,11 @@ type Store struct {
 func NewStore(logger configmap.Logger, onAfterStore ...func(name string, value interface{})) *Store {
 	store := &Store{
 		UntypedStore: configmap.NewUntypedStore(
-			"defaults",
+			"apis",
 			logger,
 			configmap.Constructors{
 				DefaultsConfigName:          NewDefaultsConfigFromConfigMap,
+				FeaturesConfigName:          NewFeaturesConfigFromConfigMap,
 				autoscalerconfig.ConfigName: autoscalerconfig.NewConfigFromConfigMap,
 			},
 			onAfterStore...,
@@ -93,6 +97,7 @@ func (s *Store) ToContext(ctx context.Context) context.Context {
 func (s *Store) Load() *Config {
 	return &Config{
 		Defaults:   s.UntypedLoad(DefaultsConfigName).(*Defaults).DeepCopy(),
+		Features:   s.UntypedLoad(FeaturesConfigName).(*Features).DeepCopy(),
 		Autoscaler: s.UntypedLoad(autoscalerconfig.ConfigName).(*autoscalerconfig.Config).DeepCopy(),
 	}
 }
diff --git a/pkg/apis/config/zz_generated.deepcopy.go b/pkg/apis/config/zz_generated.deepcopy.go
index 341f6334b..484d01ca3 100644
--- a/pkg/apis/config/zz_generated.deepcopy.go
+++ b/pkg/apis/config/zz_generated.deepcopy.go
@@ -55,3 +55,19 @@ func (in *Defaults) DeepCopy() *Defaults {
 	in.DeepCopyInto(out)
 	return out
 }
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Features) DeepCopyInto(out *Features) {
+	*out = *in
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Features.
+func (in *Features) DeepCopy() *Features {
+	if in == nil {
+		return nil
+	}
+	out := new(Features)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/pkg/apis/serving/k8s_validation.go b/pkg/apis/serving/k8s_validation.go
index 8de357613..c363073f7 100644
--- a/pkg/apis/serving/k8s_validation.go
+++ b/pkg/apis/serving/k8s_validation.go
@@ -272,9 +272,9 @@ func ValidatePodSpec(ctx context.Context, ps corev1.PodSpec) *apis.FieldError {
 
 func validateContainers(ctx context.Context, containers []corev1.Container, volumes sets.String) *apis.FieldError {
 	var errs *apis.FieldError
-	cfg := config.FromContextOrDefaults(ctx).Defaults
-	if !cfg.EnableMultiContainer {
-		errs = errs.Also(&apis.FieldError{Message: fmt.Sprintf("enable-multi-container is off, "+
+	features := config.FromContextOrDefaults(ctx).Features
+	if features.MultiContainer != config.Enabled {
+		errs = errs.Also(&apis.FieldError{Message: fmt.Sprintf("multi-container is off, "+
 			"but found %d containers", len(containers))})
 	} else {
 		errs = errs.Also(validateContainersPorts(containers).ViaField("containers"))
diff --git a/pkg/apis/serving/v1/configuration_types.go b/pkg/apis/serving/v1/configuration_types.go
index fbf1ae155..cad8cfdf9 100644
--- a/pkg/apis/serving/v1/configuration_types.go
+++ b/pkg/apis/serving/v1/configuration_types.go
@@ -24,7 +24,7 @@ import (
 )
 
 // +genclient
-// +genreconciler
+// +genreconciler:krshapedlogic=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // Configuration represents the "floating HEAD" of a linear history of Revisions.
diff --git a/pkg/apis/serving/v1/revision_types.go b/pkg/apis/serving/v1/revision_types.go
index dbad280b1..72fc15fd4 100644
--- a/pkg/apis/serving/v1/revision_types.go
+++ b/pkg/apis/serving/v1/revision_types.go
@@ -25,7 +25,7 @@ import (
 )
 
 // +genclient
-// +genreconciler
+// +genreconciler:krshapedlogic=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // Revision is an immutable snapshot of code and configuration.  A revision
@@ -139,7 +139,7 @@ type RevisionStatus struct {
 	// may be empty if the image comes from a registry listed to skip resolution.
 	// If multiple containers specified then DeprecatedImageDigest holds the digest
 	// for serving container.
-	// DEPRECATED Use ContainerStatuses instead.
+	// DEPRECATED: Use ContainerStatuses instead.
 	// TODO(savitaashture) Remove deprecatedImageDigest.
 	// ref https://kubernetes.io/docs/reference/using-api/deprecation-policy for deprecation.
 	// +optional
diff --git a/pkg/apis/serving/v1/route_lifecycle.go b/pkg/apis/serving/v1/route_lifecycle.go
index 81de8ed8a..32071031f 100644
--- a/pkg/apis/serving/v1/route_lifecycle.go
+++ b/pkg/apis/serving/v1/route_lifecycle.go
@@ -126,12 +126,16 @@ func (rs *RouteStatus) MarkCertificateNotOwned(name string) {
 		"There is an existing certificate %s that we don't own.", name)
 }
 
-// MarkAutoTLSNotEnabled sets RouteConditionCertificateProvisioned to true when
-// certificate config such as autoTLS is not enabled.
-func (rs *RouteStatus) MarkAutoTLSNotEnabled() {
+const (
+	AutoTLSNotEnabledMessage            = "autoTLS is not enabled"
+	TLSNotEnabledForClusterLocalMessage = "TLS is not enabled for cluster-local"
+)
+
+// MarkTLSNotEnabled sets RouteConditionCertificateProvisioned to true when
+// certificate config such as autoTLS is not enabled or private cluster-local service.
+func (rs *RouteStatus) MarkTLSNotEnabled(msg string) {
 	routeCondSet.Manage(rs).MarkTrueWithReason(RouteConditionCertificateProvisioned,
-		"AutoTLSNotEnabled",
-		"autoTLS is not enabled")
+		"TLSNotEnabled", msg)
 }
 
 // MarkHTTPDowngrade sets RouteConditionCertificateProvisioned to true when plain
diff --git a/pkg/apis/serving/v1/route_types.go b/pkg/apis/serving/v1/route_types.go
index 2d810ebf5..c63866062 100644
--- a/pkg/apis/serving/v1/route_types.go
+++ b/pkg/apis/serving/v1/route_types.go
@@ -25,7 +25,7 @@ import (
 )
 
 // +genclient
-// +genreconciler
+// +genreconciler:krshapedlogic=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // Route is responsible for configuring ingress over a collection of Revisions.
diff --git a/pkg/apis/serving/v1/service_types.go b/pkg/apis/serving/v1/service_types.go
index ce5174319..d91818e05 100644
--- a/pkg/apis/serving/v1/service_types.go
+++ b/pkg/apis/serving/v1/service_types.go
@@ -25,7 +25,7 @@ import (
 )
 
 // +genclient
-// +genreconciler
+// +genreconciler:krshapedlogic=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // Service acts as a top-level container that manages a Route and Configuration
diff --git a/pkg/apis/serving/v1alpha1/revision_types.go b/pkg/apis/serving/v1alpha1/revision_types.go
index f0a7ca295..51cf78435 100644
--- a/pkg/apis/serving/v1alpha1/revision_types.go
+++ b/pkg/apis/serving/v1alpha1/revision_types.go
@@ -160,7 +160,7 @@ type RevisionStatus struct {
 	// may be empty if the image comes from a registry listed to skip resolution.
 	// If multiple containers specified then DeprecatedImageDigest holds the digest
 	// for serving container.
-	// DEPRECATED Use ImageDigests instead.
+	// DEPRECATED: Use ContainerStatuses instead.
 	// TODO(savitaashture) Remove deprecatedImageDigest.
 	// ref https://kubernetes.io/docs/reference/using-api/deprecation-policy for deprecation.
 	// +optional
diff --git a/pkg/apis/serving/v1alpha1/route_lifecycle.go b/pkg/apis/serving/v1alpha1/route_lifecycle.go
index 523187d49..9644c7ade 100644
--- a/pkg/apis/serving/v1alpha1/route_lifecycle.go
+++ b/pkg/apis/serving/v1alpha1/route_lifecycle.go
@@ -134,12 +134,16 @@ func (rs *RouteStatus) MarkCertificateNotOwned(name string) {
 		"There is an existing certificate %s that we don't own.", name)
 }
 
-// MarkAutoTLSNotEnabled sets RouteConditionCertificateProvisioned to true when
-// certificate config such as autoTLS is not enabled.
-func (rs *RouteStatus) MarkAutoTLSNotEnabled() {
+const (
+	AutoTLSNotEnabledMessage            = "autoTLS is not enabled"
+	TLSNotEnabledForClusterLocalMessage = "TLS is not enabled for cluster-local"
+)
+
+// MarkTLSNotEnabled sets RouteConditionCertificateProvisioned to true when
+// certificate config such as autoTLS is not enabled or private cluster-local service.
+func (rs *RouteStatus) MarkTLSNotEnabled(msg string) {
 	routeCondSet.Manage(rs).MarkTrueWithReason(RouteConditionCertificateProvisioned,
-		"AutoTLSNotEnabled",
-		"autoTLS is not enabled")
+		"TLSNotEnabled", msg)
 }
 
 // MarkHTTPDowngrade sets RouteConditionCertificateProvisioned to true when plain
diff --git a/pkg/autoscaler/config/config.go b/pkg/autoscaler/config/config.go
index 17f26acda..6fe41e1ca 100644
--- a/pkg/autoscaler/config/config.go
+++ b/pkg/autoscaler/config/config.go
@@ -193,9 +193,12 @@ func validate(lc *Config) (*Config, error) {
 	}
 
 	// We can't permit stable window be less than our aggregation window for correctness.
-	if lc.StableWindow < autoscaling.WindowMin {
-		return nil, fmt.Errorf("stable-window = %v, must be at least %v", lc.StableWindow, autoscaling.WindowMin)
+	// Or too big, so that our desisions are too imprecise.
+	if lc.StableWindow < autoscaling.WindowMin || lc.StableWindow > autoscaling.WindowMax {
+		return nil, fmt.Errorf("stable-window = %v, must be in [%v; %v] range", lc.StableWindow,
+			autoscaling.WindowMin, autoscaling.WindowMax)
 	}
+
 	if lc.StableWindow.Round(time.Second) != lc.StableWindow {
 		return nil, fmt.Errorf("stable-window = %v, must be specified with at most second precision", lc.StableWindow)
 	}
diff --git a/pkg/client/injection/reconciler/serving/v1/configuration/reconciler.go b/pkg/client/injection/reconciler/serving/v1/configuration/reconciler.go
index 868fdfd08..e2e4c5b6e 100644
--- a/pkg/client/injection/reconciler/serving/v1/configuration/reconciler.go
+++ b/pkg/client/injection/reconciler/serving/v1/configuration/reconciler.go
@@ -164,10 +164,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
 			logger.Warnw("Failed to set finalizers", zap.Error(err))
 		}
 
+		reconciler.PreProcessReconcile(ctx, resource)
+
 		// Reconcile this copy of the resource and then write back any status
 		// updates regardless of whether the reconciliation errored out.
 		reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
 
+		reconciler.PostProcessReconcile(ctx, resource)
+
 	} else if fin, ok := r.reconciler.(Finalizer); ok {
 		// Append the target method to the logger.
 		logger = logger.With(zap.String("targetMethod", "FinalizeKind"))
diff --git a/pkg/client/injection/reconciler/serving/v1/revision/reconciler.go b/pkg/client/injection/reconciler/serving/v1/revision/reconciler.go
index 25c59cd4c..ed3c6d2e3 100644
--- a/pkg/client/injection/reconciler/serving/v1/revision/reconciler.go
+++ b/pkg/client/injection/reconciler/serving/v1/revision/reconciler.go
@@ -164,10 +164,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
 			logger.Warnw("Failed to set finalizers", zap.Error(err))
 		}
 
+		reconciler.PreProcessReconcile(ctx, resource)
+
 		// Reconcile this copy of the resource and then write back any status
 		// updates regardless of whether the reconciliation errored out.
 		reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
 
+		reconciler.PostProcessReconcile(ctx, resource)
+
 	} else if fin, ok := r.reconciler.(Finalizer); ok {
 		// Append the target method to the logger.
 		logger = logger.With(zap.String("targetMethod", "FinalizeKind"))
diff --git a/pkg/client/injection/reconciler/serving/v1/route/reconciler.go b/pkg/client/injection/reconciler/serving/v1/route/reconciler.go
index 81fc99446..2e49f4546 100644
--- a/pkg/client/injection/reconciler/serving/v1/route/reconciler.go
+++ b/pkg/client/injection/reconciler/serving/v1/route/reconciler.go
@@ -164,10 +164,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
 			logger.Warnw("Failed to set finalizers", zap.Error(err))
 		}
 
+		reconciler.PreProcessReconcile(ctx, resource)
+
 		// Reconcile this copy of the resource and then write back any status
 		// updates regardless of whether the reconciliation errored out.
 		reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
 
+		reconciler.PostProcessReconcile(ctx, resource)
+
 	} else if fin, ok := r.reconciler.(Finalizer); ok {
 		// Append the target method to the logger.
 		logger = logger.With(zap.String("targetMethod", "FinalizeKind"))
diff --git a/pkg/client/injection/reconciler/serving/v1/service/reconciler.go b/pkg/client/injection/reconciler/serving/v1/service/reconciler.go
index ba494db10..3680eb6aa 100644
--- a/pkg/client/injection/reconciler/serving/v1/service/reconciler.go
+++ b/pkg/client/injection/reconciler/serving/v1/service/reconciler.go
@@ -164,10 +164,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
 			logger.Warnw("Failed to set finalizers", zap.Error(err))
 		}
 
+		reconciler.PreProcessReconcile(ctx, resource)
+
 		// Reconcile this copy of the resource and then write back any status
 		// updates regardless of whether the reconciliation errored out.
 		reconcileEvent = r.reconciler.ReconcileKind(ctx, resource)
 
+		reconciler.PostProcessReconcile(ctx, resource)
+
 	} else if fin, ok := r.reconciler.(Finalizer); ok {
 		// Append the target method to the logger.
 		logger = logger.With(zap.String("targetMethod", "FinalizeKind"))
diff --git a/pkg/queue/stats.go b/pkg/queue/stats.go
index 3f493ee63..b727e4bc0 100644
--- a/pkg/queue/stats.go
+++ b/pkg/queue/stats.go
@@ -29,7 +29,10 @@ func ReportStats(startedAt time.Time, reqCh chan network.ReqEvent, reportCh <-ch
 
 	for {
 		select {
-		case event := <-reqCh:
+		case event, ok := <-reqCh:
+			if !ok {
+				return
+			}
 			state.HandleEvent(event)
 		case now := <-reportCh:
 			stats := state.Report(now)
diff --git a/pkg/reconciler/configuration/configuration.go b/pkg/reconciler/configuration/configuration.go
index da44dc858..31f7ee8cf 100644
--- a/pkg/reconciler/configuration/configuration.go
+++ b/pkg/reconciler/configuration/configuration.go
@@ -61,10 +61,6 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, config *v1.Configuration
 	config.SetDefaults(ctx)
 	config.Status.InitializeConditions()
 
-	// Bump observed generation to denote that we have processed this
-	// generation regardless of success or failure.
-	config.Status.ObservedGeneration = config.Generation
-
 	// First, fetch the revision that should exist for the current generation.
 	lcr, err := c.latestCreatedRevision(config)
 	if errors.IsNotFound(err) {
diff --git a/pkg/reconciler/revision/revision.go b/pkg/reconciler/revision/revision.go
index caec98227..47546b435 100644
--- a/pkg/reconciler/revision/revision.go
+++ b/pkg/reconciler/revision/revision.go
@@ -168,7 +168,6 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, rev *v1.Revision) pkgrec
 			"Revision becomes ready upon all resources being ready")
 	}
 
-	rev.Status.ObservedGeneration = rev.Generation
 	return nil
 }
 
diff --git a/pkg/reconciler/route/route.go b/pkg/reconciler/route/route.go
index 52272d3bb..6465d427b 100644
--- a/pkg/reconciler/route/route.go
+++ b/pkg/reconciler/route/route.go
@@ -116,10 +116,6 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, r *v1.Route) pkgreconcil
 	traffic, err := c.configureTraffic(ctx, r)
 	if traffic == nil || err != nil {
 		// Traffic targets aren't ready, no need to configure child resources.
-		// Need to update ObservedGeneration, otherwise Route's Ready state won't
-		// be propagated to Service and the Service's RoutesReady will stay in
-		// 'Unknown'.
-		r.Status.ObservedGeneration = r.Generation
 		return err
 	}
 
@@ -166,7 +162,6 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, r *v1.Route) pkgreconcil
 		return err
 	}
 
-	r.Status.ObservedGeneration = r.Generation
 	logger.Info("Route successfully synced")
 	return nil
 }
@@ -190,7 +185,7 @@ func (c *Reconciler) reconcileIngressResources(ctx context.Context, r *v1.Route,
 func (c *Reconciler) tls(ctx context.Context, host string, r *v1.Route, traffic *traffic.Config) ([]netv1alpha1.IngressTLS, []netv1alpha1.HTTP01Challenge, error) {
 	tls := []netv1alpha1.IngressTLS{}
 	if !config.FromContext(ctx).Network.AutoTLS {
-		r.Status.MarkAutoTLSNotEnabled()
+		r.Status.MarkTLSNotEnabled(v1.AutoTLSNotEnabledMessage)
 		return tls, nil, nil
 	}
 	domainToTagMap, err := domains.GetAllDomainsAndTags(ctx, r, getTrafficNames(traffic.Targets), traffic.Visibility)
@@ -200,6 +195,7 @@ func (c *Reconciler) tls(ctx context.Context, host string, r *v1.Route, traffic
 
 	for domain := range domainToTagMap {
 		if domains.IsClusterLocal(domain) {
+			r.Status.MarkTLSNotEnabled(v1.TLSNotEnabledForClusterLocalMessage)
 			delete(domainToTagMap, domain)
 		}
 	}
diff --git a/pkg/reconciler/service/service.go b/pkg/reconciler/service/service.go
index e20b3174c..666b2dc7f 100644
--- a/pkg/reconciler/service/service.go
+++ b/pkg/reconciler/service/service.go
@@ -117,8 +117,6 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, service *v1.Service) pkg
 	}
 
 	c.checkRoutesNotReady(config, logger, route, service)
-	service.Status.ObservedGeneration = service.Generation
-
 	return nil
 }
 
diff --git a/third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/LICENSE b/third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   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.
diff --git a/third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/NOTICE b/third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/NOTICE
deleted file mode 100644
index dd878a30e..000000000
--- a/third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/NOTICE
+++ /dev/null
@@ -1,23 +0,0 @@
-Prometheus instrumentation library for Go applications
-Copyright 2012-2015 The Prometheus Authors
-
-This product includes software developed at
-SoundCloud Ltd. (http://soundcloud.com/).
-
-
-The following components are included in this product:
-
-perks - a fork of https://github.com/bmizerany/perks
-https://github.com/beorn7/perks
-Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
-See https://github.com/beorn7/perks/blob/master/README.md for license details.
-
-Go support for Protocol Buffers - Google's data interchange format
-http://github.com/golang/protobuf/
-Copyright 2010 The Go Authors
-See source code for license details.
-
-Support for streaming Protocol Buffer messages for the Go language (golang).
-https://github.com/matttproud/golang_protobuf_extensions
-Copyright 2013 Matt T. Proud
-Licensed under the Apache License, Version 2.0
diff --git a/third_party/cert-manager-0.12.0/net-certmanager.yaml b/third_party/cert-manager-0.12.0/net-certmanager.yaml
index d33db3008..261bdd27d 100644
--- a/third_party/cert-manager-0.12.0/net-certmanager.yaml
+++ b/third_party/cert-manager-0.12.0/net-certmanager.yaml
@@ -18,7 +18,7 @@ metadata:
   # These are the permissions needed by the `cert-manager` `Certificate` implementation.
   name: knative-serving-certmanager
   labels:
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
     serving.knative.dev/controller: "true"
     networking.knative.dev/certificate-provider: cert-manager
 rules:
@@ -49,7 +49,7 @@ kind: ValidatingWebhookConfiguration
 metadata:
   name: config.webhook.net-certmanager.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
 webhooks:
 - admissionReviewVersions:
   - v1beta1
@@ -86,7 +86,7 @@ metadata:
   name: net-certmanager-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
 
 ---
 # Copyright 2020 The Knative Authors
@@ -109,7 +109,7 @@ metadata:
   name: config-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
     networking.knative.dev/certificate-provider: cert-manager
 data:
   _example: |
@@ -156,7 +156,7 @@ metadata:
   name: networking-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
     networking.knative.dev/certificate-provider: cert-manager
 spec:
   selector:
@@ -168,7 +168,7 @@ spec:
         cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
       labels:
         app: networking-certmanager
-        serving.knative.dev/release: "v20200521-e037dfb"
+        serving.knative.dev/release: "v20200526-e037dfb"
     spec:
       serviceAccountName: controller
       containers:
@@ -208,7 +208,7 @@ kind: Service
 metadata:
   labels:
     app: networking-certmanager
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
     networking.knative.dev/certificate-provider: cert-manager
   name: networking-certmanager
   namespace: knative-serving
@@ -245,7 +245,7 @@ metadata:
   name: net-certmanager-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
 spec:
   selector:
     matchLabels:
@@ -258,7 +258,7 @@ spec:
       labels:
         app: net-certmanager-webhook
         role: net-certmanager-webhook
-        serving.knative.dev/release: "v20200521-e037dfb"
+        serving.knative.dev/release: "v20200526-e037dfb"
     spec:
       serviceAccountName: controller
       containers:
@@ -319,7 +319,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: net-certmanager-webhook
-    serving.knative.dev/release: "v20200521-e037dfb"
+    serving.knative.dev/release: "v20200526-e037dfb"
 spec:
   ports:
   - # Define metrics and profiling for them to be accessible within service meshes.
diff --git a/third_party/net-istio.yaml b/third_party/net-istio.yaml
index 82a618419..3a85c59df 100644
--- a/third_party/net-istio.yaml
+++ b/third_party/net-istio.yaml
@@ -18,7 +18,7 @@ metadata:
   # These are the permissions needed by the Istio Ingress implementation.
   name: knative-serving-istio
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     serving.knative.dev/controller: "true"
     networking.knative.dev/ingress-provider: istio
 rules:
@@ -48,7 +48,7 @@ metadata:
   name: knative-ingress-gateway
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -85,7 +85,7 @@ metadata:
   name: cluster-local-gateway
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -118,7 +118,7 @@ kind: MutatingWebhookConfiguration
 metadata:
   name: webhook.istio.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 webhooks:
 - admissionReviewVersions:
@@ -154,7 +154,7 @@ kind: ValidatingWebhookConfiguration
 metadata:
   name: config.webhook.istio.networking.internal.knative.dev
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 webhooks:
 - admissionReviewVersions:
@@ -192,7 +192,7 @@ metadata:
   name: istio-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 
 ---
@@ -216,7 +216,7 @@ metadata:
   name: config-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 data:
   _example: |
@@ -286,7 +286,7 @@ metadata:
   name: networking-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -302,14 +302,14 @@ spec:
         sidecar.istio.io/inject: "false"
       labels:
         app: networking-istio
-        serving.knative.dev/release: "v20200520-4af052c"
+        serving.knative.dev/release: "v20200522-dc16e1e"
     spec:
       serviceAccountName: controller
       containers:
       - name: networking-istio
         # This is the Go import path for the binary that is containerized
         # and substituted here.
-        image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:b26d2befffe5bf846a010e7b25f8df38af4af93b12bb8a7192673acf100510de
+        image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:250c68ac1458f524fb8aaf271747aa047b72d16b4e5a8800390c344266380fc9
         resources:
           requests:
             cpu: 30m
@@ -361,7 +361,7 @@ metadata:
   name: istio-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -375,14 +375,14 @@ spec:
       labels:
         app: istio-webhook
         role: istio-webhook
-        serving.knative.dev/release: "v20200520-4af052c"
+        serving.knative.dev/release: "v20200522-dc16e1e"
     spec:
       serviceAccountName: controller
       containers:
       - name: webhook
         # This is the Go import path for the binary that is containerized
         # and substituted here.
-        image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:069954d05ab18ff3cc54c58878a57391291c5a9b7023f36462c9cdcbc59b278c
+        image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:29978f12c8f25eeab4ecbcf1af73a9d65527f5a5331711197613d3b769089c6b
         resources:
           requests:
             cpu: 20m
@@ -436,7 +436,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: istio-webhook
-    serving.knative.dev/release: "v20200520-4af052c"
+    serving.knative.dev/release: "v20200522-dc16e1e"
     networking.knative.dev/ingress-provider: istio
 spec:
   ports:
diff --git a/vendor/github.com/prometheus/client_golang/api/client.go b/vendor/github.com/prometheus/client_golang/api/client.go
deleted file mode 100644
index 09af749ca..000000000
--- a/vendor/github.com/prometheus/client_golang/api/client.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2015 The Prometheus 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.
-
-// +build go1.7
-
-// Package api provides clients for the HTTP APIs.
-package api
-
-import (
-	"context"
-	"io/ioutil"
-	"net"
-	"net/http"
-	"net/url"
-	"path"
-	"strings"
-	"time"
-)
-
-// DefaultRoundTripper is used if no RoundTripper is set in Config.
-var DefaultRoundTripper http.RoundTripper = &http.Transport{
-	Proxy: http.ProxyFromEnvironment,
-	DialContext: (&net.Dialer{
-		Timeout:   30 * time.Second,
-		KeepAlive: 30 * time.Second,
-	}).DialContext,
-	TLSHandshakeTimeout: 10 * time.Second,
-}
-
-// Config defines configuration parameters for a new client.
-type Config struct {
-	// The address of the Prometheus to connect to.
-	Address string
-
-	// RoundTripper is used by the Client to drive HTTP requests. If not
-	// provided, DefaultRoundTripper will be used.
-	RoundTripper http.RoundTripper
-}
-
-func (cfg *Config) roundTripper() http.RoundTripper {
-	if cfg.RoundTripper == nil {
-		return DefaultRoundTripper
-	}
-	return cfg.RoundTripper
-}
-
-// Client is the interface for an API client.
-type Client interface {
-	URL(ep string, args map[string]string) *url.URL
-	Do(context.Context, *http.Request) (*http.Response, []byte, error)
-}
-
-// NewClient returns a new Client.
-//
-// It is safe to use the returned Client from multiple goroutines.
-func NewClient(cfg Config) (Client, error) {
-	u, err := url.Parse(cfg.Address)
-	if err != nil {
-		return nil, err
-	}
-	u.Path = strings.TrimRight(u.Path, "/")
-
-	return &httpClient{
-		endpoint: u,
-		client:   http.Client{Transport: cfg.roundTripper()},
-	}, nil
-}
-
-type httpClient struct {
-	endpoint *url.URL
-	client   http.Client
-}
-
-func (c *httpClient) URL(ep string, args map[string]string) *url.URL {
-	p := path.Join(c.endpoint.Path, ep)
-
-	for arg, val := range args {
-		arg = ":" + arg
-		p = strings.Replace(p, arg, val, -1)
-	}
-
-	u := *c.endpoint
-	u.Path = p
-
-	return &u
-}
-
-func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
-	if ctx != nil {
-		req = req.WithContext(ctx)
-	}
-	resp, err := c.client.Do(req)
-	defer func() {
-		if resp != nil {
-			resp.Body.Close()
-		}
-	}()
-
-	if err != nil {
-		return nil, nil, err
-	}
-
-	var body []byte
-	done := make(chan struct{})
-	go func() {
-		body, err = ioutil.ReadAll(resp.Body)
-		close(done)
-	}()
-
-	select {
-	case <-ctx.Done():
-		err = resp.Body.Close()
-		<-done
-		if err == nil {
-			err = ctx.Err()
-		}
-	case <-done:
-	}
-
-	return resp, body, err
-}
diff --git a/vendor/github.com/prometheus/client_golang/api/prometheus/v1/api.go b/vendor/github.com/prometheus/client_golang/api/prometheus/v1/api.go
deleted file mode 100644
index 642418890..000000000
--- a/vendor/github.com/prometheus/client_golang/api/prometheus/v1/api.go
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright 2017 The Prometheus 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.
-
-// +build go1.7
-
-// Package v1 provides bindings to the Prometheus HTTP API v1:
-// http://prometheus.io/docs/querying/api/
-package v1
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"net/http"
-	"strconv"
-	"time"
-
-	"github.com/prometheus/client_golang/api"
-	"github.com/prometheus/common/model"
-)
-
-const (
-	statusAPIError = 422
-
-	apiPrefix = "/api/v1"
-
-	epAlertManagers   = apiPrefix + "/alertmanagers"
-	epQuery           = apiPrefix + "/query"
-	epQueryRange      = apiPrefix + "/query_range"
-	epLabelValues     = apiPrefix + "/label/:name/values"
-	epSeries          = apiPrefix + "/series"
-	epTargets         = apiPrefix + "/targets"
-	epSnapshot        = apiPrefix + "/admin/tsdb/snapshot"
-	epDeleteSeries    = apiPrefix + "/admin/tsdb/delete_series"
-	epCleanTombstones = apiPrefix + "/admin/tsdb/clean_tombstones"
-	epConfig          = apiPrefix + "/status/config"
-	epFlags           = apiPrefix + "/status/flags"
-)
-
-// ErrorType models the different API error types.
-type ErrorType string
-
-// HealthStatus models the health status of a scrape target.
-type HealthStatus string
-
-const (
-	// Possible values for ErrorType.
-	ErrBadData     ErrorType = "bad_data"
-	ErrTimeout     ErrorType = "timeout"
-	ErrCanceled    ErrorType = "canceled"
-	ErrExec        ErrorType = "execution"
-	ErrBadResponse ErrorType = "bad_response"
-	ErrServer      ErrorType = "server_error"
-	ErrClient      ErrorType = "client_error"
-
-	// Possible values for HealthStatus.
-	HealthGood    HealthStatus = "up"
-	HealthUnknown HealthStatus = "unknown"
-	HealthBad     HealthStatus = "down"
-)
-
-// Error is an error returned by the API.
-type Error struct {
-	Type   ErrorType
-	Msg    string
-	Detail string
-}
-
-func (e *Error) Error() string {
-	return fmt.Sprintf("%s: %s", e.Type, e.Msg)
-}
-
-// Range represents a sliced time range.
-type Range struct {
-	// The boundaries of the time range.
-	Start, End time.Time
-	// The maximum time between two slices within the boundaries.
-	Step time.Duration
-}
-
-// API provides bindings for Prometheus's v1 API.
-type API interface {
-	// AlertManagers returns an overview of the current state of the Prometheus alert manager discovery.
-	AlertManagers(ctx context.Context) (AlertManagersResult, error)
-	// CleanTombstones removes the deleted data from disk and cleans up the existing tombstones.
-	CleanTombstones(ctx context.Context) error
-	// Config returns the current Prometheus configuration.
-	Config(ctx context.Context) (ConfigResult, error)
-	// DeleteSeries deletes data for a selection of series in a time range.
-	DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error
-	// Flags returns the flag values that Prometheus was launched with.
-	Flags(ctx context.Context) (FlagsResult, error)
-	// LabelValues performs a query for the values of the given label.
-	LabelValues(ctx context.Context, label string) (model.LabelValues, error)
-	// Query performs a query for the given time.
-	Query(ctx context.Context, query string, ts time.Time) (model.Value, error)
-	// QueryRange performs a query for the given range.
-	QueryRange(ctx context.Context, query string, r Range) (model.Value, error)
-	// Series finds series by label matchers.
-	Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error)
-	// Snapshot creates a snapshot of all current data into snapshots/<datetime>-<rand>
-	// under the TSDB's data directory and returns the directory as response.
-	Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, error)
-	// Targets returns an overview of the current state of the Prometheus target discovery.
-	Targets(ctx context.Context) (TargetsResult, error)
-}
-
-// AlertManagersResult contains the result from querying the alertmanagers endpoint.
-type AlertManagersResult struct {
-	Active  []AlertManager `json:"activeAlertManagers"`
-	Dropped []AlertManager `json:"droppedAlertManagers"`
-}
-
-// AlertManager models a configured Alert Manager.
-type AlertManager struct {
-	URL string `json:"url"`
-}
-
-// ConfigResult contains the result from querying the config endpoint.
-type ConfigResult struct {
-	YAML string `json:"yaml"`
-}
-
-// FlagsResult contains the result from querying the flag endpoint.
-type FlagsResult map[string]string
-
-// SnapshotResult contains the result from querying the snapshot endpoint.
-type SnapshotResult struct {
-	Name string `json:"name"`
-}
-
-// TargetsResult contains the result from querying the targets endpoint.
-type TargetsResult struct {
-	Active  []ActiveTarget  `json:"activeTargets"`
-	Dropped []DroppedTarget `json:"droppedTargets"`
-}
-
-// ActiveTarget models an active Prometheus scrape target.
-type ActiveTarget struct {
-	DiscoveredLabels model.LabelSet `json:"discoveredLabels"`
-	Labels           model.LabelSet `json:"labels"`
-	ScrapeURL        string         `json:"scrapeUrl"`
-	LastError        string         `json:"lastError"`
-	LastScrape       time.Time      `json:"lastScrape"`
-	Health           HealthStatus   `json:"health"`
-}
-
-// DroppedTarget models a dropped Prometheus scrape target.
-type DroppedTarget struct {
-	DiscoveredLabels model.LabelSet `json:"discoveredLabels"`
-}
-
-// queryResult contains result data for a query.
-type queryResult struct {
-	Type   model.ValueType `json:"resultType"`
-	Result interface{}     `json:"result"`
-
-	// The decoded value.
-	v model.Value
-}
-
-func (qr *queryResult) UnmarshalJSON(b []byte) error {
-	v := struct {
-		Type   model.ValueType `json:"resultType"`
-		Result json.RawMessage `json:"result"`
-	}{}
-
-	err := json.Unmarshal(b, &v)
-	if err != nil {
-		return err
-	}
-
-	switch v.Type {
-	case model.ValScalar:
-		var sv model.Scalar
-		err = json.Unmarshal(v.Result, &sv)
-		qr.v = &sv
-
-	case model.ValVector:
-		var vv model.Vector
-		err = json.Unmarshal(v.Result, &vv)
-		qr.v = vv
-
-	case model.ValMatrix:
-		var mv model.Matrix
-		err = json.Unmarshal(v.Result, &mv)
-		qr.v = mv
-
-	default:
-		err = fmt.Errorf("unexpected value type %q", v.Type)
-	}
-	return err
-}
-
-// NewAPI returns a new API for the client.
-//
-// It is safe to use the returned API from multiple goroutines.
-func NewAPI(c api.Client) API {
-	return &httpAPI{client: apiClient{c}}
-}
-
-type httpAPI struct {
-	client api.Client
-}
-
-func (h *httpAPI) AlertManagers(ctx context.Context) (AlertManagersResult, error) {
-	u := h.client.URL(epAlertManagers, nil)
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return AlertManagersResult{}, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return AlertManagersResult{}, err
-	}
-
-	var res AlertManagersResult
-	err = json.Unmarshal(body, &res)
-	return res, err
-}
-
-func (h *httpAPI) CleanTombstones(ctx context.Context) error {
-	u := h.client.URL(epCleanTombstones, nil)
-
-	req, err := http.NewRequest(http.MethodPost, u.String(), nil)
-	if err != nil {
-		return err
-	}
-
-	_, _, err = h.client.Do(ctx, req)
-	return err
-}
-
-func (h *httpAPI) Config(ctx context.Context) (ConfigResult, error) {
-	u := h.client.URL(epConfig, nil)
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return ConfigResult{}, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return ConfigResult{}, err
-	}
-
-	var res ConfigResult
-	err = json.Unmarshal(body, &res)
-	return res, err
-}
-
-func (h *httpAPI) DeleteSeries(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) error {
-	u := h.client.URL(epDeleteSeries, nil)
-	q := u.Query()
-
-	for _, m := range matches {
-		q.Add("match[]", m)
-	}
-
-	q.Set("start", startTime.Format(time.RFC3339Nano))
-	q.Set("end", endTime.Format(time.RFC3339Nano))
-
-	u.RawQuery = q.Encode()
-
-	req, err := http.NewRequest(http.MethodPost, u.String(), nil)
-	if err != nil {
-		return err
-	}
-
-	_, _, err = h.client.Do(ctx, req)
-	return err
-}
-
-func (h *httpAPI) Flags(ctx context.Context) (FlagsResult, error) {
-	u := h.client.URL(epFlags, nil)
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return FlagsResult{}, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return FlagsResult{}, err
-	}
-
-	var res FlagsResult
-	err = json.Unmarshal(body, &res)
-	return res, err
-}
-
-func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
-	u := h.client.URL(epLabelValues, map[string]string{"name": label})
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return nil, err
-	}
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-	var labelValues model.LabelValues
-	err = json.Unmarshal(body, &labelValues)
-	return labelValues, err
-}
-
-func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
-	u := h.client.URL(epQuery, nil)
-	q := u.Query()
-
-	q.Set("query", query)
-	if !ts.IsZero() {
-		q.Set("time", ts.Format(time.RFC3339Nano))
-	}
-
-	u.RawQuery = q.Encode()
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return nil, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-
-	var qres queryResult
-	err = json.Unmarshal(body, &qres)
-
-	return model.Value(qres.v), err
-}
-
-func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, error) {
-	u := h.client.URL(epQueryRange, nil)
-	q := u.Query()
-
-	var (
-		start = r.Start.Format(time.RFC3339Nano)
-		end   = r.End.Format(time.RFC3339Nano)
-		step  = strconv.FormatFloat(r.Step.Seconds(), 'f', 3, 64)
-	)
-
-	q.Set("query", query)
-	q.Set("start", start)
-	q.Set("end", end)
-	q.Set("step", step)
-
-	u.RawQuery = q.Encode()
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return nil, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-
-	var qres queryResult
-	err = json.Unmarshal(body, &qres)
-
-	return model.Value(qres.v), err
-}
-
-func (h *httpAPI) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) {
-	u := h.client.URL(epSeries, nil)
-	q := u.Query()
-
-	for _, m := range matches {
-		q.Add("match[]", m)
-	}
-
-	q.Set("start", startTime.Format(time.RFC3339Nano))
-	q.Set("end", endTime.Format(time.RFC3339Nano))
-
-	u.RawQuery = q.Encode()
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return nil, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return nil, err
-	}
-
-	var mset []model.LabelSet
-	err = json.Unmarshal(body, &mset)
-	return mset, err
-}
-
-func (h *httpAPI) Snapshot(ctx context.Context, skipHead bool) (SnapshotResult, error) {
-	u := h.client.URL(epSnapshot, nil)
-	q := u.Query()
-
-	q.Set("skip_head", strconv.FormatBool(skipHead))
-
-	u.RawQuery = q.Encode()
-
-	req, err := http.NewRequest(http.MethodPost, u.String(), nil)
-	if err != nil {
-		return SnapshotResult{}, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return SnapshotResult{}, err
-	}
-
-	var res SnapshotResult
-	err = json.Unmarshal(body, &res)
-	return res, err
-}
-
-func (h *httpAPI) Targets(ctx context.Context) (TargetsResult, error) {
-	u := h.client.URL(epTargets, nil)
-
-	req, err := http.NewRequest(http.MethodGet, u.String(), nil)
-	if err != nil {
-		return TargetsResult{}, err
-	}
-
-	_, body, err := h.client.Do(ctx, req)
-	if err != nil {
-		return TargetsResult{}, err
-	}
-
-	var res TargetsResult
-	err = json.Unmarshal(body, &res)
-	return res, err
-}
-
-// apiClient wraps a regular client and processes successful API responses.
-// Successful also includes responses that errored at the API level.
-type apiClient struct {
-	api.Client
-}
-
-type apiResponse struct {
-	Status    string          `json:"status"`
-	Data      json.RawMessage `json:"data"`
-	ErrorType ErrorType       `json:"errorType"`
-	Error     string          `json:"error"`
-}
-
-func apiError(code int) bool {
-	// These are the codes that Prometheus sends when it returns an error.
-	return code == statusAPIError || code == http.StatusBadRequest
-}
-
-func errorTypeAndMsgFor(resp *http.Response) (ErrorType, string) {
-	switch resp.StatusCode / 100 {
-	case 4:
-		return ErrClient, fmt.Sprintf("client error: %d", resp.StatusCode)
-	case 5:
-		return ErrServer, fmt.Sprintf("server error: %d", resp.StatusCode)
-	}
-	return ErrBadResponse, fmt.Sprintf("bad response code %d", resp.StatusCode)
-}
-
-func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
-	resp, body, err := c.Client.Do(ctx, req)
-	if err != nil {
-		return resp, body, err
-	}
-
-	code := resp.StatusCode
-
-	if code/100 != 2 && !apiError(code) {
-		errorType, errorMsg := errorTypeAndMsgFor(resp)
-		return resp, body, &Error{
-			Type:   errorType,
-			Msg:    errorMsg,
-			Detail: string(body),
-		}
-	}
-
-	var result apiResponse
-
-	if http.StatusNoContent != code {
-		if err = json.Unmarshal(body, &result); err != nil {
-			return resp, body, &Error{
-				Type: ErrBadResponse,
-				Msg:  err.Error(),
-			}
-		}
-	}
-
-	if apiError(code) != (result.Status == "error") {
-		err = &Error{
-			Type: ErrBadResponse,
-			Msg:  "inconsistent body for response code",
-		}
-	}
-
-	if apiError(code) && result.Status == "error" {
-		err = &Error{
-			Type: result.ErrorType,
-			Msg:  result.Error,
-		}
-	}
-
-	return resp, []byte(result.Data), err
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5e5a4e26f..b70eb18b9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -308,8 +308,6 @@ github.com/pborman/uuid
 github.com/pkg/errors
 # github.com/prometheus/client_golang v1.5.0 => github.com/prometheus/client_golang v0.9.2
 ## explicit
-github.com/prometheus/client_golang/api
-github.com/prometheus/client_golang/api/prometheus/v1
 github.com/prometheus/client_golang/prometheus
 github.com/prometheus/client_golang/prometheus/internal
 github.com/prometheus/client_golang/prometheus/promhttp
@@ -1148,7 +1146,7 @@ k8s.io/utils/integer
 k8s.io/utils/path
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/caching v0.0.0-20200519161457-43a93f35737e
+# knative.dev/caching v0.0.0-20200521155757-e78d17bc250e
 ## explicit
 knative.dev/caching/config
 knative.dev/caching/pkg/apis/caching
@@ -1257,7 +1255,6 @@ knative.dev/pkg/test/mako/alerter/slack
 knative.dev/pkg/test/mako/config
 knative.dev/pkg/test/monitoring
 knative.dev/pkg/test/performance
-knative.dev/pkg/test/prometheus
 knative.dev/pkg/test/prow
 knative.dev/pkg/test/slackutil
 knative.dev/pkg/test/spoof


Test patch:
diff --git a/pkg/apis/autoscaling/v1alpha1/metric_types_test.go b/pkg/apis/autoscaling/v1alpha1/metric_types_test.go
index 8c0363982..3f1de95fc 100644
--- a/pkg/apis/autoscaling/v1alpha1/metric_types_test.go
+++ b/pkg/apis/autoscaling/v1alpha1/metric_types_test.go
@@ -27,7 +27,7 @@ func TestMetricGetStatus(t *testing.T) {
 	}
 
 	if got, want := r.GetStatus(), &r.Status.Status; got != want {
-		t.Errorf("GotStatus=%v, want=%v", got, want)
+		t.Errorf("GetStatus=%v, want=%v", got, want)
 	}
 }
 
diff --git a/pkg/apis/autoscaling/v1alpha1/pa_defaults_test.go b/pkg/apis/autoscaling/v1alpha1/pa_defaults_test.go
index 52e60a508..253d42002 100644
--- a/pkg/apis/autoscaling/v1alpha1/pa_defaults_test.go
+++ b/pkg/apis/autoscaling/v1alpha1/pa_defaults_test.go
@@ -60,6 +60,12 @@ func TestPodAutoscalerDefaulting(t *testing.T) {
 				},
 				Data: map[string]string{},
 			})
+			s.OnConfigChanged(&v1.ConfigMap{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: config.FeaturesConfigName,
+				},
+				Data: map[string]string{},
+			})
 			s.OnConfigChanged(&v1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: autoscalerconfig.ConfigName,
diff --git a/pkg/apis/autoscaling/v1alpha1/pa_types_test.go b/pkg/apis/autoscaling/v1alpha1/pa_types_test.go
index 865fb297b..c2b80debd 100644
--- a/pkg/apis/autoscaling/v1alpha1/pa_types_test.go
+++ b/pkg/apis/autoscaling/v1alpha1/pa_types_test.go
@@ -27,7 +27,7 @@ func TestPodAutoscalerGetStatus(t *testing.T) {
 	}
 
 	if got, want := r.GetStatus(), &r.Status.Status; got != want {
-		t.Errorf("GotStatus=%v, want=%v", got, want)
+		t.Errorf("GetStatus=%v, want=%v", got, want)
 	}
 }
 
diff --git a/pkg/apis/config/defaults_test.go b/pkg/apis/config/defaults_test.go
index b534f4eb4..e5c99a163 100644
--- a/pkg/apis/config/defaults_test.go
+++ b/pkg/apis/config/defaults_test.go
@@ -35,21 +35,22 @@ func TestDefaultsConfigurationFromFile(t *testing.T) {
 	cm, example := ConfigMapsFromTestFile(t, DefaultsConfigName)
 
 	if _, err := NewDefaultsConfigFromConfigMap(cm); err != nil {
-		t.Errorf("NewDefaultsConfigFromConfigMap(actual) = %v", err)
+		t.Error("NewDefaultsConfigFromConfigMap(actual) =", err)
 	}
 
-	if got, err := NewDefaultsConfigFromConfigMap(example); err != nil {
-		t.Errorf("NewDefaultsConfigFromConfigMap(example) = %v", err)
-	} else {
-		// Those are in example, to show usage,
-		// but default is nil, i.e. inheriting k8s.
-		// So for this test we ignore those, but verify the other fields.
-		got.RevisionCPULimit, got.RevisionCPURequest = nil, nil
-		got.RevisionMemoryLimit, got.RevisionMemoryRequest = nil, nil
-		if want := defaultConfig(); !cmp.Equal(got, want) {
-			t.Errorf("Example does not represent default config: diff(-want,+got)\n%s",
-				cmp.Diff(want, got))
-		}
+	got, err := NewDefaultsConfigFromConfigMap(example)
+	if err != nil {
+		t.Fatal("NewDefaultsConfigFromConfigMap(example) =", err)
+	}
+
+	// Those are in example, to show usage,
+	// but default is nil, i.e. inheriting k8s.
+	// So for this test we ignore those, but verify the other fields.
+	got.RevisionCPULimit, got.RevisionCPURequest = nil, nil
+	got.RevisionMemoryLimit, got.RevisionMemoryRequest = nil, nil
+	want := defaultDefaultsConfig()
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Error("Example does not represent default config: diff(-want,+got)\n", diff)
 	}
 }
 
@@ -64,22 +65,19 @@ func TestDefaultsConfiguration(t *testing.T) {
 	}{{
 		name:         "default configuration",
 		wantErr:      false,
-		wantDefaults: defaultConfig(),
+		wantDefaults: defaultDefaultsConfig(),
 		data:         map[string]string{},
 	}, {
 		name:    "specified values",
 		wantErr: false,
 		wantDefaults: &Defaults{
-			EnableMultiContainer:          true,
-			RevisionTimeoutSeconds:        123,
-			MaxRevisionTimeoutSeconds:     456,
-			ContainerConcurrencyMaxLimit:  1984,
-			RevisionCPURequest:            &oneTwoThree,
-			UserContainerNameTemplate:     "{{.Name}}",
-			AllowContainerConcurrencyZero: false,
+			RevisionTimeoutSeconds:       123,
+			MaxRevisionTimeoutSeconds:    456,
+			ContainerConcurrencyMaxLimit: 1984,
+			RevisionCPURequest:           &oneTwoThree,
+			UserContainerNameTemplate:    "{{.Name}}",
 		},
 		data: map[string]string{
-			"enable-multi-container":           "true",
 			"revision-timeout-seconds":         "123",
 			"max-revision-timeout-seconds":     "456",
 			"revision-cpu-request":             "123m",
@@ -91,7 +89,6 @@ func TestDefaultsConfiguration(t *testing.T) {
 		name:    "invalid multi container flag value",
 		wantErr: false,
 		wantDefaults: &Defaults{
-			EnableMultiContainer:          false,
 			RevisionTimeoutSeconds:        DefaultRevisionTimeoutSeconds,
 			MaxRevisionTimeoutSeconds:     DefaultMaxRevisionTimeoutSeconds,
 			UserContainerNameTemplate:     DefaultUserContainerName,
@@ -105,7 +102,6 @@ func TestDefaultsConfiguration(t *testing.T) {
 		name:    "invalid allow container concurrency zero flag value",
 		wantErr: false,
 		wantDefaults: &Defaults{
-			EnableMultiContainer:          false,
 			RevisionTimeoutSeconds:        DefaultRevisionTimeoutSeconds,
 			MaxRevisionTimeoutSeconds:     DefaultMaxRevisionTimeoutSeconds,
 			UserContainerNameTemplate:     DefaultUserContainerName,
@@ -212,7 +208,7 @@ func TestTemplating(t *testing.T) {
 				},
 			})
 			if err != nil {
-				t.Errorf("Error parsing defaults: %v", err)
+				t.Fatal("Error parsing defaults:", err)
 			}
 
 			ctx := apis.WithinParent(context.Background(), metav1.ObjectMeta{
diff --git a/pkg/apis/config/features_test.go b/pkg/apis/config/features_test.go
new file mode 100644
index 000000000..d0972ca84
--- /dev/null
+++ b/pkg/apis/config/features_test.go
@@ -0,0 +1,93 @@
+/*
+Copyright 2020 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.
+*/
+
+package config
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	corev1 "k8s.io/api/core/v1"
+	. "knative.dev/pkg/configmap/testing"
+	_ "knative.dev/pkg/system/testing"
+)
+
+func TestFeaturesConfigurationFromFile(t *testing.T) {
+	cm, example := ConfigMapsFromTestFile(t, FeaturesConfigName)
+
+	if _, err := NewFeaturesConfigFromConfigMap(cm); err != nil {
+		t.Error("NewFeaturesConfigFromConfigMap(actual) =", err)
+	}
+
+	got, err := NewFeaturesConfigFromConfigMap(example)
+	if err != nil {
+		t.Fatal("NewFeaturesConfigFromConfigMap(example) =", err)
+	}
+
+	want := defaultFeaturesConfig()
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Error("Example does not represent default config: diff(-want,+got)\n", diff)
+	}
+}
+
+func TestFeaturesConfiguration(t *testing.T) {
+	configTests := []struct {
+		name         string
+		wantErr      bool
+		wantFeatures *Features
+		data         map[string]string
+	}{{
+		name:         "default configuration",
+		wantErr:      false,
+		wantFeatures: defaultFeaturesConfig(),
+		data:         map[string]string{},
+	}, {
+		name:    "multi-container Allowed",
+		wantErr: false,
+		wantFeatures: &Features{
+			MultiContainer: Allowed,
+		},
+		data: map[string]string{
+			"multi-container": "Allowed",
+		},
+	}, {
+		name:    "multi-container Enabled",
+		wantErr: false,
+		wantFeatures: &Features{
+			MultiContainer: Enabled,
+		},
+		data: map[string]string{
+			"multi-container": "Enabled",
+		},
+	}}
+
+	for _, tt := range configTests {
+		t.Run(tt.name, func(t *testing.T) {
+			actualFeatures, err := NewFeaturesConfigFromConfigMap(&corev1.ConfigMap{
+				Data: tt.data,
+			})
+
+			if (err != nil) != tt.wantErr {
+				t.Fatalf("NewFeaturesConfigFromConfigMap() error = %v, WantErr %v", err, tt.wantErr)
+			}
+
+			got, want := actualFeatures, tt.wantFeatures
+			if diff := cmp.Diff(want, got); diff != "" {
+				t.Error("Config mismatch: diff(-want,+got):\n", diff)
+			}
+		})
+	}
+}
diff --git a/pkg/apis/config/store_test.go b/pkg/apis/config/store_test.go
index 11ec92d35..2debf2d59 100644
--- a/pkg/apis/config/store_test.go
+++ b/pkg/apis/config/store_test.go
@@ -37,9 +37,11 @@ func TestStoreLoadWithContext(t *testing.T) {
 	store := NewStore(logtesting.TestLogger(t))
 
 	defaultsConfig := ConfigMapFromTestFile(t, DefaultsConfigName)
+	featuresConfig := ConfigMapFromTestFile(t, FeaturesConfigName)
 	autoscalerConfig := ConfigMapFromTestFile(t, autoscalerconfig.ConfigName)
 
 	store.OnConfigChanged(defaultsConfig)
+	store.OnConfigChanged(featuresConfig)
 	store.OnConfigChanged(autoscalerConfig)
 
 	config := FromContextOrDefaults(store.ToContext(context.Background()))
@@ -47,34 +49,49 @@ func TestStoreLoadWithContext(t *testing.T) {
 	t.Run("defaults", func(t *testing.T) {
 		expected, _ := NewDefaultsConfigFromConfigMap(defaultsConfig)
 		if diff := cmp.Diff(expected, config.Defaults, ignoreStuff...); diff != "" {
-			t.Errorf("Unexpected defaults config (-want, +got): %v", diff)
+			t.Errorf("Unexpected defaults config (-want, +got):\n%v", diff)
+		}
+	})
+
+	t.Run("features", func(t *testing.T) {
+		expected, _ := NewFeaturesConfigFromConfigMap(featuresConfig)
+		if diff := cmp.Diff(expected, config.Features, ignoreStuff...); diff != "" {
+			t.Errorf("Unexpected features config (-want, +got):\n%v", diff)
 		}
 	})
 
 	t.Run("autoscaler", func(t *testing.T) {
 		expected, _ := autoscalerconfig.NewConfigFromConfigMap(autoscalerConfig)
 		if diff := cmp.Diff(expected, config.Autoscaler, ignoreStuff...); diff != "" {
-			t.Errorf("Unexpected autoscaler config (-want, +got): %v", diff)
+			t.Errorf("Unexpected autoscaler config (-want, +got):\n%v", diff)
 		}
 	})
 }
 
 func TestStoreLoadWithContextOrDefaults(t *testing.T) {
 	defaultsConfig := ConfigMapFromTestFile(t, DefaultsConfigName)
+	featuresConfig := ConfigMapFromTestFile(t, FeaturesConfigName)
 	autoscalerConfig := ConfigMapFromTestFile(t, autoscalerconfig.ConfigName)
 	config := FromContextOrDefaults(context.Background())
 
 	t.Run("defaults", func(t *testing.T) {
 		expected, _ := NewDefaultsConfigFromConfigMap(defaultsConfig)
 		if diff := cmp.Diff(expected, config.Defaults, ignoreStuff...); diff != "" {
-			t.Errorf("Unexpected defaults config (-want, +got): %v", diff)
+			t.Errorf("Unexpected defaults config (-want, +got):\n%v", diff)
+		}
+	})
+
+	t.Run("features", func(t *testing.T) {
+		expected, _ := NewFeaturesConfigFromConfigMap(featuresConfig)
+		if diff := cmp.Diff(expected, config.Features, ignoreStuff...); diff != "" {
+			t.Errorf("Unexpected features config (-want, +got):\n%v", diff)
 		}
 	})
 
 	t.Run("autoscaler", func(t *testing.T) {
 		expected, _ := autoscalerconfig.NewConfigFromConfigMap(autoscalerConfig)
 		if diff := cmp.Diff(expected, config.Autoscaler, ignoreStuff...); diff != "" {
-			t.Errorf("Unexpected autoscaler config (-want, +got): %v", diff)
+			t.Errorf("Unexpected autoscaler config (-want, +got):\n%v", diff)
 		}
 	})
 }
@@ -83,11 +100,13 @@ func TestStoreImmutableConfig(t *testing.T) {
 	store := NewStore(logtesting.TestLogger(t))
 
 	store.OnConfigChanged(ConfigMapFromTestFile(t, DefaultsConfigName))
+	store.OnConfigChanged(ConfigMapFromTestFile(t, FeaturesConfigName))
 	store.OnConfigChanged(ConfigMapFromTestFile(t, autoscalerconfig.ConfigName))
 
 	config := store.Load()
 
 	config.Defaults.RevisionTimeoutSeconds = 1234
+	config.Features.MultiContainer = Enabled
 	config.Autoscaler.TargetBurstCapacity = 99
 
 	newConfig := store.Load()
@@ -96,6 +115,10 @@ func TestStoreImmutableConfig(t *testing.T) {
 		t.Error("Defaults config is not immutable")
 	}
 
+	if newConfig.Features.MultiContainer == Enabled {
+		t.Error("Features config is not immutable")
+	}
+
 	if newConfig.Autoscaler.TargetBurstCapacity == 99 {
 		t.Error("Autoscaler config is not immutable")
 	}
diff --git a/pkg/apis/config/testdata/config-features.yaml b/pkg/apis/config/testdata/config-features.yaml
new file mode 120000
index 000000000..e9cda5cbe
--- /dev/null
+++ b/pkg/apis/config/testdata/config-features.yaml
@@ -0,0 +1,1 @@
+../../../../config/core/configmaps/features.yaml
\ No newline at end of file
diff --git a/pkg/apis/networking/v1alpha1/certificate_lifecycle_test.go b/pkg/apis/networking/v1alpha1/certificate_lifecycle_test.go
index eed31127a..066b1a563 100644
--- a/pkg/apis/networking/v1alpha1/certificate_lifecycle_test.go
+++ b/pkg/apis/networking/v1alpha1/certificate_lifecycle_test.go
@@ -49,7 +49,7 @@ func TestCertificateGetConditionSet(t *testing.T) {
 	r := &Certificate{}
 
 	if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want {
-		t.Errorf("GotConditionSet=%v, want=%v", got, want)
+		t.Errorf("GetConditionSet=%v, want=%v", got, want)
 	}
 }
 
diff --git a/pkg/apis/networking/v1alpha1/ingress_lifecycle_test.go b/pkg/apis/networking/v1alpha1/ingress_lifecycle_test.go
index c4bf343da..af2d8fa11 100644
--- a/pkg/apis/networking/v1alpha1/ingress_lifecycle_test.go
+++ b/pkg/apis/networking/v1alpha1/ingress_lifecycle_test.go
@@ -49,7 +49,7 @@ func TestIngressGetConditionSet(t *testing.T) {
 	r := &Ingress{}
 
 	if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want {
-		t.Errorf("GotConditionSet=%v, want=%v", got, want)
+		t.Errorf("GetConditionSet=%v, want=%v", got, want)
 	}
 }
 
diff --git a/pkg/apis/networking/v1alpha1/serverlessservice_lifecycle_test.go b/pkg/apis/networking/v1alpha1/serverlessservice_lifecycle_test.go
index 56408e07a..88205aaef 100644
--- a/pkg/apis/networking/v1alpha1/serverlessservice_lifecycle_test.go
+++ b/pkg/apis/networking/v1alpha1/serverlessservice_lifecycle_test.go
@@ -48,7 +48,7 @@ func TestServerlessServiceDuckTypes(t *testing.T) {
 func TestServerlessServiceGetConditionSet(t *testing.T) {
 	r := &ServerlessService{}
 	if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want {
-		t.Errorf("GotConditionSet=%v, want=%v", got, want)
+		t.Errorf("GetConditionSet=%v, want=%v", got, want)
 	}
 }
 
diff --git a/pkg/apis/serving/k8s_validation_test.go b/pkg/apis/serving/k8s_validation_test.go
index a644e8380..e78a74a2d 100644
--- a/pkg/apis/serving/k8s_validation_test.go
+++ b/pkg/apis/serving/k8s_validation_test.go
@@ -34,8 +34,8 @@ import (
 
 func enableMultiContainer(ctx context.Context, t *testing.T) context.Context {
 	return config.ToContext(ctx, &config.Config{
-		Defaults: &config.Defaults{
-			EnableMultiContainer: true,
+		Features: &config.Features{
+			MultiContainer: config.Enabled,
 		},
 	})
 }
@@ -168,7 +168,7 @@ func TestPodSpecValidation(t *testing.T) {
 				Image: "helloworld",
 			}},
 		},
-		want: &apis.FieldError{Message: "enable-multi-container is off, but found 2 containers"},
+		want: &apis.FieldError{Message: "multi-container is off, but found 2 containers"},
 	}, {
 		name: "extra field",
 		ps: corev1.PodSpec{
@@ -219,7 +219,7 @@ func TestPodSpecMultiContainerValidation(t *testing.T) {
 				Image: "helloworld",
 			}},
 		},
-		want: &apis.FieldError{Message: "enable-multi-container is off, but found 2 containers"},
+		want: &apis.FieldError{Message: "multi-container is off, but found 2 containers"},
 	}, {
 		name: "flag enabled: more than one container with one container port",
 		ps: corev1.PodSpec{
diff --git a/pkg/apis/serving/v1/revision_defaults_test.go b/pkg/apis/serving/v1/revision_defaults_test.go
index 59583b8cb..f327de9ee 100644
--- a/pkg/apis/serving/v1/revision_defaults_test.go
+++ b/pkg/apis/serving/v1/revision_defaults_test.go
@@ -66,6 +66,7 @@ func TestRevisionDefaulting(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logger)
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
@@ -130,6 +131,7 @@ func TestRevisionDefaulting(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logger)
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
@@ -261,6 +263,7 @@ func TestRevisionDefaulting(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logger)
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
diff --git a/pkg/apis/serving/v1/revision_validation_test.go b/pkg/apis/serving/v1/revision_validation_test.go
index 288594fb4..20dc82e9e 100644
--- a/pkg/apis/serving/v1/revision_validation_test.go
+++ b/pkg/apis/serving/v1/revision_validation_test.go
@@ -383,7 +383,7 @@ func TestRevisionSpecValidation(t *testing.T) {
 				}},
 			},
 		},
-		want: &apis.FieldError{Message: "enable-multi-container is off, but found 2 containers"},
+		want: &apis.FieldError{Message: "multi-container is off, but found 2 containers"},
 	}, {
 		name: "exceed max timeout",
 		rs: &RevisionSpec{
@@ -410,6 +410,7 @@ func TestRevisionSpecValidation(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
@@ -518,6 +519,7 @@ func TestImmutableFields(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
diff --git a/pkg/apis/serving/v1/route_lifecycle_test.go b/pkg/apis/serving/v1/route_lifecycle_test.go
index 7f35cb6ab..8aa5ff4ed 100644
--- a/pkg/apis/serving/v1/route_lifecycle_test.go
+++ b/pkg/apis/serving/v1/route_lifecycle_test.go
@@ -177,7 +177,7 @@ func TestTypicalRouteFlow(t *testing.T) {
 	apistest.CheckConditionOngoing(r, RouteConditionReady, t)
 
 	r.MarkTrafficAssigned()
-	r.MarkAutoTLSNotEnabled()
+	r.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
 	apistest.CheckConditionSucceeded(r, RouteConditionAllTrafficAssigned, t)
 	apistest.CheckConditionOngoing(r, RouteConditionIngressReady, t)
 	apistest.CheckConditionOngoing(r, RouteConditionReady, t)
@@ -291,7 +291,7 @@ func TestIngressFailureRecovery(t *testing.T) {
 	apistest.CheckConditionOngoing(r, RouteConditionReady, t)
 
 	r.MarkTrafficAssigned()
-	r.MarkAutoTLSNotEnabled()
+	r.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
 	r.PropagateIngressStatus(netv1alpha1.IngressStatus{
 		Status: duckv1.Status{
 			Conditions: duckv1.Conditions{{
@@ -386,7 +386,7 @@ func TestRouteNotOwnCertificate(t *testing.T) {
 func TestRouteAutoTLSNotEnabled(t *testing.T) {
 	r := &RouteStatus{}
 	r.InitializeConditions()
-	r.MarkAutoTLSNotEnabled()
+	r.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
 
 	apistest.CheckConditionSucceeded(r, RouteConditionCertificateProvisioned, t)
 }
diff --git a/pkg/apis/serving/v1alpha1/revision_defaults_test.go b/pkg/apis/serving/v1alpha1/revision_defaults_test.go
index b26d4b9a4..a577cd83d 100644
--- a/pkg/apis/serving/v1alpha1/revision_defaults_test.go
+++ b/pkg/apis/serving/v1alpha1/revision_defaults_test.go
@@ -89,6 +89,7 @@ func TestRevisionDefaulting(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
diff --git a/pkg/apis/serving/v1alpha1/revision_validation_test.go b/pkg/apis/serving/v1alpha1/revision_validation_test.go
index 9e21de31f..2c81f043c 100644
--- a/pkg/apis/serving/v1alpha1/revision_validation_test.go
+++ b/pkg/apis/serving/v1alpha1/revision_validation_test.go
@@ -244,6 +244,7 @@ func TestRevisionSpecValidation(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
@@ -645,6 +646,7 @@ func TestImmutableFields(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
diff --git a/pkg/apis/serving/v1alpha1/route_lifecycle_test.go b/pkg/apis/serving/v1alpha1/route_lifecycle_test.go
index b1685869e..8f626abd3 100644
--- a/pkg/apis/serving/v1alpha1/route_lifecycle_test.go
+++ b/pkg/apis/serving/v1alpha1/route_lifecycle_test.go
@@ -160,7 +160,7 @@ func TestTypicalRouteFlow(t *testing.T) {
 	apistest.CheckConditionOngoing(r, RouteConditionReady, t)
 
 	r.MarkTrafficAssigned()
-	r.MarkAutoTLSNotEnabled()
+	r.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
 	apistest.CheckConditionSucceeded(r, RouteConditionAllTrafficAssigned, t)
 	apistest.CheckConditionOngoing(r, RouteConditionIngressReady, t)
 	apistest.CheckConditionOngoing(r, RouteConditionReady, t)
@@ -274,7 +274,7 @@ func TestIngressFailureRecovery(t *testing.T) {
 	apistest.CheckConditionOngoing(r, RouteConditionReady, t)
 
 	r.MarkTrafficAssigned()
-	r.MarkAutoTLSNotEnabled()
+	r.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
 	r.PropagateIngressStatus(netv1alpha1.IngressStatus{
 		Status: duckv1.Status{
 			Conditions: duckv1.Conditions{{
@@ -381,7 +381,7 @@ func TestRouteNotOwnCertificate(t *testing.T) {
 func TestRouteAutoTLSNotEnabled(t *testing.T) {
 	r := &RouteStatus{}
 	r.InitializeConditions()
-	r.MarkAutoTLSNotEnabled()
+	r.MarkTLSNotEnabled(AutoTLSNotEnabledMessage)
 
 	apistest.CheckConditionSucceeded(r, RouteConditionCertificateProvisioned, t)
 }
diff --git a/pkg/apis/serving/v1beta1/revision_defaults_test.go b/pkg/apis/serving/v1beta1/revision_defaults_test.go
index 2b131d917..e88286b62 100644
--- a/pkg/apis/serving/v1beta1/revision_defaults_test.go
+++ b/pkg/apis/serving/v1beta1/revision_defaults_test.go
@@ -67,6 +67,7 @@ func TestRevisionDefaulting(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logger)
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
@@ -131,6 +132,7 @@ func TestRevisionDefaulting(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logger)
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
diff --git a/pkg/apis/serving/v1beta1/revision_validation_test.go b/pkg/apis/serving/v1beta1/revision_validation_test.go
index 4e08987c7..3ee08493b 100644
--- a/pkg/apis/serving/v1beta1/revision_validation_test.go
+++ b/pkg/apis/serving/v1beta1/revision_validation_test.go
@@ -384,7 +384,7 @@ func TestRevisionSpecValidation(t *testing.T) {
 				}},
 			},
 		},
-		want: &apis.FieldError{Message: "enable-multi-container is off, but found 2 containers"},
+		want: &apis.FieldError{Message: "multi-container is off, but found 2 containers"},
 	}, {
 		name: "exceed max timeout",
 		rs: &v1.RevisionSpec{
@@ -411,6 +411,7 @@ func TestRevisionSpecValidation(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
@@ -519,6 +520,7 @@ func TestImmutableFields(t *testing.T) {
 		wc: func(ctx context.Context) context.Context {
 			s := config.NewStore(logtesting.TestLogger(t))
 			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: autoscalerconfig.ConfigName}})
+			s.OnConfigChanged(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: config.FeaturesConfigName}})
 			s.OnConfigChanged(&corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: config.DefaultsConfigName,
diff --git a/pkg/autoscaler/config/config_test.go b/pkg/autoscaler/config/config_test.go
index d03aaa40d..21133d3e6 100644
--- a/pkg/autoscaler/config/config_test.go
+++ b/pkg/autoscaler/config/config_test.go
@@ -203,6 +203,12 @@ func TestNewConfig(t *testing.T) {
 			"max-scale-down-rate": "1",
 		},
 		wantErr: true,
+	}, {
+		name: "stable window too big",
+		input: map[string]string{
+			"stable-window": "1h1s",
+		},
+		wantErr: true,
 	}, {
 		name: "stable window too small",
 		input: map[string]string{
diff --git a/pkg/queue/stats_test.go b/pkg/queue/stats_test.go
index be577d92f..2a2296ef5 100644
--- a/pkg/queue/stats_test.go
+++ b/pkg/queue/stats_test.go
@@ -33,7 +33,7 @@ type reportedStat struct {
 
 func TestNoData(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	got := s.report(now)
 	want := reportedStat{
@@ -47,7 +47,7 @@ func TestNoData(t *testing.T) {
 
 func TestSingleRequestWholeTime(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	s.requestStart(now)
 	now = now.Add(1 * time.Second)
@@ -66,7 +66,7 @@ func TestSingleRequestWholeTime(t *testing.T) {
 
 func TestSingleRequestHalfTime(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	s.requestStart(now)
 	now = now.Add(1 * time.Second)
@@ -85,7 +85,7 @@ func TestSingleRequestHalfTime(t *testing.T) {
 
 func TestVeryShortLivedRequest(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	s.requestStart(now)
 	now = now.Add(10 * time.Millisecond)
@@ -105,7 +105,7 @@ func TestVeryShortLivedRequest(t *testing.T) {
 
 func TestMultipleRequestsWholeTime(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	s.requestStart(now)
 	now = now.Add(300 * time.Millisecond)
@@ -132,7 +132,7 @@ func TestMultipleRequestsWholeTime(t *testing.T) {
 
 func TestMultipleRequestsInterleaved(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	s.requestStart(now)
 	now = now.Add(100 * time.Millisecond)
@@ -155,7 +155,7 @@ func TestMultipleRequestsInterleaved(t *testing.T) {
 
 func TestOneRequestAcrossReportings(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 
 	s.requestStart(now)
 	now = now.Add(1 * time.Second)
@@ -184,7 +184,7 @@ func TestOneRequestAcrossReportings(t *testing.T) {
 
 func TestOneProxiedRequest(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 	s.proxiedStart(now)
 	now = now.Add(1 * time.Second)
 	got := s.report(now)
@@ -201,7 +201,7 @@ func TestOneProxiedRequest(t *testing.T) {
 
 func TestOneEndedProxiedRequest(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 	s.proxiedStart(now)
 	now = now.Add(500 * time.Millisecond)
 	s.proxiedEnd(now)
@@ -220,7 +220,7 @@ func TestOneEndedProxiedRequest(t *testing.T) {
 
 func TestTwoRequestsOneProxied(t *testing.T) {
 	now := time.Now()
-	s := newTestStats(now)
+	s := newTestStats(t, now)
 	s.proxiedStart(now)
 	now = now.Add(500 * time.Millisecond)
 	s.proxiedEnd(now)
@@ -245,9 +245,11 @@ type testStats struct {
 	statChan     chan reportedStat
 }
 
-func newTestStats(now time.Time) *testStats {
-	reportBiChan := make(chan time.Time)
+func newTestStats(t *testing.T, now time.Time) *testStats {
 	reqChan := make(chan network.ReqEvent)
+	t.Cleanup(func() { close(reqChan) })
+
+	reportBiChan := make(chan time.Time)
 	statChan := make(chan reportedStat)
 	report := func(acr float64, apcr float64, rc float64, prc float64) {
 		statChan <- reportedStat{
diff --git a/pkg/reconciler/route/table_test.go b/pkg/reconciler/route/table_test.go
index f8694c521..b5cec4151 100644
--- a/pkg/reconciler/route/table_test.go
+++ b/pkg/reconciler/route/table_test.go
@@ -2350,7 +2350,7 @@ func TestReconcile_EnableAutoTLS(t *testing.T) {
 		WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
 			Object: Route("default", "becomes-local", WithConfigTarget("config"),
 				WithRouteUID("65-23"),
-				MarkTrafficAssigned, MarkIngressNotConfigured,
+				MarkTrafficAssigned, MarkIngressNotConfigured, WithRouteConditionsTLSNotEnabledForClusterLocalMessage,
 				WithLocalDomain, WithAddress, WithInitRouteConditions,
 				WithRouteLabel(map[string]string{serving.VisibilityLabelKey: serving.VisibilityClusterLocal}),
 				WithStatusTraffic(
diff --git a/pkg/testing/v1/route.go b/pkg/testing/v1/route.go
index 54394f379..77b3aee67 100644
--- a/pkg/testing/v1/route.go
+++ b/pkg/testing/v1/route.go
@@ -159,10 +159,18 @@ func WithInitRouteConditions(rt *v1.Route) {
 	rt.Status.InitializeConditions()
 }
 
-// WithRouteConditionsAutoTLSDisabled calls MarkAutoTLSNotEnabled after initialized the Service's conditions.
+// WithRouteConditionsAutoTLSDisabled calls MarkTLSNotEnabled with AutoTLSNotEnabledMessage
+// after initialized the Service's conditions.
 func WithRouteConditionsAutoTLSDisabled(rt *v1.Route) {
 	rt.Status.InitializeConditions()
-	rt.Status.MarkAutoTLSNotEnabled()
+	rt.Status.MarkTLSNotEnabled(v1.AutoTLSNotEnabledMessage)
+}
+
+// TLSNotEnabledForClusterLocalMessage calls MarkTLSNotEnabled with TLSNotEnabledForClusterLocalMessage
+// after initialized the Service's conditions.
+func WithRouteConditionsTLSNotEnabledForClusterLocalMessage(rt *v1.Route) {
+	rt.Status.InitializeConditions()
+	rt.Status.MarkTLSNotEnabled(v1.TLSNotEnabledForClusterLocalMessage)
 }
 
 // WithRouteConditionsHTTPDowngrade calls MarkHTTPDowngrade after initialized the Service's conditions.
diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh
index d21fbc66c..a9a2dce34 100755
--- a/test/e2e-tests.sh
+++ b/test/e2e-tests.sh
@@ -85,11 +85,17 @@ add_trap "kubectl -n ${SYSTEM_NAMESPACE} patch configmap/config-autoscaler --typ
 # Run conformance and e2e tests.
 
 go_test_e2e -timeout=30m \
-  $(go list ./test/conformance/... | grep -v certificate) \
+  $(go list ./test/conformance/... | grep -v 'certificate\|ingress' ) \
   ./test/e2e ./test/e2e/hpa \
   ${parallelism} \
   "--resolvabledomain=$(use_resolvable_domain)" "${use_https}" "$(ingress_class)" || failed=1
 
+# We run KIngress conformance ingress separately, to make it easier to skip some tests.
+go_test_e2e -timeout=20m ./test/conformance/ingress ${parallelism}  \
+  `# Skip TestUpdate due to excessive flaking https://github.com/knative/serving/issues/8032` \
+  -run="Test[^U]" \
+  "--resolvabledomain=$(use_resolvable_domain)" "${use_https}" "$(ingress_class)" || failed=1
+
 if (( HTTPS )); then
   kubectl delete -f ${TMP_DIR}/test/config/autotls/certmanager/caissuer/ --ignore-not-found
   turn_off_auto_tls
diff --git a/test/ha/activator_test.go b/test/ha/activator_test.go
index cd8025ed4..80282dd08 100644
--- a/test/ha/activator_test.go
+++ b/test/ha/activator_test.go
@@ -42,6 +42,7 @@ const (
 )
 
 func TestActivatorHAGraceful(t *testing.T) {
+	t.Skip("TODO(8066): This was added too optimistically. Needs debugging and triaging.")
 	testActivatorHA(t, nil, 1)
 }
 
diff --git a/test/performance/latency_test.go b/test/performance/latency_test.go
index 7af54f07b..47081f451 100644
--- a/test/performance/latency_test.go
+++ b/test/performance/latency_test.go
@@ -49,19 +49,18 @@ const (
 func timeToServe(t *testing.T, img, query string, reqTimeout time.Duration) {
 	t.Helper()
 	tName := t.Name()
-	perfClients, err := Setup(t)
+	clients, err := Setup()
 	if err != nil {
-		t.Fatal("Cannot initialize performance client:", err)
+		t.Fatal("Cannot initialize performance clients:", err)
 	}
 
-	clients := perfClients.E2EClients
 	names := test.ResourceNames{
 		Service: test.ObjectNameForTest(t),
 		Image:   img,
 	}
 
-	defer TearDown(perfClients, names, t.Logf)
-	test.CleanupOnInterrupt(func() { TearDown(perfClients, names, t.Logf) })
+	defer TearDown(clients, names, t.Logf)
+	test.CleanupOnInterrupt(func() { TearDown(clients, names, t.Logf) })
 
 	t.Log("Creating a new Service")
 	objs, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names)
diff --git a/test/performance/observed_concurency_test.go b/test/performance/observed_concurency_test.go
index 1efd838ef..7f6f4eba1 100644
--- a/test/performance/observed_concurency_test.go
+++ b/test/performance/observed_concurency_test.go
@@ -137,7 +137,7 @@ func TestObservedConcurrency(t *testing.T) {
 }
 
 func testConcurrencyN(t *testing.T, concurrency int) []junit.TestCase {
-	perfClients, err := Setup(t)
+	clients, err := Setup()
 	if err != nil {
 		t.Fatal("Cannot initialize performance client:", err)
 	}
@@ -146,10 +146,9 @@ func testConcurrencyN(t *testing.T, concurrency int) []junit.TestCase {
 		Service: test.ObjectNameForTest(t),
 		Image:   "observed-concurrency",
 	}
-	clients := perfClients.E2EClients
 
-	defer TearDown(perfClients, names, t.Logf)
-	test.CleanupOnInterrupt(func() { TearDown(perfClients, names, t.Logf) })
+	defer TearDown(clients, names, t.Logf)
+	test.CleanupOnInterrupt(func() { TearDown(clients, names, t.Logf) })
 
 	t.Log("Creating a new Service")
 	objs, err := v1test.CreateServiceReady(t, clients, &names,
diff --git a/test/performance/performance.go b/test/performance/performance.go
index 0984b4b91..763ced9d3 100644
--- a/test/performance/performance.go
+++ b/test/performance/performance.go
@@ -21,7 +21,6 @@ import (
 	"fmt"
 	"log"
 	"net/http"
-	"testing"
 	"time"
 
 	v1 "k8s.io/api/core/v1"
@@ -30,7 +29,6 @@ import (
 	podinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/pod"
 	pkgTest "knative.dev/pkg/test"
 	"knative.dev/pkg/test/logging"
-	"knative.dev/pkg/test/prometheus"
 	"knative.dev/serving/test"
 
 	"knative.dev/pkg/test/spoof"
@@ -40,50 +38,18 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
 )
 
-const (
-	monitoringNS = "knative-monitoring"
-	duration     = 1 * time.Minute
-
-	EnablePrometheus = iota
-)
-
-// Client is the client used in the performance tests.
-type Client struct {
-	E2EClients *test.Clients
-	PromClient *prometheus.PromProxy
-}
+const duration = 1 * time.Minute
 
 // Setup creates all the clients that we need to interact with in our tests
-func Setup(t *testing.T, monitoring ...int) (*Client, error) {
+func Setup() (*test.Clients, error) {
 	pkgTest.SetupLoggingFlags()
 	clients, err := test.NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, test.ServingNamespace)
-	if err != nil {
-		return nil, err
-	}
-
-	var p *prometheus.PromProxy
-	for _, m := range monitoring {
-		switch m {
-		case EnablePrometheus:
-			t.Log("Creating prometheus proxy client")
-			p = &prometheus.PromProxy{Namespace: monitoringNS}
-			p.Setup(clients.KubeClient.Kube, t.Logf)
-		default:
-			t.Log("No monitoring components enabled")
-		}
-	}
-
-	return &Client{E2EClients: clients, PromClient: p}, nil
+	return clients, err
 }
 
 // TearDown cleans up resources used
-func TearDown(client *Client, names test.ResourceNames, logf logging.FormatLogger) {
-	test.TearDown(client.E2EClients, names)
-
-	// Teardown prometheus client
-	if client.PromClient != nil {
-		client.PromClient.Teardown(logf)
-	}
+func TearDown(clients *test.Clients, names test.ResourceNames, logf logging.FormatLogger) {
+	test.TearDown(clients, names)
 }
 
 // ProbeTargetTillReady will probe the target once per second for the given duration, until it's ready or error happens
@@ -113,7 +79,7 @@ func ProbeTargetTillReady(target string, duration time.Duration) error {
 func WaitForScaleToZero(ctx context.Context, namespace string, selector labels.Selector, duration time.Duration) error {
 	pl := podinformer.Get(ctx).Lister()
 	begin := time.Now()
-	return wait.PollImmediate(1*time.Second, duration, func() (bool, error) {
+	return wait.PollImmediate(time.Second, duration, func() (bool, error) {
 		pods, err := pl.Pods(namespace).List(selector)
 		if err != nil {
 			return false, err
diff --git a/third_party/contour-latest/contour.yaml b/third_party/contour-latest/contour.yaml
index 43bafdbea..14c1ca8b1 100644
--- a/third_party/contour-latest/contour.yaml
+++ b/third_party/contour-latest/contour.yaml
@@ -2,6 +2,8 @@ apiVersion: rbac.authorization.k8s.io/v1beta1
 kind: ClusterRoleBinding
 metadata:
   name: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
@@ -15,24 +17,32 @@ apiVersion: v1
 kind: Namespace
 metadata:
   name: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: contour
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: envoy
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: contour
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 data:
   contour.yaml: |
     leaderelection:
@@ -98,6 +108,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: ingressroutes.contour.heptio.com
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   additionalPrinterColumns:
   - JSONPath: .spec.virtualhost.fqdn
@@ -467,6 +479,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: tlscertificatedelegations.contour.heptio.com
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   group: contour.heptio.com
   names:
@@ -543,6 +557,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: httpproxies.projectcontour.io
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   additionalPrinterColumns:
   - JSONPath: .spec.virtualhost.fqdn
@@ -1278,6 +1294,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: tlscertificatedelegations.projectcontour.io
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   group: projectcontour.io
   names:
@@ -1354,12 +1372,16 @@ kind: ServiceAccount
 metadata:
   name: contour-certgen
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: rbac.authorization.k8s.io/v1beta1
 kind: RoleBinding
 metadata:
   name: contour
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: Role
@@ -1374,6 +1396,8 @@ kind: Role
 metadata:
   name: contour-certgen
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 rules:
 - apiGroups:
   - ""
@@ -1393,6 +1417,8 @@ kind: Job
 metadata:
   name: contour-certgen
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   ttlSecondsAfterFinished: 0
   template:
@@ -1406,7 +1432,7 @@ spec:
         # if we change this on each version, you can no longer upgrade
         # just by applying the deployment YAML.
         # See #2423, #2395, #2150, and #2030 for earlier questions about this.
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         command:
         - contour
@@ -1433,6 +1459,8 @@ apiVersion: rbac.authorization.k8s.io/v1beta1
 kind: ClusterRole
 metadata:
   name: contour
+  labels:
+    networking.knative.dev/ingress-provider: contour
 rules:
 - apiGroups:
   - ""
@@ -1511,6 +1539,8 @@ kind: Role
 metadata:
   name: contour-leaderelection
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 rules:
 - apiGroups:
   - ""
@@ -1536,6 +1566,8 @@ kind: RoleBinding
 metadata:
   name: contour-leaderelection
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: Role
@@ -1550,6 +1582,8 @@ kind: Service
 metadata:
   name: contour
   namespace: contour-external
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   ports:
   - port: 8001
@@ -1573,6 +1607,8 @@ metadata:
     # for information about enabling the PROXY protocol on the ELB to recover
     # the original remote IP address.
     service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   externalTrafficPolicy: Local
   ports:
@@ -1591,6 +1627,7 @@ kind: Deployment
 metadata:
   labels:
     app: contour
+    networking.knative.dev/ingress-provider: contour
   name: contour
   namespace: contour-external
 spec:
@@ -1635,7 +1672,7 @@ spec:
         - --contour-key-file=/certs/tls.key
         - --config-path=/config/contour.yaml
         command: ["contour"]
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         name: contour
         ports:
@@ -1701,6 +1738,7 @@ kind: DaemonSet
 metadata:
   labels:
     app: envoy
+    networking.knative.dev/ingress-provider: contour
   name: envoy
   namespace: contour-external
 spec:
@@ -1726,7 +1764,7 @@ spec:
         args:
         - envoy
         - shutdown-manager
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         lifecycle:
           preStop:
@@ -1802,7 +1840,7 @@ spec:
         - --envoy-key-file=/certs/tls.key
         command:
         - contour
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         name: envoy-initconfig
         volumeMounts:
@@ -1831,14 +1869,14 @@ spec:
         secret:
           secretName: cacert
       restartPolicy: Always
----
-
 
 ---
 apiVersion: rbac.authorization.k8s.io/v1beta1
 kind: ClusterRoleBinding
 metadata:
   name: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: ClusterRole
@@ -1852,24 +1890,32 @@ apiVersion: v1
 kind: Namespace
 metadata:
   name: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: contour
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: v1
 kind: ServiceAccount
 metadata:
   name: envoy
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: contour
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 data:
   contour.yaml: |
     leaderelection:
@@ -1935,6 +1981,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: ingressroutes.contour.heptio.com
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   additionalPrinterColumns:
   - JSONPath: .spec.virtualhost.fqdn
@@ -2304,6 +2352,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: tlscertificatedelegations.contour.heptio.com
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   group: contour.heptio.com
   names:
@@ -2380,6 +2430,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: httpproxies.projectcontour.io
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   additionalPrinterColumns:
   - JSONPath: .spec.virtualhost.fqdn
@@ -3115,6 +3167,8 @@ metadata:
     controller-gen.kubebuilder.io/version: v0.2.4
   creationTimestamp: null
   name: tlscertificatedelegations.projectcontour.io
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   group: projectcontour.io
   names:
@@ -3191,12 +3245,16 @@ kind: ServiceAccount
 metadata:
   name: contour-certgen
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 ---
 apiVersion: rbac.authorization.k8s.io/v1beta1
 kind: RoleBinding
 metadata:
   name: contour
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: Role
@@ -3211,6 +3269,8 @@ kind: Role
 metadata:
   name: contour-certgen
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 rules:
 - apiGroups:
   - ""
@@ -3230,6 +3290,8 @@ kind: Job
 metadata:
   name: contour-certgen
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   ttlSecondsAfterFinished: 0
   template:
@@ -3243,7 +3305,7 @@ spec:
         # if we change this on each version, you can no longer upgrade
         # just by applying the deployment YAML.
         # See #2423, #2395, #2150, and #2030 for earlier questions about this.
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         command:
         - contour
@@ -3270,6 +3332,8 @@ apiVersion: rbac.authorization.k8s.io/v1beta1
 kind: ClusterRole
 metadata:
   name: contour
+  labels:
+    networking.knative.dev/ingress-provider: contour
 rules:
 - apiGroups:
   - ""
@@ -3348,6 +3412,8 @@ kind: Role
 metadata:
   name: contour-leaderelection
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 rules:
 - apiGroups:
   - ""
@@ -3373,6 +3439,8 @@ kind: RoleBinding
 metadata:
   name: contour-leaderelection
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 roleRef:
   apiGroup: rbac.authorization.k8s.io
   kind: Role
@@ -3387,6 +3455,8 @@ kind: Service
 metadata:
   name: contour
   namespace: contour-internal
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   ports:
   - port: 8001
@@ -3410,6 +3480,8 @@ metadata:
     # for information about enabling the PROXY protocol on the ELB to recover
     # the original remote IP address.
     service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp
+  labels:
+    networking.knative.dev/ingress-provider: contour
 spec:
   # externalTrafficPolicy: Local
   ports:
@@ -3428,6 +3500,7 @@ kind: Deployment
 metadata:
   labels:
     app: contour
+    networking.knative.dev/ingress-provider: contour
   name: contour
   namespace: contour-internal
 spec:
@@ -3472,7 +3545,7 @@ spec:
         - --contour-key-file=/certs/tls.key
         - --config-path=/config/contour.yaml
         command: ["contour"]
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         name: contour
         ports:
@@ -3538,6 +3611,7 @@ kind: DaemonSet
 metadata:
   labels:
     app: envoy
+    networking.knative.dev/ingress-provider: contour
   name: envoy
   namespace: contour-internal
 spec:
@@ -3563,7 +3637,7 @@ spec:
         args:
         - envoy
         - shutdown-manager
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         lifecycle:
           preStop:
@@ -3639,7 +3713,7 @@ spec:
         - --envoy-key-file=/certs/tls.key
         command:
         - contour
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:6a39b0cb1005c9c4d033c0e4ea20b86eb17f4561b11ef9087454aeb02cfb5fc6
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:05026eaed72965d6215b3d33578bc8bd35ff65e2c4373464305ee3173f0d9ccd
         imagePullPolicy: Always
         name: envoy-initconfig
         volumeMounts:
@@ -3668,7 +3742,5 @@ spec:
         secret:
           secretName: cacert
       restartPolicy: Always
----
-
 
 ---
diff --git a/third_party/contour-latest/net-contour.yaml b/third_party/contour-latest/net-contour.yaml
index c1d3fda3c..665502523 100644
--- a/third_party/contour-latest/net-contour.yaml
+++ b/third_party/contour-latest/net-contour.yaml
@@ -35,7 +35,7 @@ metadata:
   namespace: knative-serving
   labels:
     networking.knative.dev/ingress-provider: contour
-    serving.knative.dev/release: "v20200521-8096bd0"
+    serving.knative.dev/release: "v20200526-e8fb3d9"
 data:
   _example: |
     ################################
@@ -94,7 +94,7 @@ spec:
       - name: controller
         # This is the Go import path for the binary that is containerized
         # and substituted here.
-        image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:79dde0f3d4cd43eacf229b70c3b0005a0624b57e5ba4acb6145ee5f231d53f38
+        image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:97b343f5065e35af98a6119f10e7d416a64b2c0c53a70208444cb84cfe3fc8c4
         resources:
           requests:
             cpu: 40m
diff --git a/third_party/kourier-latest/kourier.yaml b/third_party/kourier-latest/kourier.yaml
index ac6031fba..c016164c8 100644
--- a/third_party/kourier-latest/kourier.yaml
+++ b/third_party/kourier-latest/kourier.yaml
@@ -115,7 +115,7 @@ spec:
         - /tmp/config/envoy-bootstrap.yaml
         command:
         - /usr/local/bin/envoy
-        image: docker.io/maistra/proxyv2-ubi8:1.0.8
+        image: docker.io/maistra/proxyv2-ubi8:1.1.0
         imagePullPolicy: Always
         name: kourier-gateway
         ports:
@@ -128,16 +128,20 @@ spec:
         volumeMounts:
         - name: config-volume
           mountPath: /tmp/config
+        lifecycle:
+          preStop:
+            exec:
+              command: ["curl", "-X", "POST", "--unix", "/tmp/envoy.admin", "http://localhost/healthcheck/fail"]
         readinessProbe:
           httpGet:
             httpHeaders:
             - name: Host
               value: internalkourier
-            path: /__internalkouriersnapshot
+            path: /ready
             port: 8081
             scheme: HTTP
-          initialDelaySeconds: 5
-          periodSeconds: 2
+          initialDelaySeconds: 10
+          periodSeconds: 5
       volumes:
       - name: config-volume
         configMap:
@@ -162,7 +166,7 @@ spec:
         app: 3scale-kourier-control
     spec:
       containers:
-      - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:725bc36f71568b0a9be3bd98816ed4b76ca48548c5ef48decc8a5199914d119f
+      - image: gcr.io/knative-nightly/knative.dev/net-kourier/cmd/kourier@sha256:f1ec90d11071ec5fbe9e83fa8fa340bf1b338a395e52e4dd3de2f5ce89ad5679
         imagePullPolicy: Always
         name: kourier-control
         env:
diff --git a/vendor/knative.dev/pkg/test/prometheus/prometheus.go b/vendor/knative.dev/pkg/test/prometheus/prometheus.go
deleted file mode 100644
index 270927f23..000000000
--- a/vendor/knative.dev/pkg/test/prometheus/prometheus.go
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-Copyright 2018 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
-
-	https://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package prometheus
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"sync"
-	"time"
-
-	"github.com/prometheus/client_golang/api"
-	v1 "github.com/prometheus/client_golang/api/prometheus/v1"
-	"github.com/prometheus/common/model"
-	"k8s.io/client-go/kubernetes"
-	"knative.dev/pkg/test/logging"
-	"knative.dev/pkg/test/monitoring"
-)
-
-const (
-	prometheusPort = 9090
-	appLabel       = "prometheus"
-)
-
-var (
-	// sync.Once variable to ensure we execute zipkin setup only once.
-	setupOnce sync.Once
-
-	// sync.Once variable to ensure we execute zipkin cleanup only if zipkin is setup and it is executed only once.
-	teardownOnce sync.Once
-)
-
-// PromProxy defines a proxy to the prometheus server
-type PromProxy struct {
-	Namespace string
-	processID int
-}
-
-// Setup performs a port forwarding for app prometheus-test in given namespace
-func (p *PromProxy) Setup(kubeClientset *kubernetes.Clientset, logf logging.FormatLogger) {
-	setupOnce.Do(func() {
-		if err := monitoring.CheckPortAvailability(prometheusPort); err != nil {
-			logf("Prometheus port not available: %v", err)
-			return
-		}
-
-		promPods, err := monitoring.GetPods(kubeClientset, appLabel, p.Namespace)
-		if err != nil {
-			logf("Error retrieving prometheus pod details: %v", err)
-			return
-		}
-
-		p.processID, err = monitoring.PortForward(logf, promPods, prometheusPort, prometheusPort, p.Namespace)
-		if err != nil {
-			logf("Error starting kubectl port-forward command: %v", err)
-			return
-		}
-	})
-}
-
-// Teardown will kill the port forwarding process if running.
-func (p *PromProxy) Teardown(logf logging.FormatLogger) {
-	teardownOnce.Do(func() {
-		if err := monitoring.Cleanup(p.processID); err != nil {
-			logf("Encountered error killing port-forward process: %v", err)
-			return
-		}
-	})
-}
-
-// PromAPI gets a handle to the prometheus API
-func PromAPI() (v1.API, error) {
-	client, err := api.NewClient(api.Config{Address: fmt.Sprintf("http://localhost:%d", prometheusPort)})
-	if err != nil {
-		return nil, err
-	}
-	return v1.NewAPI(client), nil
-}
-
-// AllowPrometheusSync sleeps for sometime to allow prometheus time to scrape the metrics.
-func AllowPrometheusSync(logf logging.FormatLogger) {
-	logf("Sleeping to allow prometheus to record metrics...")
-	time.Sleep(30 * time.Second)
-}
-
-// RunQuery runs a prometheus query and returns the metric value
-func RunQuery(ctx context.Context, logf logging.FormatLogger, promAPI v1.API, query string) (float64, error) {
-	logf("Running prometheus query: %s", query)
-
-	value, err := promAPI.Query(ctx, query, time.Now())
-	if err != nil {
-		return 0, err
-	}
-
-	return VectorValue(value)
-}
-
-// RunQueryRange runs a prometheus query over the given range
-func RunQueryRange(ctx context.Context, logf logging.FormatLogger, promAPI v1.API, query string, r v1.Range) (float64, error) {
-	logf("Running prometheus query: %s", query)
-
-	value, err := promAPI.QueryRange(ctx, query, r)
-	if err != nil {
-		return 0, err
-	}
-
-	return VectorValue(value)
-}
-
-// VectorValue gets the vector value from the value type
-func VectorValue(val model.Value) (float64, error) {
-	if val.Type() != model.ValVector {
-		return 0, fmt.Errorf("Value type is %s. Expected: Valvector", val.String())
-	}
-	value := val.(model.Vector)
-	if len(value) == 0 {
-		return 0, errors.New("Query returned no results")
-	}
-
-	return float64(value[0].Value), nil
-}