diff --git a/go.mod b/go.mod index f4917bfba497..84539a88753a 100644 --- a/go.mod +++ b/go.mod @@ -40,8 +40,8 @@ require ( k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29 knative.dev/caching v0.0.0-20200707200344-95a2aaeace0f knative.dev/networking v0.0.0-20200707203944-725ec013d8a2 - knative.dev/pkg v0.0.0-20200710163519-a0cb3d689532 - knative.dev/test-infra v0.0.0-20200710160019-5b9732bc24f7 + knative.dev/pkg v0.0.0-20200713031612-b09a159e12c9 + knative.dev/test-infra v0.0.0-20200713045417-850e4e37918d ) replace ( diff --git a/go.sum b/go.sum index 531a2c743ad3..1656e86c46f8 100644 --- a/go.sum +++ b/go.sum @@ -1634,11 +1634,13 @@ knative.dev/networking v0.0.0-20200707203944-725ec013d8a2 h1:Co9j0Q4ZJxwkzVFKUc6 knative.dev/networking v0.0.0-20200707203944-725ec013d8a2/go.mod h1:e1NL29AarTcgaR240oc4GUzqHtTfTu62JNrUHN3kIG0= knative.dev/pkg v0.0.0-20200207155214-fef852970f43/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= knative.dev/pkg v0.0.0-20200707190344-0a8314b44495/go.mod h1:AqAJV6rYi8IGikDjJ/9ZQd9qKdkXVlesVnVjwx62YB8= -knative.dev/pkg v0.0.0-20200710163519-a0cb3d689532 h1:1dSRUstjueNPF06yxGlmeEzzMZpQJnlddA4VehDuTp8= -knative.dev/pkg v0.0.0-20200710163519-a0cb3d689532/go.mod h1:AqAJV6rYi8IGikDjJ/9ZQd9qKdkXVlesVnVjwx62YB8= +knative.dev/pkg v0.0.0-20200713031612-b09a159e12c9 h1:YSapebbZZbpH31YMSF0Egt7+IDi/og4S574eWqEXReo= +knative.dev/pkg v0.0.0-20200713031612-b09a159e12c9/go.mod h1:aWPsPIHISvZetAm/2pnz+v6Ro5EYaX704Z/Zd9rTZ4M= knative.dev/test-infra v0.0.0-20200707183444-aed09e56ddc7/go.mod h1:RjYAhXnZqeHw9+B0zsbqSPlae0lCvjekO/nw5ZMpLCs= knative.dev/test-infra v0.0.0-20200710160019-5b9732bc24f7 h1:fAl3pG2I323tie8kuuNlB88B7RB8WJtCrsXIKuNh1U8= knative.dev/test-infra v0.0.0-20200710160019-5b9732bc24f7/go.mod h1:vtT6dLs/iNj8pKcfag8CSVqHKNMgyCFtU/g1pV7Bovs= +knative.dev/test-infra v0.0.0-20200713045417-850e4e37918d h1:Q3LrAYSi+Ii2yZVUiA5Y3Jr4TCU6g/XN9ClVosejpJk= +knative.dev/test-infra v0.0.0-20200713045417-850e4e37918d/go.mod h1:vtT6dLs/iNj8pKcfag8CSVqHKNMgyCFtU/g1pV7Bovs= 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/vendor/knative.dev/pkg/apis/duck/ducktypes/ducktypes.go b/vendor/knative.dev/pkg/apis/duck/ducktypes/ducktypes.go new file mode 100644 index 000000000000..6f99e0882393 --- /dev/null +++ b/vendor/knative.dev/pkg/apis/duck/ducktypes/ducktypes.go @@ -0,0 +1,43 @@ +/* +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 ducktypes + +import ( + "knative.dev/pkg/apis" +) + +// Implementable is implemented by the Fooable duck type that consumers +// are expected to embed as a `.status.fooable` field. +type Implementable interface { + // GetFullType returns an instance of a full resource wrapping + // an instance of this Implementable that can populate its fields + // to verify json roundtripping. + GetFullType() Populatable +} + +// Populatable is implemented by a skeleton resource wrapping an Implementable +// duck type. It will generally have TypeMeta, ObjectMeta, and a Status field +// wrapping a Fooable field. +type Populatable interface { + apis.Listable + + // Populate fills in all possible fields, so that we can verify that + // they roundtrip properly through JSON. + Populate() +} + +const GroupName = "duck.knative.dev" diff --git a/vendor/knative.dev/pkg/apis/duck/register.go b/vendor/knative.dev/pkg/apis/duck/register.go index d84cd49d18b0..93cf55d7fcc1 100644 --- a/vendor/knative.dev/pkg/apis/duck/register.go +++ b/vendor/knative.dev/pkg/apis/duck/register.go @@ -16,8 +16,12 @@ limitations under the License. package duck +import ( + "knative.dev/pkg/apis/duck/ducktypes" +) + const ( - GroupName = "duck.knative.dev" + GroupName = ducktypes.GroupName // AddressableDuckVersionLabel is the label we use to declare // that a type conforms to the Addressable duck type. diff --git a/vendor/knative.dev/pkg/apis/duck/v1/addressable_types.go b/vendor/knative.dev/pkg/apis/duck/v1/addressable_types.go index 579e6976ee85..3cfcac331476 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/addressable_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/addressable_types.go @@ -24,7 +24,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/ducktypes" ) // +genduck @@ -40,8 +40,6 @@ type Addressable struct { } var ( - // Addressable is an Implementable "duck type". - _ duck.Implementable = (*Addressable)(nil) // Addressable is a Convertible type. _ apis.Convertible = (*Addressable)(nil) ) @@ -66,13 +64,11 @@ type AddressStatus struct { } var ( - // Verify AddressableType resources meet duck contracts. - _ duck.Populatable = (*AddressableType)(nil) - _ apis.Listable = (*AddressableType)(nil) + _ apis.Listable = (*AddressableType)(nil) ) // GetFullType implements duck.Implementable -func (*Addressable) GetFullType() duck.Populatable { +func (*Addressable) GetFullType() ducktypes.Populatable { return &AddressableType{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1/podspec_types.go b/vendor/knative.dev/pkg/apis/duck/v1/podspec_types.go index 0dd9ec338685..92ed7f1c4ccd 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/podspec_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/podspec_types.go @@ -22,7 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/ducktypes" ) // +genduck @@ -50,13 +50,11 @@ type WithPodSpec struct { // Assert that we implement the interfaces necessary to // use duck.VerifyType. var ( - _ duck.Populatable = (*WithPod)(nil) - _ duck.Implementable = (*PodSpecable)(nil) - _ apis.Listable = (*WithPod)(nil) + _ apis.Listable = (*WithPod)(nil) ) // GetFullType implements duck.Implementable -func (*PodSpecable) GetFullType() duck.Populatable { +func (*PodSpecable) GetFullType() ducktypes.Populatable { return &WithPod{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1/register.go b/vendor/knative.dev/pkg/apis/duck/v1/register.go index e3af46d6f8d6..69bb11578383 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/register.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/register.go @@ -20,11 +20,12 @@ 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" + + "knative.dev/pkg/apis/duck/ducktypes" ) // SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: duck.GroupName, Version: "v1"} +var SchemeGroupVersion = schema.GroupVersion{Group: ducktypes.GroupName, Version: "v1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { diff --git a/vendor/knative.dev/pkg/apis/duck/v1/source_types.go b/vendor/knative.dev/pkg/apis/duck/v1/source_types.go index 3b378ca3d48f..03c4d40b9b5a 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/source_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/source_types.go @@ -24,12 +24,9 @@ import ( "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/ducktypes" ) -// Source is an Implementable "duck type". -var _ duck.Implementable = (*Source)(nil) - // +genduck // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -113,9 +110,7 @@ func (ss *SourceStatus) IsReady() bool { } var ( - // Verify Source resources meet duck contracts. - _ duck.Populatable = (*Source)(nil) - _ apis.Listable = (*Source)(nil) + _ apis.Listable = (*Source)(nil) ) const ( @@ -125,7 +120,7 @@ const ( ) // GetFullType implements duck.Implementable -func (*Source) GetFullType() duck.Populatable { +func (*Source) GetFullType() ducktypes.Populatable { return &Source{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1/status_types.go b/vendor/knative.dev/pkg/apis/duck/v1/status_types.go index aab246b1f90a..f25212e576db 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/status_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/status_types.go @@ -20,7 +20,7 @@ import ( "context" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/ducktypes" "knative.dev/pkg/kmeta" ) @@ -29,9 +29,6 @@ import ( // Conditions is a simple wrapper around apis.Conditions to implement duck.Implementable. type Conditions apis.Conditions -// Conditions is an Implementable "duck type". -var _ duck.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. @@ -66,14 +63,11 @@ func (s *Status) SetConditions(c apis.Conditions) { s.Conditions = Conditions(c) } -// In order for Conditions to be Implementable, KResource must be Populatable. -var _ duck.Populatable = (*KResource)(nil) - // Ensure KResource satisfies apis.Listable var _ apis.Listable = (*KResource)(nil) // GetFullType implements duck.Implementable -func (*Conditions) GetFullType() duck.Populatable { +func (*Conditions) GetFullType() ducktypes.Populatable { return &KResource{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1_tests.go b/vendor/knative.dev/pkg/apis/duck/v1_tests.go new file mode 100644 index 000000000000..ca68b4c89613 --- /dev/null +++ b/vendor/knative.dev/pkg/apis/duck/v1_tests.go @@ -0,0 +1,78 @@ +/* +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" + + "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/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go index 3e3f8286763f..46cfed16018b 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/addressable_types.go @@ -24,8 +24,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" - v1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/apis/duck/ducktypes" + "knative.dev/pkg/apis/duck/v1" ) // +genduck @@ -41,8 +41,6 @@ type Addressable struct { } var ( - // Addressable is an Implementable "duck type". - _ duck.Implementable = (*Addressable)(nil) // Addressable is a Convertible type. _ apis.Convertible = (*Addressable)(nil) ) @@ -67,13 +65,11 @@ type AddressStatus struct { } var ( - // Verify AddressableType resources meet duck contracts. - _ duck.Populatable = (*AddressableType)(nil) - _ apis.Listable = (*AddressableType)(nil) + _ apis.Listable = (*AddressableType)(nil) ) // GetFullType implements duck.Implementable -func (*Addressable) GetFullType() duck.Populatable { +func (*Addressable) GetFullType() ducktypes.Populatable { return &AddressableType{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go index ca8388ad4843..324639c065bd 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/register.go @@ -20,11 +20,12 @@ 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" + + "knative.dev/pkg/apis/duck/ducktypes" ) // SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: duck.GroupName, Version: "v1beta1"} +var SchemeGroupVersion = schema.GroupVersion{Group: ducktypes.GroupName, Version: "v1beta1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go index 5853a1ae4108..1a9be0d6c377 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go @@ -24,12 +24,9 @@ import ( "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/ducktypes" ) -// Source is an Implementable "duck type". -var _ duck.Implementable = (*Source)(nil) - // +genduck // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -98,9 +95,7 @@ func (ss *SourceStatus) IsReady() bool { } var ( - // Verify Source resources meet duck contracts. - _ duck.Populatable = (*Source)(nil) - _ apis.Listable = (*Source)(nil) + _ apis.Listable = (*Source)(nil) ) const ( @@ -110,7 +105,7 @@ const ( ) // GetFullType implements duck.Implementable -func (*Source) GetFullType() duck.Populatable { +func (*Source) GetFullType() ducktypes.Populatable { return &Source{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go index 107592e85dd2..8054c53bee39 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go @@ -25,7 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" - "knative.dev/pkg/apis/duck" + "knative.dev/pkg/apis/duck/ducktypes" "knative.dev/pkg/kmeta" ) @@ -34,9 +34,6 @@ import ( // Conditions is a simple wrapper around apis.Conditions to implement duck.Implementable. type Conditions apis.Conditions -// Conditions is an Implementable "duck type". -var _ duck.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 @@ -84,14 +81,11 @@ func (s *Status) SetConditions(c apis.Conditions) { s.Conditions = Conditions(c) } -// In order for Conditions to be Implementable, KResource must be Populatable. -var _ duck.Populatable = (*KResource)(nil) - // Ensure KResource satisfies apis.Listable var _ apis.Listable = (*KResource)(nil) // GetFullType implements duck.Implementable -func (*Conditions) GetFullType() duck.Populatable { +func (*Conditions) GetFullType() ducktypes.Populatable { return &KResource{} } diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1_tests.go b/vendor/knative.dev/pkg/apis/duck/v1beta1_tests.go new file mode 100644 index 000000000000..23731d8c79e3 --- /dev/null +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1_tests.go @@ -0,0 +1,56 @@ +/* +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/vendor/knative.dev/pkg/apis/duck/verify.go b/vendor/knative.dev/pkg/apis/duck/verify.go index 3f42330fff2b..cbcc51117cef 100644 --- a/vendor/knative.dev/pkg/apis/duck/verify.go +++ b/vendor/knative.dev/pkg/apis/duck/verify.go @@ -20,29 +20,12 @@ import ( "encoding/json" "fmt" - "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck/ducktypes" "knative.dev/pkg/kmp" ) -// Implementable is implemented by the Fooable duck type that consumers -// are expected to embed as a `.status.fooable` field. -type Implementable interface { - // GetFullType returns an instance of a full resource wrapping - // an instance of this Implementable that can populate its fields - // to verify json roundtripping. - GetFullType() Populatable -} - -// Populatable is implemented by a skeleton resource wrapping an Implementable -// duck type. It will generally have TypeMeta, ObjectMeta, and a Status field -// wrapping a Fooable field. -type Populatable interface { - apis.Listable - - // Populate fills in all possible fields, so that we can verify that - // they roundtrip properly through JSON. - Populate() -} +type Implementable = ducktypes.Implementable +type Populatable = ducktypes.Populatable // VerifyType verifies that a particular concrete resource properly implements // the provided Implementable duck type. It is expected that under the resource diff --git a/vendor/knative.dev/pkg/hash/bucketer.go b/vendor/knative.dev/pkg/hash/bucketer.go new file mode 100644 index 000000000000..45f1100ab554 --- /dev/null +++ b/vendor/knative.dev/pkg/hash/bucketer.go @@ -0,0 +1,112 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file contains the utilities to make bucketing decisions. + +package hash + +import ( + "sync" + + lru "github.com/hashicorp/golang-lru" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" + "knative.dev/pkg/reconciler" +) + +var _ reconciler.Bucket = (*Bucket)(nil) + +// BucketSet answers to what bucket does key X belong in a +// consistent manner (consistent as in consistent hashing). +type BucketSet struct { + // Stores the cached lookups. cache is internally thread safe. + cache *lru.Cache + + // mu guards buckets. + mu sync.RWMutex + // All the bucket names. Needed for building hash universe. + // `name` must be in this set. + buckets sets.String +} + +// Bucket implements reconciler.Bucket and wraps around BuketSet +// for bucketing functions. +type Bucket struct { + name string + buckets *BucketSet +} + +// Scientifically inferred preferred cache size. +const cacheSize = 4096 + +func newCache() *lru.Cache { + c, _ := lru.New(cacheSize) + return c +} + +// NewBucketSet creates a new bucket set with the given universe +// of bucket names. +func NewBucketSet(bucketList sets.String) *BucketSet { + return &BucketSet{ + cache: newCache(), + buckets: bucketList, + } +} + +// NewBucket creates a new bucket. +func NewBucket(name string, bl *BucketSet) *Bucket { + return &Bucket{ + name: name, + buckets: bl, + } +} + +// Name implements Bucket. +func (b *Bucket) Name() string { + return b.name +} + +// Has returns true if this bucket owns the key and +// implements reconciler.Bucket interface. +func (b *Bucket) Has(nn types.NamespacedName) bool { + return b.buckets.Owner(nn.String()) == b.name +} + +// Owner returns the owner of the key. +// Owner will cache the results for faster lookup. +func (b *BucketSet) Owner(key string) string { + if v, ok := b.cache.Get(key); ok { + return v.(string) + } + b.mu.RLock() + defer b.mu.RUnlock() + l := ChooseSubset(b.buckets, 1 /*single query wanted*/, key) + ret := l.UnsortedList()[0] + b.cache.Add(key, ret) + return ret +} + +// Update updates the universe of buckets. +func (b *BucketSet) Update(newB sets.String) { + b.mu.Lock() + defer b.mu.Unlock() + // In theory we can iterate over the map and + // purge only the keys that moved to a new shard. + // But this might be more expensive than re-build + // the cache as reconciliations happen. + b.cache.Purge() + b.buckets = newB +} diff --git a/vendor/knative.dev/pkg/hash/doc.go b/vendor/knative.dev/pkg/hash/doc.go index 36569b84a246..5cb01faa6372 100644 --- a/vendor/knative.dev/pkg/hash/doc.go +++ b/vendor/knative.dev/pkg/hash/doc.go @@ -17,6 +17,11 @@ limitations under the License. // Package hash contains various Knative specific hashing utilities. // // - ChooseSubset is a consistent hashing/mapping function providing -// a consistent selection of N keys from M (N<=M) keys for a given +// a consistent selection of N keys from M (N<=M) keys for a given // target. +// - BucketSet is a bucketer library which uses ChooseSubset under the +// the hood in order to implement consistent mapping between keys and +// set of buckets, indentified by unique names. Compared to basic bucket +// implementtion which just does hash%num_buckets, when the number of +// buckets change only a small subset of keys are supposed to migrate. package hash diff --git a/vendor/knative.dev/pkg/test/ha/ha.go b/vendor/knative.dev/pkg/test/ha/ha.go index c1b5c045b438..2859cc872854 100644 --- a/vendor/knative.dev/pkg/test/ha/ha.go +++ b/vendor/knative.dev/pkg/test/ha/ha.go @@ -26,17 +26,36 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" + "knative.dev/pkg/test" "knative.dev/pkg/test/logging" ) +func countingRFind(wr rune, wc int) func(rune) bool { + cnt := 0 + return func(r rune) bool { + if r == wr { + cnt++ + } + return cnt == wc + } +} + +func extractDeployment(pod string) string { + if x := strings.LastIndexFunc(pod, countingRFind('-', 2)); x != -1 { + return pod[:x] + } + return "" +} + // GetLeaders collects all of the leader pods from the specified deployment. +// GetLeaders will return duplicate pods by design. func GetLeaders(t *testing.T, client *test.KubeClient, deploymentName, namespace string) ([]string, error) { leases, err := client.Kube.CoordinationV1().Leases(namespace).List(metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("error getting leases for deployment %q: %w", deploymentName, err) } - var pods []string + ret := make([]string, 0, len(leases.Items)) for _, lease := range leases.Items { if lease.Spec.HolderIdentity == nil { continue @@ -44,16 +63,12 @@ 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. - parts := strings.Split(pod, "-") - if len(parts) < 3 { - continue - } - if strings.Join(parts[:len(parts)-2], "-") != deploymentName { + if extractDeployment(pod) != deploymentName { continue } - pods = append(pods, pod) + ret = append(ret, pod) } - return pods, nil + return ret, nil } // WaitForNewLeaders waits until the collection of current leaders consists of "n" leaders @@ -64,19 +79,20 @@ func WaitForNewLeaders(t *testing.T, client *test.KubeClient, deploymentName, na var leaders sets.String err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) { - currentLeaders, err := GetLeaders(t, client, deploymentName, namespace) + currLeaders, err := GetLeaders(t, client, deploymentName, namespace) if err != nil { return false, err } - if len(currentLeaders) < n { - t.Logf("WaitForNewLeaders[%s] not enough leaders, got: %d, want: %d", deploymentName, len(currentLeaders), n) + if len(currLeaders) < n { + t.Logf("WaitForNewLeaders[%s] not enough leaders, got: %d, want: %d", deploymentName, len(currLeaders), n) return false, nil } - if previousLeaders.HasAny(currentLeaders...) { - t.Logf("WaitForNewLeaders[%s] still see intersection: %v", deploymentName, previousLeaders.Intersection(sets.NewString(currentLeaders...))) + l := sets.NewString(currLeaders...) + if previousLeaders.HasAny(currLeaders...) { + t.Logf("WaitForNewLeaders[%s] still see intersection: %v", deploymentName, previousLeaders.Intersection(l)) return false, nil } - leaders = sets.NewString(currentLeaders...) + leaders = l return true, nil }) return leaders, err diff --git a/vendor/modules.txt b/vendor/modules.txt index 39360dfb3d1d..42758046f958 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1034,12 +1034,13 @@ 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-20200710163519-a0cb3d689532 +# knative.dev/pkg v0.0.0-20200713031612-b09a159e12c9 ## explicit knative.dev/pkg/apiextensions/storageversion knative.dev/pkg/apiextensions/storageversion/cmd/migrate knative.dev/pkg/apis knative.dev/pkg/apis/duck +knative.dev/pkg/apis/duck/ducktypes knative.dev/pkg/apis/duck/v1 knative.dev/pkg/apis/duck/v1alpha1 knative.dev/pkg/apis/duck/v1beta1 @@ -1154,7 +1155,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-20200710160019-5b9732bc24f7 +# knative.dev/test-infra v0.0.0-20200713045417-850e4e37918d ## explicit knative.dev/test-infra/scripts # sigs.k8s.io/yaml v1.2.0