Repository: knative/pkg
Pull request #1945 (2020-12-07 18:06:47)

[0.19] Backport "Add host config option to the prometheus exporter (#1882)"
Backporting #1882, cherry-picked c73d344c89a7e80d9e416cea5b4a797e1195cf0.

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

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

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

- **[metrics/OWNERS](https://github.com/knative/pkg/blob/master/metrics/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":["yanweiguo"]} -->
knative-prow-robot: Hi @skonto. Thanks for your PR.

I'm waiting for a [knative](https://github.com/orgs/knative/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://github.com/orgs/knative/people) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=knative%2Fpkg).

<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.
</details>

skonto: @markusthoemmes pls review.
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=h1) Report
> Merging [#1945](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=desc) (865d1f5) into [master](https://codecov.io/gh/knative/pkg/commit/5514ab0c1fdffe6ad771ab2ff84daf694d1f4ca1?el=desc) (5514ab0) will **decrease** coverage by `0.27%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/knative/pkg/pull/1945/graphs/tree.svg?width=650&height=150&src=pr&token=rlqpDnfxbO)](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1945      +/-   ##
==========================================
- Coverage   69.13%   68.86%   -0.28%     
==========================================
  Files         215      208       -7     
  Lines        9088     8755     -333     
==========================================
- Hits         6283     6029     -254     
+ Misses       2511     2450      -61     
+ Partials      294      276      -18     
```


| [Impacted Files](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [metrics/exporter.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-bWV0cmljcy9leHBvcnRlci5nbw==) | `78.26% <ø> (ø)` | |
| [metrics/config.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-bWV0cmljcy9jb25maWcuZ28=) | `83.20% <100.00%> (+0.70%)` | :arrow_up: |
| [metrics/prometheus\_exporter.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-bWV0cmljcy9wcm9tZXRoZXVzX2V4cG9ydGVyLmdv) | `89.28% <100.00%> (ø)` | |
| [version/version.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-dmVyc2lvbi92ZXJzaW9uLmdv) | `87.50% <0.00%> (-12.50%)` | :arrow_down: |
| [network/handlers/drain.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-bmV0d29yay9oYW5kbGVycy9kcmFpbi5nbw==) | `82.50% <0.00%> (-5.74%)` | :arrow_down: |
| [websocket/connection.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-d2Vic29ja2V0L2Nvbm5lY3Rpb24uZ28=) | `92.91% <0.00%> (-3.81%)` | :arrow_down: |
| [logging/config.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-bG9nZ2luZy9jb25maWcuZ28=) | `84.37% <0.00%> (-3.13%)` | :arrow_down: |
| [test/logstream/v2/stream.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-dGVzdC9sb2dzdHJlYW0vdjIvc3RyZWFtLmdv) | `86.95% <0.00%> (-1.81%)` | :arrow_down: |
| [webhook/psbinding/psbinding.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-d2ViaG9vay9wc2JpbmRpbmcvcHNiaW5kaW5nLmdv) | `84.39% <0.00%> (-1.32%)` | :arrow_down: |
| [webhook/env.go](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree#diff-d2ViaG9vay9lbnYuZ28=) | `100.00% <0.00%> (ø)` | |
| ... and [22 more](https://codecov.io/gh/knative/pkg/pull/1945/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=footer). Last update [5514ab0...865d1f5](https://codecov.io/gh/knative/pkg/pull/1945?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.github/workflows/knative-boilerplate.yaml b/.github/workflows/knative-boilerplate.yaml
index 9329fdd7e..c0e648b1c 100644
--- a/.github/workflows/knative-boilerplate.yaml
+++ b/.github/workflows/knative-boilerplate.yaml
@@ -19,7 +19,7 @@ name: Boilerplate
 
 on:
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
 
diff --git a/.github/workflows/knative-donotsubmit.yaml b/.github/workflows/knative-donotsubmit.yaml
index d9131173d..cec5c3077 100644
--- a/.github/workflows/knative-donotsubmit.yaml
+++ b/.github/workflows/knative-donotsubmit.yaml
@@ -19,7 +19,7 @@ name: Do Not Submit
 
 on:
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
 
diff --git a/.github/workflows/knative-go-build.yaml b/.github/workflows/knative-go-build.yaml
index 226eac87d..7bd13004a 100644
--- a/.github/workflows/knative-go-build.yaml
+++ b/.github/workflows/knative-go-build.yaml
@@ -19,7 +19,7 @@ name: Build
 
 on:
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
 
diff --git a/.github/workflows/knative-security.yaml b/.github/workflows/knative-security.yaml
index 47186ef2e..00fa9fccf 100644
--- a/.github/workflows/knative-security.yaml
+++ b/.github/workflows/knative-security.yaml
@@ -19,10 +19,10 @@ name: 'Security'
 
 on:
   push:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
   analyze:
diff --git a/.github/workflows/knative-style.yaml b/.github/workflows/knative-style.yaml
index 5d3d3163e..b38122ab6 100644
--- a/.github/workflows/knative-style.yaml
+++ b/.github/workflows/knative-style.yaml
@@ -19,7 +19,7 @@ name: Code Style
 
 on:
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
 
diff --git a/.github/workflows/knative-verify.yaml b/.github/workflows/knative-verify.yaml
index ed5bb3a13..3443a0496 100644
--- a/.github/workflows/knative-verify.yaml
+++ b/.github/workflows/knative-verify.yaml
@@ -19,7 +19,7 @@ name: Verify
 
 on:
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
 
diff --git a/leaderelection/context.go b/leaderelection/context.go
index 17a7a1b1f..d30ecd462 100644
--- a/leaderelection/context.go
+++ b/leaderelection/context.go
@@ -41,7 +41,7 @@ func WithDynamicLeaderElectorBuilder(ctx context.Context, kc kubernetes.Interfac
 	b, _, err := NewStatefulSetBucketAndSet(int(cc.Buckets))
 	if err == nil {
 		logger.Info("Running with StatefulSet leader election")
-		return withStatefulSetElectorBuilder(ctx, cc, b)
+		return WithStatefulSetElectorBuilder(ctx, cc, b)
 	}
 	logger.Info("Running with Standard leader election")
 	return WithStandardLeaderElectorBuilder(ctx, kc, cc)
@@ -57,10 +57,10 @@ func WithStandardLeaderElectorBuilder(ctx context.Context, kc kubernetes.Interfa
 	})
 }
 
-// withStatefulSetElectorBuilder infuses a context with the ability to build
+// WithStatefulSetElectorBuilder infuses a context with the ability to build
 // Electors which are assigned leadership based on the StatefulSet ordinal from
 // the provided component configuration.
-func withStatefulSetElectorBuilder(ctx context.Context, cc ComponentConfig, bkt reconciler.Bucket) context.Context {
+func WithStatefulSetElectorBuilder(ctx context.Context, cc ComponentConfig, bkt reconciler.Bucket) context.Context {
 	return context.WithValue(ctx, builderKey{}, &statefulSetBuilder{
 		lec: cc,
 		bkt: bkt,
diff --git a/logging/config.go b/logging/config.go
index 65b50395a..1effe1b35 100644
--- a/logging/config.go
+++ b/logging/config.go
@@ -62,9 +62,9 @@ func NewLogger(configJSON string, levelOverride string, opts ...zap.Option) (*za
 		}
 	}
 
-	logger, err2 := loggingCfg.Build(append(opts, zapdriver.WrapCore())...)
-	if err2 != nil {
-		panic(err2)
+	logger, err = loggingCfg.Build(append(opts, zapdriver.WrapCore())...)
+	if err != nil {
+		panic(err)
 	}
 
 	slogger := enrichLoggerWithCommitID(logger.Named(fallbackLoggerName))
@@ -74,13 +74,14 @@ func NewLogger(configJSON string, levelOverride string, opts ...zap.Option) (*za
 
 func enrichLoggerWithCommitID(logger *zap.Logger) *zap.SugaredLogger {
 	commitID, err := changeset.Get()
-	if err == nil {
-		// Enrich logs with GitHub commit ID.
-		return logger.With(zap.String(logkey.GitHubCommitID, commitID)).Sugar()
+	if err != nil {
+		logger.Info("Fetch GitHub commit ID from kodata failed", zap.Error(err))
+		return logger.Sugar()
 	}
 
-	logger.Info("Fetch GitHub commit ID from kodata failed", zap.Error(err))
-	return logger.Sugar()
+	// Enrich logs with GitHub commit ID.
+	return logger.With(zap.String(logkey.GitHubCommitID, commitID)).Sugar()
+
 }
 
 // NewLoggerFromConfig creates a logger using the provided Config
@@ -94,7 +95,7 @@ func NewLoggerFromConfig(config *Config, name string, opts ...zap.Option) (*zap.
 	return logger.Named(name), level
 }
 
-func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Option) (*zap.Logger, zap.AtomicLevel, error) {
+func newLoggerFromConfig(configJSON, levelOverride string, opts []zap.Option) (*zap.Logger, zap.AtomicLevel, error) {
 	loggingCfg, err := zapConfigFromJSON(configJSON)
 	if err != nil {
 		return nil, zap.AtomicLevel{}, err
@@ -179,7 +180,6 @@ func levelFromString(level string) (*zapcore.Level, error) {
 // when a config map is updated
 func UpdateLevelFromConfigMap(logger *zap.SugaredLogger, atomicLevel zap.AtomicLevel,
 	levelKey string) func(configMap *corev1.ConfigMap) {
-
 	return func(configMap *corev1.ConfigMap) {
 		config, err := NewConfigFromConfigMap(configMap)
 		if err != nil {
diff --git a/profiling/server.go b/profiling/server.go
index 9ac2c5f05..9d61c0981 100644
--- a/profiling/server.go
+++ b/profiling/server.go
@@ -20,6 +20,7 @@ import (
 	"fmt"
 	"net/http"
 	"net/http/pprof"
+	"os"
 	"strconv"
 
 	"go.uber.org/atomic"
@@ -28,7 +29,11 @@ import (
 )
 
 const (
-	// ProfilingPort specifies the port where profiling data is available when profiling is enabled
+	// ProfilingPortKey specified the name of an environment variable that
+	// may be used to override the default profiling port.
+	ProfilingPortKey = "PROFILING_PORT"
+
+	// ProfilingPort specifies the default port where profiling data is available when profiling is enabled
 	ProfilingPort = 8008
 
 	// profilingKey is the name of the key in config-observability config map
@@ -100,8 +105,13 @@ func (h *Handler) UpdateFromConfigMap(configMap *corev1.ConfigMap) {
 
 // NewServer creates a new http server that exposes profiling data on the default profiling port
 func NewServer(handler http.Handler) *http.Server {
+	port := os.Getenv(ProfilingPortKey)
+	if port == "" {
+		port = strconv.Itoa(ProfilingPort)
+	}
+
 	return &http.Server{
-		Addr:    ":" + strconv.Itoa(ProfilingPort),
+		Addr:    ":" + port,
 		Handler: handler,
 	}
 }
diff --git a/webhook/helper.go b/webhook/helper.go
new file mode 100644
index 000000000..cbcbb58c7
--- /dev/null
+++ b/webhook/helper.go
@@ -0,0 +1,64 @@
+/*
+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 webhook
+
+import (
+	"strings"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EnsureLabelSelectorExpressions merges the current label selector's MatchExpressions
+// with the ones wanted.
+// It keeps all non-knative keys intact, removes all knative-keys no longer wanted and
+// adds all knative-keys not yet there.
+func EnsureLabelSelectorExpressions(
+	current *metav1.LabelSelector,
+	want *metav1.LabelSelector) *metav1.LabelSelector {
+
+	if current == nil {
+		return want
+	}
+
+	if len(current.MatchExpressions) == 0 {
+		return want
+	}
+
+	var wantExpressions []metav1.LabelSelectorRequirement
+	if want != nil {
+		wantExpressions = want.MatchExpressions
+	}
+
+	return &metav1.LabelSelector{
+		MatchExpressions: ensureLabelSelectorRequirements(
+			current.MatchExpressions, wantExpressions),
+	}
+}
+
+func ensureLabelSelectorRequirements(
+	current []metav1.LabelSelectorRequirement,
+	want []metav1.LabelSelectorRequirement) []metav1.LabelSelectorRequirement {
+
+	nonKnative := make([]metav1.LabelSelectorRequirement, 0, len(current))
+	for _, r := range current {
+		if !strings.Contains(r.Key, "knative.dev") {
+			nonKnative = append(nonKnative, r)
+		}
+	}
+
+	return append(want, nonKnative...)
+}
diff --git a/webhook/psbinding/psbinding.go b/webhook/psbinding/psbinding.go
index 5a3a6b258..2b762ba22 100644
--- a/webhook/psbinding/psbinding.go
+++ b/webhook/psbinding/psbinding.go
@@ -131,11 +131,6 @@ var (
 			Key:      duck.BindingExcludeLabel,
 			Operator: metav1.LabelSelectorOpNotIn,
 			Values:   []string{"true"},
-		}, {
-			// "control-plane" is added to support Azure's AKS, otherwise the controllers fight.
-			// See knative/pkg#1590 for details.
-			Key:      "control-plane",
-			Operator: metav1.LabelSelectorOpDoesNotExist,
 		}},
 		// TODO(mattmoor): Consider also having a GVR-based one, e.g.
 		//    foobindings.blah.knative.dev/exclude: "true"
@@ -145,11 +140,6 @@ var (
 			Key:      duck.BindingIncludeLabel,
 			Operator: metav1.LabelSelectorOpIn,
 			Values:   []string{"true"},
-		}, {
-			// "control-plane" is added to support Azure's AKS, otherwise the controllers fight.
-			// See knative/pkg#1590 for details.
-			Key:      "control-plane",
-			Operator: metav1.LabelSelectorOpDoesNotExist,
 		}},
 		// TODO(mattmoor): Consider also having a GVR-based one, e.g.
 		//    foobindings.blah.knative.dev/include: "true"
@@ -338,31 +328,34 @@ func (ac *Reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt
 	if err != nil {
 		return fmt.Errorf("error retrieving webhook: %w", err)
 	}
-	webhook := configuredWebhook.DeepCopy()
+	current := configuredWebhook.DeepCopy()
 
 	// Use the "Equivalent" match policy so that we don't need to enumerate versions for same-types.
 	// This is only supported by 1.15+ clusters.
 	matchPolicy := admissionregistrationv1.Equivalent
 
-	for i, wh := range webhook.Webhooks {
-		if wh.Name != webhook.Name {
+	for i, wh := range current.Webhooks {
+		if wh.Name != current.Name {
 			continue
 		}
-		webhook.Webhooks[i].MatchPolicy = &matchPolicy
-		webhook.Webhooks[i].Rules = rules
-		webhook.Webhooks[i].NamespaceSelector = &ac.selector
-		webhook.Webhooks[i].ObjectSelector = &ac.selector // 1.15+ only
-		webhook.Webhooks[i].ClientConfig.CABundle = caCert
-		if webhook.Webhooks[i].ClientConfig.Service == nil {
+		cur := &current.Webhooks[i]
+		selector := webhook.EnsureLabelSelectorExpressions(cur.NamespaceSelector, &ac.selector)
+
+		cur.MatchPolicy = &matchPolicy
+		cur.Rules = rules
+		cur.NamespaceSelector = selector
+		cur.ObjectSelector = selector // 1.15+ only
+		cur.ClientConfig.CABundle = caCert
+		if cur.ClientConfig.Service == nil {
 			return fmt.Errorf("missing service reference for webhook: %s", wh.Name)
 		}
-		webhook.Webhooks[i].ClientConfig.Service.Path = ptr.String(ac.Path())
+		cur.ClientConfig.Service.Path = ptr.String(ac.Path())
 	}
 
-	if ok := equality.Semantic.DeepEqual(configuredWebhook, webhook); !ok {
+	if ok := equality.Semantic.DeepEqual(configuredWebhook, current); !ok {
 		logging.FromContext(ctx).Info("Updating webhook")
 		mwhclient := ac.Client.AdmissionregistrationV1().MutatingWebhookConfigurations()
-		if _, err := mwhclient.Update(ctx, webhook, metav1.UpdateOptions{}); err != nil {
+		if _, err := mwhclient.Update(ctx, current, metav1.UpdateOptions{}); err != nil {
 			return fmt.Errorf("failed to update webhook: %w", err)
 		}
 	} else {
diff --git a/webhook/resourcesemantics/defaulting/defaulting.go b/webhook/resourcesemantics/defaulting/defaulting.go
index 69d0e9ae8..acdc6f33d 100644
--- a/webhook/resourcesemantics/defaulting/defaulting.go
+++ b/webhook/resourcesemantics/defaulting/defaulting.go
@@ -171,41 +171,42 @@ func (ac *reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt
 		return fmt.Errorf("error retrieving webhook: %w", err)
 	}
 
-	webhook := configuredWebhook.DeepCopy()
+	current := configuredWebhook.DeepCopy()
 
 	// Clear out any previous (bad) OwnerReferences.
 	// See: https://github.com/knative/serving/issues/5845
-	webhook.OwnerReferences = nil
+	current.OwnerReferences = nil
 
-	for i, wh := range webhook.Webhooks {
-		if wh.Name != webhook.Name {
+	for i, wh := range current.Webhooks {
+		if wh.Name != current.Name {
 			continue
 		}
-		webhook.Webhooks[i].Rules = rules
-		webhook.Webhooks[i].NamespaceSelector = &metav1.LabelSelector{
-			MatchExpressions: []metav1.LabelSelectorRequirement{{
-				Key:      "webhooks.knative.dev/exclude",
-				Operator: metav1.LabelSelectorOpDoesNotExist,
-			}, {
-				// "control-plane" is added to support Azure's AKS, otherwise the controllers fight.
-				// See knative/pkg#1590 for details.
-				Key:      "control-plane",
-				Operator: metav1.LabelSelectorOpDoesNotExist,
-			}},
-		}
-		webhook.Webhooks[i].ClientConfig.CABundle = caCert
-		if webhook.Webhooks[i].ClientConfig.Service == nil {
+
+		cur := &current.Webhooks[i]
+		cur.Rules = rules
+
+		cur.NamespaceSelector = webhook.EnsureLabelSelectorExpressions(
+			cur.NamespaceSelector,
+			&metav1.LabelSelector{
+				MatchExpressions: []metav1.LabelSelectorRequirement{{
+					Key:      "webhooks.knative.dev/exclude",
+					Operator: metav1.LabelSelectorOpDoesNotExist,
+				}},
+			})
+
+		cur.ClientConfig.CABundle = caCert
+		if cur.ClientConfig.Service == nil {
 			return fmt.Errorf("missing service reference for webhook: %s", wh.Name)
 		}
-		webhook.Webhooks[i].ClientConfig.Service.Path = ptr.String(ac.Path())
+		cur.ClientConfig.Service.Path = ptr.String(ac.Path())
 	}
 
-	if ok, err := kmp.SafeEqual(configuredWebhook, webhook); err != nil {
+	if ok, err := kmp.SafeEqual(configuredWebhook, current); err != nil {
 		return fmt.Errorf("error diffing webhooks: %w", err)
 	} else if !ok {
 		logger.Info("Updating webhook")
 		mwhclient := ac.client.AdmissionregistrationV1().MutatingWebhookConfigurations()
-		if _, err := mwhclient.Update(ctx, webhook, metav1.UpdateOptions{}); err != nil {
+		if _, err := mwhclient.Update(ctx, current, metav1.UpdateOptions{}); err != nil {
 			return fmt.Errorf("failed to update webhook: %w", err)
 		}
 	} else {
diff --git a/webhook/resourcesemantics/validation/reconcile_config.go b/webhook/resourcesemantics/validation/reconcile_config.go
index 281a12e43..3abe55e16 100644
--- a/webhook/resourcesemantics/validation/reconcile_config.go
+++ b/webhook/resourcesemantics/validation/reconcile_config.go
@@ -134,41 +134,41 @@ func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []b
 		return fmt.Errorf("error retrieving webhook: %w", err)
 	}
 
-	webhook := configuredWebhook.DeepCopy()
+	current := configuredWebhook.DeepCopy()
 
 	// Clear out any previous (bad) OwnerReferences.
 	// See: https://github.com/knative/serving/issues/5845
-	webhook.OwnerReferences = nil
+	current.OwnerReferences = nil
 
-	for i, wh := range webhook.Webhooks {
-		if wh.Name != webhook.Name {
+	for i, wh := range current.Webhooks {
+		if wh.Name != current.Name {
 			continue
 		}
-		webhook.Webhooks[i].Rules = rules
-		webhook.Webhooks[i].NamespaceSelector = &metav1.LabelSelector{
-			MatchExpressions: []metav1.LabelSelectorRequirement{{
-				Key:      "webhooks.knative.dev/exclude",
-				Operator: metav1.LabelSelectorOpDoesNotExist,
-			}, {
-				// "control-plane" is added to support Azure's AKS, otherwise the controllers fight.
-				// See knative/pkg#1590 for details.
-				Key:      "control-plane",
-				Operator: metav1.LabelSelectorOpDoesNotExist,
-			}},
-		}
-		webhook.Webhooks[i].ClientConfig.CABundle = caCert
-		if webhook.Webhooks[i].ClientConfig.Service == nil {
+		cur := &current.Webhooks[i]
+		cur.Rules = rules
+
+		cur.NamespaceSelector = webhook.EnsureLabelSelectorExpressions(
+			cur.NamespaceSelector,
+			&metav1.LabelSelector{
+				MatchExpressions: []metav1.LabelSelectorRequirement{{
+					Key:      "webhooks.knative.dev/exclude",
+					Operator: metav1.LabelSelectorOpDoesNotExist,
+				}},
+			})
+
+		cur.ClientConfig.CABundle = caCert
+		if cur.ClientConfig.Service == nil {
 			return fmt.Errorf("missing service reference for webhook: %s", wh.Name)
 		}
-		webhook.Webhooks[i].ClientConfig.Service.Path = ptr.String(ac.Path())
+		cur.ClientConfig.Service.Path = ptr.String(ac.Path())
 	}
 
-	if ok, err := kmp.SafeEqual(configuredWebhook, webhook); err != nil {
+	if ok, err := kmp.SafeEqual(configuredWebhook, current); err != nil {
 		return fmt.Errorf("error diffing webhooks: %w", err)
 	} else if !ok {
 		logger.Info("Updating webhook")
 		vwhclient := ac.client.AdmissionregistrationV1().ValidatingWebhookConfigurations()
-		if _, err := vwhclient.Update(ctx, webhook, metav1.UpdateOptions{}); err != nil {
+		if _, err := vwhclient.Update(ctx, current, metav1.UpdateOptions{}); err != nil {
 			return fmt.Errorf("failed to update webhook: %w", err)
 		}
 	} else {


Test patch:
diff --git a/.github/workflows/knative-go-test.yaml b/.github/workflows/knative-go-test.yaml
index 9a77276c1..965df1e74 100644
--- a/.github/workflows/knative-go-test.yaml
+++ b/.github/workflows/knative-go-test.yaml
@@ -20,10 +20,10 @@ name: Test
 on:
 
   push:
-    branches: [ 'master' ]
+    branches: [ 'main', 'master' ]
 
   pull_request:
-    branches: [ 'master', 'release-*' ]
+    branches: [ 'main', 'master', 'release-*' ]
 
 jobs:
 
diff --git a/test/logstream/v2/stream_test.go b/test/logstream/v2/stream_test.go
index adbc73f93..202b33712 100644
--- a/test/logstream/v2/stream_test.go
+++ b/test/logstream/v2/stream_test.go
@@ -80,17 +80,16 @@ func TestFailToStartStream(t *testing.T) {
 	pod.Status = readyStatus
 
 	const want = "hungry for apples"
-	f := newK8sFake(fake.NewSimpleClientset(), nil, /*watcherr*/
+	f := newK8sFake(fake.NewSimpleClientset(), nil, /*watcher*/
 		errors.New(want) /*getlogs err*/)
 
 	logFuncInvoked := make(chan struct{})
-	t.Cleanup(func() { close(logFuncInvoked) })
 	logFunc := func(format string, args ...interface{}) {
 		res := fmt.Sprintf(format, args...)
 		if !strings.Contains(res, want) {
 			t.Errorf("Expected message to contain %q, but message was: %s", want, res)
 		}
-		logFuncInvoked <- struct{}{}
+		close(logFuncInvoked)
 	}
 	ctx, cancel := context.WithCancel(context.Background())
 	stream := logstream.FromNamespace(ctx, f, pod.Namespace)
diff --git a/test/spoof/spoof.go b/test/spoof/spoof.go
index 9d00bad9e..48ffcffa8 100644
--- a/test/spoof/spoof.go
+++ b/test/spoof/spoof.go
@@ -96,7 +96,7 @@ func New(
 	opts ...TransportOption) (*SpoofingClient, error) {
 	endpoint, mapper, err := ResolveEndpoint(ctx, kubeClientset, domain, resolvable, endpointOverride)
 	if err != nil {
-		return nil, fmt.Errorf("failed get the cluster endpoint: %w", err)
+		return nil, fmt.Errorf("failed to get the cluster endpoint: %w", err)
 	}
 
 	// Spoof the hostname at the resolver level
diff --git a/webhook/helper_test.go b/webhook/helper_test.go
index 1abcd0baf..9f3928f83 100644
--- a/webhook/helper_test.go
+++ b/webhook/helper_test.go
@@ -26,6 +26,7 @@ import (
 	"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/wait"
@@ -36,6 +37,98 @@ import (
 	. "knative.dev/pkg/logging/testing"
 )
 
+func TestEnsureLabelSelectorExpressions(t *testing.T) {
+	fooExpression := metav1.LabelSelectorRequirement{
+		Key:      "foo.bar/baz",
+		Operator: metav1.LabelSelectorOpDoesNotExist,
+	}
+	knativeExpression := metav1.LabelSelectorRequirement{
+		Key:      "knative.dev/foo",
+		Operator: metav1.LabelSelectorOpDoesNotExist,
+	}
+
+	tests := []struct {
+		name    string
+		current *metav1.LabelSelector
+		want    *metav1.LabelSelector
+		expect  *metav1.LabelSelector
+	}{{
+		name: "all nil",
+	}, {
+		name:    "current nil",
+		current: nil,
+		want: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+		expect: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+	}, {
+		name:    "current empty",
+		current: &metav1.LabelSelector{},
+		want: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+		expect: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+	}, {
+		name: "want nil",
+		current: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+		want: nil,
+		expect: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+	}, {
+		name: "want empty",
+		current: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+		want: &metav1.LabelSelector{},
+		expect: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+	}, {
+		name: "add new",
+		current: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression},
+		},
+		want: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{knativeExpression},
+		},
+		expect: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{
+				knativeExpression, fooExpression},
+		},
+	}, {
+		name: "remove obsolete",
+		current: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{fooExpression, {
+				Key:      "knative.dev/bar",
+				Operator: metav1.LabelSelectorOpDoesNotExist,
+			}},
+		},
+		want: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{knativeExpression},
+		},
+		expect: &metav1.LabelSelector{
+			MatchExpressions: []metav1.LabelSelectorRequirement{
+				knativeExpression, fooExpression},
+		},
+	}}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			got := EnsureLabelSelectorExpressions(tc.current, tc.want)
+			if !cmp.Equal(got, tc.expect) {
+				t.Errorf("LabelSelector mismatch: diff(-want,+got):\n%s", cmp.Diff(tc.expect, got))
+			}
+		})
+	}
+}
+
 func waitForServerAvailable(t *testing.T, serverURL string, timeout time.Duration) error {
 	t.Helper()
 	var interval = 100 * time.Millisecond
diff --git a/webhook/resourcesemantics/defaulting/table_test.go b/webhook/resourcesemantics/defaulting/table_test.go
index c9770f2c6..99f205631 100644
--- a/webhook/resourcesemantics/defaulting/table_test.go
+++ b/webhook/resourcesemantics/defaulting/table_test.go
@@ -66,9 +66,6 @@ func TestReconcile(t *testing.T) {
 		MatchExpressions: []metav1.LabelSelectorRequirement{{
 			Key:      "webhooks.knative.dev/exclude",
 			Operator: metav1.LabelSelectorOpDoesNotExist,
-		}, {
-			Key:      "control-plane",
-			Operator: metav1.LabelSelectorOpDoesNotExist,
 		}},
 	}
 
@@ -322,11 +319,85 @@ func TestReconcile(t *testing.T) {
 						CABundle: []byte("present"),
 					},
 					// Rules are fine.
-					Rules:             expectedRules,
-					NamespaceSelector: namespaceSelector,
+					Rules: expectedRules,
+					// A non-knative key in the namespace selector is fine.
+					NamespaceSelector: &metav1.LabelSelector{
+						MatchExpressions: []metav1.LabelSelectorRequirement{{
+							Key:      "webhooks.knative.dev/exclude",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}, {
+							Key:      "foo.bar/baz",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}},
+					},
+				}},
+			},
+		},
+	}, {
+		Name: "secret and MWH exist, correcting namespaceSelector",
+		Key:  key,
+		Objects: []runtime.Object{secret,
+			&admissionregistrationv1.MutatingWebhookConfiguration{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: name,
+				},
+				Webhooks: []admissionregistrationv1.MutatingWebhook{{
+					Name: name,
+					ClientConfig: admissionregistrationv1.WebhookClientConfig{
+						Service: &admissionregistrationv1.ServiceReference{
+							Namespace: system.Namespace(),
+							Name:      "webhook",
+							// Path is fine.
+							Path: ptr.String(path),
+						},
+						// CABundle is fine.
+						CABundle: []byte("present"),
+					},
+					// Rules are fine.
+					Rules: expectedRules,
+					// NamespaceSelector contains non-knative things.
+					NamespaceSelector: &metav1.LabelSelector{
+						MatchExpressions: []metav1.LabelSelectorRequirement{{
+							Key:      "foo.knative.dev/exclude",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}, {
+							Key:      "foo.bar/baz",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}},
+					},
 				}},
 			},
 		},
+		WantUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: &admissionregistrationv1.MutatingWebhookConfiguration{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: name,
+				},
+				Webhooks: []admissionregistrationv1.MutatingWebhook{{
+					Name: name,
+					ClientConfig: admissionregistrationv1.WebhookClientConfig{
+						Service: &admissionregistrationv1.ServiceReference{
+							Namespace: system.Namespace(),
+							Name:      "webhook",
+							Path:      ptr.String(path),
+						},
+						CABundle: []byte("present"),
+					},
+					Rules: expectedRules,
+					NamespaceSelector: &metav1.LabelSelector{
+						// The knative key is added while the non-knative key is kept.
+						// Old knative key is removed.
+						MatchExpressions: []metav1.LabelSelectorRequirement{{
+							Key:      "webhooks.knative.dev/exclude",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}, {
+							Key:      "foo.bar/baz",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}},
+					},
+				}},
+			},
+		}},
 	}}
 
 	table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler {
diff --git a/webhook/resourcesemantics/validation/reconcile_config_test.go b/webhook/resourcesemantics/validation/reconcile_config_test.go
index 27562f423..8ce774c3e 100644
--- a/webhook/resourcesemantics/validation/reconcile_config_test.go
+++ b/webhook/resourcesemantics/validation/reconcile_config_test.go
@@ -66,9 +66,6 @@ func TestReconcile(t *testing.T) {
 		MatchExpressions: []metav1.LabelSelectorRequirement{{
 			Key:      "webhooks.knative.dev/exclude",
 			Operator: metav1.LabelSelectorOpDoesNotExist,
-		}, {
-			Key:      "control-plane",
-			Operator: metav1.LabelSelectorOpDoesNotExist,
 		}},
 	}
 
@@ -322,11 +319,85 @@ func TestReconcile(t *testing.T) {
 						CABundle: []byte("present"),
 					},
 					// Rules are fine.
-					Rules:             expectedRules,
-					NamespaceSelector: namespaceSelector,
+					Rules: expectedRules,
+					// A non-knative key in the namespace selector is fine.
+					NamespaceSelector: &metav1.LabelSelector{
+						MatchExpressions: []metav1.LabelSelectorRequirement{{
+							Key:      "webhooks.knative.dev/exclude",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}, {
+							Key:      "foo.bar/baz",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}},
+					},
+				}},
+			},
+		},
+	}, {
+		Name: "secret and VWH exist, correcting namespaceSelector",
+		Key:  key,
+		Objects: []runtime.Object{secret,
+			&admissionregistrationv1.ValidatingWebhookConfiguration{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: name,
+				},
+				Webhooks: []admissionregistrationv1.ValidatingWebhook{{
+					Name: name,
+					ClientConfig: admissionregistrationv1.WebhookClientConfig{
+						Service: &admissionregistrationv1.ServiceReference{
+							Namespace: system.Namespace(),
+							Name:      "webhook",
+							// Path is fine.
+							Path: ptr.String(path),
+						},
+						// CABundle is fine.
+						CABundle: []byte("present"),
+					},
+					// Rules are fine.
+					Rules: expectedRules,
+					// NamespaceSelector contains non-knative things.
+					NamespaceSelector: &metav1.LabelSelector{
+						MatchExpressions: []metav1.LabelSelectorRequirement{{
+							Key:      "foo.knative.dev/exclude",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}, {
+							Key:      "foo.bar/baz",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}},
+					},
 				}},
 			},
 		},
+		WantUpdates: []clientgotesting.UpdateActionImpl{{
+			Object: &admissionregistrationv1.ValidatingWebhookConfiguration{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: name,
+				},
+				Webhooks: []admissionregistrationv1.ValidatingWebhook{{
+					Name: name,
+					ClientConfig: admissionregistrationv1.WebhookClientConfig{
+						Service: &admissionregistrationv1.ServiceReference{
+							Namespace: system.Namespace(),
+							Name:      "webhook",
+							Path:      ptr.String(path),
+						},
+						CABundle: []byte("present"),
+					},
+					Rules: expectedRules,
+					NamespaceSelector: &metav1.LabelSelector{
+						// The knative key is added while the non-knative key is kept.
+						// Old knative key is removed.
+						MatchExpressions: []metav1.LabelSelectorRequirement{{
+							Key:      "webhooks.knative.dev/exclude",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}, {
+							Key:      "foo.bar/baz",
+							Operator: metav1.LabelSelectorOpDoesNotExist,
+						}},
+					},
+				}},
+			},
+		}},
 	}}
 
 	table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler {