Repository: knative/serving
Pull request #8308 (2020-06-12 15:07:12)

Extract and add comments to standalone exec probe flow
The fact that the Queue Proxy's main.go actually has a standalone exec probe mode, and what it does (and why :)), is pretty confusing to new readers (or it was to me, anyway).

This just makes it a bit clearer by adding some clarifying comments and pulling the standalone-exec-probe stuff (and corresponding tests) out to their own file alongside the existing main.go.

/assign @vagababov 

<!--
Request Prow to automatically lint any go code in this PR:

/lint
-->

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

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

- **[cmd/queue/OWNERS](https://github.com/knative/serving/blob/master/cmd/queue/OWNERS)**
- **[pkg/network/OWNERS](https://github.com/knative/serving/blob/master/pkg/network/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":["zhiminxiang"]} -->
knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

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

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

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

- **[cmd/queue/OWNERS](https://github.com/knative/serving/blob/master/cmd/queue/OWNERS)**
- **[pkg/network/OWNERS](https://github.com/knative/serving/blob/master/pkg/network/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["vagababov"]} -->
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
---- |:------------:|:------------:|:-----:
[cmd/queue/execprobe.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_serving/8308/pull-knative-serving-go-coverage/1271459636741935104/artifacts/line-cov.html#file0) | Do not exist | 72.2% | 

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

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

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

<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/cmd/queue/execprobe.go b/cmd/queue/execprobe.go
new file mode 100644
index 000000000..cefb70576
--- /dev/null
+++ b/cmd/queue/execprobe.go
@@ -0,0 +1,134 @@
+/*
+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 main
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"strconv"
+	"time"
+
+	"k8s.io/apimachinery/pkg/util/wait"
+	"knative.dev/serving/pkg/network"
+	"knative.dev/serving/pkg/queue"
+	"knative.dev/serving/pkg/queue/health"
+	"knative.dev/serving/pkg/queue/readiness"
+)
+
+const (
+	healthURLPrefix = "http://127.0.0.1:"
+
+	// The 25 millisecond retry interval is an unscientific compromise between wanting to get
+	// started as early as possible while still wanting to give the container some breathing
+	// room to get up and running.
+	aggressivePollInterval = 25 * time.Millisecond
+)
+
+// As well as running as a long-running proxy server, the Queue Proxy can be
+// run as an exec probe if the `--probe-period` flag is passed.
+//
+// In this mode, the exec probe (repeatedly) sends an HTTP request to the Queue
+// Proxy server with a Probe header. The handler for this probe request
+// (knativeProbeHandler) then performs the actual health check against the user
+// container. The exec probe binary exits 0 (success) if it eventually gets a
+// 200 status code back from the knativeProbeHandler, or 1 (fail) if it never
+// does.
+//
+// The reason we use an exec probe to hit an HTTP endpoint on the Queue
+// Proxy to then run the actual probe against the user container rather than
+// using an HTTP probe directly is because an exec probe can be launched
+// immediately after the container starts, whereas an HTTP probe would
+// initially race with the server starting up and fail. The minimum retry
+// period after this failure in upstream kubernetes is a second. The exec
+// probe, on the other hand, automatically polls on an aggressivePollInterval
+// until the HTTP endpoint responds with success. This allows us to get an
+// initial readiness result much faster than the effective upstream Kubernetes
+// minimum of 1 second.
+func standaloneProbeMain(timeout int) (exitCode int) {
+	queueServingPort, err := strconv.Atoi(os.Getenv("QUEUE_SERVING_PORT"))
+	if err != nil {
+		fmt.Fprintln(os.Stderr, "parse queue port:", err)
+		return 1
+	}
+
+	if err := probeQueueHealthPath(timeout, queueServingPort); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		return 1
+	}
+
+	return 0
+}
+
+func probeQueueHealthPath(timeoutSeconds, queueServingPort int) error {
+	if queueServingPort <= 0 {
+		return fmt.Errorf("port must be a positive value, got %d", queueServingPort)
+	}
+
+	url := healthURLPrefix + strconv.Itoa(queueServingPort)
+	timeoutDuration := readiness.PollTimeout
+	if timeoutSeconds != 0 {
+		timeoutDuration = time.Duration(timeoutSeconds) * time.Second
+	}
+
+	req, err := http.NewRequest(http.MethodGet, url, nil)
+	if err != nil {
+		return fmt.Errorf("probe failed: error creating request: %w", err)
+	}
+
+	// Add the header to indicate this is a probe request.
+	req.Header.Add(network.ProbeHeaderName, queue.Name)
+	req.Header.Add(network.UserAgentKey, network.QueueProxyUserAgent)
+
+	httpClient := &http.Client{
+		Timeout: timeoutDuration,
+	}
+	ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
+	defer cancel()
+
+	var lastErr error
+	// Using PollImmediateUntil instead of PollImmediate because if timeout is reached while waiting for first
+	// invocation of conditionFunc, it exits immediately without trying for a second time.
+	timeoutErr := wait.PollImmediateUntil(aggressivePollInterval, func() (bool, error) {
+		res, lastErr := httpClient.Do(req)
+		if lastErr != nil {
+			// Return nil error for retrying
+			return false, nil
+		}
+		defer res.Body.Close()
+
+		// fail readiness immediately rather than retrying if we get a header indicating we're shutting down.
+		if health.IsHTTPProbeShuttingDown(res) {
+			return false, errors.New("failing probe deliberately for shutdown")
+		}
+
+		return health.IsHTTPProbeReady(res), nil
+	}, ctx.Done())
+
+	if lastErr != nil {
+		return fmt.Errorf("failed to probe: %w", lastErr)
+	}
+
+	// An http.StatusOK was never returned during probing
+	if timeoutErr != nil {
+		return errors.New("probe returned not ready")
+	}
+
+	return nil
+}
diff --git a/cmd/queue/main.go b/cmd/queue/main.go
index b0334470e..176d26550 100644
--- a/cmd/queue/main.go
+++ b/cmd/queue/main.go
@@ -18,7 +18,6 @@ package main
 
 import (
 	"context"
-	"errors"
 	"flag"
 	"fmt"
 	"net"
@@ -36,7 +35,6 @@ import (
 	"go.uber.org/zap"
 
 	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/apimachinery/pkg/util/wait"
 
 	"knative.dev/networking/pkg/apis/networking"
 	pkglogging "knative.dev/pkg/logging"
@@ -59,14 +57,8 @@ import (
 )
 
 const (
-	badProbeTemplate   = "unexpected probe header value: %s"
-	failingHealthcheck = "failing healthcheck"
-
-	healthURLPrefix = "http://127.0.0.1:"
-	// The 25 millisecond retry interval is an unscientific compromise between wanting to get
-	// started as early as possible while still wanting to give the container some breathing
-	// room to get up and running.
-	aggressivePollInterval = 25 * time.Millisecond
+	badProbeTemplate = "unexpected probe header value: %s"
+
 	// reportingPeriod is the interval of time between reporting stats by queue proxy.
 	reportingPeriod = 1 * time.Second
 )
@@ -197,81 +189,12 @@ func knativeProbeHandler(healthState *health.State, prober func() bool, isAggres
 	}
 }
 
-func probeQueueHealthPath(timeoutSeconds, queueServingPort int) error {
-	if queueServingPort <= 0 {
-		return fmt.Errorf("port must be a positive value, got %d", queueServingPort)
-	}
-
-	url := healthURLPrefix + strconv.Itoa(queueServingPort)
-	timeoutDuration := readiness.PollTimeout
-	if timeoutSeconds != 0 {
-		timeoutDuration = time.Duration(timeoutSeconds) * time.Second
-	}
-
-	req, err := http.NewRequest(http.MethodGet, url, nil)
-	if err != nil {
-		return fmt.Errorf("probe failed: error creating request: %w", err)
-	}
-	// Add the header to indicate this is a probe request.
-	req.Header.Add(network.ProbeHeaderName, queue.Name)
-	req.Header.Add(network.UserAgentKey, network.QueueProxyUserAgent)
-
-	httpClient := &http.Client{
-		Timeout: timeoutDuration,
-	}
-	ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration)
-	defer cancel()
-
-	var lastErr error
-	// Using PollImmediateUntil instead of PollImmediate because if timeout is reached while waiting for first
-	// invocation of conditionFunc, it exits immediately without trying for a second time.
-	timeoutErr := wait.PollImmediateUntil(aggressivePollInterval, func() (bool, error) {
-		res, lastErr := httpClient.Do(req)
-		if lastErr != nil {
-			// Return nil error for retrying
-			return false, nil
-		}
-		defer res.Body.Close()
-
-		// fail readiness immediately rather than retrying if we get a header indicating we're shutting down.
-		if health.IsHTTPProbeShuttingDown(res) {
-			return false, errors.New("failing probe deliberately for shutdown")
-		}
-
-		return health.IsHTTPProbeReady(res), nil
-	}, ctx.Done())
-
-	if lastErr != nil {
-		return fmt.Errorf("failed to probe: %w", lastErr)
-	}
-
-	// An http.StatusOK was never returned during probing
-	if timeoutErr != nil {
-		return errors.New("probe returned not ready")
-	}
-
-	return nil
-}
-
 func main() {
 	flag.Parse()
 
 	// If this is set, we run as a standalone binary to probe the queue-proxy.
 	if *readinessProbeTimeout >= 0 {
-		queueServingPort, err := strconv.Atoi(os.Getenv("QUEUE_SERVING_PORT"))
-		if err != nil {
-			// used instead of the logger to produce a concise event message
-			fmt.Fprintln(os.Stderr, "parse queue port:", err)
-			os.Exit(1)
-		}
-
-		if err := probeQueueHealthPath(*readinessProbeTimeout, queueServingPort); err != nil {
-			// used instead of the logger to produce a concise event message
-			fmt.Fprintln(os.Stderr, err)
-			os.Exit(1)
-		}
-
-		os.Exit(0)
+		os.Exit(standaloneProbeMain(*readinessProbeTimeout))
 	}
 
 	// Parse the environment.
diff --git a/go.mod b/go.mod
index 5385b5110..95e31b092 100644
--- a/go.mod
+++ b/go.mod
@@ -42,9 +42,9 @@ require (
 	k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
 	k8s.io/metrics v0.17.6
 	knative.dev/caching v0.0.0-20200606210318-787aec80f71c
-	knative.dev/networking v0.0.0-20200607161819-2086ac6759c2
-	knative.dev/pkg v0.0.0-20200609184032-fef70cc2616b
-	knative.dev/test-infra v0.0.0-20200610052322-f0f63d4ead3d
+	knative.dev/networking v0.0.0-20200611155523-bd13675bcf70
+	knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2
+	knative.dev/test-infra v0.0.0-20200612005123-35b61c499a41
 )
 
 // pin the older grpc - see: https://github.com/grpc/grpc-go/issues/3180
diff --git a/go.sum b/go.sum
index 189fc8773..7844f8472 100644
--- a/go.sum
+++ b/go.sum
@@ -1339,8 +1339,8 @@ knative.dev/caching v0.0.0-20200606210318-787aec80f71c h1:4w9QOkxY1VNH/82LIefx8u
 knative.dev/caching v0.0.0-20200606210318-787aec80f71c/go.mod h1:rWD+0zSqcE7L//jJyt866xtXsOi9hCdB0FoD4w2Rygg=
 knative.dev/eventing-contrib v0.6.1-0.20190723221543-5ce18048c08b/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g=
 knative.dev/eventing-contrib v0.11.2/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g=
-knative.dev/networking v0.0.0-20200607161819-2086ac6759c2 h1:Y/MvHoNKQxY1rBZ9Q7tOI0qnrhxkBPDH42pfGcTfy+s=
-knative.dev/networking v0.0.0-20200607161819-2086ac6759c2/go.mod h1:Li97sQaAoh+CaIApZECftaXD+LxdzucIoLSccq2t/kA=
+knative.dev/networking v0.0.0-20200611155523-bd13675bcf70 h1:xS3YAzmfFwmNXFXj6rM2n3FbBHziWvN3FMQmgUKv7bU=
+knative.dev/networking v0.0.0-20200611155523-bd13675bcf70/go.mod h1:PU1dM8mNwh+k3xDBXR54h2fafRgp8pIU5W43dYV7LkA=
 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-20200207155214-fef852970f43/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
@@ -1354,10 +1354,10 @@ knative.dev/pkg v0.0.0-20200519155757-14eb3ae3a5a7/go.mod h1:QgNZTxnwpB/oSpNcfnL
 knative.dev/pkg v0.0.0-20200520073958-94316e20e860/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA=
 knative.dev/pkg v0.0.0-20200603222317-b79e4a24ca50 h1:sbJMCCtOENPgfE5dUSwBUxZtJzhfqORhExyWFX7L0Fk=
 knative.dev/pkg v0.0.0-20200603222317-b79e4a24ca50/go.mod h1:8IfPj/lpuKHHg82xZCl2wuFZ3BM96To72sN1W8T9wjQ=
-knative.dev/pkg v0.0.0-20200605170718-b7125260dc6f h1:2WVJ2b5Yws8klA2yCNkprY8EaQAR/mCVdV9XeI/4/Y0=
-knative.dev/pkg v0.0.0-20200605170718-b7125260dc6f/go.mod h1:ItJ3UvcHFt7qMoowI2uXfaGMWNGIMYAtzAbdsi+b0Cg=
 knative.dev/pkg v0.0.0-20200609184032-fef70cc2616b h1:L25RYK4WW4kVVUQHl6JA3oacGTMZxiiOG1QETHtBxR8=
 knative.dev/pkg v0.0.0-20200609184032-fef70cc2616b/go.mod h1:rA+FklsrVahwF4a+D63NyHJlzDoAFH81K4J5CYuE3bA=
+knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2 h1:GMCS1McFzXLs+Q5jj/iKyue+Gbx4BytNZAhRpLamdz8=
+knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2/go.mod h1:rA+FklsrVahwF4a+D63NyHJlzDoAFH81K4J5CYuE3bA=
 knative.dev/sample-controller v0.0.0-20200510050845-bf7c19498b7e/go.mod h1:D2ZDLrR9Dq9LiiVN7TatzI7WMcEPgk1MHbbhgBKE6W8=
 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=
@@ -1371,12 +1371,11 @@ knative.dev/test-infra v0.0.0-20200519161858-554a95a37986 h1:ZDy43jkWPQ75d4l4DGy
 knative.dev/test-infra v0.0.0-20200519161858-554a95a37986/go.mod h1:LeNa1Wvn47efeQUkpkn3XG7Fx9Ga+rhAP13SZyjaEGg=
 knative.dev/test-infra v0.0.0-20200522180958-6a0a9b9d893a h1:c0qTABRcNoxZVu5gsryLWPZtGa/s4zsvovz0nGefuzg=
 knative.dev/test-infra v0.0.0-20200522180958-6a0a9b9d893a/go.mod h1:n9eQkzmSNj8BiqNFl1lzoz68D09uMeJfyOjc132Gbik=
-knative.dev/test-infra v0.0.0-20200605033518-4b5d9e1bbdbe h1:8jvsC2cS3Xc/KOPnCOJSpxtQqgx8ZoDPEgaoRrNq8Uk=
-knative.dev/test-infra v0.0.0-20200605033518-4b5d9e1bbdbe/go.mod h1:wsGme3loBZjSjhuaTUhejJ34EOwKZ5KXkweKL0zSKhM=
 knative.dev/test-infra v0.0.0-20200606045118-14ebc4a42974 h1:CrZmlbB+j3ZF/aTrfyypY5ulX2w7XrkfeXKQsbkqzTg=
 knative.dev/test-infra v0.0.0-20200606045118-14ebc4a42974/go.mod h1://I6IZIF0QDgs5wotU243ZZ5cTpm6/GthayjUenBBc0=
-knative.dev/test-infra v0.0.0-20200610052322-f0f63d4ead3d h1:O0Zh5UuL+cj7POqNSsvoMvk8wi3vY/2tYFfMIdIEn9A=
-knative.dev/test-infra v0.0.0-20200610052322-f0f63d4ead3d/go.mod h1://I6IZIF0QDgs5wotU243ZZ5cTpm6/GthayjUenBBc0=
+knative.dev/test-infra v0.0.0-20200610141822-fd009ecf10fe/go.mod h1:vyiP+4ospN/PJgwVzHkjnhlNP4uBPnvwkgb9dPCFSj4=
+knative.dev/test-infra v0.0.0-20200612005123-35b61c499a41 h1:KJMDpNdLRN39P/U6rspOTLorWEKcUZfy09gkLmWB0Ik=
+knative.dev/test-infra v0.0.0-20200612005123-35b61c499a41/go.mod h1:vyiP+4ospN/PJgwVzHkjnhlNP4uBPnvwkgb9dPCFSj4=
 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/network/stats.go b/pkg/network/stats.go
index d4be2f734..bff893e1d 100644
--- a/pkg/network/stats.go
+++ b/pkg/network/stats.go
@@ -130,8 +130,8 @@ func (s *RequestStats) HandleEvent(event ReqEvent) {
 	}
 }
 
-// Report returns averageConcurrency, averageProxiedConcurrency, requestCount and proxiedCount
-// relative to the given time. The state will be reset for another reporting cycle afterwards.
+// Report returns a RequestStatsReport relative to the given time. The state
+// will be reset for another reporting cycle afterwards.
 func (s *RequestStats) Report(now time.Time) RequestStatsReport {
 	s.mux.Lock()
 	defer s.mux.Unlock()
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 2a8f11763..8dcd4e41a 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: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
     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: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
 webhooks:
 - admissionReviewVersions:
   - v1beta1
@@ -86,7 +86,7 @@ metadata:
   name: net-certmanager-webhook-certs
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
 
 ---
 # Copyright 2020 The Knative Authors
@@ -109,7 +109,7 @@ metadata:
   name: config-certmanager
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
     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: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
     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: "v20200611-92e2c6a"
+        serving.knative.dev/release: "v20200612-92e2c6a"
     spec:
       serviceAccountName: controller
       containers:
@@ -208,7 +208,7 @@ kind: Service
 metadata:
   labels:
     app: networking-certmanager
-    serving.knative.dev/release: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
     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: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
 spec:
   selector:
     matchLabels:
@@ -258,7 +258,7 @@ spec:
       labels:
         app: net-certmanager-webhook
         role: net-certmanager-webhook
-        serving.knative.dev/release: "v20200611-92e2c6a"
+        serving.knative.dev/release: "v20200612-92e2c6a"
     spec:
       serviceAccountName: controller
       containers:
@@ -319,7 +319,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: net-certmanager-webhook
-    serving.knative.dev/release: "v20200611-92e2c6a"
+    serving.knative.dev/release: "v20200612-92e2c6a"
 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 2d3e1c138..b911f063d 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: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     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: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     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: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     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: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     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: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     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: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     networking.knative.dev/ingress-provider: istio
 
 ---
@@ -216,7 +216,7 @@ metadata:
   name: config-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     networking.knative.dev/ingress-provider: istio
 data:
   _example: |
@@ -286,7 +286,7 @@ metadata:
   name: networking-istio
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     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: "v20200611-f8dd995"
+        serving.knative.dev/release: "v20200612-8788226"
     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:b56627580cfbd947cd89b7630d3fcfa0b902363849dda0b0bc34873fceab95b2
+        image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/controller@sha256:e894c59c2b8687d582442879e307c332a746f6fed510ae2751cd18f68dcc7951
         resources:
           requests:
             cpu: 30m
@@ -361,7 +361,7 @@ metadata:
   name: istio-webhook
   namespace: knative-serving
   labels:
-    serving.knative.dev/release: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     networking.knative.dev/ingress-provider: istio
 spec:
   selector:
@@ -375,14 +375,14 @@ spec:
       labels:
         app: istio-webhook
         role: istio-webhook
-        serving.knative.dev/release: "v20200611-f8dd995"
+        serving.knative.dev/release: "v20200612-8788226"
     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:6113d10d4410ac72e21e56b5627dc5611a26a41ce89a760d3422596e130581dd
+        image: gcr.io/knative-nightly/knative.dev/net-istio/cmd/webhook@sha256:5bed1363a9c30cc884af6eacb0c2606ec9e4f298bedaec80d195671b82dd3901
         resources:
           requests:
             cpu: 20m
@@ -436,7 +436,7 @@ metadata:
   namespace: knative-serving
   labels:
     role: istio-webhook
-    serving.knative.dev/release: "v20200611-f8dd995"
+    serving.knative.dev/release: "v20200612-8788226"
     networking.knative.dev/ingress-provider: istio
 spec:
   ports:
diff --git a/vendor/knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serverlessservice/reconciler.go b/vendor/knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serverlessservice/reconciler.go
index d1e3d09ae..42dc01860 100644
--- a/vendor/knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serverlessservice/reconciler.go
+++ b/vendor/knative.dev/networking/pkg/client/injection/reconciler/networking/v1alpha1/serverlessservice/reconciler.go
@@ -299,10 +299,11 @@ func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource
 
 	patcher := r.Client.NetworkingV1alpha1().ServerlessServices(resource.Namespace)
 
-	resource, err = patcher.Patch(resource.Name, types.MergePatchType, patch)
+	resourceName := resource.Name
+	resource, err = patcher.Patch(resourceName, types.MergePatchType, patch)
 	if err != nil {
 		r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed",
-			"Failed to update finalizers for %q: %v", resource.Name, err)
+			"Failed to update finalizers for %q: %v", resourceName, err)
 	} else {
 		r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate",
 			"Updated %q finalizers", resource.GetName())
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 25e3eeaeb..7daba08e8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1200,7 +1200,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-20200607161819-2086ac6759c2
+# knative.dev/networking v0.0.0-20200611155523-bd13675bcf70
 ## explicit
 knative.dev/networking/pkg/apis/config
 knative.dev/networking/pkg/apis/networking
@@ -1227,7 +1227,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-20200609184032-fef70cc2616b
+# knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2
 ## explicit
 knative.dev/pkg/apiextensions/storageversion
 knative.dev/pkg/apiextensions/storageversion/cmd/migrate
@@ -1344,7 +1344,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-20200610052322-f0f63d4ead3d
+# knative.dev/test-infra v0.0.0-20200612005123-35b61c499a41
 ## explicit
 knative.dev/test-infra/scripts
 # sigs.k8s.io/structured-merge-diff/v2 v2.0.1


Test patch:
diff --git a/cmd/queue/execprobe_test.go b/cmd/queue/execprobe_test.go
new file mode 100644
index 000000000..50acbb8aa
--- /dev/null
+++ b/cmd/queue/execprobe_test.go
@@ -0,0 +1,199 @@
+/*
+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 main
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strconv"
+	"sync/atomic"
+	"testing"
+	"time"
+
+	"github.com/google/go-cmp/cmp"
+	"knative.dev/pkg/ptr"
+	"knative.dev/serving/pkg/network"
+)
+
+func TestProbeQueueInvalidPort(t *testing.T) {
+	if err := probeQueueHealthPath(1, 0); err == nil {
+		t.Error("Expected error, got nil")
+	} else if diff := cmp.Diff(err.Error(), "port must be a positive value, got 0"); diff != "" {
+		t.Errorf("Unexpected not ready message: %s", diff)
+	}
+}
+
+func TestProbeQueueConnectionFailure(t *testing.T) {
+	if err := probeQueueHealthPath(1, 12345); err == nil {
+		t.Error("Expected error, got nil")
+	}
+}
+
+func TestProbeQueueNotReady(t *testing.T) {
+	queueProbed := ptr.Int32(0)
+	ts := newProbeTestServer(func(w http.ResponseWriter) {
+		atomic.AddInt32(queueProbed, 1)
+		w.WriteHeader(http.StatusBadRequest)
+	})
+
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
+	}
+
+	port, err := strconv.Atoi(u.Port())
+	if err != nil {
+		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
+	}
+
+	err = probeQueueHealthPath(1, port)
+
+	if diff := cmp.Diff(err.Error(), "probe returned not ready"); diff != "" {
+		t.Errorf("Unexpected not ready message: %s", diff)
+	}
+
+	if atomic.LoadInt32(queueProbed) == 0 {
+		t.Error("Expected the queue proxy server to be probed")
+	}
+}
+
+func TestProbeQueueShuttingDownFailsFast(t *testing.T) {
+	ts := newProbeTestServer(func(w http.ResponseWriter) {
+		w.WriteHeader(http.StatusGone)
+	})
+
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
+	}
+
+	port, err := strconv.Atoi(u.Port())
+	if err != nil {
+		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
+	}
+
+	start := time.Now()
+	if err = probeQueueHealthPath(1, port); err == nil {
+		t.Error("probeQueueHealthPath did not fail")
+	}
+
+	// if fails due to timeout and not cancelation, then it took too long
+	if time.Since(start) >= 1*time.Second {
+		t.Error("took too long to fail")
+	}
+}
+
+func TestProbeQueueReady(t *testing.T) {
+	queueProbed := ptr.Int32(0)
+	ts := newProbeTestServer(func(w http.ResponseWriter) {
+		atomic.AddInt32(queueProbed, 1)
+		w.WriteHeader(http.StatusOK)
+	})
+
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
+	}
+
+	port, err := strconv.Atoi(u.Port())
+	if err != nil {
+		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
+	}
+
+	if err = probeQueueHealthPath(1, port); err != nil {
+		t.Errorf("probeQueueHealthPath(%d, 1s) = %s", port, err)
+	}
+
+	if atomic.LoadInt32(queueProbed) == 0 {
+		t.Error("Expected the queue proxy server to be probed")
+	}
+}
+
+func TestProbeQueueTimeout(t *testing.T) {
+	queueProbed := ptr.Int32(0)
+	ts := newProbeTestServer(func(w http.ResponseWriter) {
+		atomic.AddInt32(queueProbed, 1)
+		time.Sleep(2 * time.Second)
+		w.WriteHeader(http.StatusOK)
+	})
+
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
+	}
+
+	port, err := strconv.Atoi(u.Port())
+	if err != nil {
+		t.Fatalf("failed to convert port(%s) to int", u.Port())
+	}
+
+	timeout := 1
+	if err = probeQueueHealthPath(timeout, port); err == nil {
+		t.Errorf("Expected probeQueueHealthPath(%d, %v) to return timeout error", port, timeout)
+	}
+
+	ts.Close()
+
+	if atomic.LoadInt32(queueProbed) == 0 {
+		t.Error("Expected the queue proxy server to be probed")
+	}
+}
+
+func TestProbeQueueDelayedReady(t *testing.T) {
+	count := ptr.Int32(0)
+	ts := newProbeTestServer(func(w http.ResponseWriter) {
+		if atomic.AddInt32(count, 1) < 9 {
+			w.WriteHeader(http.StatusBadRequest)
+			return
+		}
+		w.WriteHeader(http.StatusOK)
+	})
+
+	defer ts.Close()
+
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
+	}
+
+	port, err := strconv.Atoi(u.Port())
+	if err != nil {
+		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
+	}
+
+	timeout := 0
+	if err := probeQueueHealthPath(timeout, port); err != nil {
+		t.Errorf("probeQueueHealthPath(%d) = %s", port, err)
+	}
+}
+
+func newProbeTestServer(f func(w http.ResponseWriter)) *httptest.Server {
+	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Header.Get(network.UserAgentKey) == network.QueueProxyUserAgent {
+			f(w)
+		}
+	}))
+}
diff --git a/cmd/queue/main_test.go b/cmd/queue/main_test.go
index 5d7f5b6db..a52204edc 100644
--- a/cmd/queue/main_test.go
+++ b/cmd/queue/main_test.go
@@ -22,16 +22,13 @@ import (
 	"net/http/httptest"
 	"net/http/httputil"
 	"net/url"
-	"strconv"
 	"strings"
-	"sync/atomic"
 	"testing"
 	"time"
 
 	"github.com/google/go-cmp/cmp"
 	"go.opencensus.io/plugin/ochttp"
 	pkgnet "knative.dev/pkg/network"
-	"knative.dev/pkg/ptr"
 	"knative.dev/pkg/tracing"
 	tracingconfig "knative.dev/pkg/tracing/config"
 	tracetesting "knative.dev/pkg/tracing/testing"
@@ -149,166 +146,6 @@ func TestProbeHandler(t *testing.T) {
 	}
 }
 
-func TestProbeQueueInvalidPort(t *testing.T) {
-	if err := probeQueueHealthPath(1, 0); err == nil {
-		t.Error("Expected error, got nil")
-	} else if diff := cmp.Diff(err.Error(), "port must be a positive value, got 0"); diff != "" {
-		t.Errorf("Unexpected not ready message: %s", diff)
-	}
-}
-
-func TestProbeQueueConnectionFailure(t *testing.T) {
-	if err := probeQueueHealthPath(1, 12345); err == nil {
-		t.Error("Expected error, got nil")
-	}
-}
-
-func TestProbeQueueNotReady(t *testing.T) {
-	queueProbed := ptr.Int32(0)
-	ts := newProbeTestServer(func(w http.ResponseWriter) {
-		atomic.AddInt32(queueProbed, 1)
-		w.WriteHeader(http.StatusBadRequest)
-	})
-
-	defer ts.Close()
-
-	u, err := url.Parse(ts.URL)
-	if err != nil {
-		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
-	}
-
-	port, err := strconv.Atoi(u.Port())
-	if err != nil {
-		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
-	}
-
-	err = probeQueueHealthPath(1, port)
-
-	if diff := cmp.Diff(err.Error(), "probe returned not ready"); diff != "" {
-		t.Errorf("Unexpected not ready message: %s", diff)
-	}
-
-	if atomic.LoadInt32(queueProbed) == 0 {
-		t.Error("Expected the queue proxy server to be probed")
-	}
-}
-
-func TestProbeQueueShuttingDownFailsFast(t *testing.T) {
-	ts := newProbeTestServer(func(w http.ResponseWriter) {
-		w.WriteHeader(http.StatusGone)
-	})
-
-	defer ts.Close()
-
-	u, err := url.Parse(ts.URL)
-	if err != nil {
-		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
-	}
-
-	port, err := strconv.Atoi(u.Port())
-	if err != nil {
-		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
-	}
-
-	start := time.Now()
-	if err = probeQueueHealthPath(1, port); err == nil {
-		t.Error("probeQueueHealthPath did not fail")
-	}
-
-	// if fails due to timeout and not cancelation, then it took too long
-	if time.Since(start) >= 1*time.Second {
-		t.Error("took too long to fail")
-	}
-}
-
-func TestProbeQueueReady(t *testing.T) {
-	queueProbed := ptr.Int32(0)
-	ts := newProbeTestServer(func(w http.ResponseWriter) {
-		atomic.AddInt32(queueProbed, 1)
-		w.WriteHeader(http.StatusOK)
-	})
-
-	defer ts.Close()
-
-	u, err := url.Parse(ts.URL)
-	if err != nil {
-		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
-	}
-
-	port, err := strconv.Atoi(u.Port())
-	if err != nil {
-		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
-	}
-
-	if err = probeQueueHealthPath(1, port); err != nil {
-		t.Errorf("probeQueueHealthPath(%d, 1s) = %s", port, err)
-	}
-
-	if atomic.LoadInt32(queueProbed) == 0 {
-		t.Error("Expected the queue proxy server to be probed")
-	}
-}
-
-func TestProbeQueueTimeout(t *testing.T) {
-	queueProbed := ptr.Int32(0)
-	ts := newProbeTestServer(func(w http.ResponseWriter) {
-		atomic.AddInt32(queueProbed, 1)
-		time.Sleep(2 * time.Second)
-		w.WriteHeader(http.StatusOK)
-	})
-
-	defer ts.Close()
-
-	u, err := url.Parse(ts.URL)
-	if err != nil {
-		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
-	}
-
-	port, err := strconv.Atoi(u.Port())
-	if err != nil {
-		t.Fatalf("failed to convert port(%s) to int", u.Port())
-	}
-
-	timeout := 1
-	if err = probeQueueHealthPath(timeout, port); err == nil {
-		t.Errorf("Expected probeQueueHealthPath(%d, %v) to return timeout error", port, timeout)
-	}
-
-	ts.Close()
-
-	if atomic.LoadInt32(queueProbed) == 0 {
-		t.Error("Expected the queue proxy server to be probed")
-	}
-}
-
-func TestProbeQueueDelayedReady(t *testing.T) {
-	count := ptr.Int32(0)
-	ts := newProbeTestServer(func(w http.ResponseWriter) {
-		if atomic.AddInt32(count, 1) < 9 {
-			w.WriteHeader(http.StatusBadRequest)
-			return
-		}
-		w.WriteHeader(http.StatusOK)
-	})
-
-	defer ts.Close()
-
-	u, err := url.Parse(ts.URL)
-	if err != nil {
-		t.Fatalf("%s is not a valid URL: %v", ts.URL, err)
-	}
-
-	port, err := strconv.Atoi(u.Port())
-	if err != nil {
-		t.Fatalf("Failed to convert port(%s) to int: %v", u.Port(), err)
-	}
-
-	timeout := 0
-	if err := probeQueueHealthPath(timeout, port); err != nil {
-		t.Errorf("probeQueueHealthPath(%d) = %s", port, err)
-	}
-}
-
 func TestQueueTraceSpans(t *testing.T) {
 	logger = TestLogger(t)
 	testcases := []struct {
@@ -509,11 +346,3 @@ func BenchmarkProxyHandler(b *testing.B) {
 		})
 	}
 }
-
-func newProbeTestServer(f func(w http.ResponseWriter)) *httptest.Server {
-	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		if r.Header.Get(network.UserAgentKey) == network.QueueProxyUserAgent {
-			f(w)
-		}
-	}))
-}
diff --git a/third_party/contour-latest/contour.yaml b/third_party/contour-latest/contour.yaml
index ba8d76376..d668dc4e2 100644
--- a/third_party/contour-latest/contour.yaml
+++ b/third_party/contour-latest/contour.yaml
@@ -1432,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:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         command:
         - contour
@@ -1672,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:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         name: contour
         ports:
@@ -1764,7 +1764,7 @@ spec:
         args:
         - envoy
         - shutdown-manager
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         lifecycle:
           preStop:
@@ -1840,7 +1840,7 @@ spec:
         - --envoy-key-file=/certs/tls.key
         command:
         - contour
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         name: envoy-initconfig
         volumeMounts:
@@ -3305,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:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         command:
         - contour
@@ -3545,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:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         name: contour
         ports:
@@ -3637,7 +3637,7 @@ spec:
         args:
         - envoy
         - shutdown-manager
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         lifecycle:
           preStop:
@@ -3713,7 +3713,7 @@ spec:
         - --envoy-key-file=/certs/tls.key
         command:
         - contour
-        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:0d42a72fb7b64dd84feb9efdf68bdb877ad09ab60b9ee0186fb0681ca11c4714
+        image: gcr.io/knative-nightly/github.com/projectcontour/contour/cmd/contour@sha256:c213d4221b4f36d55a9dc1b233f929fe70e0fc0d2ee2d2f4b911d5c3adf85448
         imagePullPolicy: Always
         name: envoy-initconfig
         volumeMounts:
diff --git a/third_party/contour-latest/net-contour.yaml b/third_party/contour-latest/net-contour.yaml
index 65d797c1c..36b04574f 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: "v20200611-f789b88b"
+    serving.knative.dev/release: "v20200612-577c1744"
 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:27a1050d6c3ca0cce4c7ec31bc5ec3fbd48689657bd314f2b7f8f86da828524c
+        image: gcr.io/knative-nightly/knative.dev/net-contour/cmd/controller@sha256:fe66b0e23043f578632198f9e31f790a4ab66edfd1fd06d0db2483f1ed3e0201
         resources:
           requests:
             cpu: 40m
diff --git a/vendor/knative.dev/pkg/test/ghutil/client.go b/vendor/knative.dev/pkg/test/ghutil/client.go
index 8a9872a47..8f6466eb7 100644
--- a/vendor/knative.dev/pkg/test/ghutil/client.go
+++ b/vendor/knative.dev/pkg/test/ghutil/client.go
@@ -61,6 +61,7 @@ type GithubOperations interface {
 	ListCommits(org, repo string, ID int) ([]*github.RepositoryCommit, error)
 	ListFiles(org, repo string, ID int) ([]*github.CommitFile, error)
 	CreatePullRequest(org, repo, head, base, title, body string) (*github.PullRequest, error)
+	ListBranches(org, repo string) ([]*github.Branch, error)
 }
 
 // GithubClient provides methods to perform github operations
diff --git a/vendor/knative.dev/pkg/test/ghutil/repo.go b/vendor/knative.dev/pkg/test/ghutil/repo.go
new file mode 100644
index 000000000..1f645856e
--- /dev/null
+++ b/vendor/knative.dev/pkg/test/ghutil/repo.go
@@ -0,0 +1,49 @@
+/*
+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.
+*/
+
+// repo.go provides generic functions related to Repo
+
+package ghutil
+
+import (
+	"fmt"
+
+	"github.com/google/go-github/v27/github"
+)
+
+// ListBranches lists branchs for given repo
+func (gc *GithubClient) ListBranches(org, repo string) ([]*github.Branch, error) {
+	genericList, err := gc.depaginate(
+		fmt.Sprintf("listing Pull request from org %q and base %q", org, repo),
+		maxRetryCount,
+		&github.ListOptions{},
+		func() ([]interface{}, *github.Response, error) {
+			page, resp, err := gc.Client.Repositories.ListBranches(ctx, org, repo, nil)
+			var interfaceList []interface{}
+			if nil == err {
+				for _, PR := range page {
+					interfaceList = append(interfaceList, PR)
+				}
+			}
+			return interfaceList, resp, err
+		},
+	)
+	res := make([]*github.Branch, len(genericList))
+	for i, elem := range genericList {
+		res[i] = elem.(*github.Branch)
+	}
+	return res, err
+}