Repository: knative/serving
Pull request #8669 (2020-07-16 23:55:39)

Include RoutingState when making a new Revision
<!--
Request Prow to automatically lint any go code in this PR:

/lint
-->

Issue https://github.com/knative/serving/issues/8208

<!-- Please include the 'why' behind your changes if no issue exists -->
## Proposed Changes

* When a Configuration makes a new Revision, set servingState pending
    * Only when the feature flag is enabled
* Allow the new annotation and label to pass through validation
* Pass through a FakeClock in the Config reconciler

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

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

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["mattmoor"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/apis/serving/v1/revision_validation.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1283913304099524611/artifacts/line-cov.html#file2) | 94.6% | 94.7% | 0.1
[pkg/reconciler/configuration/configuration.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1283913304099524611/artifacts/line-cov.html#file3) | 93.4% | 94.3% | 0.9
[pkg/reconciler/configuration/resources/revision.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1283913304099524611/artifacts/line-cov.html#file5) | 96.2% | 96.4% | 0.3

knative-prow-robot: @whaught: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-upgrade-tests | 0b9160c0cfc40585d7bcbebe8c18e113647a6927 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-upgrade-tests/1283913304103718913) | `/test pull-knative-serving-upgrade-tests`

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

<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-prow-robot: @whaught: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-upgrade-tests | 0b9160c0cfc40585d7bcbebe8c18e113647a6927 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-upgrade-tests/1283913304103718913) | `/test pull-knative-serving-upgrade-tests`
pull-knative-serving-unit-tests | 0b9160c0cfc40585d7bcbebe8c18e113647a6927 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-unit-tests/1283913304099524610) | `/test pull-knative-serving-unit-tests`

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

<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]0b9160c0cfc40585d7bcbebe8c18e113647a6927[AUTOMATED-FLAKY-RETRYER]-->
The following jobs failed:

Test name | Triggers | Retries
--- | --- | ---
pull-knative-serving-unit-tests |  | 0/3

Failed non-flaky tests preventing automatic retry of pull-knative-serving-unit-tests:

```
pkg/reconciler/gc.[build failed]
pkg/reconciler/gc/v1.[build failed]
pkg/reconciler/gc/v2.[build failed]
pkg/reconciler/service.[build failed]
```
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/apis/serving/v1/revision_validation.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1283918213062594561/artifacts/line-cov.html#file2) | 94.6% | 94.7% | 0.1
[pkg/reconciler/configuration/configuration.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1283918213062594561/artifacts/line-cov.html#file3) | 93.4% | 94.3% | 0.9
[pkg/reconciler/configuration/resources/revision.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1283918213062594561/artifacts/line-cov.html#file5) | 96.2% | 96.4% | 0.3

knative-prow-robot: @whaught: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-upgrade-tests | 7c546434b5790fd8c5608777b0def1d77da45409 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-upgrade-tests/1283918213062594563) | `/test pull-knative-serving-upgrade-tests`

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

<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 -->
whaught: /test pull-knative-serving-upgrade-tests
whaught: /assign @vagababov @dprotaso @mattmoor 
knative-prow-robot: New changes are detected. LGTM label has been removed.
knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

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

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["dprotaso"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/apis/serving/v1/revision_validation.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1284281102789251075/artifacts/line-cov.html#file2) | 94.6% | 94.7% | 0.1
[pkg/reconciler/configuration/resources/revision.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1284281102789251075/artifacts/line-cov.html#file5) | 96.2% | 96.4% | 0.3

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/apis/serving/v1/revision_validation.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1284296832247140352/artifacts/line-cov.html#file2) | 94.6% | 94.7% | 0.1
[pkg/reconciler/configuration/resources/revision.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1284296832247140352/artifacts/line-cov.html#file5) | 96.2% | 96.4% | 0.3

dprotaso: /lgtm
/approve
knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/serving/pull/8669#issuecomment-660402801" title="Approved">dprotaso</a>*, *<a href="https://github.com/knative/serving/pull/8669#" title="Author self-approved">whaught</a>*

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

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

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

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-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-serving-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/apis/serving/v1/revision_validation.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1284300103535824896/artifacts/line-cov.html#file2) | 94.6% | 94.7% | 0.1
[pkg/reconciler/configuration/resources/revision.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-go-coverage/1284300103535824896/artifacts/line-cov.html#file5) | 96.2% | 96.4% | 0.3

knative-prow-robot: @whaught: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-serving-integration-tests | c399d79a029e7c527cc7430b5614c199a662197f | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_serving/8669/pull-knative-serving-integration-tests/1284300103535824897) | `/test pull-knative-serving-integration-tests`

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

<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 -->

Patch:
diff --git a/go.mod b/go.mod
index 4d90e3d0d..09d06ba19 100644
--- a/go.mod
+++ b/go.mod
@@ -38,10 +38,10 @@ require (
 	k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
 	k8s.io/code-generator v0.18.0
 	k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
-	knative.dev/caching v0.0.0-20200715190633-2825854d52e3
-	knative.dev/networking v0.0.0-20200715190634-e189256cc68f
-	knative.dev/pkg v0.0.0-20200715203233-3ba0019af6be
-	knative.dev/test-infra v0.0.0-20200715185233-6964ba126fee
+	knative.dev/caching v0.0.0-20200716164533-ea602fec68d6
+	knative.dev/networking v0.0.0-20200716201933-30a27fbaff8a
+	knative.dev/pkg v0.0.0-20200718042534-e193c4be24bb
+	knative.dev/test-infra v0.0.0-20200718013433-a19b8b74cc35
 )
 
 replace (
diff --git a/go.sum b/go.sum
index f08173f77..1a109790f 100644
--- a/go.sum
+++ b/go.sum
@@ -1622,20 +1622,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-20200116200605-67bca2c83dfa/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg=
-knative.dev/caching v0.0.0-20200715190633-2825854d52e3 h1:xkWi2V3gGiIMYGwuR9WwyAMqEXOzzWaw+n7dVmWeqds=
-knative.dev/caching v0.0.0-20200715190633-2825854d52e3/go.mod h1:5WnJneM1gQzBP7b5KXdUfjUx1IyeYzcXbXc78w0nRbI=
+knative.dev/caching v0.0.0-20200716164533-ea602fec68d6 h1:fBKFQMZai2UuBAUOBxMFxYJ1BBbd821CgOlqddrJBxU=
+knative.dev/caching v0.0.0-20200716164533-ea602fec68d6/go.mod h1:/ey35hW/9lssPtvTznIkZuhCI1UbB2UV4ZY3p8RW3BI=
 knative.dev/eventing-contrib v0.11.2/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g=
-knative.dev/networking v0.0.0-20200715190634-e189256cc68f h1:rpGB90r2QUutILNxzp5u4mdm5qjYdXXPXHP76CamvRY=
-knative.dev/networking v0.0.0-20200715190634-e189256cc68f/go.mod h1:BGHV6CNzz4HGdgrVmvPb316bjj74CzsS+CbLZJiSbcc=
+knative.dev/networking v0.0.0-20200716201933-30a27fbaff8a h1:En4OAS5aL8eYPaLOhVhyVWHYDEW0X5X1Y78MSyw5/Ps=
+knative.dev/networking v0.0.0-20200716201933-30a27fbaff8a/go.mod h1:6CW3DsOMkpK1HdMWraZ+50nl5+lbVzmWJ92CDoNmFi8=
 knative.dev/pkg v0.0.0-20200207155214-fef852970f43/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
-knative.dev/pkg v0.0.0-20200715082932-e863db03445f h1:2bO5Qm4rZlhYUYCVhlnDZ3tMQuB6JogpIMZlXggSaJM=
-knative.dev/pkg v0.0.0-20200715082932-e863db03445f/go.mod h1:yFXTzV2GIB30Qs6pdJNCbtKaIEhxH9fsmrrltAqfjWE=
-knative.dev/pkg v0.0.0-20200715203233-3ba0019af6be h1:ZQ2BDH9z+ZxeuYHH17/3APHg+tIyBipdNWifEsf1lzk=
-knative.dev/pkg v0.0.0-20200715203233-3ba0019af6be/go.mod h1:yFXTzV2GIB30Qs6pdJNCbtKaIEhxH9fsmrrltAqfjWE=
+knative.dev/pkg v0.0.0-20200716125933-cb729b8ae661/go.mod h1:yFXTzV2GIB30Qs6pdJNCbtKaIEhxH9fsmrrltAqfjWE=
+knative.dev/pkg v0.0.0-20200718042534-e193c4be24bb h1:0+6xt01+h9P8+83UEn1rYbiRnZe829eEfK5exnORtZ4=
+knative.dev/pkg v0.0.0-20200718042534-e193c4be24bb/go.mod h1:3mm5ZffkmyYnqN+SOq1cN9TX0KTjhEbiZL8YBpP4C4Y=
 knative.dev/test-infra v0.0.0-20200713220518-5a4c4cad5372 h1:NZzdNmKYP3L7fut/SNOxLgTgXVvQrygXiYpAeIMGMwM=
 knative.dev/test-infra v0.0.0-20200713220518-5a4c4cad5372/go.mod h1:vtT6dLs/iNj8pKcfag8CSVqHKNMgyCFtU/g1pV7Bovs=
 knative.dev/test-infra v0.0.0-20200715185233-6964ba126fee h1:SH4N5kSRiEgmOcgjFwsyLMipS3sPJlN6dpp783C/ILQ=
 knative.dev/test-infra v0.0.0-20200715185233-6964ba126fee/go.mod h1:mAsPDmFmlsTJjRWplWBz8xtEiarSgvGiiOjkGj4Or1g=
+knative.dev/test-infra v0.0.0-20200718013433-a19b8b74cc35 h1:HeB4f6l/HmRtadbchy+xH/gKsJpFwp+gL7xXLBPNd3A=
+knative.dev/test-infra v0.0.0-20200718013433-a19b8b74cc35/go.mod h1:mAsPDmFmlsTJjRWplWBz8xtEiarSgvGiiOjkGj4Or1g=
 modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
 modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
diff --git a/pkg/apis/serving/metadata_validation.go b/pkg/apis/serving/metadata_validation.go
index a4eef1b33..167fa8e40 100644
--- a/pkg/apis/serving/metadata_validation.go
+++ b/pkg/apis/serving/metadata_validation.go
@@ -40,6 +40,7 @@ var (
 		RoutingStateModifiedAnnotationKey,
 		GroupNamePrefix+"forceUpgrade",
 		RevisionPreservedAnnotationKey,
+		RoutingStateModifiedAnnotationKey,
 	)
 )
 
diff --git a/pkg/apis/serving/v1/revision_helpers.go b/pkg/apis/serving/v1/revision_helpers.go
index 5a5473ac6..a87d8614e 100644
--- a/pkg/apis/serving/v1/revision_helpers.go
+++ b/pkg/apis/serving/v1/revision_helpers.go
@@ -111,7 +111,7 @@ func (rs *RevisionSpec) GetContainer() *corev1.Container {
 
 // SetRoutingState sets the routingState label on this Revision and updates the
 // routingStateModified annotation.
-func (r *Revision) SetRoutingState(state RoutingState) {
+func (r *Revision) SetRoutingState(state RoutingState, clock clock.Clock) {
 	stateStr := string(state)
 	if t := r.ObjectMeta.Annotations[serving.RoutingStateModifiedAnnotationKey]; t != "" &&
 		r.Labels[serving.RoutingStateLabelKey] == stateStr {
@@ -123,7 +123,7 @@ func (r *Revision) SetRoutingState(state RoutingState) {
 
 	r.Annotations = kmeta.UnionMaps(r.Annotations,
 		map[string]string{
-			serving.RoutingStateModifiedAnnotationKey: RoutingStateModifiedString(clock.RealClock{}),
+			serving.RoutingStateModifiedAnnotationKey: RoutingStateModifiedString(clock),
 		})
 }
 
diff --git a/pkg/apis/serving/v1/revision_validation.go b/pkg/apis/serving/v1/revision_validation.go
index 5634802dc..3d12032b3 100644
--- a/pkg/apis/serving/v1/revision_validation.go
+++ b/pkg/apis/serving/v1/revision_validation.go
@@ -119,12 +119,17 @@ func (rs *RevisionStatus) Validate(ctx context.Context) *apis.FieldError {
 // ValidateLabels function validates service labels
 func (r *Revision) ValidateLabels() (errs *apis.FieldError) {
 	for key, val := range r.GetLabels() {
-		switch {
-		case key == serving.RouteLabelKey || key == serving.ServiceLabelKey || key == serving.ConfigurationGenerationLabelKey:
-		case key == serving.ConfigurationLabelKey:
+		switch key {
+		case serving.RoutingStateLabelKey:
+		case serving.RouteLabelKey:
+		case serving.ServiceLabelKey:
+		case serving.ConfigurationGenerationLabelKey:
+		case serving.ConfigurationLabelKey:
 			errs = errs.Also(verifyLabelOwnerRef(val, serving.ConfigurationLabelKey, "Configuration", r.GetOwnerReferences()))
-		case strings.HasPrefix(key, serving.GroupNamePrefix):
-			errs = errs.Also(apis.ErrInvalidKeyName(key, ""))
+		default:
+			if strings.HasPrefix(key, serving.GroupNamePrefix) {
+				errs = errs.Also(apis.ErrInvalidKeyName(key, ""))
+			}
 		}
 	}
 	return
diff --git a/pkg/reconciler/configuration/configuration.go b/pkg/reconciler/configuration/configuration.go
index cb8c3c9ec..fae375cb3 100644
--- a/pkg/reconciler/configuration/configuration.go
+++ b/pkg/reconciler/configuration/configuration.go
@@ -28,6 +28,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/selection"
+	"k8s.io/apimachinery/pkg/util/clock"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/logging"
 	pkgreconciler "knative.dev/pkg/reconciler"
@@ -45,6 +46,8 @@ type Reconciler struct {
 
 	// listers index properties about resources
 	revisionLister listers.RevisionLister
+
+	clock clock.Clock
 }
 
 // Check that our Reconciler implements configreconciler.Interface
@@ -260,7 +263,7 @@ func (c *Reconciler) latestCreatedRevision(config *v1.Configuration) (*v1.Revisi
 func (c *Reconciler) createRevision(ctx context.Context, config *v1.Configuration) (*v1.Revision, error) {
 	logger := logging.FromContext(ctx)
 
-	rev := resources.MakeRevision(config)
+	rev := resources.MakeRevision(ctx, config, c.clock)
 	created, err := c.client.ServingV1().Revisions(config.Namespace).Create(rev)
 	if err != nil {
 		return nil, err
diff --git a/pkg/reconciler/configuration/controller.go b/pkg/reconciler/configuration/controller.go
index 4dd7aab44..9df4ad684 100644
--- a/pkg/reconciler/configuration/controller.go
+++ b/pkg/reconciler/configuration/controller.go
@@ -19,6 +19,7 @@ package configuration
 import (
 	"context"
 
+	"k8s.io/apimachinery/pkg/util/clock"
 	"k8s.io/client-go/tools/cache"
 	"knative.dev/pkg/configmap"
 	"knative.dev/pkg/controller"
@@ -37,6 +38,15 @@ const controllerAgentName = "configuration-controller"
 func NewController(
 	ctx context.Context,
 	cmw configmap.Watcher,
+) *controller.Impl {
+	return NewControllerWithClock(ctx, cmw, clock.RealClock{})
+}
+
+// NewControllerWithClock creates a new Configuration controller with a clock
+func NewControllerWithClock(
+	ctx context.Context,
+	cmw configmap.Watcher,
+	clock clock.Clock,
 ) *controller.Impl {
 	ctx = servingreconciler.AnnotateLoggerWithName(ctx, controllerAgentName)
 	logger := logging.FromContext(ctx)
@@ -46,6 +56,7 @@ func NewController(
 	c := &Reconciler{
 		client:         servingclient.Get(ctx),
 		revisionLister: revisionInformer.Lister(),
+		clock:          clock,
 	}
 	impl := configreconciler.NewImpl(ctx, c)
 
diff --git a/pkg/reconciler/configuration/resources/revision.go b/pkg/reconciler/configuration/resources/revision.go
index ab4880791..e7e4a8b7c 100644
--- a/pkg/reconciler/configuration/resources/revision.go
+++ b/pkg/reconciler/configuration/resources/revision.go
@@ -17,16 +17,19 @@ limitations under the License.
 package resources
 
 import (
+	"context"
 	"fmt"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/clock"
 	"knative.dev/pkg/kmeta"
+	cfgMap "knative.dev/serving/pkg/apis/config"
 	"knative.dev/serving/pkg/apis/serving"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 )
 
 // MakeRevision creates a revision object from configuration.
-func MakeRevision(config *v1.Configuration) *v1.Revision {
+func MakeRevision(ctx context.Context, config *v1.Configuration, clock clock.Clock) *v1.Revision {
 	// Start from the ObjectMeta/Spec inlined in the Configuration resources.
 	rev := &v1.Revision{
 		ObjectMeta: config.Spec.GetTemplate().ObjectMeta,
@@ -42,6 +45,11 @@ func MakeRevision(config *v1.Configuration) *v1.Revision {
 	UpdateRevisionLabels(rev, config)
 	UpdateRevisionAnnotations(rev, config)
 
+	// Pending tells the labeler that we have not processed this revision.
+	if cfgMap.FromContextOrDefaults(ctx).Features.ResponsiveRevisionGC == cfgMap.Enabled {
+		rev.SetRoutingState(v1.RoutingStatePending, clock)
+	}
+
 	// Populate OwnerReferences so that deletes cascade.
 	rev.OwnerReferences = append(rev.OwnerReferences, *kmeta.NewControllerRef(config))
 
diff --git a/vendor/knative.dev/pkg/controller/two_lane_queue.go b/vendor/knative.dev/pkg/controller/two_lane_queue.go
new file mode 100644
index 000000000..165eb2df3
--- /dev/null
+++ b/vendor/knative.dev/pkg/controller/two_lane_queue.go
@@ -0,0 +1,159 @@
+/*
+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 controller
+
+import (
+	"k8s.io/client-go/util/workqueue"
+)
+
+// twoLaneQueue is a rate limited queue that wraps around two queues
+// -- fast queue (anonymously aliased), whose contents are processed with priority.
+// -- slow queue (slowLane queue), whose contents are processed if fast queue has no items.
+// All the default methods operate on the fast queue, unless noted otherwise.
+type twoLaneQueue struct {
+	workqueue.RateLimitingInterface
+	slowLane workqueue.RateLimitingInterface
+	// consumerQueue is necessary to ensure that we're not reconciling
+	// the same object at the exact same time (e.g. if it had been enqueued
+	// in both fast and slow and is the only object there).
+	consumerQueue workqueue.Interface
+
+	name string
+
+	fastChan chan interface{}
+	slowChan chan interface{}
+}
+
+// Creates a new twoLaneQueue.
+func newTwoLaneWorkQueue(name string) *twoLaneQueue {
+	rl := workqueue.DefaultControllerRateLimiter()
+	tlq := &twoLaneQueue{
+		RateLimitingInterface: workqueue.NewNamedRateLimitingQueue(
+			rl,
+			name+"-fast",
+		),
+		slowLane: workqueue.NewNamedRateLimitingQueue(
+			rl,
+			name+"-slow",
+		),
+		consumerQueue: workqueue.NewNamed(name + "-consumer"),
+		name:          name,
+		fastChan:      make(chan interface{}),
+		slowChan:      make(chan interface{}),
+	}
+	// Run consumer thread.
+	go tlq.runConsumer()
+	// Run producer threads.
+	go process(tlq.RateLimitingInterface, tlq.fastChan)
+	go process(tlq.slowLane, tlq.slowChan)
+	return tlq
+}
+
+func process(q workqueue.Interface, ch chan interface{}) {
+	// Sender closes the channel
+	defer close(ch)
+	for {
+		i, d := q.Get()
+		// If the queue is empty and we're shutting down — stop the loop.
+		if d {
+			break
+		}
+		ch <- i
+		q.Done(i)
+	}
+}
+
+func (tlq *twoLaneQueue) runConsumer() {
+	// Shutdown flags.
+	fast, slow := true, true
+	// When both producer queues are shutdown stop the consumerQueue.
+	defer tlq.consumerQueue.ShutDown()
+	// While any of the queues is still running, try to read off of them.
+	for fast || slow {
+		// By default drain the fast lane.
+		// Channels in select are picked random, so first
+		// we have a select that only looks at the fast lane queue.
+		if fast {
+			select {
+			case item, ok := <-tlq.fastChan:
+				if !ok {
+					// This queue is shutdown and drained. Stop looking at it.
+					fast = false
+					continue
+				}
+				tlq.consumerQueue.Add(item)
+				continue
+			default:
+				// This immediately exits the wait if the fast chan is empty.
+			}
+		}
+
+		// If the fast lane queue had no items, we can select from both.
+		// Obviously if suddenly both are populated at the same time there's a
+		// 50% chance that the slow would be picked first, but this should be
+		// a rare occasion not to really worry about it.
+		select {
+		case item, ok := <-tlq.fastChan:
+			if !ok {
+				// This queue is shutdown and drained. Stop looking at it.
+				fast = false
+				continue
+			}
+			tlq.consumerQueue.Add(item)
+		case item, ok := <-tlq.slowChan:
+			if !ok {
+				// This queue is shutdown and drained. Stop looking at it.
+				slow = false
+				continue
+			}
+			tlq.consumerQueue.Add(item)
+		}
+	}
+}
+
+// Shutdown implements workqueue.Interace.
+// Shutdown shuts down both queues.
+func (tlq *twoLaneQueue) ShutDown() {
+	tlq.RateLimitingInterface.ShutDown()
+	tlq.slowLane.ShutDown()
+}
+
+// Done implements workqueue.Interface.
+// Done marks the item as completed in all the queues.
+// NB: this will just re-enqueue the object on the queue that
+// didn't originate the object.
+func (tlq *twoLaneQueue) Done(i interface{}) {
+	tlq.consumerQueue.Done(i)
+}
+
+// Get implements workqueue.Interface.
+// It gets the item from fast lane if it has anything, alternatively
+// the slow lane.
+func (tlq *twoLaneQueue) Get() (interface{}, bool) {
+	return tlq.consumerQueue.Get()
+}
+
+// Len returns the sum of lengths.
+// NB: actual _number_ of unique object might be less than this sum.
+func (tlq *twoLaneQueue) Len() int {
+	return tlq.RateLimitingInterface.Len() + tlq.slowLane.Len() + tlq.consumerQueue.Len()
+}
+
+// SlowLane gives direct access to the slow queue.
+func (tlq *twoLaneQueue) SlowLane() workqueue.RateLimitingInterface {
+	return tlq.slowLane
+}
diff --git a/vendor/knative.dev/pkg/hack/update-codegen.sh b/vendor/knative.dev/pkg/hack/update-codegen.sh
index 8a2198335..3e030bfac 100644
--- a/vendor/knative.dev/pkg/hack/update-codegen.sh
+++ b/vendor/knative.dev/pkg/hack/update-codegen.sh
@@ -49,7 +49,7 @@ EXTERNAL_INFORMER_PKG="k8s.io/client-go/informers" \
     k8s.io/api \
     "admissionregistration:v1beta1,v1 apps:v1 autoscaling:v1,v2beta1 batch:v1,v1beta1 core:v1 rbac:v1" \
     --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \
-    --force-genreconciler-kinds "Namespace"
+    --force-genreconciler-kinds "Namespace,Deployment"
 
 OUTPUT_PKG="knative.dev/pkg/client/injection/apiextensions" \
 VERSIONED_CLIENTSET_PKG="k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" \
diff --git a/vendor/knative.dev/pkg/injection/sharedmain/main.go b/vendor/knative.dev/pkg/injection/sharedmain/main.go
index 676e47de8..4d52038e5 100644
--- a/vendor/knative.dev/pkg/injection/sharedmain/main.go
+++ b/vendor/knative.dev/pkg/injection/sharedmain/main.go
@@ -35,6 +35,8 @@ import (
 	"k8s.io/apimachinery/pkg/util/wait"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
+	"k8s.io/client-go/transport"
+	"k8s.io/klog"
 
 	"go.uber.org/zap"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -63,18 +65,39 @@ func GetConfig(masterURL, kubeconfig string) (*rest.Config, error) {
 	if kubeconfig == "" {
 		kubeconfig = os.Getenv("KUBECONFIG")
 	}
+
+	// We produce configs a bunch of ways, this gives us a single place
+	// to "decorate" them with common useful things (e.g. for debugging)
+	decorate := func(cfg *rest.Config) *rest.Config {
+
+		// Augment the rest.Config with a "wrapper" around the transport that
+		// will emit varying levels of debug logging when -v is passed with
+		// levels 6 to 9.
+		wt := transport.DebugWrappers
+		if cfg.WrapTransport != nil {
+			wt = transport.Wrappers(wt, cfg.WrapTransport)
+		}
+		cfg.WrapTransport = wt
+
+		return cfg
+	}
+
 	// If we have an explicit indication of where the kubernetes config lives, read that.
 	if kubeconfig != "" {
-		return clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
+		if c, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig); err != nil {
+			return nil, err
+		} else {
+			return decorate(c), nil
+		}
 	}
 	// If not, try the in-cluster config.
 	if c, err := rest.InClusterConfig(); err == nil {
-		return c, nil
+		return decorate(c), nil
 	}
 	// If no in-cluster config, try the default location in the user's home directory.
 	if usr, err := user.Current(); err == nil {
 		if c, err := clientcmd.BuildConfigFromFlags("", filepath.Join(usr.HomeDir, ".kube", "config")); err == nil {
-			return c, nil
+			return decorate(c), nil
 		}
 	}
 
@@ -168,9 +191,14 @@ func MainWithConfig(ctx context.Context, component string, cfg *rest.Config, cto
 
 	MemStatsOrDie(ctx)
 
-	// Adjust our client's rate limits based on the number of controllers we are running.
-	cfg.QPS = float32(len(ctors)) * rest.DefaultQPS
-	cfg.Burst = len(ctors) * rest.DefaultBurst
+	// Respect user provided settings, but if omitted customize the default behavior.
+	if cfg.QPS == 0 {
+		// Adjust our client's rate limits based on the number of controllers we are running.
+		cfg.QPS = float32(len(ctors)) * rest.DefaultQPS
+	}
+	if cfg.Burst == 0 {
+		cfg.Burst = len(ctors) * rest.DefaultBurst
+	}
 	ctx, informers := injection.Default.SetupInformers(ctx, cfg)
 
 	logger, atomicLevel := SetupLoggerOrDie(ctx, component)
@@ -260,6 +288,7 @@ func ParseAndGetConfigOrDie() *rest.Config {
 		kubeconfig = flag.String("kubeconfig", "",
 			"Path to a kubeconfig. Only required if out-of-cluster.")
 	)
+	klog.InitFlags(flag.CommandLine)
 	flag.Parse()
 
 	cfg, err := GetConfig(*masterURL, *kubeconfig)
diff --git a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go
index 96d72dd24..44ae68b68 100644
--- a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go
+++ b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go
@@ -274,12 +274,6 @@ func sdCustomMetricsRecorder(mc metricsConfig, allowCustomMetrics bool) func(con
 	}
 }
 
-// clientConfig stores the stackdriver configs for cerating additional connections.
-type clientConfig struct {
-	storeConfig *metricsConfig
-	storeLogger *zap.SugaredLogger
-}
-
 // getStackdriverExporterClientOptions creates client options for the opencensus Stackdriver exporter from the given stackdriverClientConfig.
 // On error, an empty array of client options is returned.
 func getStackdriverExporterClientOptions(config *metricsConfig) ([]option.ClientOption, error) {
diff --git a/vendor/knative.dev/pkg/network/error_handler.go b/vendor/knative.dev/pkg/network/error_handler.go
index 486518b96..8518c0401 100644
--- a/vendor/knative.dev/pkg/network/error_handler.go
+++ b/vendor/knative.dev/pkg/network/error_handler.go
@@ -25,6 +25,8 @@ import (
 
 // ErrorHandler sets up a handler suitable for use with the ErrorHandler field on
 // httputil's reverse proxy.
+// TODO(mattmoor): Move the implementation into handlers/error.go once downstream consumers
+// have adopted the alias.
 func ErrorHandler(logger *zap.SugaredLogger) func(http.ResponseWriter, *http.Request, error) {
 	return func(w http.ResponseWriter, req *http.Request, err error) {
 		ss := readSockStat(logger)
diff --git a/vendor/knative.dev/pkg/network/handlers/doc.go b/vendor/knative.dev/pkg/network/handlers/doc.go
new file mode 100644
index 000000000..3b5f97504
--- /dev/null
+++ b/vendor/knative.dev/pkg/network/handlers/doc.go
@@ -0,0 +1,18 @@
+/*
+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 handlers holds useful HTTP handler implementations.
+package handlers
diff --git a/vendor/knative.dev/pkg/network/handlers/drain.go b/vendor/knative.dev/pkg/network/handlers/drain.go
new file mode 100644
index 000000000..7bdeffb9d
--- /dev/null
+++ b/vendor/knative.dev/pkg/network/handlers/drain.go
@@ -0,0 +1,110 @@
+/*
+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 handlers
+
+import (
+	"net/http"
+	"sync"
+	"time"
+
+	"knative.dev/pkg/network"
+)
+
+// Drainer wraps an inner http.Handler to support responding to kubelet
+// probes with a "200 OK" until the handler is told to Drain.
+// When the Drainer is told to Drain, it will immediately start to fail
+// probes with a "500 shutting down", and the call will block until no
+// requests have been received for QuietPeriod (defaults to
+// network.DefaultDrainTimeout).
+type Drainer struct {
+	// Mutex guards the initialization and resets of the timer
+	sync.RWMutex
+
+	// Inner is the http.Handler to which we delegate actual requests.
+	Inner http.Handler
+
+	// QuietPeriod is the duration that must elapse without any requests
+	// after Drain is called before it may return.
+	QuietPeriod time.Duration
+
+	// once is used to initialize timer
+	once sync.Once
+
+	// timer is used to orchestrate the drain.
+	timer *time.Timer
+}
+
+// Ensure Drainer implements http.Handler
+var _ http.Handler = (*Drainer)(nil)
+
+// ServeHTTP implements http.Handler
+func (d *Drainer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	if network.IsKubeletProbe(r) { // Respond to probes regardless of path.
+		if d.draining() {
+			http.Error(w, "shutting down", http.StatusServiceUnavailable)
+		} else {
+			w.WriteHeader(http.StatusOK)
+		}
+		return
+	}
+
+	d.reset()
+	d.Inner.ServeHTTP(w, r)
+}
+
+// Drain blocks until QuietPeriod has elapsed since the last request,
+// starting when this is invoked.
+func (d *Drainer) Drain() {
+	d.once.Do(func() {
+		t := func() *time.Timer {
+			d.Lock()
+			defer d.Unlock()
+			if d.QuietPeriod <= 0 {
+				d.QuietPeriod = network.DefaultDrainTimeout
+			}
+			d.timer = time.NewTimer(d.QuietPeriod)
+			return d.timer
+		}()
+
+		<-t.C
+	})
+}
+
+// reset resets the drain timer to the full amount of time.
+func (d *Drainer) reset() {
+	if func() bool {
+		d.RLock()
+		defer d.RUnlock()
+		return d.timer == nil
+	}() {
+		return
+	}
+
+	d.Lock()
+	defer d.Unlock()
+	if d.timer.Stop() {
+		d.timer.Reset(d.QuietPeriod)
+	}
+}
+
+// draining returns whether we are draining the handler.
+func (d *Drainer) draining() bool {
+	d.RLock()
+	defer d.RUnlock()
+
+	return d.timer != nil
+}
diff --git a/vendor/knative.dev/pkg/network/handlers/error.go b/vendor/knative.dev/pkg/network/handlers/error.go
new file mode 100644
index 000000000..a6bd3bd03
--- /dev/null
+++ b/vendor/knative.dev/pkg/network/handlers/error.go
@@ -0,0 +1,23 @@
+/*
+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 handlers
+
+import "knative.dev/pkg/network"
+
+// Error sets up a handler suitable for use with the ErrorHandler field on
+// httputil's reverse proxy, which logs /proc/net/sockstat data.
+var Error = network.ErrorHandler
diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go
index 1a2988c1c..8d628c5e3 100644
--- a/vendor/knative.dev/pkg/webhook/webhook.go
+++ b/vendor/knative.dev/pkg/webhook/webhook.go
@@ -27,6 +27,7 @@ import (
 	// Injection stuff
 	kubeclient "knative.dev/pkg/client/injection/kube/client"
 	kubeinformerfactory "knative.dev/pkg/injection/clients/namespacedkube/informers/factory"
+	"knative.dev/pkg/network/handlers"
 
 	"go.uber.org/zap"
 	"golang.org/x/sync/errgroup"
@@ -83,8 +84,6 @@ type Webhook struct {
 	// synced is function that is called when the informers have been synced.
 	synced context.CancelFunc
 
-	// stopCh is closed when we should start failing readiness probes.
-	stopCh chan struct{}
 	// grace period is how long to wait after failing readiness probes
 	// before shutting down.
 	gracePeriod time.Duration
@@ -137,7 +136,6 @@ func New(
 		secretlister: secretInformer.Lister(),
 		Logger:       logger,
 		synced:       cancel,
-		stopCh:       make(chan struct{}),
 		gracePeriod:  network.DefaultDrainTimeout,
 	}
 
@@ -176,8 +174,13 @@ func (wh *Webhook) Run(stop <-chan struct{}) error {
 	logger := wh.Logger
 	ctx := logging.WithLogger(context.Background(), logger)
 
+	drainer := &handlers.Drainer{
+		Inner:       wh,
+		QuietPeriod: wh.gracePeriod,
+	}
+
 	server := &http.Server{
-		Handler: wh,
+		Handler: drainer,
 		Addr:    fmt.Sprintf(":%d", wh.Options.Port),
 		TLSConfig: &tls.Config{
 			GetCertificate: func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
@@ -215,16 +218,12 @@ func (wh *Webhook) Run(stop <-chan struct{}) error {
 	select {
 	case <-stop:
 		eg.Go(func() error {
+			// As we start to shutdown, disable keep-alives to avoid clients hanging onto connections.
+			server.SetKeepAlivesEnabled(false)
+
 			// Start failing readiness probes immediately.
 			logger.Info("Starting to fail readiness probes...")
-			close(wh.stopCh)
-
-			// Wait for a grace period for the above to take effect and this Pod's
-			// endpoint to be removed from the webhook service's Endpoints.
-			// For this to be effective, it must be greater than the probe's
-			// periodSeconds times failureThreshold by a margin suitable to
-			// propagate the new Endpoints data across the cluster.
-			time.Sleep(wh.gracePeriod)
+			drainer.Drain()
 
 			return server.Shutdown(context.Background())
 		})
@@ -238,17 +237,6 @@ func (wh *Webhook) Run(stop <-chan struct{}) error {
 }
 
 func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	// Respond to probes regardless of path.
-	if network.IsKubeletProbe(r) {
-		select {
-		case <-wh.stopCh:
-			http.Error(w, "shutting down", http.StatusInternalServerError)
-		default:
-			w.WriteHeader(http.StatusOK)
-		}
-		return
-	}
-
 	// Verify the content type is accurate.
 	contentType := r.Header.Get("Content-Type")
 	if contentType != "application/json" {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 06469fd29..5c13d3c35 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1004,7 +1004,7 @@ k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/caching v0.0.0-20200715190633-2825854d52e3
+# knative.dev/caching v0.0.0-20200716164533-ea602fec68d6
 ## explicit
 knative.dev/caching/config
 knative.dev/caching/pkg/apis/caching
@@ -1025,7 +1025,7 @@ knative.dev/caching/pkg/client/injection/informers/caching/v1alpha1/image/fake
 knative.dev/caching/pkg/client/injection/informers/factory
 knative.dev/caching/pkg/client/injection/informers/factory/fake
 knative.dev/caching/pkg/client/listers/caching/v1alpha1
-# knative.dev/networking v0.0.0-20200715190634-e189256cc68f
+# knative.dev/networking v0.0.0-20200716201933-30a27fbaff8a
 ## explicit
 knative.dev/networking/pkg/apis/networking
 knative.dev/networking/pkg/apis/networking/v1alpha1
@@ -1051,7 +1051,7 @@ knative.dev/networking/pkg/client/injection/informers/networking/v1alpha1/server
 knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serverlessservice
 knative.dev/networking/pkg/client/istio/listers/networking/v1alpha3
 knative.dev/networking/pkg/client/listers/networking/v1alpha1
-# knative.dev/pkg v0.0.0-20200715203233-3ba0019af6be
+# knative.dev/pkg v0.0.0-20200718042534-e193c4be24bb
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate
@@ -1119,6 +1119,7 @@ knative.dev/pkg/metrics/metricskey
 knative.dev/pkg/metrics/metricstest
 knative.dev/pkg/metrics/testing
 knative.dev/pkg/network
+knative.dev/pkg/network/handlers
 knative.dev/pkg/network/prober
 knative.dev/pkg/pool
 knative.dev/pkg/profiling
@@ -1174,7 +1175,7 @@ knative.dev/pkg/webhook/resourcesemantics/conversion
 knative.dev/pkg/webhook/resourcesemantics/defaulting
 knative.dev/pkg/webhook/resourcesemantics/validation
 knative.dev/pkg/websocket
-# knative.dev/test-infra v0.0.0-20200715185233-6964ba126fee
+# knative.dev/test-infra v0.0.0-20200718013433-a19b8b74cc35
 ## explicit
 knative.dev/test-infra/scripts
 # sigs.k8s.io/yaml v1.2.0


Test patch:
diff --git a/pkg/apis/serving/v1/revision_helpers_test.go b/pkg/apis/serving/v1/revision_helpers_test.go
index 834570758..50389503c 100644
--- a/pkg/apis/serving/v1/revision_helpers_test.go
+++ b/pkg/apis/serving/v1/revision_helpers_test.go
@@ -22,6 +22,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/equality"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/clock"
 	net "knative.dev/networking/pkg/apis/networking"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	"knative.dev/serving/pkg/apis/serving"
@@ -336,6 +337,7 @@ func TestGetContainer(t *testing.T) {
 func TestSetRoutingState(t *testing.T) {
 	rev := &Revision{}
 	empty := time.Time{}
+	clock := clock.RealClock{}
 
 	// Test unset timestamp
 	if rev.GetRoutingStateModified() != empty {
@@ -343,7 +345,7 @@ func TestSetRoutingState(t *testing.T) {
 	}
 
 	// Test retrieving routing state and modified
-	rev.SetRoutingState(RoutingStateActive)
+	rev.SetRoutingState(RoutingStateActive, clock)
 	if state := rev.GetRoutingState(); state != RoutingStateActive {
 		t.Errorf("retrieved the wrong state got: %v want: %v", state, RoutingStateActive)
 	}
@@ -353,13 +355,13 @@ func TestSetRoutingState(t *testing.T) {
 	}
 
 	// Test that no-op modifications don't bump timestamps.
-	rev.SetRoutingState(RoutingStateActive)
+	rev.SetRoutingState(RoutingStateActive, clock)
 	if rev.GetRoutingStateModified() != modified {
 		t.Errorf("modified was bumped, but no change expected.")
 	}
 
 	// Test the actual modifications do bump timestamps.
-	rev.SetRoutingState(RoutingStateReserve)
+	rev.SetRoutingState(RoutingStateReserve, clock)
 	if state := rev.GetRoutingState(); state != RoutingStateReserve {
 		t.Errorf("retrieved the wrong state got: %v want: %v", state, RoutingStateReserve)
 	}
diff --git a/pkg/reconciler/configuration/configuration_test.go b/pkg/reconciler/configuration/configuration_test.go
index 11130fefb..c7ad21986 100644
--- a/pkg/reconciler/configuration/configuration_test.go
+++ b/pkg/reconciler/configuration/configuration_test.go
@@ -30,18 +30,20 @@ import (
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/clock"
 	clientgotesting "k8s.io/client-go/testing"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	"knative.dev/pkg/configmap"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/logging"
 	"knative.dev/pkg/ptr"
+	cfgMap "knative.dev/serving/pkg/apis/config"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 	servingclient "knative.dev/serving/pkg/client/injection/client/fake"
 	configreconciler "knative.dev/serving/pkg/client/injection/reconciler/serving/v1/configuration"
-	"knative.dev/serving/pkg/reconciler/configuration/resources"
 
 	. "knative.dev/pkg/reconciler/testing"
+	"knative.dev/serving/pkg/reconciler/configuration/resources"
 	. "knative.dev/serving/pkg/reconciler/testing/v1"
 	. "knative.dev/serving/pkg/testing/v1"
 )
@@ -55,10 +57,32 @@ var revisionSpec = v1.RevisionSpec{
 	TimeoutSeconds: ptr.Int64(60),
 }
 
+var testCtx context.Context
+var testClock clock.Clock
+
 // This is heavily based on the way the OpenShift Ingress controller tests its reconciliation method.
 func TestReconcile(t *testing.T) {
+	testClock = clock.NewFakeClock(time.Now())
+	testCtx = context.Background()
+
+	test(t)
+}
+
+func TestReconcileNewGCEnabled(t *testing.T) {
+	testClock = clock.NewFakeClock(time.Now())
+
+	c := &cfgMap.Config{
+		Features: &cfgMap.Features{
+			ResponsiveRevisionGC: cfgMap.Enabled,
+		},
+	}
+	testCtx = cfgMap.ToContext(context.Background(), c)
+	test(t)
+}
+
+func test(t *testing.T) {
 	retryAttempted := false
-	now := time.Now()
+	now := testClock.Now()
 
 	table := TableTest{{
 		Name: "bad workqueue key",
@@ -75,6 +99,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/delete-pending",
 	}, {
 		Name: "create revision matching generation, with retry",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("no-revisions-yet", "foo", 1234),
 		},
@@ -107,6 +132,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/no-revisions-yet",
 	}, {
 		Name: "create revision byo name",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("byo-name-create", "foo", 1234, func(cfg *v1.Configuration) {
 				cfg.Spec.GetTemplate().Name = "byo-name-create-foo"
@@ -132,6 +158,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/byo-name-create",
 	}, {
 		Name: "create revision byo name (exists)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("byo-name-exists", "foo", 1234, func(cfg *v1.Configuration) {
 				cfg.Spec.GetTemplate().Name = "byo-name-exists-foo"
@@ -147,6 +174,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/byo-name-exists",
 	}, {
 		Name: "create revision byo name (exists, wrong generation, right spec)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		// This example shows what we might see with a `git revert` in GitOps.
 		Objects: []runtime.Object{
 			cfg("byo-name-git-revert", "foo", 1234, func(cfg *v1.Configuration) {
@@ -165,6 +193,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/byo-name-git-revert",
 	}, {
 		Name: "create revision byo name (exists @ wrong generation w/ wrong spec)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("byo-name-wrong-gen-wrong-spec", "foo", 1234, func(cfg *v1.Configuration) {
 				cfg.Spec.GetTemplate().Name = "byo-name-wrong-gen-wrong-spec-foo"
@@ -186,6 +215,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/byo-name-wrong-gen-wrong-spec",
 	}, {
 		Name: "create revision byo name (exists not owned)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("byo-rev-not-owned", "foo", 1234, func(cfg *v1.Configuration) {
 				cfg.Spec.GetTemplate().Name = "byo-rev-not-owned-foo"
@@ -204,6 +234,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/byo-rev-not-owned",
 	}, {
 		Name: "webhook validation failure",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		// If we attempt to create a Revision with a bad ContainerConcurrency set, we fail.
 		WantErr: true,
 		Objects: []runtime.Object{
@@ -224,6 +255,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/validation-failure",
 	}, {
 		Name: "reconcile revision matching generation (ready: unknown)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("matching-revision-not-done", "foo", 5432),
 			rev("matching-revision-not-done", "foo", 5432,
@@ -240,6 +272,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/matching-revision-not-done",
 	}, {
 		Name: "reconcile revision matching generation (ready: true)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("matching-revision-done", "foo", 5555, WithLatestCreated("matching-revision-done-00001"), WithConfigObservedGen),
 			rev("matching-revision-done", "foo", 5555,
@@ -260,6 +293,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/matching-revision-done",
 	}, {
 		Name: "reconcile revision matching generation (ready: true, idempotent)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("matching-revision-done-idempotent", "foo", 5566,
 				WithConfigObservedGen, WithLatestCreated("matching-revision"), WithLatestReady("matching-revision")),
@@ -269,6 +303,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/matching-revision-done-idempotent",
 	}, {
 		Name: "reconcile revision matching generation (ready: false)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("matching-revision-failed", "foo", 5555, WithLatestCreated("matching-revision"), WithConfigObservedGen),
 			rev("matching-revision-failed", "foo", 5555,
@@ -288,6 +323,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/matching-revision-failed",
 	}, {
 		Name: "reconcile revision matching generation (ready: bad)",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("bad-condition", "foo", 5555, WithLatestCreated("bad-condition"), WithConfigObservedGen),
 			rev("bad-condition", "foo", 5555,
@@ -309,6 +345,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/bad-condition",
 	}, {
 		Name: "failure creating revision",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		// We induce a failure creating a revision
 		WantErr: true,
 		WithReactors: []clientgotesting.ReactionFunc{
@@ -333,6 +370,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/create-revision-failure",
 	}, {
 		Name: "failure updating configuration status",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		// Induce a failure updating the status of the configuration.
 		WantErr: true,
 		WithReactors: []clientgotesting.ReactionFunc{
@@ -358,6 +396,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/update-config-failure",
 	}, {
 		Name: "failed revision recovers",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("revision-recovers", "foo", 1337,
 				WithLatestCreated("revision-recovers-00001"),
@@ -385,6 +424,7 @@ func TestReconcile(t *testing.T) {
 		// querying the latest created revision includes the configuration name
 		// as part of the selector
 		Name: "two steady state configs with same generation should be a noop",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			// double-trouble needs to be first for this test to fail
 			// when no fix is present
@@ -405,6 +445,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/double-trouble",
 	}, {
 		Name: "three revisions with the latest revision failed, the latest ready should be updated to the last ready revision",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("threerevs", "foo", 3,
 				WithLatestCreated("threerevs-00002"),
@@ -437,6 +478,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/threerevs",
 	}, {
 		Name: "revision not ready, the latest ready should be updated, but the configuration should still be ready==Unknown",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("revnotready", "foo", 3,
 				WithLatestCreated("revnotready-00002"),
@@ -470,6 +512,7 @@ func TestReconcile(t *testing.T) {
 		Key: "foo/revnotready",
 	}, {
 		Name: "current LRR doesn't exist, LCR is ready",
+		Ctx:  cfgMap.ToContext(context.Background(), cfgMap.FromContext(testCtx)),
 		Objects: []runtime.Object{
 			cfg("lrrnotexist", "foo", 2,
 				WithLatestCreated("lrrnotexist-00002"),
@@ -504,6 +547,7 @@ func TestReconcile(t *testing.T) {
 		r := &Reconciler{
 			client:         servingclient.Get(ctx),
 			revisionLister: listers.GetRevisionLister(),
+			clock:          testClock,
 		}
 
 		return configreconciler.NewReconciler(ctx, logging.FromContext(ctx),
@@ -534,7 +578,7 @@ func cfg(name, namespace string, generation int64, co ...ConfigOption) *v1.Confi
 }
 
 func rev(name, namespace string, generation int64, ro ...RevisionOption) *v1.Revision {
-	r := resources.MakeRevision(cfg(name, namespace, generation))
+	r := resources.MakeRevision(testCtx, cfg(name, namespace, generation), testClock)
 	r.SetDefaults(v1.WithUpgradeViaDefaulting(context.Background()))
 	for _, opt := range ro {
 		opt(r)
diff --git a/pkg/reconciler/configuration/resources/revision_test.go b/pkg/reconciler/configuration/resources/revision_test.go
index 792fc3473..069cb1ca2 100644
--- a/pkg/reconciler/configuration/resources/revision_test.go
+++ b/pkg/reconciler/configuration/resources/revision_test.go
@@ -16,23 +16,34 @@ limitations under the License.
 package resources
 
 import (
+	"context"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/clock"
+
 	"knative.dev/pkg/ptr"
+	cfgMap "knative.dev/serving/pkg/apis/config"
 	"knative.dev/serving/pkg/apis/serving"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
 )
 
+var fakeCurTime = time.Unix(1e9, 0)
+
 func TestMakeRevisions(t *testing.T) {
+	clock := clock.NewFakeClock(fakeCurTime)
+
 	tests := []struct {
 		name          string
+		responsiveGC  bool
 		configuration *v1.Configuration
 		want          *v1.Revision
 	}{{
-		name: "no build",
+		name:         "no build",
+		responsiveGC: true,
 		configuration: &v1.Configuration{
 			ObjectMeta: metav1.ObjectMeta{
 				Namespace:  "no",
@@ -55,7 +66,6 @@ func TestMakeRevisions(t *testing.T) {
 			ObjectMeta: metav1.ObjectMeta{
 				Namespace:    "no",
 				GenerateName: "build-",
-				Annotations:  map[string]string{},
 				OwnerReferences: []metav1.OwnerReference{{
 					APIVersion:         v1.SchemeGroupVersion.String(),
 					Kind:               "Configuration",
@@ -64,10 +74,14 @@ func TestMakeRevisions(t *testing.T) {
 					BlockOwnerDeletion: ptr.Bool(true),
 				}},
 				Labels: map[string]string{
+					serving.RoutingStateLabelKey:            "pending",
 					serving.ConfigurationLabelKey:           "build",
 					serving.ConfigurationGenerationLabelKey: "10",
 					serving.ServiceLabelKey:                 "",
 				},
+				Annotations: map[string]string{
+					serving.RoutingStateModifiedAnnotationKey: v1.RoutingStateModifiedString(clock),
+				},
 			},
 			Spec: v1.RevisionSpec{
 				PodSpec: corev1.PodSpec{
@@ -302,10 +316,26 @@ func TestMakeRevisions(t *testing.T) {
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			got := MakeRevision(test.configuration)
+			ctx := context.Background()
+			if test.responsiveGC {
+				ctx = enableResponsiveGC(ctx)
+			}
+
+			got := MakeRevision(ctx, test.configuration, clock)
 			if diff := cmp.Diff(test.want, got); diff != "" {
 				t.Errorf("MakeRevision (-want, +got) = %v", diff)
 			}
 		})
 	}
 }
+
+func enableResponsiveGC(ctx context.Context) context.Context {
+	defaultDefaults, _ := cfgMap.NewDefaultsConfigFromMap(map[string]string{})
+	c := &cfgMap.Config{
+		Features: &cfgMap.Features{
+			ResponsiveRevisionGC: cfgMap.Enabled,
+		},
+		Defaults: defaultDefaults,
+	}
+	return cfgMap.ToContext(ctx, c)
+}
diff --git a/pkg/reconciler/gc/reconciler_test.go b/pkg/reconciler/gc/reconciler_test.go
index e57bf95f6..83263e24c 100644
--- a/pkg/reconciler/gc/reconciler_test.go
+++ b/pkg/reconciler/gc/reconciler_test.go
@@ -25,6 +25,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/clock"
 	clientgotesting "k8s.io/client-go/testing"
 	"knative.dev/pkg/configmap"
 	"knative.dev/pkg/controller"
@@ -178,7 +179,7 @@ func cfg(name, namespace string, generation int64, co ...ConfigOption) *v1.Confi
 
 func rev(name, namespace string, generation int64, ro ...RevisionOption) *v1.Revision {
 	config := cfg(name, namespace, generation)
-	rev := resources.MakeRevision(config)
+	rev := resources.MakeRevision(context.Background(), config, clock.RealClock{})
 	rev.SetDefaults(context.Background())
 
 	for _, opt := range ro {
diff --git a/pkg/reconciler/gc/v1/gc_test.go b/pkg/reconciler/gc/v1/gc_test.go
index 37394d872..3e3e21140 100644
--- a/pkg/reconciler/gc/v1/gc_test.go
+++ b/pkg/reconciler/gc/v1/gc_test.go
@@ -25,6 +25,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/clock"
 	clientgotesting "k8s.io/client-go/testing"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	"knative.dev/pkg/ptr"
@@ -60,6 +61,16 @@ func TestCollect(t *testing.T) {
 	older := now.Add(-12 * time.Minute)
 	oldest := now.Add(-13 * time.Minute)
 
+	cfgMap := &config.Config{
+		RevisionGC: &gcconfig.Config{
+			StaleRevisionCreateDelay:        5 * time.Minute,
+			StaleRevisionTimeout:            5 * time.Minute,
+			StaleRevisionMinimumGenerations: 2,
+		},
+	}
+	ctx, _ := SetupFakeContext(t)
+	ctx = config.ToContext(ctx, cfgMap)
+
 	table := []struct {
 		name        string
 		cfg         *v1.Configuration
@@ -72,15 +83,15 @@ func TestCollect(t *testing.T) {
 			WithLatestReady("5556"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-two", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(tenMinutesAgo)),
-			rev("keep-two", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(tenMinutesAgo)),
-			rev("keep-two", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(tenMinutesAgo)),
@@ -105,14 +116,14 @@ func TestCollect(t *testing.T) {
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
 			// No lastPinned so we will keep this.
-			rev("keep-no-last-pinned", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-no-last-pinned", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest)),
-			rev("keep-no-last-pinned", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-no-last-pinned", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(tenMinutesAgo)),
-			rev("keep-no-last-pinned", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-no-last-pinned", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(tenMinutesAgo)),
@@ -124,16 +135,16 @@ func TestCollect(t *testing.T) {
 			WithLatestReady("5556"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-recent-last-pinned", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-recent-last-pinned", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				// This is an indication that things are still routing here.
 				WithLastPinned(now)),
-			rev("keep-recent-last-pinned", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-recent-last-pinned", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(tenMinutesAgo)),
-			rev("keep-recent-last-pinned", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-recent-last-pinned", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(tenMinutesAgo)),
@@ -149,15 +160,15 @@ func TestCollect(t *testing.T) {
 		revs: []*v1.Revision{
 			// Create a revision where the LatestReady is 5554, but LatestCreated is 5556.
 			// We should keep LatestReady even if it is old.
-			rev("keep-two", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(tenMinutesAgo)),
-			rev("keep-two", "foo", 5555, // Not Ready
+			rev(ctx, "keep-two", "foo", 5555, // Not Ready
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(tenMinutesAgo)),
-			rev("keep-two", "foo", 5556, // Not Ready
+			rev(ctx, "keep-two", "foo", 5556, // Not Ready
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(tenMinutesAgo)),
@@ -170,24 +181,16 @@ func TestCollect(t *testing.T) {
 			WithLatestCreated("keep-all"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-all", "foo", 5554,
+			rev(ctx, "keep-all", "foo", 5554,
 				WithRevName("keep-all"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(tenMinutesAgo)),
 		},
 	}}
 
-	cfgMap := &config.Config{
-		RevisionGC: &gcconfig.Config{
-			StaleRevisionCreateDelay:        5 * time.Minute,
-			StaleRevisionTimeout:            5 * time.Minute,
-			StaleRevisionMinimumGenerations: 2,
-		},
-	}
-
 	for _, test := range table {
 		t.Run(test.name, func(t *testing.T) {
-			ctx, _ := SetupFakeContext(t)
+			ctx, _ = SetupFakeContext(t)
 			ctx = config.ToContext(ctx, cfgMap)
 			client := fakeservingclient.Get(ctx)
 
@@ -365,9 +368,9 @@ func cfg(name, namespace string, generation int64, co ...ConfigOption) *v1.Confi
 	return c
 }
 
-func rev(name, namespace string, generation int64, ro ...RevisionOption) *v1.Revision {
+func rev(ctx context.Context, name, namespace string, generation int64, ro ...RevisionOption) *v1.Revision {
 	config := cfg(name, namespace, generation)
-	rev := resources.MakeRevision(config)
+	rev := resources.MakeRevision(ctx, config, clock.RealClock{})
 	rev.SetDefaults(context.Background())
 
 	for _, opt := range ro {
diff --git a/pkg/reconciler/gc/v2/gc_test.go b/pkg/reconciler/gc/v2/gc_test.go
index 2324730a2..f5e417598 100644
--- a/pkg/reconciler/gc/v2/gc_test.go
+++ b/pkg/reconciler/gc/v2/gc_test.go
@@ -25,6 +25,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/clock"
 	clientgotesting "k8s.io/client-go/testing"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	"knative.dev/pkg/ptr"
@@ -61,6 +62,16 @@ func TestCollect(t *testing.T) {
 	older := now.Add(-12 * time.Minute)
 	oldest := now.Add(-13 * time.Minute)
 
+	cfgMap := &config.Config{
+		RevisionGC: &gcconfig.Config{
+			StaleRevisionCreateDelay:        5 * time.Minute,
+			StaleRevisionTimeout:            5 * time.Minute,
+			StaleRevisionMinimumGenerations: 2,
+		},
+	}
+	ctx, _ := SetupFakeContext(t)
+	ctx = config.ToContext(ctx, cfgMap)
+
 	table := []struct {
 		name        string
 		cfg         *v1.Configuration
@@ -73,15 +84,15 @@ func TestCollect(t *testing.T) {
 			WithLatestReady("5556"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-two", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(oldest)),
-			rev("keep-two", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(older)),
-			rev("keep-two", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(old)),
@@ -105,15 +116,15 @@ func TestCollect(t *testing.T) {
 			WithLatestReady("5556"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-two", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				WithRoutingStateModified(oldest)),
-			rev("keep-two", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithRoutingStateModified(older)),
-			rev("keep-two", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithRoutingStateModified(old)),
@@ -138,14 +149,14 @@ func TestCollect(t *testing.T) {
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
 			// No lastPinned so we will keep this.
-			rev("keep-no-last-pinned", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-no-last-pinned", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest)),
-			rev("keep-no-last-pinned", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-no-last-pinned", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(older)),
-			rev("keep-no-last-pinned", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-no-last-pinned", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(old)),
@@ -157,16 +168,16 @@ func TestCollect(t *testing.T) {
 			WithLatestReady("5556"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-recent-last-pinned", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-recent-last-pinned", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				// This is an indication that things are still routing here.
 				WithLastPinned(now)),
-			rev("keep-recent-last-pinned", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-recent-last-pinned", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(nineMinutesAgo)),
-			rev("keep-recent-last-pinned", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-recent-last-pinned", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(tenMinutesAgo)),
@@ -182,15 +193,15 @@ func TestCollect(t *testing.T) {
 		revs: []*v1.Revision{
 			// Create a revision where the LatestReady is 5554, but LatestCreated is 5556.
 			// We should keep LatestReady even if it is old.
-			rev("keep-two", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-two", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(oldest)),
-			rev("keep-two", "foo", 5555, // Not Ready
+			rev(ctx, "keep-two", "foo", 5555, // Not Ready
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(older)),
-			rev("keep-two", "foo", 5556, // Not Ready
+			rev(ctx, "keep-two", "foo", 5556, // Not Ready
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(old)),
@@ -203,7 +214,7 @@ func TestCollect(t *testing.T) {
 			WithLatestCreated("keep-all"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-all", "foo", 5554,
+			rev(ctx, "keep-all", "foo", 5554,
 				WithRevName("keep-all"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(old)),
@@ -215,20 +226,20 @@ func TestCollect(t *testing.T) {
 			WithLatestReady("5556"),
 			WithConfigObservedGen),
 		revs: []*v1.Revision{
-			rev("keep-oldest", "foo", 5554, MarkRevisionReady,
+			rev(ctx, "keep-oldest", "foo", 5554, MarkRevisionReady,
 				WithRevName("5554"),
 				WithCreationTimestamp(oldest),
 				WithLastPinned(oldest),
 				WithRevisionPreserveAnnotation()),
-			rev("keep-oldest", "foo", 5555, MarkRevisionReady,
+			rev(ctx, "keep-oldest", "foo", 5555, MarkRevisionReady,
 				WithRevName("5555"),
 				WithCreationTimestamp(older),
 				WithLastPinned(older)),
-			rev("keep-oldest", "foo", 5556, MarkRevisionReady,
+			rev(ctx, "keep-oldest", "foo", 5556, MarkRevisionReady,
 				WithRevName("5556"),
 				WithCreationTimestamp(old),
 				WithLastPinned(old)),
-			rev("keep-oldest", "foo", 5557, MarkRevisionReady,
+			rev(ctx, "keep-oldest", "foo", 5557, MarkRevisionReady,
 				WithRevName("5557"),
 				WithCreationTimestamp(tenMinutesAgo),
 				WithLastPinned(tenMinutesAgo)),
@@ -247,17 +258,9 @@ func TestCollect(t *testing.T) {
 		}},
 	}}
 
-	cfgMap := &config.Config{
-		RevisionGC: &gcconfig.Config{
-			StaleRevisionCreateDelay:        5 * time.Minute,
-			StaleRevisionTimeout:            5 * time.Minute,
-			StaleRevisionMinimumGenerations: 2,
-		},
-	}
-
 	for _, test := range table {
 		t.Run(test.name, func(t *testing.T) {
-			ctx, _ := SetupFakeContext(t)
+			ctx, _ = SetupFakeContext(t)
 			ctx = config.ToContext(ctx, cfgMap)
 			client := fakeservingclient.Get(ctx)
 
@@ -435,9 +438,9 @@ func cfg(name, namespace string, generation int64, co ...ConfigOption) *v1.Confi
 	return c
 }
 
-func rev(name, namespace string, generation int64, ro ...RevisionOption) *v1.Revision {
+func rev(ctx context.Context, name, namespace string, generation int64, ro ...RevisionOption) *v1.Revision {
 	config := cfg(name, namespace, generation)
-	rev := resources.MakeRevision(config)
+	rev := resources.MakeRevision(ctx, config, clock.RealClock{})
 	rev.SetDefaults(context.Background())
 
 	for _, opt := range ro {
diff --git a/pkg/reconciler/service/service_test.go b/pkg/reconciler/service/service_test.go
index 7490135ab..71ec4a6f9 100644
--- a/pkg/reconciler/service/service_test.go
+++ b/pkg/reconciler/service/service_test.go
@@ -45,6 +45,7 @@ import (
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/clock"
 	clientgotesting "k8s.io/client-go/testing"
 
 	. "knative.dev/pkg/reconciler/testing"
@@ -855,5 +856,5 @@ func RouteFailed(reason, message string) RouteOption {
 
 func rev(name, namespace string, so ServiceOption, co ...ConfigOption) *v1.Revision {
 	cfg := config(name, namespace, so, co...)
-	return configresources.MakeRevision(cfg)
+	return configresources.MakeRevision(context.Background(), cfg, clock.RealClock{})
 }
diff --git a/pkg/testing/v1/revision.go b/pkg/testing/v1/revision.go
index 801d108e6..ba372e454 100644
--- a/pkg/testing/v1/revision.go
+++ b/pkg/testing/v1/revision.go
@@ -21,6 +21,7 @@ import (
 
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/clock"
 	"knative.dev/pkg/kmeta"
 	"knative.dev/serving/pkg/apis/serving"
 	v1 "knative.dev/serving/pkg/apis/serving/v1"
@@ -115,7 +116,7 @@ func WithRoutingStateModified(t time.Time) RevisionOption {
 // WithRoutingState updates the annotation to the provided timestamp.
 func WithRoutingState(s v1.RoutingState) RevisionOption {
 	return func(rev *v1.Revision) {
-		rev.SetRoutingState(s)
+		rev.SetRoutingState(s, clock.RealClock{})
 	}
 }
 
diff --git a/vendor/knative.dev/pkg/test/logstream/kubelogs.go b/vendor/knative.dev/pkg/test/logstream/kubelogs.go
index c120b7e1c..ed9368718 100644
--- a/vendor/knative.dev/pkg/test/logstream/kubelogs.go
+++ b/vendor/knative.dev/pkg/test/logstream/kubelogs.go
@@ -113,16 +113,13 @@ func (k *kubelogs) watchPods(t test.TLegacy) {
 				watchedPods.Delete(p.Name)
 			case watch.Added, watch.Modified:
 				if watchedPods.Has(p.Name) {
-					t.Log("Already watching pod", p.Name)
 					continue
 				}
 				if podIsReady(p) {
-					t.Log("Watching logs for pod: ", p.Name)
 					watchedPods.Insert(p.Name)
 					k.startForPod(&eg, p)
 					continue
 				}
-				t.Log("Pod is not yet ready: ", p.Name)
 			}
 		}
 	}()
diff --git a/vendor/knative.dev/test-infra/scripts/e2e-tests.sh b/vendor/knative.dev/test-infra/scripts/e2e-tests.sh
index 9f96ce57f..ade432092 100644
--- a/vendor/knative.dev/test-infra/scripts/e2e-tests.sh
+++ b/vendor/knative.dev/test-infra/scripts/e2e-tests.sh
@@ -85,6 +85,19 @@ function go_test_e2e() {
   report_go_test -v -race -count=1 ${go_options} $@ "${test_options}"
 }
 
+# Dumps the k8s api server metrics. Spins up a proxy, waits a little bit and
+# dumps the metrics to ${ARTIFACTS}/k8s.metrics.txt
+function dump_metrics() {
+    header ">> Starting kube proxy"
+    kubectl proxy --port=8080 &
+    local proxy_pid=$!
+    sleep 5
+    header ">> Grabbing k8s metrics"
+    curl -s http://localhost:8080/metrics ${ARTIFACTS}/k8s.metrics.txt
+    # Clean up proxy so it doesn't interfere with job shutting down
+    kill $proxy_pid || true
+}
+
 # Dump info about the test cluster. If dump_extra_cluster_info() is defined, calls it too.
 # This is intended to be called when a test fails to provide debugging information.
 function dump_cluster_state() {
@@ -410,6 +423,7 @@ function success() {
   echo "**************************************"
   echo "***        E2E TESTS PASSED        ***"
   echo "**************************************"
+  dump_metrics
   exit 0
 }
 
@@ -419,6 +433,7 @@ function fail_test() {
   set_test_return_code 1
   [[ -n $1 ]] && echo "ERROR: $1"
   dump_cluster_state
+  dump_metrics
   exit 1
 }
 
diff --git a/vendor/knative.dev/test-infra/scripts/library.sh b/vendor/knative.dev/test-infra/scripts/library.sh
index ab8390f1a..ce4312c60 100644
--- a/vendor/knative.dev/test-infra/scripts/library.sh
+++ b/vendor/knative.dev/test-infra/scripts/library.sh
@@ -134,7 +134,9 @@ function wait_until_pods_running() {
   echo -n "Waiting until all pods in namespace $1 are up"
   local failed_pod=""
   for i in {1..150}; do  # timeout after 5 minutes
-    local pods="$(kubectl get pods --no-headers -n $1 2>/dev/null)"
+    # List all pods. Ignore Terminating pods as those have either been replaced through
+    # a deployment or terminated on purpose (through chaosduck for example).
+    local pods="$(kubectl get pods --no-headers -n $1 2>/dev/null | grep -v Terminating)"
     # All pods must be running (ignore ImagePull error to allow the pod to retry)
     local not_running_pods=$(echo "${pods}" | grep -v Running | grep -v Completed | grep -v ErrImagePull | grep -v ImagePullBackOff)
     if [[ -n "${pods}" ]] && [[ -z "${not_running_pods}" ]]; then