Repository: knative/pkg
Pull request #1482 (2020-07-13 23:42:51)

Remove the ResourceLock field from the pkg/LE
we only use a single possible way, so no need to have, parse and validate
field that is in effect a constant.

/assign @dprotaso mattmoor

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

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

- **[OWNERS](https://github.com/knative/pkg/blob/master/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":["markusthoemmes"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-pkg-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[leaderelection/config.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_pkg/1482/pull-knative-pkg-go-coverage/1282822886830116865/artifacts/line-cov.html#file1) | 78.1% | 76.7% | -1.5

mattmoor: /lgtm
/approve
/hold

Let's wait for coordination with downstream repos.
knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/pkg/pull/1482#issuecomment-657923536" title="Approved">mattmoor</a>*, *<a href="https://github.com/knative/pkg/pull/1482#" title="Author self-approved">vagababov</a>*

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

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:

- ~~[OWNERS](https://github.com/knative/pkg/blob/master/OWNERS)~~ [mattmoor]

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":[]} -->

Patch:
diff --git a/apis/duck/v1/addressable_types.go b/apis/duck/v1/addressable_types.go
index 3cfcac331..db39ab862 100644
--- a/apis/duck/v1/addressable_types.go
+++ b/apis/duck/v1/addressable_types.go
@@ -63,8 +63,10 @@ type AddressStatus struct {
 	Address *Addressable `json:"address,omitempty"`
 }
 
+// Verify AddressableType resources meet duck contracts.
 var (
-	_ apis.Listable = (*AddressableType)(nil)
+	_ apis.Listable         = (*AddressableType)(nil)
+	_ ducktypes.Populatable = (*AddressableType)(nil)
 )
 
 // GetFullType implements duck.Implementable
diff --git a/apis/duck/v1/kresource_type.go b/apis/duck/v1/kresource_type.go
index 78d8ece66..491c13f1f 100644
--- a/apis/duck/v1/kresource_type.go
+++ b/apis/duck/v1/kresource_type.go
@@ -23,6 +23,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"knative.dev/pkg/apis/duck/ducktypes"
 
 	"knative.dev/pkg/apis"
 )
@@ -66,6 +67,12 @@ func (t *KResource) Populate() {
 	}}
 }
 
+// Verify KResource resources meet duck contracts.
+var (
+	_ apis.Listable         = (*KResource)(nil)
+	_ ducktypes.Populatable = (*KResource)(nil)
+)
+
 // GetListType implements apis.Listable
 func (*KResource) GetListType() runtime.Object {
 	return &KResourceList{}
diff --git a/apis/duck/v1/podspec_types.go b/apis/duck/v1/podspec_types.go
index 92ed7f1c4..a8d172416 100644
--- a/apis/duck/v1/podspec_types.go
+++ b/apis/duck/v1/podspec_types.go
@@ -31,6 +31,9 @@ import (
 // in the manner of ReplicaSet, Deployment, DaemonSet, StatefulSet.
 type PodSpecable corev1.PodTemplateSpec
 
+// PodSpecable is an Implementable duck type.
+var _ ducktypes.Implementable = (*PodSpecable)(nil)
+
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // WithPod is the shell that demonstrates how PodSpecable types wrap
@@ -47,10 +50,10 @@ type WithPodSpec struct {
 	Template PodSpecable `json:"template,omitempty"`
 }
 
-// Assert that we implement the interfaces necessary to
-// use duck.VerifyType.
+// Verify WithPod resources meet duck contracts.
 var (
-	_ apis.Listable = (*WithPod)(nil)
+	_ apis.Listable         = (*WithPod)(nil)
+	_ ducktypes.Populatable = (*WithPod)(nil)
 )
 
 // GetFullType implements duck.Implementable
diff --git a/apis/duck/v1/source_types.go b/apis/duck/v1/source_types.go
index 03c4d40b9..4ce3eaf60 100644
--- a/apis/duck/v1/source_types.go
+++ b/apis/duck/v1/source_types.go
@@ -88,7 +88,6 @@ type SourceStatus struct {
 // CloudEventAttributes specifies the attributes that a Source
 // uses as part of its CloudEvents.
 type CloudEventAttributes struct {
-
 	// Type refers to the CloudEvent type attribute.
 	Type string `json:"type,omitempty"`
 
@@ -109,8 +108,11 @@ func (ss *SourceStatus) IsReady() bool {
 	return false
 }
 
+// Verify Source resources meet duck contracts.
 var (
-	_ apis.Listable = (*Source)(nil)
+	_ apis.Listable           = (*Source)(nil)
+	_ ducktypes.Implementable = (*Source)(nil)
+	_ ducktypes.Populatable   = (*Source)(nil)
 )
 
 const (
diff --git a/apis/duck/v1/status_types.go b/apis/duck/v1/status_types.go
index f25212e57..5ea757694 100644
--- a/apis/duck/v1/status_types.go
+++ b/apis/duck/v1/status_types.go
@@ -29,6 +29,9 @@ import (
 // Conditions is a simple wrapper around apis.Conditions to implement duck.Implementable.
 type Conditions apis.Conditions
 
+// Conditions is an Implementable duck type.
+var _ ducktypes.Implementable = (*Conditions)(nil)
+
 // Status shows how we expect folks to embed Conditions in
 // their Status field.
 // WARNING: Adding fields to this struct will add them to all Knative resources.
diff --git a/apis/duck/v1beta1/addressable_types.go b/apis/duck/v1beta1/addressable_types.go
index d8984d8ed..ba7bbc85d 100644
--- a/apis/duck/v1beta1/addressable_types.go
+++ b/apis/duck/v1beta1/addressable_types.go
@@ -43,6 +43,9 @@ type Addressable struct {
 var (
 	// Addressable is a Convertible type.
 	_ apis.Convertible = (*Addressable)(nil)
+
+	// Addressable is an Implementable "duck type".
+	_ ducktypes.Implementable = (*Addressable)(nil)
 )
 
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -64,8 +67,10 @@ type AddressStatus struct {
 	Address *Addressable `json:"address,omitempty"`
 }
 
+// Verify AddressableType resources meet duck contracts.
 var (
-	_ apis.Listable = (*AddressableType)(nil)
+	_ apis.Listable         = (*AddressableType)(nil)
+	_ ducktypes.Populatable = (*AddressableType)(nil)
 )
 
 // GetFullType implements duck.Implementable
diff --git a/apis/duck/v1beta1/binding_types.go b/apis/duck/v1beta1/binding_types.go
new file mode 100644
index 000000000..b9e970b3a
--- /dev/null
+++ b/apis/duck/v1beta1/binding_types.go
@@ -0,0 +1,92 @@
+/*
+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 v1beta1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/pkg/apis"
+	"knative.dev/pkg/apis/duck"
+	"knative.dev/pkg/tracker"
+)
+
+// +genduck
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// Binding is a duck type that specifies the partial schema to which all
+// Binding implementations should adhere.
+type Binding struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec BindingSpec `json:"spec"`
+}
+
+// Verify that Binding implements the appropriate interfaces.
+var (
+	_ duck.Implementable = (*Binding)(nil)
+	_ duck.Populatable   = (*Binding)(nil)
+	_ apis.Listable      = (*Binding)(nil)
+)
+
+// BindingSpec specifies the spec portion of the Binding partial-schema.
+type BindingSpec struct {
+	// Subject references the resource(s) whose "runtime contract" should be
+	// augmented by Binding implementations.
+	Subject tracker.Reference `json:"subject"`
+}
+
+// GetFullType implements duck.Implementable
+func (*Binding) GetFullType() duck.Populatable {
+	return &Binding{}
+}
+
+// Populate implements duck.Populatable
+func (t *Binding) Populate() {
+	t.Spec = BindingSpec{
+		Subject: tracker.Reference{
+			APIVersion: "apps/v1",
+			Kind:       "Deployment",
+			Namespace:  "default",
+			// Name and Selector are mutually exclusive,
+			// but we fill them both in for this test.
+			Name: "bazinga",
+			Selector: &metav1.LabelSelector{
+				MatchLabels: map[string]string{
+					"foo": "bar",
+					"baz": "blah",
+				},
+			},
+		},
+	}
+}
+
+// GetListType implements apis.Listable
+func (*Binding) GetListType() runtime.Object {
+	return &BindingList{}
+}
+
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+
+// BindingList is a list of Binding resources
+type BindingList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata"`
+
+	Items []Binding `json:"items"`
+}
diff --git a/apis/duck/v1beta1/register.go b/apis/duck/v1beta1/register.go
index 324639c06..160eff56b 100644
--- a/apis/duck/v1beta1/register.go
+++ b/apis/duck/v1beta1/register.go
@@ -50,6 +50,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 		(&KResource{}).GetListType(),
 		&AddressableType{},
 		(&AddressableType{}).GetListType(),
+		&Binding{},
+		(&Binding{}).GetListType(),
 	)
 	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
 	return nil
diff --git a/apis/duck/v1beta1/source_types.go b/apis/duck/v1beta1/source_types.go
index 1a9be0d6c..60a502041 100644
--- a/apis/duck/v1beta1/source_types.go
+++ b/apis/duck/v1beta1/source_types.go
@@ -94,8 +94,11 @@ func (ss *SourceStatus) IsReady() bool {
 	return false
 }
 
+// Verify Source resources meet duck contracts.
 var (
-	_ apis.Listable = (*Source)(nil)
+	_ apis.Listable           = (*Source)(nil)
+	_ ducktypes.Implementable = (*Source)(nil)
+	_ ducktypes.Populatable   = (*Source)(nil)
 )
 
 const (
diff --git a/apis/duck/v1beta1/status_types.go b/apis/duck/v1beta1/status_types.go
index 8054c53be..ff7c68c26 100644
--- a/apis/duck/v1beta1/status_types.go
+++ b/apis/duck/v1beta1/status_types.go
@@ -34,6 +34,9 @@ import (
 // Conditions is a simple wrapper around apis.Conditions to implement duck.Implementable.
 type Conditions apis.Conditions
 
+// Conditions is an Implementable duck type.
+var _ ducktypes.Implementable = (*Conditions)(nil)
+
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
 // KResource is a skeleton type wrapping Conditions in the manner we expect
@@ -81,8 +84,11 @@ func (s *Status) SetConditions(c apis.Conditions) {
 	s.Conditions = Conditions(c)
 }
 
-// Ensure KResource satisfies apis.Listable
-var _ apis.Listable = (*KResource)(nil)
+// Verify KResource resources meet duck contracts.
+var (
+	_ apis.Listable         = (*KResource)(nil)
+	_ ducktypes.Populatable = (*KResource)(nil)
+)
 
 // GetFullType implements duck.Implementable
 func (*Conditions) GetFullType() ducktypes.Populatable {
diff --git a/apis/duck/v1beta1/zz_generated.deepcopy.go b/apis/duck/v1beta1/zz_generated.deepcopy.go
index 152bb8828..d22c6724a 100644
--- a/apis/duck/v1beta1/zz_generated.deepcopy.go
+++ b/apis/duck/v1beta1/zz_generated.deepcopy.go
@@ -128,6 +128,83 @@ func (in *AddressableTypeList) DeepCopyObject() runtime.Object {
 	return nil
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Binding) DeepCopyInto(out *Binding) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Binding.
+func (in *Binding) DeepCopy() *Binding {
+	if in == nil {
+		return nil
+	}
+	out := new(Binding)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Binding) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindingList) DeepCopyInto(out *BindingList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Binding, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindingList.
+func (in *BindingList) DeepCopy() *BindingList {
+	if in == nil {
+		return nil
+	}
+	out := new(BindingList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *BindingList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *BindingSpec) DeepCopyInto(out *BindingSpec) {
+	*out = *in
+	in.Subject.DeepCopyInto(&out.Subject)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BindingSpec.
+func (in *BindingSpec) DeepCopy() *BindingSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(BindingSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *CloudEventOverrides) DeepCopyInto(out *CloudEventOverrides) {
 	*out = *in
diff --git a/client/injection/ducks/duck/v1beta1/binding/binding.go b/client/injection/ducks/duck/v1beta1/binding/binding.go
new file mode 100644
index 000000000..ac6e4b937
--- /dev/null
+++ b/client/injection/ducks/duck/v1beta1/binding/binding.go
@@ -0,0 +1,60 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package binding
+
+import (
+	context "context"
+
+	duck "knative.dev/pkg/apis/duck"
+	v1beta1 "knative.dev/pkg/apis/duck/v1beta1"
+	controller "knative.dev/pkg/controller"
+	injection "knative.dev/pkg/injection"
+	dynamicclient "knative.dev/pkg/injection/clients/dynamicclient"
+	logging "knative.dev/pkg/logging"
+)
+
+func init() {
+	injection.Default.RegisterDuck(WithDuck)
+}
+
+// Key is used for associating the Informer inside the context.Context.
+type Key struct{}
+
+func WithDuck(ctx context.Context) context.Context {
+	dc := dynamicclient.Get(ctx)
+	dif := &duck.CachedInformerFactory{
+		Delegate: &duck.TypedInformerFactory{
+			Client:       dc,
+			Type:         (&v1beta1.Binding{}).GetFullType(),
+			ResyncPeriod: controller.GetResyncPeriod(ctx),
+			StopChannel:  ctx.Done(),
+		},
+	}
+	return context.WithValue(ctx, Key{}, dif)
+}
+
+// Get extracts the typed informer from the context.
+func Get(ctx context.Context) duck.InformerFactory {
+	untyped := ctx.Value(Key{})
+	if untyped == nil {
+		logging.FromContext(ctx).Panic(
+			"Unable to fetch knative.dev/pkg/apis/duck.InformerFactory from context.")
+	}
+	return untyped.(duck.InformerFactory)
+}
diff --git a/client/injection/ducks/duck/v1beta1/binding/fake/fake.go b/client/injection/ducks/duck/v1beta1/binding/fake/fake.go
new file mode 100644
index 000000000..b51111360
--- /dev/null
+++ b/client/injection/ducks/duck/v1beta1/binding/fake/fake.go
@@ -0,0 +1,30 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package fake
+
+import (
+	binding "knative.dev/pkg/client/injection/ducks/duck/v1beta1/binding"
+	injection "knative.dev/pkg/injection"
+)
+
+var Get = binding.Get
+
+func init() {
+	injection.Fake.RegisterDuck(binding.WithDuck)
+}
diff --git a/hash/hash.go b/hash/hash.go
index 9de437709..b6b642122 100644
--- a/hash/hash.go
+++ b/hash/hash.go
@@ -61,7 +61,7 @@ type hashData struct {
 }
 
 func (hd *hashData) fromIndexSet(s sets.Int) sets.String {
-	ret := sets.NewString()
+	ret := make(sets.String, len(s))
 	for v := range s {
 		ret.Insert(hd.nameForHIndex(v))
 	}
diff --git a/leaderelection/chaosduck/main.go b/leaderelection/chaosduck/main.go
index 6a41937fa..4f674638f 100644
--- a/leaderelection/chaosduck/main.go
+++ b/leaderelection/chaosduck/main.go
@@ -36,12 +36,30 @@ import (
 	"knative.dev/pkg/injection/sharedmain"
 	"knative.dev/pkg/signals"
 	"knative.dev/pkg/system"
-	"knative.dev/pkg/test/ha"
 )
 
 // components is a mapping from component name to the collection of leader pod names.
 type components map[string]sets.String
 
+func countingRFind(wr rune, wc int) func(rune) bool {
+	cnt := 0
+	return func(r rune) bool {
+		if r == wr {
+			cnt++
+		}
+		return cnt == wc
+	}
+}
+
+// This is a copy of test/ha/ha.go that avoids a dependency that pulls in a
+// redefinition of the kubeconfig flag.
+func extractDeployment(pod string) string {
+	if x := strings.LastIndexFunc(pod, countingRFind('-', 2)); x != -1 {
+		return pod[:x]
+	}
+	return ""
+}
+
 // buildComponents crawls the list of leases and builds a mapping from component names
 // to the set pod names that hold one or more leases.
 func buildComponents(kc kubernetes.Interface) (components, error) {
@@ -57,14 +75,14 @@ func buildComponents(kc kubernetes.Interface) (components, error) {
 			continue
 		}
 		pod := strings.SplitN(*lease.Spec.HolderIdentity, "_", 2)[0]
-		deploymentName := ha.ExtractDeployment(pod)
+		deploymentName := extractDeployment(pod)
 		if deploymentName == "" {
 			continue
 		}
 
 		set, ok := cs[deploymentName]
 		if !ok {
-			set = sets.NewString()
+			set = make(sets.String, 1)
 			cs[deploymentName] = set
 		}
 		set.Insert(pod)
diff --git a/leaderelection/config.go b/leaderelection/config.go
index b694c4fd2..326956790 100644
--- a/leaderelection/config.go
+++ b/leaderelection/config.go
@@ -32,21 +32,21 @@ import (
 	cm "knative.dev/pkg/configmap"
 )
 
-const configMapNameEnv = "CONFIG_LEADERELECTION_NAME"
+const (
+	configMapNameEnv = "CONFIG_LEADERELECTION_NAME"
+	// KnativeResourceLock is the only supported lock mechanism for Knative.
+	KnativeResourceLock = resourcelock.LeasesResourceLock
+)
 
 // MaxBuckets is the maximum number of buckets to allow users to define.
 // This is a variable so that it may be customized in the binary entrypoint.
 var MaxBuckets uint32 = 10
 
-var validResourceLocks = sets.NewString(resourcelock.LeasesResourceLock)
-
 // NewConfigFromMap returns a Config for the given map, or an error.
 func NewConfigFromMap(data map[string]string) (*Config, error) {
 	config := defaultConfig()
 
 	if err := cm.Parse(data,
-		cm.AsString("resourceLock", &config.ResourceLock),
-
 		cm.AsDuration("leaseDuration", &config.LeaseDuration),
 		cm.AsDuration("renewDeadline", &config.RenewDeadline),
 		cm.AsDuration("retryPeriod", &config.RetryPeriod),
@@ -59,10 +59,6 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
 	if config.Buckets < 1 || config.Buckets > MaxBuckets {
 		return nil, fmt.Errorf("buckets: value must be between %d <= %d <= %d", 1, config.Buckets, MaxBuckets)
 	}
-	if !validResourceLocks.Has(config.ResourceLock) {
-		return nil, fmt.Errorf(`resourceLock: invalid value %q: valid values are "leases"`, config.ResourceLock)
-	}
-
 	return config, nil
 }
 
@@ -79,7 +75,6 @@ func NewConfigFromConfigMap(configMap *corev1.ConfigMap) (*Config, error) {
 // contained within a single namespace. Typically these will correspond to a
 // single source repository, viz: serving or eventing.
 type Config struct {
-	ResourceLock  string
 	Buckets       uint32
 	LeaseDuration time.Duration
 	RenewDeadline time.Duration
@@ -95,7 +90,6 @@ func (c *Config) GetComponentConfig(name string) ComponentConfig {
 	return ComponentConfig{
 		Component:     name,
 		Buckets:       c.Buckets,
-		ResourceLock:  c.ResourceLock,
 		LeaseDuration: c.LeaseDuration,
 		RenewDeadline: c.RenewDeadline,
 		RetryPeriod:   c.RetryPeriod,
@@ -104,7 +98,6 @@ func (c *Config) GetComponentConfig(name string) ComponentConfig {
 
 func defaultConfig() *Config {
 	return &Config{
-		ResourceLock:  "leases",
 		Buckets:       1,
 		LeaseDuration: 15 * time.Second,
 		RenewDeadline: 10 * time.Second,
@@ -116,7 +109,6 @@ func defaultConfig() *Config {
 type ComponentConfig struct {
 	Component     string
 	Buckets       uint32
-	ResourceLock  string
 	LeaseDuration time.Duration
 	RenewDeadline time.Duration
 	RetryPeriod   time.Duration
diff --git a/leaderelection/context.go b/leaderelection/context.go
index 57b0586fb..18f7e23eb 100644
--- a/leaderelection/context.go
+++ b/leaderelection/context.go
@@ -123,7 +123,7 @@ func (b *standardBuilder) buildElector(ctx context.Context, la reconciler.Leader
 			total: b.lec.Buckets,
 		}
 
-		rl, err := resourcelock.New(b.lec.ResourceLock,
+		rl, err := resourcelock.New(KnativeResourceLock,
 			system.Namespace(), // use namespace we are running in
 			bkt.Name(),
 			b.kc.CoreV1(),
diff --git a/webhook/psbinding/psbinding.go b/webhook/psbinding/psbinding.go
index 0b89705c7..9472e16bd 100644
--- a/webhook/psbinding/psbinding.go
+++ b/webhook/psbinding/psbinding.go
@@ -273,7 +273,7 @@ func (ac *Reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt
 		}
 		set := gks[gk]
 		if set == nil {
-			set = sets.NewString()
+			set = make(sets.String, 1)
 		}
 		set.Insert(gv.Version)
 		gks[gk] = set


Test patch:
diff --git a/apis/duck/v1/implements_test.go b/apis/duck/v1/implements_test.go
new file mode 100644
index 000000000..a786f41f0
--- /dev/null
+++ b/apis/duck/v1/implements_test.go
@@ -0,0 +1,58 @@
+/*
+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 v1
+
+import (
+	"testing"
+
+	appsv1 "k8s.io/api/apps/v1"
+	batchv1 "k8s.io/api/batch/v1"
+
+	"knative.dev/pkg/apis/duck"
+	"knative.dev/pkg/apis/duck/ducktypes"
+)
+
+func TestTypesImplements(t *testing.T) {
+	testCases := []struct {
+		instance interface{}
+		iface    ducktypes.Implementable
+	}{
+		{instance: &AddressableType{}, iface: &Addressable{}},
+		{instance: &KResource{}, iface: &Conditions{}},
+	}
+	for _, tc := range testCases {
+		if err := duck.VerifyType(tc.instance, tc.iface); err != nil {
+			t.Error(err)
+		}
+	}
+}
+
+func TestImplementsPodSpecable(t *testing.T) {
+	instances := []interface{}{
+		&WithPod{},
+		&appsv1.ReplicaSet{},
+		&appsv1.Deployment{},
+		&appsv1.StatefulSet{},
+		&appsv1.DaemonSet{},
+		&batchv1.Job{},
+	}
+	for _, instance := range instances {
+		if err := duck.VerifyType(instance, &PodSpecable{}); err != nil {
+			t.Error(err)
+		}
+	}
+}
diff --git a/apis/duck/v1_tests.go b/apis/duck/v1_tests.go
deleted file mode 100644
index ba56a994c..000000000
--- a/apis/duck/v1_tests.go
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-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 duck
-
-import (
-	"testing"
-
-	appsv1 "k8s.io/api/apps/v1"
-	batchv1 "k8s.io/api/batch/v1"
-
-	v1 "knative.dev/pkg/apis/duck/v1"
-)
-
-// Conditions is an Implementable "duck type".
-var _ Implementable = (*v1.Conditions)(nil)
-
-// In order for Conditions to be Implementable, KResource must be Populatable.
-var _ Populatable = (*v1.KResource)(nil)
-
-// Source is an Implementable "duck type".
-var _ Implementable = (*v1.Source)(nil)
-
-// Verify Source resources meet duck contracts.
-var _ Populatable = (*v1.Source)(nil)
-
-var _ Populatable = (*v1.WithPod)(nil)
-var _ Implementable = (*v1.PodSpecable)(nil)
-
-func TestV1TypesImplements(t *testing.T) {
-	testCases := []struct {
-		instance interface{}
-		iface    Implementable
-	}{
-		{instance: &v1.AddressableType{}, iface: &v1.Addressable{}},
-		{instance: &v1.KResource{}, iface: &v1.Conditions{}},
-	}
-	for _, tc := range testCases {
-		if err := VerifyType(tc.instance, tc.iface); err != nil {
-			t.Error(err)
-		}
-	}
-}
-
-func TestV1ImplementsPodSpecable(t *testing.T) {
-	instances := []interface{}{
-		&v1.WithPod{},
-		&appsv1.ReplicaSet{},
-		&appsv1.Deployment{},
-		&appsv1.StatefulSet{},
-		&appsv1.DaemonSet{},
-		&batchv1.Job{},
-	}
-	for _, instance := range instances {
-		if err := VerifyType(instance, &v1.PodSpecable{}); err != nil {
-			t.Error(err)
-		}
-	}
-}
-
-// Addressable is an Implementable "duck type".
-var _ Implementable = (*v1.Addressable)(nil)
-
-// Verify AddressableType resources meet duck contracts.
-var _ Populatable = (*v1.AddressableType)(nil)
diff --git a/apis/duck/v1alpha1/implements_test.go b/apis/duck/v1alpha1/implements_test.go
index 60ea9689c..56a4250d6 100644
--- a/apis/duck/v1alpha1/implements_test.go
+++ b/apis/duck/v1alpha1/implements_test.go
@@ -20,7 +20,6 @@ import (
 	"testing"
 
 	"knative.dev/pkg/apis/duck"
-	"knative.dev/pkg/apis/duck/v1beta1"
 )
 
 func TestTypesImplements(t *testing.T) {
@@ -29,7 +28,6 @@ func TestTypesImplements(t *testing.T) {
 		iface    duck.Implementable
 	}{
 		{instance: &AddressableType{}, iface: &Addressable{}},
-		{instance: &AddressableType{}, iface: &v1beta1.Addressable{}},
 		{instance: &LegacyTarget{}, iface: &LegacyTargetable{}},
 		{instance: &Target{}, iface: &Targetable{}},
 		{instance: &Binding{}, iface: &Binding{}},
diff --git a/apis/duck/v1beta1/implements_test.go b/apis/duck/v1beta1/implements_test.go
new file mode 100644
index 000000000..3e6c890ae
--- /dev/null
+++ b/apis/duck/v1beta1/implements_test.go
@@ -0,0 +1,40 @@
+/*
+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 v1beta1
+
+import (
+	"testing"
+
+	"knative.dev/pkg/apis/duck"
+	"knative.dev/pkg/apis/duck/ducktypes"
+)
+
+func TestTypesImplements(t *testing.T) {
+	testCases := []struct {
+		instance interface{}
+		iface    ducktypes.Implementable
+	}{
+		{instance: &AddressableType{}, iface: &Addressable{}},
+		{instance: &KResource{}, iface: &Conditions{}},
+		{instance: &Source{}, iface: &Conditions{}},
+	}
+	for _, tc := range testCases {
+		if err := duck.VerifyType(tc.instance, tc.iface); err != nil {
+			t.Error(err)
+		}
+	}
+}
diff --git a/apis/duck/v1beta1_tests.go b/apis/duck/v1beta1_tests.go
deleted file mode 100644
index 23731d8c7..000000000
--- a/apis/duck/v1beta1_tests.go
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-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 duck
-
-import (
-	"testing"
-
-	"knative.dev/pkg/apis/duck/v1beta1"
-)
-
-// v1beta1.Conditions is an Implementable "duck type".
-var _ Implementable = (*v1beta1.Conditions)(nil)
-
-// In order for v1beta1.Conditions to be Implementable, v1beta1.KResource must be Populatable.
-var _ Populatable = (*v1beta1.KResource)(nil)
-
-// v1beta1.Source is an Implementable "duck type".
-var _ Implementable = (*v1beta1.Source)(nil)
-
-// Verify v1beta1.Source resources meet duck contracts.
-var _ Populatable = (*v1beta1.Source)(nil)
-
-// Addressable is an Implementable "duck type".
-var _ Implementable = (*v1beta1.Addressable)(nil)
-
-// Verify AddressableType resources meet duck contracts.
-var _ Populatable = (*v1beta1.AddressableType)(nil)
-
-func TestV1Beta1TypesImplements(t *testing.T) {
-	testCases := []struct {
-		instance interface{}
-		iface    Implementable
-	}{
-		{instance: &v1beta1.AddressableType{}, iface: &v1beta1.Addressable{}},
-		{instance: &v1beta1.KResource{}, iface: &v1beta1.Conditions{}},
-	}
-	for _, tc := range testCases {
-		if err := VerifyType(tc.instance, tc.iface); err != nil {
-			t.Error(err)
-		}
-	}
-}
diff --git a/controller/controller_test.go b/controller/controller_test.go
index f03afeedd..629ecc0f0 100644
--- a/controller/controller_test.go
+++ b/controller/controller_test.go
@@ -918,7 +918,6 @@ func TestStartAndShutdownWithLeaderAwareWithLostElection(t *testing.T) {
 	}
 	cc := leaderelection.ComponentConfig{
 		Component:     "component",
-		ResourceLock:  "leases",
 		LeaseDuration: 15 * time.Second,
 		RenewDeadline: 10 * time.Second,
 		RetryPeriod:   2 * time.Second,
diff --git a/leaderelection/config_test.go b/leaderelection/config_test.go
index 44a1516a5..2dfdcd389 100644
--- a/leaderelection/config_test.go
+++ b/leaderelection/config_test.go
@@ -30,7 +30,6 @@ import (
 
 func okConfig() *Config {
 	return &Config{
-		ResourceLock:  "leases",
 		Buckets:       1,
 		LeaseDuration: 15 * time.Second,
 		RenewDeadline: 10 * time.Second,
@@ -40,8 +39,7 @@ func okConfig() *Config {
 
 func okData() map[string]string {
 	return map[string]string{
-		"resourceLock": "leases",
-		"buckets":      "1",
+		"buckets": "1",
 		// values in this data come from the defaults suggested in the
 		// code:
 		// https://github.com/kubernetes/client-go/blob/kubernetes-1.16.0/tools/leaderelection/leaderelection.go
@@ -71,12 +69,6 @@ func TestNewConfigMapFromData(t *testing.T) {
 			config.Buckets = 5
 			return config
 		}(),
-	}, {
-		name: "invalid resourceLock",
-		data: kmeta.UnionMaps(okData(), map[string]string{
-			"resourceLock": "flarps",
-		}),
-		err: errors.New(`resourceLock: invalid value "flarps": valid values are "leases"`),
 	}, {
 		name: "invalid leaseDuration",
 		data: kmeta.UnionMaps(okData(), map[string]string{
@@ -142,14 +134,12 @@ func TestGetComponentConfig(t *testing.T) {
 	}{{
 		name: "component enabled",
 		config: Config{
-			ResourceLock:  "leases",
 			LeaseDuration: 15 * time.Second,
 			RenewDeadline: 10 * time.Second,
 			RetryPeriod:   2 * time.Second,
 		},
 		expected: ComponentConfig{
 			Component:     expectedName,
-			ResourceLock:  "leases",
 			LeaseDuration: 15 * time.Second,
 			RenewDeadline: 10 * time.Second,
 			RetryPeriod:   2 * time.Second,
diff --git a/leaderelection/context_test.go b/leaderelection/context_test.go
index 0a66ae3f2..d46ebb628 100644
--- a/leaderelection/context_test.go
+++ b/leaderelection/context_test.go
@@ -38,7 +38,6 @@ func TestWithBuilder(t *testing.T) {
 	cc := ComponentConfig{
 		Component:     "the-component",
 		Buckets:       1,
-		ResourceLock:  "leases",
 		LeaseDuration: 15 * time.Second,
 		RenewDeadline: 10 * time.Second,
 		RetryPeriod:   2 * time.Second,
diff --git a/test/ha/ha.go b/test/ha/ha.go
index a88e8f173..2859cc872 100644
--- a/test/ha/ha.go
+++ b/test/ha/ha.go
@@ -41,7 +41,7 @@ func countingRFind(wr rune, wc int) func(rune) bool {
 	}
 }
 
-func ExtractDeployment(pod string) string {
+func extractDeployment(pod string) string {
 	if x := strings.LastIndexFunc(pod, countingRFind('-', 2)); x != -1 {
 		return pod[:x]
 	}
@@ -63,7 +63,7 @@ func GetLeaders(t *testing.T, client *test.KubeClient, deploymentName, namespace
 		pod := strings.SplitN(*lease.Spec.HolderIdentity, "_", 2)[0]
 
 		// Deconstruct the pod name and look for the deployment.  This won't work for very long deployment names.
-		if ExtractDeployment(pod) != deploymentName {
+		if extractDeployment(pod) != deploymentName {
 			continue
 		}
 		ret = append(ret, pod)
diff --git a/test/ha/ha_test.go b/test/ha/ha_test.go
index 4b460ccde..41b6ca9da 100644
--- a/test/ha/ha_test.go
+++ b/test/ha/ha_test.go
@@ -20,10 +20,10 @@ import "testing"
 
 func TestExtractDeployment(t *testing.T) {
 	const want = "gke-cluster-michigan-pool-2"
-	if got := ExtractDeployment("gke-cluster-michigan-pool-2-03f384a0-2zu1"); got != want {
+	if got := extractDeployment("gke-cluster-michigan-pool-2-03f384a0-2zu1"); got != want {
 		t.Errorf("Deployment = %q, want: %q", got, want)
 	}
-	if got := ExtractDeployment("a-b"); got != "" {
+	if got := extractDeployment("a-b"); got != "" {
 		t.Errorf("Deployment = %q, want empty string", got)
 	}
 }