From 9da07987c05e319964b30dc18df6258bb4f44ffd Mon Sep 17 00:00:00 2001 From: Nicolas Lopez Date: Fri, 19 Jun 2020 09:02:15 -0400 Subject: [PATCH 1/9] WIP: types for v1 duck and messaging --- pkg/apis/duck/v1/channelable_types.go | 152 +++++++++++++++++ pkg/apis/duck/v1/delivery_types.go | 95 +++++++++++ pkg/apis/duck/v1/doc.go | 24 +++ pkg/apis/duck/v1/subscribable_types.go | 157 ++++++++++++++++++ pkg/apis/messaging/v1/channel_types.go | 97 +++++++++++ pkg/apis/messaging/v1/doc.go | 24 +++ .../messaging/v1/in_memory_channel_types.go | 91 ++++++++++ pkg/apis/messaging/v1/subscription_types.go | 156 +++++++++++++++++ 8 files changed, 796 insertions(+) create mode 100644 pkg/apis/duck/v1/channelable_types.go create mode 100644 pkg/apis/duck/v1/delivery_types.go create mode 100644 pkg/apis/duck/v1/doc.go create mode 100644 pkg/apis/duck/v1/subscribable_types.go create mode 100644 pkg/apis/messaging/v1/channel_types.go create mode 100644 pkg/apis/messaging/v1/doc.go create mode 100644 pkg/apis/messaging/v1/in_memory_channel_types.go create mode 100644 pkg/apis/messaging/v1/subscription_types.go diff --git a/pkg/apis/duck/v1/channelable_types.go b/pkg/apis/duck/v1/channelable_types.go new file mode 100644 index 00000000000..2e177fe9ac2 --- /dev/null +++ b/pkg/apis/duck/v1/channelable_types.go @@ -0,0 +1,152 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// +genduck +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Channelable is a skeleton type wrapping Subscribable and Addressable in the manner we expect resource writers +// defining compatible resources to embed it. We will typically use this type to deserialize +// Channelable ObjectReferences and access their subscription and address data. This is not a real resource. +type Channelable struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec is the part where the Channelable fulfills the Subscribable contract. + Spec ChannelableSpec `json:"spec,omitempty"` + + Status ChannelableStatus `json:"status,omitempty"` +} + +// ChannelableSpec contains Spec of the Channelable object +type ChannelableSpec struct { + SubscribableSpec `json:",inline"` + + // DeliverySpec contains options controlling the event delivery + // +optional + Delivery *DeliverySpec `json:"delivery,omitempty"` +} + +// ChannelableStatus contains the Status of a Channelable object. +type ChannelableStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + // AddressStatus is the part where the Channelable fulfills the Addressable contract. + duckv1.AddressStatus `json:",inline"` + // Subscribers is populated with the statuses of each of the Channelable's subscribers. + SubscribableStatus `json:",inline"` + // DeadLetterChannel is a KReference and is set by the channel when it supports native error handling via a channel + // Failed messages are delivered here. + // +optional + DeadLetterChannel *duckv1.KReference `json:"deadLetterChannel,omitempty"` +} + +var ( + // Verify Channelable resources meet duck contracts. + _ duck.Populatable = (*Channelable)(nil) + _ duck.Implementable = (*Channelable)(nil) + _ apis.Listable = (*Channelable)(nil) +) + +// Populate implements duck.Populatable +func (c *Channelable) Populate() { + c.Spec.SubscribableSpec = SubscribableSpec{ + // Populate ALL fields + Subscribers: []SubscriberSpec{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 1, + SubscriberURI: apis.HTTP("call1"), + ReplyURI: apis.HTTP("sink2"), + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 2, + SubscriberURI: apis.HTTP("call2"), + ReplyURI: apis.HTTP("sink2"), + }}, + } + retry := int32(5) + linear := BackoffPolicyLinear + delay := "5s" + c.Spec.Delivery = &DeliverySpec{ + DeadLetterSink: &duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: "aname", + }, + URI: &apis.URL{ + Scheme: "http", + Host: "test-error-domain", + }, + }, + Retry: &retry, + BackoffPolicy: &linear, + BackoffDelay: &delay, + } + c.Status = ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "test-domain", + }, + }, + }, + SubscribableStatus: SubscribableStatus{ + Subscribers: []SubscriberStatus{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 1, + Ready: corev1.ConditionTrue, + Message: "Some message", + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 2, + Ready: corev1.ConditionFalse, + Message: "Some message", + }}, + }, + } +} + +// GetFullType implements duck.Implementable +func (s *Channelable) GetFullType() duck.Populatable { + return &Channelable{} +} + +// GetListType implements apis.Listable +func (c *Channelable) GetListType() runtime.Object { + return &ChannelableList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ChannelableList is a list of Channelable resources. +type ChannelableList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Channelable `json:"items"` +} diff --git a/pkg/apis/duck/v1/delivery_types.go b/pkg/apis/duck/v1/delivery_types.go new file mode 100644 index 00000000000..70c2b280b4a --- /dev/null +++ b/pkg/apis/duck/v1/delivery_types.go @@ -0,0 +1,95 @@ +/* +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 ( + "context" + "time" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// DeliverySpec contains the delivery options for event senders, +// such as channelable and source. +type DeliverySpec struct { + // DeadLetterSink is the sink receiving event that could not be sent to + // a destination. + // +optional + DeadLetterSink *duckv1.Destination `json:"deadLetterSink,omitempty"` + + // Retry is the minimum number of retries the sender should attempt when + // sending an event before moving it to the dead letter sink. + // +optional + Retry *int32 `json:"retry,omitempty"` + + // BackoffPolicy is the retry backoff policy (linear, exponential). + // +optional + BackoffPolicy *BackoffPolicyType `json:"backoffPolicy,omitempty"` + + // BackoffDelay is the delay before retrying. + // More information on Duration format: https://www.ietf.org/rfc/rfc3339.txt + // + // For linear policy, backoff delay is the time interval between retries. + // For exponential policy , backoff delay is backoffDelay*2^. + // +optional + BackoffDelay *string `json:"backoffDelay,omitempty"` +} + +func (ds *DeliverySpec) Validate(ctx context.Context) *apis.FieldError { + if ds == nil { + return nil + } + var errs *apis.FieldError + if dlse := ds.DeadLetterSink.Validate(ctx); dlse != nil { + errs = errs.Also(dlse).ViaField("deadLetterSink") + } + if ds.BackoffPolicy != nil { + switch *ds.BackoffPolicy { + case BackoffPolicyExponential, BackoffPolicyLinear: + // nothing + default: + errs = errs.Also(apis.ErrInvalidValue(*ds.BackoffPolicy, "backoffPolicy")) + } + } + if ds.BackoffDelay != nil { + _, te := time.Parse(time.RFC3339, *ds.BackoffDelay) + if te != nil { + errs = errs.Also(apis.ErrInvalidValue(*ds.BackoffDelay, "backoffDelay")) + } + } + return errs +} + +// BackoffPolicyType is the type for backoff policies +type BackoffPolicyType string + +const ( + // Linear backoff policy + BackoffPolicyLinear BackoffPolicyType = "linear" + + // Exponential backoff policy + BackoffPolicyExponential BackoffPolicyType = "exponential" +) + +// DeliveryStatus contains the Status of an object supporting delivery options. +type DeliveryStatus struct { + // DeadLetterChannel is a KReference that is the reference to the native, platform specific channel + // where failed events are sent to. + // +optional + DeadLetterChannel *duckv1.KReference `json:"deadLetterChannel,omitempty"` +} diff --git a/pkg/apis/duck/v1/doc.go b/pkg/apis/duck/v1/doc.go new file mode 100644 index 00000000000..ff5ac0c20b1 --- /dev/null +++ b/pkg/apis/duck/v1/doc.go @@ -0,0 +1,24 @@ +/* +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. +*/ + +// Api versions allow the api contract for a resource to be changed while keeping +// backward compatibility by support multiple concurrent versions +// of the same resource + +// Package v1 is the v1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=duck.knative.dev +package v1 diff --git a/pkg/apis/duck/v1/subscribable_types.go b/pkg/apis/duck/v1/subscribable_types.go new file mode 100644 index 00000000000..b744334e19c --- /dev/null +++ b/pkg/apis/duck/v1/subscribable_types.go @@ -0,0 +1,157 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "knative.dev/pkg/apis" + "knative.dev/pkg/apis/duck" +) + +// +genduck + +var _ duck.Implementable = (*Subscribable)(nil) + +// SubscriberSpec defines a single subscriber to a Subscribable. +// +// At least one of SubscriberURI and ReplyURI must be present +type SubscriberSpec struct { + // UID is used to understand the origin of the subscriber. + // +optional + UID types.UID `json:"uid,omitempty"` + // Generation of the origin of the subscriber with uid:UID. + // +optional + Generation int64 `json:"generation,omitempty"` + // SubscriberURI is the endpoint for the subscriber + // +optional + SubscriberURI *apis.URL `json:"subscriberUri,omitempty"` + // ReplyURI is the endpoint for the reply + // +optional + ReplyURI *apis.URL `json:"replyUri,omitempty"` + // +optional + // DeliverySpec contains options controlling the event delivery + // +optional + Delivery *DeliverySpec `json:"delivery,omitempty"` +} + +// SubscriberStatus defines the status of a single subscriber to a Channel. +type SubscriberStatus struct { + // UID is used to understand the origin of the subscriber. + // +optional + UID types.UID `json:"uid,omitempty"` + // Generation of the origin of the subscriber with uid:UID. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + // Status of the subscriber. + Ready corev1.ConditionStatus `json:"ready,omitempty"` + // A human readable message indicating details of Ready status. + // +optional + Message string `json:"message,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Subscribable is a skeleton type wrapping Subscribable in the manner we expect resource writers +// defining compatible resources to embed it. We will typically use this type to deserialize +// SubscribableType ObjectReferences and access the Subscription data. This is not a real resource. +type Subscribable struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // SubscribableSpec is the part where Subscribable object is + // configured as to be compatible with Subscribable contract. + Spec SubscribableSpec `json:"spec"` + + // SubscribableStatus is the part where SubscribableStatus object is + // configured as to be compatible with Subscribable contract. + Status SubscribableStatus `json:"status"` +} + +// SubscribableSpec shows how we expect folks to embed Subscribable in their Spec field. +type SubscribableSpec struct { + // This is the list of subscriptions for this subscribable. + // +patchMergeKey=uid + // +patchStrategy=merge + Subscribers []SubscriberSpec `json:"subscribers,omitempty" patchStrategy:"merge" patchMergeKey:"uid"` +} + +// SubscribableStatus is the schema for the subscribable's status portion of the status +// section of the resource. +type SubscribableStatus struct { + // This is the list of subscription's statuses for this channel. + // +patchMergeKey=uid + // +patchStrategy=merge + Subscribers []SubscriberStatus `json:"subscribers,omitempty" patchStrategy:"merge" patchMergeKey:"uid"` +} + +var ( + // Verify SubscribableType resources meet duck contracts. + _ duck.Populatable = (*Subscribable)(nil) + _ apis.Listable = (*Subscribable)(nil) + + _ apis.Convertible = (*Subscribable)(nil) +) + +// GetFullType implements duck.Implementable +func (s *Subscribable) GetFullType() duck.Populatable { + return &Subscribable{} +} + +// Populate implements duck.Populatable +func (c *Subscribable) Populate() { + c.Spec.Subscribers = []SubscriberSpec{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 1, + SubscriberURI: apis.HTTP("call1"), + ReplyURI: apis.HTTP("sink2"), + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 2, + SubscriberURI: apis.HTTP("call2"), + ReplyURI: apis.HTTP("sink2"), + }} + c.Status.Subscribers = // Populate ALL fields + []SubscriberStatus{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 1, + Ready: corev1.ConditionTrue, + Message: "Some message", + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 2, + Ready: corev1.ConditionFalse, + Message: "Some message", + }} +} + +// GetListType implements apis.Listable +func (c *Subscribable) GetListType() runtime.Object { + return &SubscribableList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SubscribableTypeList is a list of SubscribableType resources +type SubscribableList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Subscribable `json:"items"` +} diff --git a/pkg/apis/messaging/v1/channel_types.go b/pkg/apis/messaging/v1/channel_types.go new file mode 100644 index 00000000000..a49288081be --- /dev/null +++ b/pkg/apis/messaging/v1/channel_types.go @@ -0,0 +1,97 @@ +/* + * 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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + eventingduck "knative.dev/eventing/pkg/apis/duck/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Channel represents a generic Channel. It is normally used when we want a Channel, but don't need a specific Channel implementation. +type Channel struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Channel. + Spec ChannelSpec `json:"spec,omitempty"` + + // Status represents the current state of the Channel. This data may be out of + // date. + // +optional + Status ChannelStatus `json:"status,omitempty"` +} + +var ( + // Check that Channel can be validated and defaulted. + _ apis.Validatable = (*Channel)(nil) + _ apis.Defaultable = (*Channel)(nil) + + // Check that Channel can return its spec untyped. + _ apis.HasSpec = (*Channel)(nil) + + _ runtime.Object = (*Channel)(nil) + + // Check that we can create OwnerReferences to a Channel. + _ kmeta.OwnerRefable = (*Channel)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Channel)(nil) +) + +// ChannelSpec defines which subscribers have expressed interest in receiving events from this Channel. +// It also defines the ChannelTemplate to use in order to create the CRD Channel backing this Channel. +type ChannelSpec struct { + // ChannelTemplate specifies which Channel CRD to use to create the CRD Channel backing this Channel. + // This is immutable after creation. Normally this is set by the Channel defaulter, not directly by the user. + ChannelTemplate *ChannelTemplateSpec `json:"channelTemplate"` + + // Channel conforms to ChannelableSpec + eventingduck.ChannelableSpec `json:",inline"` +} + +// ChannelStatus represents the current state of a Channel. +type ChannelStatus struct { + // Channel conforms to ChannelableStatus + eventingduck.ChannelableStatus `json:",inline"` + + // Channel is an KReference to the Channel CRD backing this Channel. + Channel *duckv1.KReference `json:"channel,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ChannelList is a collection of Channels. +type ChannelList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Channel `json:"items"` +} + +// GetStatus retrieves the status of the Channel. Implements the KRShaped interface. +func (t *Channel) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/messaging/v1/doc.go b/pkg/apis/messaging/v1/doc.go new file mode 100644 index 00000000000..056ab44b742 --- /dev/null +++ b/pkg/apis/messaging/v1/doc.go @@ -0,0 +1,24 @@ +/* +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. +*/ + +// Api versions allow the api contract for a resource to be changed while keeping +// backward compatibility by support multiple concurrent versions +// of the same resource + +// Package v1 is the v1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=messaging.knative.dev +package v1 diff --git a/pkg/apis/messaging/v1/in_memory_channel_types.go b/pkg/apis/messaging/v1/in_memory_channel_types.go new file mode 100644 index 00000000000..ec45460e059 --- /dev/null +++ b/pkg/apis/messaging/v1/in_memory_channel_types.go @@ -0,0 +1,91 @@ +/* + * 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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + eventingduck "knative.dev/eventing/pkg/apis/duck/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InMemoryChannel is a resource representing an in memory channel +type InMemoryChannel struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Channel. + Spec InMemoryChannelSpec `json:"spec,omitempty"` + + // Status represents the current state of the Channel. This data may be out of + // date. + // +optional + Status InMemoryChannelStatus `json:"status,omitempty"` +} + +var ( + // Check that InMemoryChannel can be validated and defaulted. + _ apis.Validatable = (*InMemoryChannel)(nil) + _ apis.Defaultable = (*InMemoryChannel)(nil) + + // Check that InMemoryChannel can return its spec untyped. + _ apis.HasSpec = (*InMemoryChannel)(nil) + + _ runtime.Object = (*InMemoryChannel)(nil) + + // Check that we can create OwnerReferences to an InMemoryChannel. + _ kmeta.OwnerRefable = (*InMemoryChannel)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*InMemoryChannel)(nil) +) + +// InMemoryChannelSpec defines which subscribers have expressed interest in +// receiving events from this InMemoryChannel. +// arguments for a Channel. +type InMemoryChannelSpec struct { + // Channel conforms to Duck type Channelable. + eventingduck.ChannelableSpec `json:",inline"` +} + +// ChannelStatus represents the current state of a Channel. +type InMemoryChannelStatus struct { + // Channel conforms to Duck type Channelable. + eventingduck.ChannelableStatus `json:",inline"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InMemoryChannelList is a collection of in-memory channels. +type InMemoryChannelList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []InMemoryChannel `json:"items"` +} + +// GetStatus retrieves the status of the InMemoryChannel. Implements the KRShaped interface. +func (t *InMemoryChannel) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/messaging/v1/subscription_types.go b/pkg/apis/messaging/v1/subscription_types.go new file mode 100644 index 00000000000..621e48fc669 --- /dev/null +++ b/pkg/apis/messaging/v1/subscription_types.go @@ -0,0 +1,156 @@ +/* + * 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 ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" + + eventingduck "knative.dev/eventing/pkg/apis/duck/v1" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:defaulter-gen=true + +// Subscription routes events received on a Channel to a DNS name and +// corresponds to the subscriptions.channels.knative.dev CRD. +type Subscription struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + Spec SubscriptionSpec `json:"spec"` + Status SubscriptionStatus `json:"status,omitempty"` +} + +var ( + // Check that Subscription can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Subscription)(nil) + _ apis.Defaultable = (*Subscription)(nil) + + // Check that Subscription can return its spec untyped. + _ apis.HasSpec = (*Subscription)(nil) + + _ runtime.Object = (*Subscription)(nil) + + // Check that we can create OwnerReferences to a Subscription. + _ kmeta.OwnerRefable = (*Subscription)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Subscription)(nil) +) + +// SubscriptionSpec specifies the Channel for incoming events, a Subscriber target +// for processing those events and where to put the result of the processing. Only +// From (where the events are coming from) is always required. You can optionally +// only Process the events (results in no output events) by leaving out the Result. +// You can also perform an identity transformation on the incoming events by leaving +// out the Subscriber and only specifying Result. +// +// The following are all valid specifications: +// channel --[subscriber]--> reply +// Sink, no outgoing events: +// channel -- subscriber +// no-op function (identity transformation): +// channel --> reply +type SubscriptionSpec struct { + // Reference to a channel that will be used to create the subscription + // You can specify only the following fields of the ObjectReference: + // - Kind + // - APIVersion + // - Name + // The resource pointed by this ObjectReference must meet the + // contract to the ChannelableSpec duck type. If the resource does not + // meet this contract it will be reflected in the Subscription's status. + // + // This field is immutable. We have no good answer on what happens to + // the events that are currently in the channel being consumed from + // and what the semantics there should be. For now, you can always + // delete the Subscription and recreate it to point to a different + // channel, giving the user more control over what semantics should + // be used (drain the channel first, possibly have events dropped, + // etc.) + Channel corev1.ObjectReference `json:"channel"` + + // Subscriber is reference to (optional) function for processing events. + // Events from the Channel will be delivered here and replies are + // sent to a Destination as specified by the Reply. + // +optional + Subscriber *duckv1.Destination `json:"subscriber,omitempty"` + + // Reply specifies (optionally) how to handle events returned from + // the Subscriber target. + // +optional + Reply *duckv1.Destination `json:"reply,omitempty"` + + // Delivery configuration + // +optional + Delivery *eventingduck.DeliverySpec `json:"delivery,omitempty"` +} + +// SubscriptionStatus (computed) for a subscription +type SubscriptionStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // PhysicalSubscription is the fully resolved values that this Subscription represents. + PhysicalSubscription SubscriptionStatusPhysicalSubscription `json:"physicalSubscription,omitempty"` +} + +// SubscriptionStatusPhysicalSubscription represents the fully resolved values for this +// Subscription. +type SubscriptionStatusPhysicalSubscription struct { + // SubscriberURI is the fully resolved URI for spec.subscriber. + SubscriberURI *apis.URL `json:"subscriberUri,omitempty"` + + // ReplyURI is the fully resolved URI for the spec.reply. + ReplyURI *apis.URL `json:"replyUri,omitempty"` + + // ReplyURI is the fully resolved URI for the spec.delivery.deadLetterSink. + DeadLetterSinkURI *apis.URL `json:"deadLetterSinkUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SubscriptionList returned in list operations +type SubscriptionList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + Items []Subscription `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for Subscriptions +func (*Subscription) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Subscription") +} + +// GetUntypedSpec returns the spec of the Subscription. +func (s *Subscription) GetUntypedSpec() interface{} { + return s.Spec +} + +// GetStatus retrieves the status of the Subscription. Implements the KRShaped interface. +func (s *Subscription) GetStatus() *duckv1.Status { + return &s.Status.Status +} From f473eee06be9581a9229b7c7c1568ac490aa0b51 Mon Sep 17 00:00:00 2001 From: Nicolas Lopez Date: Fri, 19 Jun 2020 10:23:51 -0400 Subject: [PATCH 2/9] start adding some meat --- hack/update-codegen.sh | 4 +- pkg/apis/duck/v1/channelable_types_test.go | 107 ++++++ pkg/apis/duck/v1/delivery_conversion.go | 44 +++ pkg/apis/duck/v1/delivery_conversion_test.go | 46 +++ pkg/apis/duck/v1/delivery_types_test.go | 64 ++++ .../duck/v1/subscribable_types_conversion.go | 34 ++ .../v1/subscribable_types_conversion_test.go | 34 ++ pkg/apis/duck/v1/subscribable_types_test.go | 86 +++++ pkg/apis/duck/v1/zz_generated.deepcopy.go | 343 ++++++++++++++++++ .../v1alpha1/subscribable_types_conversion.go | 8 +- pkg/apis/duck/v1beta1/delivery_conversion.go | 60 ++- .../v1beta1/subscribable_types_conversion.go | 98 ++++- .../k8s.io/code-generator/generate-groups.sh | 0 .../knative.dev/pkg/hack/generate-knative.sh | 0 14 files changed, 909 insertions(+), 19 deletions(-) create mode 100644 pkg/apis/duck/v1/channelable_types_test.go create mode 100644 pkg/apis/duck/v1/delivery_conversion.go create mode 100644 pkg/apis/duck/v1/delivery_conversion_test.go create mode 100644 pkg/apis/duck/v1/delivery_types_test.go create mode 100644 pkg/apis/duck/v1/subscribable_types_conversion.go create mode 100644 pkg/apis/duck/v1/subscribable_types_conversion_test.go create mode 100644 pkg/apis/duck/v1/subscribable_types_test.go create mode 100644 pkg/apis/duck/v1/zz_generated.deepcopy.go mode change 100644 => 100755 vendor/k8s.io/code-generator/generate-groups.sh mode change 100644 => 100755 vendor/knative.dev/pkg/hack/generate-knative.sh diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 996656cc7f6..50d7b7c174d 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -58,14 +58,14 @@ ${GOPATH}/bin/deepcopy-gen \ # Only deepcopy the Duck types, as they are not real resources. ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "duck:v1alpha1 duck:v1beta1" \ + "duck:v1alpha1 duck:v1beta1 duck:v1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Knative Injection chmod +x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 configs:v1alpha1" \ + "eventing:v1beta1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/duck/v1/channelable_types_test.go b/pkg/apis/duck/v1/channelable_types_test.go new file mode 100644 index 00000000000..6577074976e --- /dev/null +++ b/pkg/apis/duck/v1/channelable_types_test.go @@ -0,0 +1,107 @@ +/* +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" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + + "github.com/google/go-cmp/cmp" +) + +func TestChannelableGetListType(t *testing.T) { + c := &Channelable{} + switch c.GetListType().(type) { + case *ChannelableList: + // expected + default: + t.Errorf("expected GetListType to return *ChannelableList, got %T", c.GetListType()) + } +} + +func TestChannelablePopulate(t *testing.T) { + got := &Channelable{} + + retry := int32(5) + linear := BackoffPolicyLinear + delay := "5s" + want := &Channelable{ + Spec: ChannelableSpec{ + SubscribableSpec: SubscribableSpec{ + Subscribers: []SubscriberSpec{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 1, + SubscriberURI: apis.HTTP("call1"), + ReplyURI: apis.HTTP("sink2"), + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 2, + SubscriberURI: apis.HTTP("call2"), + ReplyURI: apis.HTTP("sink2"), + }}, + }, + Delivery: &DeliverySpec{ + DeadLetterSink: &duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: "aname", + }, + URI: &apis.URL{ + Scheme: "http", + Host: "test-error-domain", + }, + }, + Retry: &retry, + BackoffPolicy: &linear, + BackoffDelay: &delay, + }, + }, + + Status: ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "test-domain", + }, + }, + }, + SubscribableStatus: SubscribableStatus{ + Subscribers: []SubscriberStatus{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 1, + Ready: corev1.ConditionTrue, + Message: "Some message", + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 2, + Ready: corev1.ConditionFalse, + Message: "Some message", + }}, + }, + }, + } + + got.Populate() + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Unexpected difference (-want, +got): %v", diff) + } + +} diff --git a/pkg/apis/duck/v1/delivery_conversion.go b/pkg/apis/duck/v1/delivery_conversion.go new file mode 100644 index 00000000000..bae7a804ec2 --- /dev/null +++ b/pkg/apis/duck/v1/delivery_conversion.go @@ -0,0 +1,44 @@ +/* +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 ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *DeliverySpec) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *DeliverySpec) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} + +// ConvertTo implements apis.Convertible +func (source *DeliveryStatus) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *DeliveryStatus) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/duck/v1/delivery_conversion_test.go b/pkg/apis/duck/v1/delivery_conversion_test.go new file mode 100644 index 00000000000..bc348da09cc --- /dev/null +++ b/pkg/apis/duck/v1/delivery_conversion_test.go @@ -0,0 +1,46 @@ +/* +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 ( + "context" + "testing" +) + +func TestDeliverySpecConversionBadType(t *testing.T) { + good, bad := &DeliverySpec{}, &DeliverySpec{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} + +func TestDeliveryStatusConversionBadType(t *testing.T) { + good, bad := &DeliveryStatus{}, &DeliveryStatus{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/duck/v1/delivery_types_test.go b/pkg/apis/duck/v1/delivery_types_test.go new file mode 100644 index 00000000000..678eb08f338 --- /dev/null +++ b/pkg/apis/duck/v1/delivery_types_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2020 The Knative Authors. All Rights Reserved. +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 ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestDeliverySpecValidation(t *testing.T) { + invalidString := "invalid time" + bop := BackoffPolicyExponential + tests := []struct { + name string + spec *DeliverySpec + want *apis.FieldError + }{{ + name: "nil is valid", + spec: nil, + want: nil, + }, { + name: "invalid time format", + spec: &DeliverySpec{BackoffDelay: &invalidString}, + want: func() *apis.FieldError { + return apis.ErrInvalidValue(invalidString, "backoffDelay") + }(), + }, { + name: "invalid deadLetterSink", + spec: &DeliverySpec{DeadLetterSink: &duckv1.Destination{}}, + want: func() *apis.FieldError { + return apis.ErrGeneric("expected at least one, got none", "ref", "uri").ViaField("deadLetterSink") + }(), + }, { + name: "valid backoffPolicy", + spec: &DeliverySpec{BackoffPolicy: &bop}, + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.spec.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("DeliverySpec.Validate (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/duck/v1/subscribable_types_conversion.go b/pkg/apis/duck/v1/subscribable_types_conversion.go new file mode 100644 index 00000000000..b61470ddac9 --- /dev/null +++ b/pkg/apis/duck/v1/subscribable_types_conversion.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Subscribable) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Subscribable) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/duck/v1/subscribable_types_conversion_test.go b/pkg/apis/duck/v1/subscribable_types_conversion_test.go new file mode 100644 index 00000000000..d516391417a --- /dev/null +++ b/pkg/apis/duck/v1/subscribable_types_conversion_test.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "testing" +) + +func TestInMemoryChannelConversionBadType(t *testing.T) { + good, bad := &Subscribable{}, &Subscribable{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/duck/v1/subscribable_types_test.go b/pkg/apis/duck/v1/subscribable_types_test.go new file mode 100644 index 00000000000..b9e3d5ee53c --- /dev/null +++ b/pkg/apis/duck/v1/subscribable_types_test.go @@ -0,0 +1,86 @@ +/* +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" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +func TestSubscribableGetFullType(t *testing.T) { + s := &Subscribable{} + switch s.GetFullType().(type) { + case *Subscribable: + // expected + default: + t.Errorf("expected GetFullType to return *Subscribable, got %T", s.GetFullType()) + } +} + +func TestSubscribableGetListType(t *testing.T) { + c := &Subscribable{} + switch c.GetListType().(type) { + case *SubscribableList: + // expected + default: + t.Errorf("expected GetListType to return *SubscribableList, got %T", c.GetListType()) + } +} + +func TestSubscribablePopulate(t *testing.T) { + got := &Subscribable{} + + want := &Subscribable{ + Spec: SubscribableSpec{ + Subscribers: []SubscriberSpec{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 1, + SubscriberURI: apis.HTTP("call1"), + ReplyURI: apis.HTTP("sink2"), + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + Generation: 2, + SubscriberURI: apis.HTTP("call2"), + ReplyURI: apis.HTTP("sink2"), + }}, + }, + Status: SubscribableStatus{ + // Populate ALL fields + Subscribers: []SubscriberStatus{{ + UID: "2f9b5e8e-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 1, + Ready: corev1.ConditionTrue, + Message: "Some message", + }, { + UID: "34c5aec8-deb6-11e8-9f32-f2801f1b9fd1", + ObservedGeneration: 2, + Ready: corev1.ConditionFalse, + Message: "Some message", + }}, + }, + } + + got.Populate() + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Unexpected difference (-want, +got): %v", diff) + } + +} diff --git a/pkg/apis/duck/v1/zz_generated.deepcopy.go b/pkg/apis/duck/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..253cf94fc7d --- /dev/null +++ b/pkg/apis/duck/v1/zz_generated.deepcopy.go @@ -0,0 +1,343 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + apis "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Channelable) DeepCopyInto(out *Channelable) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Channelable. +func (in *Channelable) DeepCopy() *Channelable { + if in == nil { + return nil + } + out := new(Channelable) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Channelable) 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 *ChannelableList) DeepCopyInto(out *ChannelableList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Channelable, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelableList. +func (in *ChannelableList) DeepCopy() *ChannelableList { + if in == nil { + return nil + } + out := new(ChannelableList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ChannelableList) 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 *ChannelableSpec) DeepCopyInto(out *ChannelableSpec) { + *out = *in + in.SubscribableSpec.DeepCopyInto(&out.SubscribableSpec) + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelableSpec. +func (in *ChannelableSpec) DeepCopy() *ChannelableSpec { + if in == nil { + return nil + } + out := new(ChannelableSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelableStatus) DeepCopyInto(out *ChannelableStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.AddressStatus.DeepCopyInto(&out.AddressStatus) + in.SubscribableStatus.DeepCopyInto(&out.SubscribableStatus) + if in.DeadLetterChannel != nil { + in, out := &in.DeadLetterChannel, &out.DeadLetterChannel + *out = new(duckv1.KReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelableStatus. +func (in *ChannelableStatus) DeepCopy() *ChannelableStatus { + if in == nil { + return nil + } + out := new(ChannelableStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeliverySpec) DeepCopyInto(out *DeliverySpec) { + *out = *in + if in.DeadLetterSink != nil { + in, out := &in.DeadLetterSink, &out.DeadLetterSink + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + if in.Retry != nil { + in, out := &in.Retry, &out.Retry + *out = new(int32) + **out = **in + } + if in.BackoffPolicy != nil { + in, out := &in.BackoffPolicy, &out.BackoffPolicy + *out = new(BackoffPolicyType) + **out = **in + } + if in.BackoffDelay != nil { + in, out := &in.BackoffDelay, &out.BackoffDelay + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeliverySpec. +func (in *DeliverySpec) DeepCopy() *DeliverySpec { + if in == nil { + return nil + } + out := new(DeliverySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DeliveryStatus) DeepCopyInto(out *DeliveryStatus) { + *out = *in + if in.DeadLetterChannel != nil { + in, out := &in.DeadLetterChannel, &out.DeadLetterChannel + *out = new(duckv1.KReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeliveryStatus. +func (in *DeliveryStatus) DeepCopy() *DeliveryStatus { + if in == nil { + return nil + } + out := new(DeliveryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Subscribable) DeepCopyInto(out *Subscribable) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subscribable. +func (in *Subscribable) DeepCopy() *Subscribable { + if in == nil { + return nil + } + out := new(Subscribable) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Subscribable) 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 *SubscribableList) DeepCopyInto(out *SubscribableList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Subscribable, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscribableList. +func (in *SubscribableList) DeepCopy() *SubscribableList { + if in == nil { + return nil + } + out := new(SubscribableList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubscribableList) 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 *SubscribableSpec) DeepCopyInto(out *SubscribableSpec) { + *out = *in + if in.Subscribers != nil { + in, out := &in.Subscribers, &out.Subscribers + *out = make([]SubscriberSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscribableSpec. +func (in *SubscribableSpec) DeepCopy() *SubscribableSpec { + if in == nil { + return nil + } + out := new(SubscribableSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscribableStatus) DeepCopyInto(out *SubscribableStatus) { + *out = *in + if in.Subscribers != nil { + in, out := &in.Subscribers, &out.Subscribers + *out = make([]SubscriberStatus, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscribableStatus. +func (in *SubscribableStatus) DeepCopy() *SubscribableStatus { + if in == nil { + return nil + } + out := new(SubscribableStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriberSpec) DeepCopyInto(out *SubscriberSpec) { + *out = *in + if in.SubscriberURI != nil { + in, out := &in.SubscriberURI, &out.SubscriberURI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + if in.ReplyURI != nil { + in, out := &in.ReplyURI, &out.ReplyURI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriberSpec. +func (in *SubscriberSpec) DeepCopy() *SubscriberSpec { + if in == nil { + return nil + } + out := new(SubscriberSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriberStatus) DeepCopyInto(out *SubscriberStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriberStatus. +func (in *SubscriberStatus) DeepCopy() *SubscriberStatus { + if in == nil { + return nil + } + out := new(SubscriberStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/duck/v1alpha1/subscribable_types_conversion.go b/pkg/apis/duck/v1alpha1/subscribable_types_conversion.go index cfaf63cb474..9d5f6ace044 100644 --- a/pkg/apis/duck/v1alpha1/subscribable_types_conversion.go +++ b/pkg/apis/duck/v1alpha1/subscribable_types_conversion.go @@ -24,7 +24,6 @@ import ( duckv1 "knative.dev/pkg/apis/duck/v1" duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" - eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" ) // ConvertTo implements apis.Convertible @@ -87,7 +86,7 @@ func (source *SubscribableTypeStatus) ConvertTo(ctx context.Context, sink *duckv } // ConvertFrom implements apis.Convertible. -// Converts obj v1beta1.Subscribable into v1alpha1.Subscribable +// Converts obj v1beta1.Subscribable into v1alpha1.SubscribableType func (sink *SubscribableType) ConvertFrom(ctx context.Context, obj apis.Convertible) error { switch source := obj.(type) { case *duckv1beta1.Subscribable: @@ -112,6 +111,7 @@ func (sink *SubscribableTypeSpec) ConvertFrom(ctx context.Context, source duckv1 } } +// ConvertFrom helps implement apis.Convertible func (sink *SubscriberSpec) ConvertFrom(ctx context.Context, source duckv1beta1.SubscriberSpec) { var deadLetterSinkURI *apis.URL if source.Delivery != nil && source.Delivery.DeadLetterSink != nil { @@ -130,10 +130,10 @@ func (sink *SubscriberSpec) ConvertFrom(ctx context.Context, source duckv1beta1. func (sink *SubscribableTypeStatus) ConvertFrom(ctx context.Context, source duckv1beta1.SubscribableStatus) error { if len(source.Subscribers) > 0 { sink.SubscribableStatus = &SubscribableStatus{ - Subscribers: make([]eventingduckv1beta1.SubscriberStatus, len(source.Subscribers)), + Subscribers: make([]duckv1beta1.SubscriberStatus, len(source.Subscribers)), } for i, ss := range source.Subscribers { - sink.SubscribableStatus.Subscribers[i] = eventingduckv1beta1.SubscriberStatus{ + sink.SubscribableStatus.Subscribers[i] = duckv1beta1.SubscriberStatus{ UID: ss.UID, ObservedGeneration: ss.ObservedGeneration, Ready: ss.Ready, diff --git a/pkg/apis/duck/v1beta1/delivery_conversion.go b/pkg/apis/duck/v1beta1/delivery_conversion.go index 07a729884cc..8601032c943 100644 --- a/pkg/apis/duck/v1beta1/delivery_conversion.go +++ b/pkg/apis/duck/v1beta1/delivery_conversion.go @@ -21,24 +21,68 @@ import ( "fmt" "knative.dev/pkg/apis" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" ) // ConvertTo implements apis.Convertible -func (source *DeliverySpec) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *DeliverySpec) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *eventingduckv1.DeliverySpec: + sink.Retry = source.Retry + sink.BackoffDelay = source.BackoffDelay + if *source.BackoffPolicy == BackoffPolicyLinear { + linear := eventingduckv1.BackoffPolicyLinear + sink.BackoffPolicy = &linear + } else if *source.BackoffPolicy == BackoffPolicyExponential { + exponential := eventingduckv1.BackoffPolicyExponential + sink.BackoffPolicy = &exponential + } + sink.DeadLetterSink = source.DeadLetterSink + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *DeliverySpec) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *DeliverySpec) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *eventingduckv1.DeliverySpec: + sink.Retry = source.Retry + sink.BackoffDelay = source.BackoffDelay + if *source.BackoffPolicy == eventingduckv1.BackoffPolicyLinear { + linear := BackoffPolicyLinear + sink.BackoffPolicy = &linear + } else if *source.BackoffPolicy == eventingduckv1.BackoffPolicyExponential { + exponential := BackoffPolicyExponential + sink.BackoffPolicy = &exponential + } + sink.DeadLetterSink = source.DeadLetterSink + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } // ConvertTo implements apis.Convertible -func (source *DeliveryStatus) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *DeliveryStatus) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *eventingduckv1.DeliveryStatus: + sink.DeadLetterChannel = source.DeadLetterChannel + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *DeliveryStatus) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *DeliveryStatus) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *eventingduckv1.DeliveryStatus: + sink.DeadLetterChannel = source.DeadLetterChannel + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } diff --git a/pkg/apis/duck/v1beta1/subscribable_types_conversion.go b/pkg/apis/duck/v1beta1/subscribable_types_conversion.go index f25a6755ceb..14e768da372 100644 --- a/pkg/apis/duck/v1beta1/subscribable_types_conversion.go +++ b/pkg/apis/duck/v1beta1/subscribable_types_conversion.go @@ -21,14 +21,102 @@ import ( "fmt" "knative.dev/pkg/apis" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" ) // ConvertTo implements apis.Convertible -func (source *Subscribable) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *Subscribable) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *eventingduckv1.Subscribable: + sink.ObjectMeta = source.ObjectMeta + source.Status.ConvertTo(ctx, &sink.Status) + return source.Spec.ConvertTo(ctx, &sink.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} + +// ConvertTo helps implement apis.Convertible +func (source *SubscribableSpec) ConvertTo(ctx context.Context, sink *eventingduckv1.SubscribableSpec) error { + sink.Subscribers = make([]eventingduckv1.SubscriberSpec, len(source.Subscribers)) + for i, s := range source.Subscribers { + s.ConvertTo(ctx, &sink.Subscribers[i]) + } + return nil +} + +// ConvertTo helps implement apis.Convertible +func (source *SubscriberSpec) ConvertTo(ctx context.Context, sink *eventingduckv1.SubscriberSpec) { + sink.UID = source.UID + sink.Generation = source.Generation + sink.SubscriberURI = source.SubscriberURI + sink.ReplyURI = source.ReplyURI + sink.Delivery.ConvertTo(ctx, source.Delivery) + +} + +// ConvertTo helps implement apis.Convertible +func (source *SubscribableStatus) ConvertTo(ctx context.Context, sink *eventingduckv1.SubscribableStatus) { + if len(source.Subscribers) > 0 { + sink.Subscribers = make([]eventingduckv1.SubscriberStatus, len(source.Subscribers)) + for i, ss := range source.Subscribers { + sink.Subscribers[i] = eventingduckv1.SubscriberStatus{ + UID: ss.UID, + ObservedGeneration: ss.ObservedGeneration, + Ready: ss.Ready, + Message: ss.Message, + } + } + } +} + +// ConvertFrom implements apis.Convertible. +func (sink *Subscribable) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *eventingduckv1.Subscribable: + sink.ObjectMeta = source.ObjectMeta + sink.Status.ConvertFrom(ctx, source.Status) + sink.Spec.ConvertFrom(ctx, source.Spec) + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } +} + +// ConvertFrom helps implement apis.Convertible +func (sink *SubscribableSpec) ConvertFrom(ctx context.Context, source eventingduckv1.SubscribableSpec) { + if len(source.Subscribers) > 0 { + sink.Subscribers = make([]SubscriberSpec, len(source.Subscribers)) + for i, s := range source.Subscribers { + sink.Subscribers[i].ConvertFrom(ctx, s) + } + } +} + +// ConvertFrom helps implement apis.Convertible +func (sink *SubscriberSpec) ConvertFrom(ctx context.Context, source eventingduckv1.SubscriberSpec) { + sink.UID = source.UID + sink.Generation = source.Generation + sink.SubscriberURI = source.SubscriberURI + sink.ReplyURI = source.ReplyURI + sink.Delivery.ConvertFrom(ctx, source.Delivery) } -// ConvertFrom implements apis.Convertible -func (sink *Subscribable) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +// ConvertFrom helps implement apis.Convertible +func (sink *SubscribableStatus) ConvertFrom(ctx context.Context, source eventingduckv1.SubscribableStatus) error { + if len(source.Subscribers) > 0 { + sink = &SubscribableStatus{ + Subscribers: make([]SubscriberStatus, len(source.Subscribers)), + } + for i, ss := range source.Subscribers { + sink.Subscribers[i] = SubscriberStatus{ + UID: ss.UID, + ObservedGeneration: ss.ObservedGeneration, + Ready: ss.Ready, + Message: ss.Message, + } + } + } + return nil } diff --git a/vendor/k8s.io/code-generator/generate-groups.sh b/vendor/k8s.io/code-generator/generate-groups.sh old mode 100644 new mode 100755 diff --git a/vendor/knative.dev/pkg/hack/generate-knative.sh b/vendor/knative.dev/pkg/hack/generate-knative.sh old mode 100644 new mode 100755 From 77875dd39ecf9b2ac963cdd33beff4ac7eafecae Mon Sep 17 00:00:00 2001 From: Nicolas Lopez Date: Fri, 19 Jun 2020 20:29:46 -0400 Subject: [PATCH 3/9] add tests --- .../subscribable_types_conversion_test.go | 3 +- .../subscribable_types_conversion_test.go | 100 +++++++++++++++++- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/pkg/apis/duck/v1alpha1/subscribable_types_conversion_test.go b/pkg/apis/duck/v1alpha1/subscribable_types_conversion_test.go index f9542c7b105..80239f2541e 100644 --- a/pkg/apis/duck/v1alpha1/subscribable_types_conversion_test.go +++ b/pkg/apis/duck/v1alpha1/subscribable_types_conversion_test.go @@ -28,7 +28,6 @@ import ( pkgduckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/eventing/pkg/apis/duck/v1beta1" - eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" ) func TestSubscribableTypeConversionBadType(t *testing.T) { @@ -101,7 +100,7 @@ func TestSubscribableTypeConversion(t *testing.T) { }, Status: SubscribableTypeStatus{ SubscribableStatus: &SubscribableStatus{ - Subscribers: []eventingduckv1beta1.SubscriberStatus{ + Subscribers: []v1beta1.SubscriberStatus{ { UID: "status-uid-1", ObservedGeneration: 99, diff --git a/pkg/apis/duck/v1beta1/subscribable_types_conversion_test.go b/pkg/apis/duck/v1beta1/subscribable_types_conversion_test.go index 15b15f359d9..f24882b9346 100644 --- a/pkg/apis/duck/v1beta1/subscribable_types_conversion_test.go +++ b/pkg/apis/duck/v1beta1/subscribable_types_conversion_test.go @@ -19,10 +19,19 @@ package v1beta1 import ( "context" "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + "knative.dev/pkg/apis" + pkgduckv1 "knative.dev/pkg/apis/duck/v1" + + eventingv1 "knative.dev/eventing/pkg/apis/duck/v1" ) -func TestInMemoryChannelConversionBadType(t *testing.T) { - good, bad := &Subscribable{}, &Subscribable{} +func TestSubscribableTypeConversionBadType(t *testing.T) { + good, bad := &Subscribable{}, &pkgduckv1.Addressable{} if err := good.ConvertTo(context.Background(), bad); err == nil { t.Errorf("ConvertTo() = %#v, wanted error", bad) @@ -32,3 +41,90 @@ func TestInMemoryChannelConversionBadType(t *testing.T) { t.Errorf("ConvertFrom() = %#v, wanted error", good) } } + +// Test v1beta1 -> v1 -> v1beta1 +func TestSubscribableTypeConversion(t *testing.T) { + versions := []apis.Convertible{&eventingv1.Subscribable{}} + + linear := BackoffPolicyLinear + + tests := []struct { + name string + in *Subscribable + }{{ + name: "min configuration", + in: &Subscribable{ + ObjectMeta: metav1.ObjectMeta{ + Name: "subscribable-name", + Namespace: "subscribable-ns", + Generation: 17, + }, + Spec: SubscribableSpec{}, + Status: SubscribableStatus{}, + }, + }, { + name: "full configuration", + in: &Subscribable{ + ObjectMeta: metav1.ObjectMeta{ + Name: "subscribable-name", + Namespace: "subscribable-ns", + Generation: 17, + }, + Spec: SubscribableSpec{ + Subscribers: []SubscriberSpec{ + { + UID: "uid-1", + Generation: 7, + SubscriberURI: apis.HTTP("subscriber.example.com"), + ReplyURI: apis.HTTP("reply.example.com"), + Delivery: &DeliverySpec{ + DeadLetterSink: &pkgduckv1.Destination{ + Ref: &pkgduckv1.KReference{ + Kind: "dlKind", + Namespace: "dlNamespace", + Name: "dlName", + APIVersion: "dlAPIVersion", + }, + URI: apis.HTTP("subscriber.dls.example.com"), + }, + Retry: pointer.Int32Ptr(5), + BackoffPolicy: &linear, + BackoffDelay: pointer.StringPtr("5s"), + }, + }, + }, + }, + Status: SubscribableStatus{ + Subscribers: []SubscriberStatus{ + { + UID: "status-uid-1", + ObservedGeneration: 99, + Ready: corev1.ConditionTrue, + Message: "msg", + }, + }, + }, + }, + }} + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertTo(context.Background(), ver); err != nil { + t.Errorf("ConvertTo() = %v", err) + } + got := &Subscribable{} + if err := got.ConvertFrom(context.Background(), ver); err != nil { + t.Errorf("ConvertFrom() = %v", err) + } + if diff := cmp.Diff(test.in, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} + +// Test v1 -> v1beta1 -> v1 +func TestSubscribableTypeConversionWithV1(t *testing.T) { +} From cf6dbcd82d39ee2c7a2046a36b47022a6ef5512d Mon Sep 17 00:00:00 2001 From: Matt Moore Date: Fri, 19 Jun 2020 08:38:25 -0700 Subject: [PATCH 4/9] Add the default Bucket count that was introduced in knative/pkg. (#3352) --- go.mod | 6 +- go.sum | 6 + .../configmappropagation/reconciler.go | 2 +- .../eventing/v1beta1/broker/reconciler.go | 2 +- .../eventing/v1beta1/eventtype/reconciler.go | 2 +- .../eventing/v1beta1/trigger/reconciler.go | 2 +- .../flows/v1beta1/parallel/reconciler.go | 2 +- .../flows/v1beta1/sequence/reconciler.go | 2 +- .../messaging/v1beta1/channel/reconciler.go | 2 +- .../v1beta1/inmemorychannel/reconciler.go | 2 +- .../v1beta1/subscription/reconciler.go | 2 +- .../v1alpha2/apiserversource/reconciler.go | 2 +- .../v1alpha2/containersource/reconciler.go | 2 +- .../sources/v1alpha2/pingsource/reconciler.go | 2 +- pkg/leaderelection/leader_election_test.go | 3 + pkg/reconciler/testing/factory.go | 7 + pkg/reconciler/testing/v1beta1/factory.go | 7 + vendor/go.opencensus.io/Makefile | 27 ++- .../go.opencensus.io/plugin/ocgrpc/client.go | 2 +- .../go.opencensus.io/plugin/ocgrpc/server.go | 3 +- .../plugin/ocgrpc/trace_common.go | 8 +- .../plugin/ochttp/propagation/b3/b3.go | 4 +- vendor/go.opencensus.io/stats/record.go | 20 ++ vendor/go.opencensus.io/stats/view/export.go | 17 +- .../stats/view/view_to_metric.go | 5 +- vendor/go.opencensus.io/stats/view/worker.go | 188 ++++++++++++--- .../stats/view/worker_commands.go | 6 +- vendor/go.opencensus.io/trace/lrumap.go | 2 +- vendor/go.opencensus.io/trace/trace.go | 12 +- .../generators/reconciler_reconciler.go | 2 +- vendor/knative.dev/pkg/configmap/parse.go | 14 ++ .../knative.dev/pkg/controller/controller.go | 32 ++- vendor/knative.dev/pkg/injection/README.md | 2 +- .../pkg/injection/sharedmain/main.go | 12 + .../knative.dev/pkg/leaderelection/config.go | 13 + .../knative.dev/pkg/leaderelection/context.go | 223 ++++++++++++++++++ .../pkg/metrics/metricstest/metricstest.go | 117 +++++---- vendor/knative.dev/pkg/reconciler/leader.go | 118 +++++++++ .../pkg/reconciler/reconcile_common.go | 28 ++- .../knative.dev/pkg/test/presubmit-tests.sh | 12 + vendor/modules.txt | 6 +- 41 files changed, 783 insertions(+), 143 deletions(-) create mode 100644 vendor/knative.dev/pkg/leaderelection/context.go create mode 100644 vendor/knative.dev/pkg/reconciler/leader.go diff --git a/go.mod b/go.mod index ed7552bb4db..8e7d3c1465d 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/stretchr/testify v1.5.1 github.com/tsenart/vegeta v12.7.1-0.20190725001342-b5f4fca92137+incompatible github.com/wavesoftware/go-ensure v1.0.0 - go.opencensus.io v0.22.3 + go.opencensus.io v0.22.4 go.opentelemetry.io/otel v0.2.3 go.uber.org/atomic v1.6.0 go.uber.org/zap v1.14.1 @@ -37,8 +37,8 @@ require ( k8s.io/apiserver v0.17.6 k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible k8s.io/utils v0.0.0-20200124190032-861946025e34 - knative.dev/pkg v0.0.0-20200618002824-96c250871fac - knative.dev/test-infra v0.0.0-20200617235125-6382dba95484 + knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743 + knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index aa90000c44e..cec054a8ea0 100644 --- a/go.sum +++ b/go.sum @@ -925,6 +925,8 @@ go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/otel v0.2.3 h1:o97YpRYk0PyhCyuanlJY0DepUgAlyzl3rJ+4kb+456c= go.opentelemetry.io/otel v0.2.3/go.mod h1:OgNpQOjrlt33Ew6Ds0mGjmcTQg/rhUctsbkRdk/g1fw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1402,6 +1404,8 @@ knative.dev/pkg v0.0.0-20200603222317-b79e4a24ca50/go.mod h1:8IfPj/lpuKHHg82xZCl knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2/go.mod h1:rA+FklsrVahwF4a+D63NyHJlzDoAFH81K4J5CYuE3bA= knative.dev/pkg v0.0.0-20200618002824-96c250871fac h1:X8XHaSFsUIW2IJCIEQEzNfPbs/gGib3CUK/+lkZuoEo= knative.dev/pkg v0.0.0-20200618002824-96c250871fac/go.mod h1:4ty6MSlNjZk5qBaGb3Gt4gopjMD4gRknfTABblcFpQ8= +knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743 h1:W1NKMizoXYYX5e2mkFXnn21T7X6ROKKwL8YetGu7xCQ= +knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ= knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU= knative.dev/test-infra v0.0.0-20200513011557-d03429a76034/go.mod h1:aMif0KXL4g19YCYwsy4Ocjjz5xgPlseYV+B95Oo4JGE= @@ -1413,6 +1417,8 @@ knative.dev/test-infra v0.0.0-20200615231324-3a016f44102c h1:pzn7d3gVWX6p10CpdSF knative.dev/test-infra v0.0.0-20200615231324-3a016f44102c/go.mod h1:+BfrTJpc++rH30gX/C0QY6NT2eYVzycll52uw6CrQnc= knative.dev/test-infra v0.0.0-20200617235125-6382dba95484 h1:5D1Fm6aA1T1QQXLb1HkJ5t8gB9pTkhLYak1CCqIP+pE= knative.dev/test-infra v0.0.0-20200617235125-6382dba95484/go.mod h1:+BfrTJpc++rH30gX/C0QY6NT2eYVzycll52uw6CrQnc= +knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884 h1:qGxu/U/8VxhAuyFedrrne4s0vfY+YfoRwJJCY0AKpbw= +knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884/go.mod h1:qeiTuhDKO/HHheqVfepbxy5/q+O9toSJW6CO/DgjxFY= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go b/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go index b3977c47406..d5d1a5ee258 100644 --- a/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go +++ b/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go b/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go index 06bebafb30a..fd6162b837b 100644 --- a/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go @@ -181,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go b/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go index 72525e48b27..5f5c66ca30f 100644 --- a/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go b/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go index 14a3a0edb6e..40817b92cad 100644 --- a/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go b/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go index d58064c39a6..866e1ae02b8 100644 --- a/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go +++ b/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go b/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go index af6ba039bf4..b38b39f3de8 100644 --- a/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go +++ b/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go index 2355d6f1520..ed189706212 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go index e72274ed63a..8f7e7950ba6 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go index bf51425c830..f33e35311af 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go index fed4ec42754..51a50204bac 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go index 8ebbaba7001..ea36257bf13 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go index b4185e67e43..845abd970e1 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go @@ -170,7 +170,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/pkg/leaderelection/leader_election_test.go b/pkg/leaderelection/leader_election_test.go index 82ac1b2707d..6382be9c357 100644 --- a/pkg/leaderelection/leader_election_test.go +++ b/pkg/leaderelection/leader_election_test.go @@ -33,6 +33,7 @@ import ( func okConfig() *kle.Config { return &kle.Config{ ResourceLock: "leases", + Buckets: 1, LeaseDuration: 15 * time.Second, RenewDeadline: 10 * time.Second, RetryPeriod: 2 * time.Second, @@ -101,6 +102,7 @@ func TestServingConfig(t *testing.T) { name: "Default config", want: &kle.Config{ ResourceLock: "leases", + Buckets: 1, LeaseDuration: 15 * time.Second, RenewDeadline: 10 * time.Second, RetryPeriod: 2 * time.Second, @@ -110,6 +112,7 @@ func TestServingConfig(t *testing.T) { name: "Example config", want: &kle.Config{ ResourceLock: "leases", + Buckets: 1, LeaseDuration: 15 * time.Second, RenewDeadline: 10 * time.Second, RetryPeriod: 2 * time.Second, diff --git a/pkg/reconciler/testing/factory.go b/pkg/reconciler/testing/factory.go index 488eab0336c..86489de24d8 100644 --- a/pkg/reconciler/testing/factory.go +++ b/pkg/reconciler/testing/factory.go @@ -28,12 +28,14 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" "go.uber.org/zap" ktesting "k8s.io/client-go/testing" "knative.dev/pkg/controller" + "knative.dev/pkg/reconciler" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" fakedynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake" @@ -94,6 +96,11 @@ func MakeFactory(ctor Ctor, unstructured bool, logger *zap.SugaredLogger) Factor // Set up our Controller from the fakes. c := ctor(ctx, &ls, cmw) + // If the reconcilers is leader aware, then promote it. + if la, ok := c.(reconciler.LeaderAware); ok { + la.Promote(reconciler.UniversalBucket(), func(reconciler.Bucket, types.NamespacedName) {}) + } + for _, reactor := range r.WithReactors { kubeClient.PrependReactor("*", "*", reactor) client.PrependReactor("*", "*", reactor) diff --git a/pkg/reconciler/testing/v1beta1/factory.go b/pkg/reconciler/testing/v1beta1/factory.go index 36b78348960..4a03c6e4f3d 100644 --- a/pkg/reconciler/testing/v1beta1/factory.go +++ b/pkg/reconciler/testing/v1beta1/factory.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" @@ -38,6 +39,7 @@ import ( fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" fakedynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake" + "knative.dev/pkg/reconciler" . "knative.dev/pkg/reconciler/testing" ) @@ -82,6 +84,11 @@ func MakeFactory(ctor Ctor, unstructured bool, logger *zap.SugaredLogger) Factor // Set up our Controller from the fakes. c := ctor(ctx, &ls, configmap.NewStaticWatcher()) + // If the reconcilers is leader aware, then promote it. + if la, ok := c.(reconciler.LeaderAware); ok { + la.Promote(reconciler.UniversalBucket(), func(reconciler.Bucket, types.NamespacedName) {}) + } + for _, reactor := range r.WithReactors { kubeClient.PrependReactor("*", "*", reactor) client.PrependReactor("*", "*", reactor) diff --git a/vendor/go.opencensus.io/Makefile b/vendor/go.opencensus.io/Makefile index 457866cb1f2..b3ce3df3032 100644 --- a/vendor/go.opencensus.io/Makefile +++ b/vendor/go.opencensus.io/Makefile @@ -8,7 +8,7 @@ ALL_PKGS := $(shell go list $(sort $(dir $(ALL_SRC)))) GOTEST_OPT?=-v -race -timeout 30s GOTEST_OPT_WITH_COVERAGE = $(GOTEST_OPT) -coverprofile=coverage.txt -covermode=atomic GOTEST=go test -GOFMT=gofmt +GOIMPORTS=goimports GOLINT=golint GOVET=go vet EMBEDMD=embedmd @@ -17,14 +17,14 @@ TRACE_ID_LINT_EXCEPTION="type name will be used as trace.TraceID by other packag TRACE_OPTION_LINT_EXCEPTION="type name will be used as trace.TraceOptions by other packages" README_FILES := $(shell find . -name '*README.md' | sort | tr '\n' ' ') -.DEFAULT_GOAL := fmt-lint-vet-embedmd-test +.DEFAULT_GOAL := imports-lint-vet-embedmd-test -.PHONY: fmt-lint-vet-embedmd-test -fmt-lint-vet-embedmd-test: fmt lint vet embedmd test +.PHONY: imports-lint-vet-embedmd-test +imports-lint-vet-embedmd-test: imports lint vet embedmd test # TODO enable test-with-coverage in tavis .PHONY: travis-ci -travis-ci: fmt lint vet embedmd test test-386 +travis-ci: imports lint vet embedmd test test-386 all-pkgs: @echo $(ALL_PKGS) | tr ' ' '\n' | sort @@ -44,15 +44,15 @@ test-386: test-with-coverage: $(GOTEST) $(GOTEST_OPT_WITH_COVERAGE) $(ALL_PKGS) -.PHONY: fmt -fmt: - @FMTOUT=`$(GOFMT) -s -l $(ALL_SRC) 2>&1`; \ - if [ "$$FMTOUT" ]; then \ - echo "$(GOFMT) FAILED => gofmt the following files:\n"; \ - echo "$$FMTOUT\n"; \ +.PHONY: imports +imports: + @IMPORTSOUT=`$(GOIMPORTS) -l $(ALL_SRC) 2>&1`; \ + if [ "$$IMPORTSOUT" ]; then \ + echo "$(GOIMPORTS) FAILED => goimports the following files:\n"; \ + echo "$$IMPORTSOUT\n"; \ exit 1; \ else \ - echo "Fmt finished successfully"; \ + echo "Imports finished successfully"; \ fi .PHONY: lint @@ -91,6 +91,7 @@ embedmd: .PHONY: install-tools install-tools: - go get -u golang.org/x/tools/cmd/cover go get -u golang.org/x/lint/golint + go get -u golang.org/x/tools/cmd/cover + go get -u golang.org/x/tools/cmd/goimports go get -u github.com/rakyll/embedmd diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/client.go b/vendor/go.opencensus.io/plugin/ocgrpc/client.go index 28fddb84407..2063b6f76a1 100644 --- a/vendor/go.opencensus.io/plugin/ocgrpc/client.go +++ b/vendor/go.opencensus.io/plugin/ocgrpc/client.go @@ -16,8 +16,8 @@ package ocgrpc import ( "context" - "go.opencensus.io/trace" + "go.opencensus.io/trace" "google.golang.org/grpc/stats" ) diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/server.go b/vendor/go.opencensus.io/plugin/ocgrpc/server.go index 15ada839d6f..8a53e097274 100644 --- a/vendor/go.opencensus.io/plugin/ocgrpc/server.go +++ b/vendor/go.opencensus.io/plugin/ocgrpc/server.go @@ -16,9 +16,10 @@ package ocgrpc import ( "context" - "go.opencensus.io/trace" "google.golang.org/grpc/stats" + + "go.opencensus.io/trace" ) // ServerHandler implements gRPC stats.Handler recording OpenCensus stats and diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go b/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go index fef58275662..61bc543d0a2 100644 --- a/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go +++ b/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go @@ -15,16 +15,16 @@ package ocgrpc import ( + "context" "strings" "google.golang.org/grpc/codes" - - "context" - "go.opencensus.io/trace" - "go.opencensus.io/trace/propagation" "google.golang.org/grpc/metadata" "google.golang.org/grpc/stats" "google.golang.org/grpc/status" + + "go.opencensus.io/trace" + "go.opencensus.io/trace/propagation" ) const traceContextKey = "grpc-trace-bin" diff --git a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go index 2f1c7f0063e..9ad8852198d 100644 --- a/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go +++ b/vendor/go.opencensus.io/plugin/ochttp/propagation/b3/b3.go @@ -68,7 +68,7 @@ func ParseTraceID(tid string) (trace.TraceID, bool) { return trace.TraceID{}, false } b, err := hex.DecodeString(tid) - if err != nil { + if err != nil || len(b) > 16 { return trace.TraceID{}, false } var traceID trace.TraceID @@ -90,7 +90,7 @@ func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) { return trace.SpanID{}, false } b, err := hex.DecodeString(sid) - if err != nil { + if err != nil || len(b) > 8 { return trace.SpanID{}, false } start := 8 - len(b) diff --git a/vendor/go.opencensus.io/stats/record.go b/vendor/go.opencensus.io/stats/record.go index ad4691184df..2b97283462e 100644 --- a/vendor/go.opencensus.io/stats/record.go +++ b/vendor/go.opencensus.io/stats/record.go @@ -31,10 +31,19 @@ func init() { } } +// Recorder provides an interface for exporting measurement information from +// the static Record method by using the WithRecorder option. +type Recorder interface { + // Record records a set of measurements associated with the given tags and attachments. + // The second argument is a `[]Measurement`. + Record(*tag.Map, interface{}, map[string]interface{}) +} + type recordOptions struct { attachments metricdata.Attachments mutators []tag.Mutator measurements []Measurement + recorder Recorder } // WithAttachments applies provided exemplar attachments. @@ -58,6 +67,14 @@ func WithMeasurements(measurements ...Measurement) Options { } } +// WithRecorder records the measurements to the specified `Recorder`, rather +// than to the global metrics recorder. +func WithRecorder(meter Recorder) Options { + return func(ro *recordOptions) { + ro.recorder = meter + } +} + // Options apply changes to recordOptions. type Options func(*recordOptions) @@ -93,6 +110,9 @@ func RecordWithOptions(ctx context.Context, ros ...Options) error { return nil } recorder := internal.DefaultRecorder + if o.recorder != nil { + recorder = o.recorder.Record + } if recorder == nil { return nil } diff --git a/vendor/go.opencensus.io/stats/view/export.go b/vendor/go.opencensus.io/stats/view/export.go index 7cb59718f5f..73ba11f5b6e 100644 --- a/vendor/go.opencensus.io/stats/view/export.go +++ b/vendor/go.opencensus.io/stats/view/export.go @@ -14,13 +14,6 @@ package view -import "sync" - -var ( - exportersMu sync.RWMutex // guards exporters - exporters = make(map[Exporter]struct{}) -) - // Exporter exports the collected records as view data. // // The ExportView method should return quickly; if an @@ -43,16 +36,10 @@ type Exporter interface { // // Binaries can register exporters, libraries shouldn't register exporters. func RegisterExporter(e Exporter) { - exportersMu.Lock() - defer exportersMu.Unlock() - - exporters[e] = struct{}{} + defaultWorker.RegisterExporter(e) } // UnregisterExporter unregisters an exporter. func UnregisterExporter(e Exporter) { - exportersMu.Lock() - defer exportersMu.Unlock() - - delete(exporters, e) + defaultWorker.UnregisterExporter(e) } diff --git a/vendor/go.opencensus.io/stats/view/view_to_metric.go b/vendor/go.opencensus.io/stats/view/view_to_metric.go index 293c1646df2..5e1656a1f2b 100644 --- a/vendor/go.opencensus.io/stats/view/view_to_metric.go +++ b/vendor/go.opencensus.io/stats/view/view_to_metric.go @@ -18,6 +18,8 @@ package view import ( "time" + "go.opencensus.io/resource" + "go.opencensus.io/metric/metricdata" "go.opencensus.io/stats" ) @@ -125,7 +127,7 @@ func rowToTimeseries(v *viewInternal, row *Row, now time.Time, startTime time.Ti } } -func viewToMetric(v *viewInternal, now time.Time, startTime time.Time) *metricdata.Metric { +func viewToMetric(v *viewInternal, r *resource.Resource, now time.Time, startTime time.Time) *metricdata.Metric { if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 || v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 { startTime = time.Time{} @@ -144,6 +146,7 @@ func viewToMetric(v *viewInternal, now time.Time, startTime time.Time) *metricda m := &metricdata.Metric{ Descriptor: *v.metricDescriptor, TimeSeries: ts, + Resource: r, } return m } diff --git a/vendor/go.opencensus.io/stats/view/worker.go b/vendor/go.opencensus.io/stats/view/worker.go index 2f3c018af0e..ab8bfd46d0b 100644 --- a/vendor/go.opencensus.io/stats/view/worker.go +++ b/vendor/go.opencensus.io/stats/view/worker.go @@ -20,6 +20,8 @@ import ( "sync" "time" + "go.opencensus.io/resource" + "go.opencensus.io/metric/metricdata" "go.opencensus.io/metric/metricproducer" "go.opencensus.io/stats" @@ -28,7 +30,7 @@ import ( ) func init() { - defaultWorker = newWorker() + defaultWorker = NewMeter().(*worker) go defaultWorker.start() internal.DefaultRecorder = record } @@ -47,8 +49,69 @@ type worker struct { c chan command quit, done chan bool mu sync.RWMutex + r *resource.Resource + + exportersMu sync.RWMutex + exporters map[Exporter]struct{} +} + +// Meter defines an interface which allows a single process to maintain +// multiple sets of metrics exports (intended for the advanced case where a +// single process wants to report metrics about multiple objects, such as +// multiple databases or HTTP services). +// +// Note that this is an advanced use case, and the static functions in this +// module should cover the common use cases. +type Meter interface { + stats.Recorder + // Find returns a registered view associated with this name. + // If no registered view is found, nil is returned. + Find(name string) *View + // Register begins collecting data for the given views. + // Once a view is registered, it reports data to the registered exporters. + Register(views ...*View) error + // Unregister the given views. Data will not longer be exported for these views + // after Unregister returns. + // It is not necessary to unregister from views you expect to collect for the + // duration of your program execution. + Unregister(views ...*View) + // SetReportingPeriod sets the interval between reporting aggregated views in + // the program. If duration is less than or equal to zero, it enables the + // default behavior. + // + // Note: each exporter makes different promises about what the lowest supported + // duration is. For example, the Stackdriver exporter recommends a value no + // lower than 1 minute. Consult each exporter per your needs. + SetReportingPeriod(time.Duration) + + // RegisterExporter registers an exporter. + // Collected data will be reported via all the + // registered exporters. Once you no longer + // want data to be exported, invoke UnregisterExporter + // with the previously registered exporter. + // + // Binaries can register exporters, libraries shouldn't register exporters. + RegisterExporter(Exporter) + // UnregisterExporter unregisters an exporter. + UnregisterExporter(Exporter) + // SetResource may be used to set the Resource associated with this registry. + // This is intended to be used in cases where a single process exports metrics + // for multiple Resources, typically in a multi-tenant situation. + SetResource(*resource.Resource) + + // Start causes the Meter to start processing Record calls and aggregating + // statistics as well as exporting data. + Start() + // Stop causes the Meter to stop processing calls and terminate data export. + Stop() + + // RetrieveData gets a snapshot of the data collected for the the view registered + // with the given name. It is intended for testing only. + RetrieveData(viewName string) ([]*Row, error) } +var _ Meter = (*worker)(nil) + var defaultWorker *worker var defaultReportingDuration = 10 * time.Second @@ -56,11 +119,17 @@ var defaultReportingDuration = 10 * time.Second // Find returns a registered view associated with this name. // If no registered view is found, nil is returned. func Find(name string) (v *View) { + return defaultWorker.Find(name) +} + +// Find returns a registered view associated with this name. +// If no registered view is found, nil is returned. +func (w *worker) Find(name string) (v *View) { req := &getViewByNameReq{ name: name, c: make(chan *getViewByNameResp), } - defaultWorker.c <- req + w.c <- req resp := <-req.c return resp.v } @@ -68,11 +137,17 @@ func Find(name string) (v *View) { // Register begins collecting data for the given views. // Once a view is registered, it reports data to the registered exporters. func Register(views ...*View) error { + return defaultWorker.Register(views...) +} + +// Register begins collecting data for the given views. +// Once a view is registered, it reports data to the registered exporters. +func (w *worker) Register(views ...*View) error { req := ®isterViewReq{ views: views, err: make(chan error), } - defaultWorker.c <- req + w.c <- req return <-req.err } @@ -81,6 +156,14 @@ func Register(views ...*View) error { // It is not necessary to unregister from views you expect to collect for the // duration of your program execution. func Unregister(views ...*View) { + defaultWorker.Unregister(views...) +} + +// Unregister the given views. Data will not longer be exported for these views +// after Unregister returns. +// It is not necessary to unregister from views you expect to collect for the +// duration of your program execution. +func (w *worker) Unregister(views ...*View) { names := make([]string, len(views)) for i := range views { names[i] = views[i].Name @@ -89,31 +172,42 @@ func Unregister(views ...*View) { views: names, done: make(chan struct{}), } - defaultWorker.c <- req + w.c <- req <-req.done } // RetrieveData gets a snapshot of the data collected for the the view registered // with the given name. It is intended for testing only. func RetrieveData(viewName string) ([]*Row, error) { + return defaultWorker.RetrieveData(viewName) +} + +// RetrieveData gets a snapshot of the data collected for the the view registered +// with the given name. It is intended for testing only. +func (w *worker) RetrieveData(viewName string) ([]*Row, error) { req := &retrieveDataReq{ now: time.Now(), v: viewName, c: make(chan *retrieveDataResp), } - defaultWorker.c <- req + w.c <- req resp := <-req.c return resp.rows, resp.err } func record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) { + defaultWorker.Record(tags, ms, attachments) +} + +// Record records a set of measurements ms associated with the given tags and attachments. +func (w *worker) Record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) { req := &recordReq{ tm: tags, ms: ms.([]stats.Measurement), attachments: attachments, t: time.Now(), } - defaultWorker.c <- req + w.c <- req } // SetReportingPeriod sets the interval between reporting aggregated views in @@ -124,17 +218,31 @@ func record(tags *tag.Map, ms interface{}, attachments map[string]interface{}) { // duration is. For example, the Stackdriver exporter recommends a value no // lower than 1 minute. Consult each exporter per your needs. func SetReportingPeriod(d time.Duration) { + defaultWorker.SetReportingPeriod(d) +} + +// SetReportingPeriod sets the interval between reporting aggregated views in +// the program. If duration is less than or equal to zero, it enables the +// default behavior. +// +// Note: each exporter makes different promises about what the lowest supported +// duration is. For example, the Stackdriver exporter recommends a value no +// lower than 1 minute. Consult each exporter per your needs. +func (w *worker) SetReportingPeriod(d time.Duration) { // TODO(acetechnologist): ensure that the duration d is more than a certain // value. e.g. 1s req := &setReportingPeriodReq{ d: d, c: make(chan bool), } - defaultWorker.c <- req + w.c <- req <-req.c // don't return until the timer is set to the new duration. } -func newWorker() *worker { +// NewMeter constructs a Meter instance. You should only need to use this if +// you need to separate out Measurement recordings and View aggregations within +// a single process. +func NewMeter() Meter { return &worker{ measures: make(map[string]*measureRef), views: make(map[string]*viewInternal), @@ -143,9 +251,23 @@ func newWorker() *worker { c: make(chan command, 1024), quit: make(chan bool), done: make(chan bool), + + exporters: make(map[Exporter]struct{}), } } +// SetResource associates all data collected by this Meter with the specified +// resource. This resource is reported when using metricexport.ReadAndExport; +// it is not provided when used with ExportView/RegisterExporter, because that +// interface does not provide a means for reporting the Resource. +func (w *worker) SetResource(r *resource.Resource) { + w.r = r +} + +func (w *worker) Start() { + go w.start() +} + func (w *worker) start() { prodMgr := metricproducer.GlobalManager() prodMgr.AddProducer(w) @@ -155,7 +277,7 @@ func (w *worker) start() { case cmd := <-w.c: cmd.handleCommand(w) case <-w.timer.C: - w.reportUsage(time.Now()) + w.reportUsage() case <-w.quit: w.timer.Stop() close(w.c) @@ -165,7 +287,7 @@ func (w *worker) start() { } } -func (w *worker) stop() { +func (w *worker) Stop() { prodMgr := metricproducer.GlobalManager() prodMgr.DeleteProducer(w) @@ -202,44 +324,45 @@ func (w *worker) tryRegisterView(v *View) (*viewInternal, error) { return x, nil } w.views[vi.view.Name] = vi + w.startTimes[vi] = time.Now() ref := w.getMeasureRef(vi.view.Measure.Name()) ref.views[vi] = struct{}{} return vi, nil } -func (w *worker) unregisterView(viewName string) { +func (w *worker) unregisterView(v *viewInternal) { w.mu.Lock() defer w.mu.Unlock() - delete(w.views, viewName) + delete(w.views, v.view.Name) + delete(w.startTimes, v) + if measure := w.measures[v.view.Measure.Name()]; measure != nil { + delete(measure.views, v) + } } -func (w *worker) reportView(v *viewInternal, now time.Time) { +func (w *worker) reportView(v *viewInternal) { if !v.isSubscribed() { return } rows := v.collectedRows() - _, ok := w.startTimes[v] - if !ok { - w.startTimes[v] = now - } viewData := &Data{ View: v.view, Start: w.startTimes[v], End: time.Now(), Rows: rows, } - exportersMu.Lock() - for e := range exporters { + w.exportersMu.Lock() + defer w.exportersMu.Unlock() + for e := range w.exporters { e.ExportView(viewData) } - exportersMu.Unlock() } -func (w *worker) reportUsage(now time.Time) { +func (w *worker) reportUsage() { w.mu.Lock() defer w.mu.Unlock() for _, v := range w.views { - w.reportView(v, now) + w.reportView(v) } } @@ -248,11 +371,6 @@ func (w *worker) toMetric(v *viewInternal, now time.Time) *metricdata.Metric { return nil } - _, ok := w.startTimes[v] - if !ok { - w.startTimes[v] = now - } - var startTime time.Time if v.metricDescriptor.Type == metricdata.TypeGaugeInt64 || v.metricDescriptor.Type == metricdata.TypeGaugeFloat64 { @@ -261,7 +379,7 @@ func (w *worker) toMetric(v *viewInternal, now time.Time) *metricdata.Metric { startTime = w.startTimes[v] } - return viewToMetric(v, now, startTime) + return viewToMetric(v, w.r, now, startTime) } // Read reads all view data and returns them as metrics. @@ -279,3 +397,17 @@ func (w *worker) Read() []*metricdata.Metric { } return metrics } + +func (w *worker) RegisterExporter(e Exporter) { + w.exportersMu.Lock() + defer w.exportersMu.Unlock() + + w.exporters[e] = struct{}{} +} + +func (w *worker) UnregisterExporter(e Exporter) { + w.exportersMu.Lock() + defer w.exportersMu.Unlock() + + delete(w.exporters, e) +} diff --git a/vendor/go.opencensus.io/stats/view/worker_commands.go b/vendor/go.opencensus.io/stats/view/worker_commands.go index 0267e179aed..9ac4cc05992 100644 --- a/vendor/go.opencensus.io/stats/view/worker_commands.go +++ b/vendor/go.opencensus.io/stats/view/worker_commands.go @@ -95,7 +95,7 @@ func (cmd *unregisterFromViewReq) handleCommand(w *worker) { } // Report pending data for this view before removing it. - w.reportView(vi, time.Now()) + w.reportView(vi) vi.unsubscribe() if !vi.isSubscribed() { @@ -103,7 +103,7 @@ func (cmd *unregisterFromViewReq) handleCommand(w *worker) { // The collected data can be cleared. vi.clearRows() } - w.unregisterView(name) + w.unregisterView(vi) } cmd.done <- struct{}{} } @@ -163,7 +163,7 @@ func (cmd *recordReq) handleCommand(w *worker) { } ref := w.getMeasureRef(m.Measure().Name()) for v := range ref.views { - v.addSample(cmd.tm, m.Value(), cmd.attachments, time.Now()) + v.addSample(cmd.tm, m.Value(), cmd.attachments, cmd.t) } } } diff --git a/vendor/go.opencensus.io/trace/lrumap.go b/vendor/go.opencensus.io/trace/lrumap.go index dc7a295c773..908c2497ed5 100644 --- a/vendor/go.opencensus.io/trace/lrumap.go +++ b/vendor/go.opencensus.io/trace/lrumap.go @@ -44,7 +44,7 @@ func (lm lruMap) len() int { } func (lm lruMap) keys() []interface{} { - keys := []interface{}{} + keys := make([]interface{}, len(lm.cacheKeys)) for k := range lm.cacheKeys { keys = append(keys, k) } diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go index 3f8977b41b4..125e2cd9012 100644 --- a/vendor/go.opencensus.io/trace/trace.go +++ b/vendor/go.opencensus.io/trace/trace.go @@ -345,7 +345,7 @@ func (s *Span) SetStatus(status Status) { } func (s *Span) interfaceArrayToLinksArray() []Link { - linksArr := make([]Link, 0) + linksArr := make([]Link, 0, len(s.links.queue)) for _, value := range s.links.queue { linksArr = append(linksArr, value.(Link)) } @@ -353,7 +353,7 @@ func (s *Span) interfaceArrayToLinksArray() []Link { } func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent { - messageEventArr := make([]MessageEvent, 0) + messageEventArr := make([]MessageEvent, 0, len(s.messageEvents.queue)) for _, value := range s.messageEvents.queue { messageEventArr = append(messageEventArr, value.(MessageEvent)) } @@ -361,7 +361,7 @@ func (s *Span) interfaceArrayToMessageEventArray() []MessageEvent { } func (s *Span) interfaceArrayToAnnotationArray() []Annotation { - annotationArr := make([]Annotation, 0) + annotationArr := make([]Annotation, 0, len(s.annotations.queue)) for _, value := range s.annotations.queue { annotationArr = append(annotationArr, value.(Annotation)) } @@ -369,7 +369,7 @@ func (s *Span) interfaceArrayToAnnotationArray() []Annotation { } func (s *Span) lruAttributesToAttributeMap() map[string]interface{} { - attributes := make(map[string]interface{}) + attributes := make(map[string]interface{}, s.lruAttributes.len()) for _, key := range s.lruAttributes.keys() { value, ok := s.lruAttributes.get(key) if ok { @@ -420,7 +420,7 @@ func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...in var m map[string]interface{} s.mu.Lock() if len(attributes) != 0 { - m = make(map[string]interface{}) + m = make(map[string]interface{}, len(attributes)) copyAttributes(m, attributes) } s.annotations.add(Annotation{ @@ -436,7 +436,7 @@ func (s *Span) printStringInternal(attributes []Attribute, str string) { var a map[string]interface{} s.mu.Lock() if len(attributes) != 0 { - a = make(map[string]interface{}) + a = make(map[string]interface{}, len(attributes)) copyAttributes(a, attributes) } s.annotations.add(Annotation{ diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go index 647b82fd0ec..8b4d0c73318 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go @@ -320,7 +320,7 @@ func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) erro reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) {{if .isKRShaped}} - reconciler.PostProcessReconcile(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) {{end}} } else if fin, ok := r.reconciler.(Finalizer); ok { // Append the target method to the logger. diff --git a/vendor/knative.dev/pkg/configmap/parse.go b/vendor/knative.dev/pkg/configmap/parse.go index 210d2114ede..1ef67581810 100644 --- a/vendor/knative.dev/pkg/configmap/parse.go +++ b/vendor/knative.dev/pkg/configmap/parse.go @@ -77,6 +77,20 @@ func AsInt64(key string, target *int64) ParseFunc { } } +// AsUint32 parses the value at key as an uint32 into the target, if it exists. +func AsUint32(key string, target *uint32) ParseFunc { + return func(data map[string]string) error { + if raw, ok := data[key]; ok { + val, err := strconv.ParseUint(raw, 10, 32) + if err != nil { + return fmt.Errorf("failed to parse %q: %w", key, err) + } + *target = uint32(val) + } + return nil + } +} + // AsFloat64 parses the value at key as a float64 into the target, if it exists. func AsFloat64(key string, target *float64) ParseFunc { return func(data map[string]string) error { diff --git a/vendor/knative.dev/pkg/controller/controller.go b/vendor/knative.dev/pkg/controller/controller.go index 3981c58204e..6024ec2536e 100644 --- a/vendor/knative.dev/pkg/controller/controller.go +++ b/vendor/knative.dev/pkg/controller/controller.go @@ -36,8 +36,10 @@ import ( "k8s.io/client-go/util/workqueue" "knative.dev/pkg/kmeta" + kle "knative.dev/pkg/leaderelection" "knative.dev/pkg/logging" "knative.dev/pkg/logging/logkey" + "knative.dev/pkg/reconciler" ) const ( @@ -176,6 +178,10 @@ func FilterWithNameAndNamespace(namespace, name string) func(obj interface{}) bo // Impl is our core controller implementation. It handles queuing and feeding work // from the queue to an implementation of Reconciler. type Impl struct { + // Name is the unique name for this controller workqueue within this process. + // This is used for surfacing metrics, and per-controller leader election. + Name string + // Reconciler is the workhorse of this controller, it is fed the keys // from the workqueue to process. Public for testing. Reconciler Reconciler @@ -205,7 +211,9 @@ func NewImpl(r Reconciler, logger *zap.SugaredLogger, workQueueName string) *Imp } func NewImplWithStats(r Reconciler, logger *zap.SugaredLogger, workQueueName string, reporter StatsReporter) *Impl { + logger = logger.Named(workQueueName) return &Impl{ + Name: workQueueName, Reconciler: r, WorkQueue: workqueue.NewNamedRateLimitingQueue( workqueue.DefaultControllerRateLimiter(), @@ -341,6 +349,14 @@ func (c *Impl) EnqueueKey(key types.NamespacedName) { c.logger.Debugf("Adding to queue %s (depth: %d)", safeKey(key), c.WorkQueue.Len()) } +// MaybeEnqueueBucketKey takes a Bucket and namespace/name string and puts it onto the work queue. +func (c *Impl) MaybeEnqueueBucketKey(bkt reconciler.Bucket, key types.NamespacedName) { + if bkt.Has(key) { + c.WorkQueue.Add(key) + c.logger.Debugf("Adding to queue %s (depth: %d)", safeKey(key), c.WorkQueue.Len()) + } +} + // EnqueueKeyAfter takes a namespace/name string and schedules its execution in // the work queue after given delay. func (c *Impl) EnqueueKeyAfter(key types.NamespacedName, delay time.Duration) { @@ -349,10 +365,12 @@ func (c *Impl) EnqueueKeyAfter(key types.NamespacedName, delay time.Duration) { } // RunContext starts the controller's worker threads, the number of which is threadiness. +// If the context has been decorated for LeaderElection, then an elector is built and run. // It then blocks until the context is cancelled, at which point it shuts down its // internal work queue and waits for workers to finish processing their current // work items. func (c *Impl) RunContext(ctx context.Context, threadiness int) error { + logger := c.logger defer runtime.HandleCrash() sg := sync.WaitGroup{} defer sg.Wait() @@ -363,8 +381,20 @@ func (c *Impl) RunContext(ctx context.Context, threadiness int) error { } }() + if la, ok := c.Reconciler.(reconciler.LeaderAware); ok { + // Build and execute an elector. + le, err := kle.BuildElector(ctx, la, c.Name, c.MaybeEnqueueBucketKey) + if err != nil { + return err + } + sg.Add(1) + go func() { + defer sg.Done() + le.Run(ctx) + }() + } + // Launch workers to process resources that get enqueued to our workqueue. - logger := c.logger logger.Info("Starting controller and workers") for i := 0; i < threadiness; i++ { sg.Add(1) diff --git a/vendor/knative.dev/pkg/injection/README.md b/vendor/knative.dev/pkg/injection/README.md index d30b090bc7f..e23ff32f527 100644 --- a/vendor/knative.dev/pkg/injection/README.md +++ b/vendor/knative.dev/pkg/injection/README.md @@ -471,7 +471,7 @@ reconciler.PreProcessReconcile(ctx, resource) reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) -reconciler.PostProcessReconcile(ctx, resource) +reconciler.PostProcessReconcile(ctx, resource, oldResource) ``` #### Stubs diff --git a/vendor/knative.dev/pkg/injection/sharedmain/main.go b/vendor/knative.dev/pkg/injection/sharedmain/main.go index 1410138e1f0..5c2ba94a36c 100644 --- a/vendor/knative.dev/pkg/injection/sharedmain/main.go +++ b/vendor/knative.dev/pkg/injection/sharedmain/main.go @@ -52,6 +52,7 @@ import ( "knative.dev/pkg/logging" "knative.dev/pkg/metrics" "knative.dev/pkg/profiling" + "knative.dev/pkg/reconciler" "knative.dev/pkg/signals" "knative.dev/pkg/system" "knative.dev/pkg/version" @@ -399,6 +400,11 @@ func SecretFetcher(ctx context.Context) metrics.SecretFetcher { func ControllersAndWebhooksFromCtors(ctx context.Context, cmw *configmap.InformedWatcher, ctors ...injection.ControllerConstructor) ([]*controller.Impl, []interface{}) { + + // Check whether the context has been infused with a leader elector builder. + // If it has, then every reconciler we plan to start MUST implement LeaderAware. + leEnabled := kle.HasLeaderElection(ctx) + controllers := make([]*controller.Impl, 0, len(ctors)) webhooks := make([]interface{}, 0) for _, cf := range ctors { @@ -410,6 +416,12 @@ func ControllersAndWebhooksFromCtors(ctx context.Context, case webhook.AdmissionController, webhook.ConversionController: webhooks = append(webhooks, c) } + + if leEnabled { + if _, ok := ctrl.Reconciler.(reconciler.LeaderAware); !ok { + log.Fatalf("%T is not leader-aware, all reconcilers must be leader-aware to enable fine-grained leader election.", ctrl.Reconciler) + } + } } return controllers, webhooks diff --git a/vendor/knative.dev/pkg/leaderelection/config.go b/vendor/knative.dev/pkg/leaderelection/config.go index 06f0874e2a4..44378d30cc5 100644 --- a/vendor/knative.dev/pkg/leaderelection/config.go +++ b/vendor/knative.dev/pkg/leaderelection/config.go @@ -30,6 +30,10 @@ import ( const configMapNameEnv = "CONFIG_LEADERELECTION_NAME" +// 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("leases", "configmaps", "endpoints") // NewConfigFromMap returns a Config for the given map, or an error. @@ -43,6 +47,8 @@ func NewConfigFromMap(data map[string]string) (*Config, error) { cm.AsDuration("renewDeadline", &config.RenewDeadline), cm.AsDuration("retryPeriod", &config.RetryPeriod), + cm.AsUint32("buckets", &config.Buckets), + // enabledComponents are not validated here, because they are dependent on // the component. Components should provide additional validation for this // field. @@ -51,6 +57,9 @@ func NewConfigFromMap(data map[string]string) (*Config, error) { return nil, err } + 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","configmaps","endpoints"`, config.ResourceLock) } @@ -72,6 +81,7 @@ func NewConfigFromConfigMap(configMap *corev1.ConfigMap) (*Config, error) { // single source repository, viz: serving or eventing. type Config struct { ResourceLock string + Buckets uint32 LeaseDuration time.Duration RenewDeadline time.Duration RetryPeriod time.Duration @@ -83,6 +93,7 @@ func (c *Config) GetComponentConfig(name string) ComponentConfig { return ComponentConfig{ Component: name, LeaderElect: true, + Buckets: c.Buckets, ResourceLock: c.ResourceLock, LeaseDuration: c.LeaseDuration, RenewDeadline: c.RenewDeadline, @@ -96,6 +107,7 @@ func (c *Config) GetComponentConfig(name string) ComponentConfig { func defaultConfig() *Config { return &Config{ ResourceLock: "leases", + Buckets: 1, LeaseDuration: 15 * time.Second, RenewDeadline: 10 * time.Second, RetryPeriod: 2 * time.Second, @@ -107,6 +119,7 @@ func defaultConfig() *Config { type ComponentConfig struct { Component string LeaderElect bool + Buckets uint32 ResourceLock string LeaseDuration time.Duration RenewDeadline time.Duration diff --git a/vendor/knative.dev/pkg/leaderelection/context.go b/vendor/knative.dev/pkg/leaderelection/context.go new file mode 100644 index 00000000000..a0d8555f971 --- /dev/null +++ b/vendor/knative.dev/pkg/leaderelection/context.go @@ -0,0 +1,223 @@ +/* +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 leaderelection + +import ( + "context" + "fmt" + "hash/fnv" + "strings" + "sync" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/leaderelection" + "k8s.io/client-go/tools/leaderelection/resourcelock" + "knative.dev/pkg/logging" + "knative.dev/pkg/reconciler" + "knative.dev/pkg/system" +) + +// WithStandardLeaderElectorBuilder infuses a context with the ability to build +// LeaderElectors with the provided component configuration acquiring resource +// locks via the provided kubernetes client. +func WithStandardLeaderElectorBuilder(ctx context.Context, kc kubernetes.Interface, cc ComponentConfig) context.Context { + return context.WithValue(ctx, builderKey{}, &standardBuilder{ + kc: kc, + lec: cc, + }) +} + +// HasLeaderElection returns whether there is leader election configuration +// associated with the context +func HasLeaderElection(ctx context.Context) bool { + val := ctx.Value(builderKey{}) + return val != nil +} + +// Elector is the interface for running a leader elector. +type Elector interface { + Run(context.Context) +} + +// BuildElector builds a leaderelection.LeaderElector for the named LeaderAware +// reconciler using a builder added to the context via WithStandardLeaderElectorBuilder. +func BuildElector(ctx context.Context, la reconciler.LeaderAware, name string, enq func(reconciler.Bucket, types.NamespacedName)) (Elector, error) { + if val := ctx.Value(builderKey{}); val != nil { + switch builder := val.(type) { + case *standardBuilder: + return builder.BuildElector(ctx, la, name, enq) + } + // TODO(mattmoor): Add a flavor of builder that relies on StatefulSet to partition the key space. + } + + return &unopposedElector{ + la: la, + bkt: reconciler.UniversalBucket(), + enq: enq, + }, nil +} + +type builderKey struct{} + +type standardBuilder struct { + kc kubernetes.Interface + lec ComponentConfig +} + +func (b *standardBuilder) BuildElector(ctx context.Context, la reconciler.LeaderAware, name string, enq func(reconciler.Bucket, types.NamespacedName)) (Elector, error) { + logger := logging.FromContext(ctx) + + id, err := UniqueID() + if err != nil { + return nil, err + } + + buckets := make([]Elector, 0, b.lec.Buckets) + for i := uint32(0); i < b.lec.Buckets; i++ { + bkt := &bucket{ + component: b.lec.Component, + name: name, + index: i, + total: b.lec.Buckets, + } + + rl, err := resourcelock.New(b.lec.ResourceLock, + system.Namespace(), // use namespace we are running in + bkt.Name(), + b.kc.CoreV1(), + b.kc.CoordinationV1(), + resourcelock.ResourceLockConfig{ + Identity: id, + }) + if err != nil { + return nil, err + } + logger.Infof("%s will run in leader-elected mode with id %q", bkt.Name(), rl.Identity()) + + le, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{ + Lock: rl, + LeaseDuration: b.lec.LeaseDuration, + RenewDeadline: b.lec.RenewDeadline, + RetryPeriod: b.lec.RetryPeriod, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(context.Context) { + logger.Infof("%q has started leading %q", rl.Identity(), bkt.Name()) + if err := la.Promote(bkt, enq); err != nil { + // TODO(mattmoor): We expect this to effectively never happen, + // but if it does, we should support wrapping `le` in an elector + // we can cancel here. + logger.Fatalf("%q failed to Promote: %v", rl.Identity(), err) + } + }, + OnStoppedLeading: func() { + logger.Infof("%q has stopped leading %q", rl.Identity(), bkt.Name()) + la.Demote(bkt) + }, + }, + ReleaseOnCancel: true, + + Name: rl.Identity(), + }) + if err != nil { + return nil, err + } + // TODO: use health check watchdog, knative/pkg#1048 + // if lec.WatchDog != nil { + // lec.WatchDog.SetLeaderElection(le) + // } + buckets = append(buckets, &runUntilCancelled{Elector: le}) + } + return &runAll{les: buckets}, nil +} + +// unopposedElector promotes when run without needing to be elected. +type unopposedElector struct { + bkt reconciler.Bucket + la reconciler.LeaderAware + enq func(reconciler.Bucket, types.NamespacedName) +} + +// Run implements Elector +func (ue *unopposedElector) Run(ctx context.Context) { + ue.la.Promote(ue.bkt, ue.enq) +} + +type runAll struct { + les []Elector +} + +// Run implements Elector +func (ra *runAll) Run(ctx context.Context) { + sg := sync.WaitGroup{} + defer sg.Wait() + + for _, le := range ra.les { + sg.Add(1) + go func(le Elector) { + defer sg.Done() + le.Run(ctx) + }(le) + } +} + +// runUntilCancelled wraps a single-term Elector into one that runs until +// the passed context is cancelled. +type runUntilCancelled struct { + // Elector is a single-term elector as we get from K8s leaderelection package. + Elector +} + +// Run implements Elector +func (ruc *runUntilCancelled) Run(ctx context.Context) { + // Turn the single-term elector into a continuous election cycle. + for { + ruc.Elector.Run(ctx) + select { + case <-ctx.Done(): + return // Run quit because context was cancelled, we are done! + default: + // Context wasn't cancelled, start over. + } + } +} + +type bucket struct { + component string + name string + + // We are bucket {index} of {total} + index uint32 + total uint32 +} + +var _ reconciler.Bucket = (*bucket)(nil) + +// Name implements reconciler.Bucket +func (b *bucket) Name() string { + // The resource name is the lowercase: + // {component}.{workqueue}.{index}-of-{total} + return strings.ToLower(fmt.Sprintf("%s.%s.%02d-of-%02d", b.component, b.name, b.index, b.total)) +} + +// Has implements reconciler.Bucket +func (b *bucket) Has(nn types.NamespacedName) bool { + h := fnv.New32a() + h.Write([]byte(nn.Namespace + "." + nn.Name)) + ii := h.Sum32() % b.total + return b.index == ii +} diff --git a/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go b/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go index 7cf8df8cc19..9d74c4019ff 100644 --- a/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go +++ b/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go @@ -17,8 +17,10 @@ limitations under the License. package metricstest import ( + "fmt" "reflect" + "go.opencensus.io/metric/metricproducer" "go.opencensus.io/stats/view" "knative.dev/pkg/test" ) @@ -56,14 +58,17 @@ func CheckStatsNotReported(t test.T, names ...string) { // reported are tagged with the tags in wantTags and that wantValue matches reported count. func CheckCountData(t test.T, name string, wantTags map[string]string, wantValue int64) { t.Helper() - if row := checkExactlyOneRow(t, name); row != nil { - checkRowTags(t, row, name, wantTags) + row, err := checkExactlyOneRow(t, name) + if err != nil { + t.Error(err) + return + } + checkRowTags(t, row, name, wantTags) - if s, ok := row.Data.(*view.CountData); !ok { - t.Error("want CountData", "metric", name, "got", reflect.TypeOf(row.Data)) - } else if s.Value != wantValue { - t.Error("Wrong value", "metric", name, "value", s.Value, "want", wantValue) - } + if s, ok := row.Data.(*view.CountData); !ok { + t.Error("want CountData", "metric", name, "got", reflect.TypeOf(row.Data)) + } else if s.Value != wantValue { + t.Error("Wrong value", "metric", name, "value", s.Value, "want", wantValue) } } @@ -72,21 +77,24 @@ func CheckCountData(t test.T, name string, wantTags map[string]string, wantValue // It also checks that expectedMin and expectedMax match the minimum and maximum reported values, respectively. func CheckDistributionData(t test.T, name string, wantTags map[string]string, expectedCount int64, expectedMin float64, expectedMax float64) { t.Helper() - if row := checkExactlyOneRow(t, name); row != nil { - checkRowTags(t, row, name, wantTags) + row, err := checkExactlyOneRow(t, name) + if err != nil { + t.Error(err) + return + } + checkRowTags(t, row, name, wantTags) - if s, ok := row.Data.(*view.DistributionData); !ok { - t.Error("want DistributionData", "metric", name, "got", reflect.TypeOf(row.Data)) - } else { - if s.Count != expectedCount { - t.Error("reporter count wrong", "metric", name, "got", s.Count, "want", expectedCount) - } - if s.Min != expectedMin { - t.Error("reporter count wrong", "metric", name, "got", s.Min, "want", expectedMin) - } - if s.Max != expectedMax { - t.Error("reporter count wrong", "metric", name, "got", s.Max, "want", expectedMax) - } + if s, ok := row.Data.(*view.DistributionData); !ok { + t.Error("want DistributionData", "metric", name, "got", reflect.TypeOf(row.Data)) + } else { + if s.Count != expectedCount { + t.Error("reporter count wrong", "metric", name, "got", s.Count, "want", expectedCount) + } + if s.Min != expectedMin { + t.Error("reporter count wrong", "metric", name, "got", s.Min, "want", expectedMin) + } + if s.Max != expectedMax { + t.Error("reporter count wrong", "metric", name, "got", s.Max, "want", expectedMax) } } } @@ -95,15 +103,19 @@ func CheckDistributionData(t test.T, name string, wantTags map[string]string, ex // are tagged with the tags in wantTags and that expectedCount number of records were reported. func CheckDistributionCount(t test.T, name string, wantTags map[string]string, expectedCount int64) { t.Helper() - if row := checkExactlyOneRow(t, name); row != nil { - checkRowTags(t, row, name, wantTags) + row, err := checkExactlyOneRow(t, name) + if err != nil { + t.Error(err) + return + } + checkRowTags(t, row, name, wantTags) - if s, ok := row.Data.(*view.DistributionData); !ok { - t.Error("want DistributionData", "metric", name, "got", reflect.TypeOf(row.Data)) - } else if s.Count != expectedCount { - t.Error("reporter count wrong", "metric", name, "got", s.Count, "want", expectedCount) - } + if s, ok := row.Data.(*view.DistributionData); !ok { + t.Error("want DistributionData", "metric", name, "got", reflect.TypeOf(row.Data)) + } else if s.Count != expectedCount { + t.Error("reporter count wrong", "metric", name, "got", s.Count, "want", expectedCount) } + } // CheckLastValueData checks the view with a name matching string name to verify that the LastValueData stats @@ -125,14 +137,17 @@ func CheckLastValueData(t test.T, name string, wantTags map[string]string, wantV // reported are tagged with the tags in wantTags and that wantValue matches the reported sum. func CheckSumData(t test.T, name string, wantTags map[string]string, wantValue float64) { t.Helper() - if row := checkExactlyOneRow(t, name); row != nil { - checkRowTags(t, row, name, wantTags) + row, err := checkExactlyOneRow(t, name) + if err != nil { + t.Error(err) + return + } + checkRowTags(t, row, name, wantTags) - if s, ok := row.Data.(*view.SumData); !ok { - t.Error("Wrong type", "metric", name, "got", reflect.TypeOf(row.Data), "want", "SumData") - } else if s.Value != wantValue { - t.Error("Wrong sumdata", "metric", name, "got", s.Value, "want", wantValue) - } + if s, ok := row.Data.(*view.SumData); !ok { + t.Error("Wrong type", "metric", name, "got", reflect.TypeOf(row.Data), "want", "SumData") + } else if s.Value != wantValue { + t.Error("Wrong sumdata", "metric", name, "got", s.Value, "want", wantValue) } } @@ -166,19 +181,29 @@ func lastRow(t test.T, name string) *view.Row { return d[len(d)-1] } -func checkExactlyOneRow(t test.T, name string) *view.Row { - t.Helper() - d, err := view.RetrieveData(name) - if err != nil { - t.Error("Reporter.Report() error", "metric", name, "error", err) - return nil +func checkExactlyOneRow(t test.T, name string) (*view.Row, error) { + // view.Meter implements (and is exposed by) metricproducer.GetAll. Since + // this is a test, reach around and cast these to view.Meter. + var retval *view.Row + for _, producer := range metricproducer.GlobalManager().GetAll() { + meter := producer.(view.Meter) + + d, err := meter.RetrieveData(name) + if err != nil || len(d) == 0 { + continue + } + if len(d) > 1 { + return nil, fmt.Errorf("expected 1 row for metric %q got %d", name, len(d)) + } + if retval != nil { + return nil, fmt.Errorf("got 2 rows from different meters: %+v, %+v", *retval, d[0]) + } + retval = d[0] } - if len(d) != 1 { - t.Error("Reporter.Report() wrong length", "metric", name, "got", len(d), "want", 1) - return nil + if retval == nil { + return nil, fmt.Errorf("could not find row for %q", name) } - - return d[0] + return retval, nil } func checkRowTags(t test.T, row *view.Row, name string, wantTags map[string]string) { diff --git a/vendor/knative.dev/pkg/reconciler/leader.go b/vendor/knative.dev/pkg/reconciler/leader.go new file mode 100644 index 00000000000..3d5f68fdce0 --- /dev/null +++ b/vendor/knative.dev/pkg/reconciler/leader.go @@ -0,0 +1,118 @@ +/* +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 reconciler + +import ( + "sync" + + "k8s.io/apimachinery/pkg/types" +) + +// Bucket is an opaque type used to scope leadership. +type Bucket interface { + // Name returns a string representing this bucket, which uniquely + // identifies the bucket and is suitable for use as a resource lock name. + Name() string + + // Has determines whether this Bucket contains a particular key. + Has(key types.NamespacedName) bool +} + +// UniversalBucket returns a Bucket that "Has()" all keys. +func UniversalBucket() Bucket { + return &bucket{} +} + +type bucket struct{} + +var _ Bucket = (*bucket)(nil) + +// Name implements Bucket +func (b *bucket) Name() string { + return "" +} + +// Has implements Bucket +func (b *bucket) Has(nn types.NamespacedName) bool { + return true +} + +// LeaderAware is implemented by Reconcilers that are aware of their leader status. +type LeaderAware interface { + // Promote is called when we become the leader of a given Bucket. It must be + // supplied with an enqueue function through which a Bucket resync may be triggered. + Promote(b Bucket, enq func(Bucket, types.NamespacedName)) error + + // Demote is called when we stop being the leader for the specified Bucket. + Demote(Bucket) +} + +// LeaderAwareFuncs implements LeaderAware using the given functions for handling +// promotion and demotion. +type LeaderAwareFuncs struct { + sync.RWMutex + buckets map[string]Bucket + + PromoteFunc func(b Bucket, enq func(Bucket, types.NamespacedName)) error + DemoteFunc func(b Bucket) +} + +var _ LeaderAware = (*LeaderAwareFuncs)(nil) + +// IsLeaderFor implements LeaderAware +func (laf *LeaderAwareFuncs) IsLeaderFor(key types.NamespacedName) bool { + laf.RLock() + defer laf.RUnlock() + + for _, bkt := range laf.buckets { + if bkt.Has(key) { + return true + } + } + return false +} + +// Promote implements LeaderAware +func (laf *LeaderAwareFuncs) Promote(b Bucket, enq func(Bucket, types.NamespacedName)) error { + func() { + laf.Lock() + defer laf.Unlock() + if laf.buckets == nil { + laf.buckets = make(map[string]Bucket, 1) + } + laf.buckets[b.Name()] = b + return + }() + + if promote := laf.PromoteFunc; promote != nil { + return promote(b, enq) + } + return nil +} + +// Demote implements LeaderAware +func (laf *LeaderAwareFuncs) Demote(b Bucket) { + func() { + laf.Lock() + defer laf.Unlock() + delete(laf.buckets, b.Name()) + }() + + if demote := laf.DemoteFunc; demote != nil { + demote(b) + } +} diff --git a/vendor/knative.dev/pkg/reconciler/reconcile_common.go b/vendor/knative.dev/pkg/reconciler/reconcile_common.go index c9f8b5cb843..a807edfb688 100644 --- a/vendor/knative.dev/pkg/reconciler/reconcile_common.go +++ b/vendor/knative.dev/pkg/reconciler/reconcile_common.go @@ -18,6 +18,10 @@ package reconciler import ( "context" + "reflect" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" @@ -50,7 +54,7 @@ func PreProcessReconcile(ctx context.Context, resource duckv1.KRShaped) { } // PostProcessReconcile contains logic to apply after reconciliation of a resource. -func PostProcessReconcile(ctx context.Context, resource duckv1.KRShaped) { +func PostProcessReconcile(ctx context.Context, resource, oldResource duckv1.KRShaped) { logger := logging.FromContext(ctx) status := resource.GetStatus() mgr := resource.GetConditionSet().Manage(status) @@ -64,4 +68,26 @@ func PostProcessReconcile(ctx context.Context, resource duckv1.KRShaped) { } else if rc.Reason == failedGenerationBump { logger.Warn("A reconciler observed a new generation without updating the resource status") } + + groomConditionsTransitionTime(resource, oldResource) +} + +// groomConditionsTransitionTime ensures that the LastTransitionTime only advances for resources +// where the condition has changed during reconciliation. This also ensures that all advanced +// conditions share the same timestamp. +func groomConditionsTransitionTime(resource, oldResource duckv1.KRShaped) { + now := apis.VolatileTime{Inner: metav1.NewTime(time.Now())} + sts := resource.GetStatus() + for i := range sts.Conditions { + cond := &sts.Conditions[i] + + if oldCond := oldResource.GetStatus().GetCondition(cond.Type); oldCond != nil { + cond.LastTransitionTime = oldCond.LastTransitionTime + if reflect.DeepEqual(cond, oldCond) { + continue + } + } + + cond.LastTransitionTime = now + } } diff --git a/vendor/knative.dev/pkg/test/presubmit-tests.sh b/vendor/knative.dev/pkg/test/presubmit-tests.sh index 261599f7168..af8199dd008 100644 --- a/vendor/knative.dev/pkg/test/presubmit-tests.sh +++ b/vendor/knative.dev/pkg/test/presubmit-tests.sh @@ -37,4 +37,16 @@ function pre_build_tests() { return 0 } +# Run the unit tests with an additional flag '-mod=vendor' to avoid +# downloading the deps in unit tests CI job +function unit_tests() { + # Run the default way. + default_unit_test_runner || failed=1 + + # Run unit testing select packages without race detection, + # so that they may use: // +build !race + report_go_test ./leaderelection || failed=1 + +} + main $@ diff --git a/vendor/modules.txt b/vendor/modules.txt index 0bbc998db35..d72b67efc06 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -281,7 +281,7 @@ github.com/valyala/bytebufferpool # github.com/wavesoftware/go-ensure v1.0.0 ## explicit github.com/wavesoftware/go-ensure -# go.opencensus.io v0.22.3 +# go.opencensus.io v0.22.4 ## explicit go.opencensus.io go.opencensus.io/internal @@ -943,7 +943,7 @@ k8s.io/utils/buffer k8s.io/utils/integer k8s.io/utils/pointer k8s.io/utils/trace -# knative.dev/pkg v0.0.0-20200618002824-96c250871fac +# knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743 ## explicit knative.dev/pkg/apiextensions/storageversion knative.dev/pkg/apiextensions/storageversion/cmd/migrate @@ -1056,7 +1056,7 @@ knative.dev/pkg/webhook/resourcesemantics knative.dev/pkg/webhook/resourcesemantics/conversion knative.dev/pkg/webhook/resourcesemantics/defaulting knative.dev/pkg/webhook/resourcesemantics/validation -# knative.dev/test-infra v0.0.0-20200617235125-6382dba95484 +# knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884 ## explicit knative.dev/test-infra/scripts # sigs.k8s.io/yaml v1.2.0 From a285474e7b639373fec3dd2b4da9a8f310e821db Mon Sep 17 00:00:00 2001 From: Matt Moore Date: Fri, 19 Jun 2020 15:13:25 -0700 Subject: [PATCH 5/9] Enable webhook leader election (#3355) Fixes: https://github.com/knative/eventing/issues/3239 --- config/core/configmaps/leader-election.yaml | 4 +- go.mod | 4 +- go.sum | 10 +- .../configmappropagation/reconciler.go | 5 +- .../eventing/v1beta1/broker/reconciler.go | 5 +- .../eventing/v1beta1/eventtype/reconciler.go | 5 +- .../eventing/v1beta1/trigger/reconciler.go | 5 +- .../flows/v1beta1/parallel/reconciler.go | 5 +- .../flows/v1beta1/sequence/reconciler.go | 5 +- .../messaging/v1beta1/channel/reconciler.go | 5 +- .../v1beta1/inmemorychannel/reconciler.go | 5 +- .../v1beta1/subscription/reconciler.go | 5 +- .../sources/v1alpha1/pingsource/reconciler.go | 5 +- .../v1alpha2/apiserversource/reconciler.go | 5 +- .../v1alpha2/containersource/reconciler.go | 5 +- .../sources/v1alpha2/pingsource/reconciler.go | 5 +- pkg/leaderelection/leader_election.go | 1 + pkg/leaderelection/leader_election_test.go | 6 +- .../api/admission/{v1beta1 => v1}/doc.go | 4 +- .../admission/{v1beta1 => v1}/generated.pb.go | 138 +++++++++--------- .../admission/{v1beta1 => v1}/generated.proto | 6 +- .../api/admission/{v1beta1 => v1}/register.go | 6 +- .../api/admission/{v1beta1 => v1}/types.go | 6 +- .../types_swagger_doc_generated.go | 4 +- .../{v1beta1 => v1}/zz_generated.deepcopy.go | 10 +- .../customresourcedefinition.go | 52 +++++++ .../mutatingwebhookconfiguration.go | 10 +- .../validatingwebhookconfiguration.go | 10 +- .../core/v1/namespace/reconciler.go | 5 +- .../generators/reconciler_reconciler.go | 5 +- vendor/knative.dev/pkg/hack/update-codegen.sh | 4 +- .../pkg/injection/sharedmain/main.go | 13 +- vendor/knative.dev/pkg/webhook/admission.go | 12 +- .../pkg/webhook/certificates/certificates.go | 26 ++-- .../pkg/webhook/certificates/controller.go | 21 ++- .../pkg/webhook/configmaps/configmaps.go | 43 +++--- .../pkg/webhook/configmaps/controller.go | 21 ++- vendor/knative.dev/pkg/webhook/conversion.go | 8 +- .../pkg/webhook/psbinding/controller.go | 13 +- .../pkg/webhook/psbinding/psbinding.go | 46 +++--- .../pkg/webhook/psbinding/reconciler.go | 13 ++ .../conversion/controller.go | 17 ++- .../conversion/conversion.go | 8 +- .../conversion/reconciler.go | 26 +++- .../defaulting/controller.go | 18 ++- .../defaulting/defaulting.go | 47 +++--- .../validation/controller.go | 18 ++- .../validation/reconcile_config.go | 33 +++-- .../validation/validation_admit.go | 24 +-- .../knative.dev/pkg/webhook/stats_reporter.go | 6 +- vendor/knative.dev/pkg/webhook/webhook.go | 12 +- vendor/modules.txt | 11 +- 52 files changed, 500 insertions(+), 286 deletions(-) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/doc.go (87%) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/generated.pb.go (87%) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/generated.proto (98%) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/register.go (95%) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/types.go (98%) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/types_swagger_doc_generated.go (98%) rename vendor/k8s.io/api/admission/{v1beta1 => v1}/zz_generated.deepcopy.go (95%) create mode 100644 vendor/knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1/customresourcedefinition/customresourcedefinition.go rename vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/{v1beta1 => v1}/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go (79%) rename vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/{v1beta1 => v1}/validatingwebhookconfiguration/validatingwebhookconfiguration.go (79%) diff --git a/config/core/configmaps/leader-election.yaml b/config/core/configmaps/leader-election.yaml index 1751c9fa44c..6b94d5543b8 100644 --- a/config/core/configmaps/leader-election.yaml +++ b/config/core/configmaps/leader-election.yaml @@ -21,7 +21,7 @@ metadata: eventing.knative.dev/release: devel knative.dev/example-checksum: "43edfe90" annotations: - knative.dev/example-checksum: e5193acb + knative.dev/example-checksum: a2104fac data: _example: | ################################ @@ -63,4 +63,4 @@ data: # - broker-controller # - inmemorychannel-dispatcher # - inmemorychannel-controller - enabledComponents: "controller,broker-controller,inmemorychannel-dispatcher,inmemorychannel-controller" + enabledComponents: "controller,broker-controller,inmemorychannel-dispatcher,inmemorychannel-controller,webhook" diff --git a/go.mod b/go.mod index 8e7d3c1465d..614d96a8b2f 100644 --- a/go.mod +++ b/go.mod @@ -37,8 +37,8 @@ require ( k8s.io/apiserver v0.17.6 k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible k8s.io/utils v0.0.0-20200124190032-861946025e34 - knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743 - knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884 + knative.dev/pkg v0.0.0-20200619182625-b6a13e2894ee + knative.dev/test-infra v0.0.0-20200619200026-0b0587234302 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index cec054a8ea0..4ebf1302d4c 100644 --- a/go.sum +++ b/go.sum @@ -1402,10 +1402,10 @@ knative.dev/pkg v0.0.0-20200515002500-16d7b963416f/go.mod h1:tMOHGbxtRz8zYFGEGpV knative.dev/pkg v0.0.0-20200520073958-94316e20e860/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA= knative.dev/pkg v0.0.0-20200603222317-b79e4a24ca50/go.mod h1:8IfPj/lpuKHHg82xZCl2wuFZ3BM96To72sN1W8T9wjQ= knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2/go.mod h1:rA+FklsrVahwF4a+D63NyHJlzDoAFH81K4J5CYuE3bA= -knative.dev/pkg v0.0.0-20200618002824-96c250871fac h1:X8XHaSFsUIW2IJCIEQEzNfPbs/gGib3CUK/+lkZuoEo= -knative.dev/pkg v0.0.0-20200618002824-96c250871fac/go.mod h1:4ty6MSlNjZk5qBaGb3Gt4gopjMD4gRknfTABblcFpQ8= knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743 h1:W1NKMizoXYYX5e2mkFXnn21T7X6ROKKwL8YetGu7xCQ= knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= +knative.dev/pkg v0.0.0-20200619182625-b6a13e2894ee h1:nudgQQo72NJuzaB4gBHE7Vm2BJVBTmpRt7M2psgvKxY= +knative.dev/pkg v0.0.0-20200619182625-b6a13e2894ee/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ= knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU= knative.dev/test-infra v0.0.0-20200513011557-d03429a76034/go.mod h1:aMif0KXL4g19YCYwsy4Ocjjz5xgPlseYV+B95Oo4JGE= @@ -1413,12 +1413,10 @@ knative.dev/test-infra v0.0.0-20200519015156-82551620b0a9/go.mod h1:A5b2OAXTOeHT knative.dev/test-infra v0.0.0-20200522180958-6a0a9b9d893a/go.mod h1:n9eQkzmSNj8BiqNFl1lzoz68D09uMeJfyOjc132Gbik= knative.dev/test-infra v0.0.0-20200606045118-14ebc4a42974 h1:CrZmlbB+j3ZF/aTrfyypY5ulX2w7XrkfeXKQsbkqzTg= knative.dev/test-infra v0.0.0-20200606045118-14ebc4a42974/go.mod h1://I6IZIF0QDgs5wotU243ZZ5cTpm6/GthayjUenBBc0= -knative.dev/test-infra v0.0.0-20200615231324-3a016f44102c h1:pzn7d3gVWX6p10CpdSFAYlgFhLwI6hGQ8H4sxQfvob4= -knative.dev/test-infra v0.0.0-20200615231324-3a016f44102c/go.mod h1:+BfrTJpc++rH30gX/C0QY6NT2eYVzycll52uw6CrQnc= knative.dev/test-infra v0.0.0-20200617235125-6382dba95484 h1:5D1Fm6aA1T1QQXLb1HkJ5t8gB9pTkhLYak1CCqIP+pE= knative.dev/test-infra v0.0.0-20200617235125-6382dba95484/go.mod h1:+BfrTJpc++rH30gX/C0QY6NT2eYVzycll52uw6CrQnc= -knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884 h1:qGxu/U/8VxhAuyFedrrne4s0vfY+YfoRwJJCY0AKpbw= -knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884/go.mod h1:qeiTuhDKO/HHheqVfepbxy5/q+O9toSJW6CO/DgjxFY= +knative.dev/test-infra v0.0.0-20200619200026-0b0587234302 h1:nGw173QprRCSZab6KT4uSj0GTp3WNRo0nfk9Lpo3F1I= +knative.dev/test-infra v0.0.0-20200619200026-0b0587234302/go.mod h1:H8QEB2Y35+vAuVtDbn7QBD+NQr9zQbbxNiovCLNH7F4= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go b/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go index d5d1a5ee258..cccbef52db2 100644 --- a/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go +++ b/pkg/client/injection/reconciler/configs/v1alpha1/configmappropagation/reconciler.go @@ -21,6 +21,7 @@ package configmappropagation import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go b/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go index fd6162b837b..88712aa9b87 100644 --- a/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1beta1/broker/reconciler.go @@ -21,6 +21,7 @@ package broker import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -172,7 +173,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -191,7 +192,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go b/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go index 5f5c66ca30f..170ebceb131 100644 --- a/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1beta1/eventtype/reconciler.go @@ -21,6 +21,7 @@ package eventtype import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go b/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go index 40817b92cad..b65c86fec8f 100644 --- a/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1beta1/trigger/reconciler.go @@ -21,6 +21,7 @@ package trigger import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go b/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go index 866e1ae02b8..362e955a04f 100644 --- a/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go +++ b/pkg/client/injection/reconciler/flows/v1beta1/parallel/reconciler.go @@ -21,6 +21,7 @@ package parallel import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go b/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go index b38b39f3de8..6c2170941a9 100644 --- a/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go +++ b/pkg/client/injection/reconciler/flows/v1beta1/sequence/reconciler.go @@ -21,6 +21,7 @@ package sequence import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go index ed189706212..d1170b9bcb6 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go @@ -21,6 +21,7 @@ package channel import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go index 8f7e7950ba6..9b9f9137d3b 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/inmemorychannel/reconciler.go @@ -21,6 +21,7 @@ package inmemorychannel import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go index f33e35311af..a57edd980e0 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/subscription/reconciler.go @@ -21,6 +21,7 @@ package subscription import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/sources/v1alpha1/pingsource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha1/pingsource/reconciler.go index cda3acbe218..2112be1f07a 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha1/pingsource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha1/pingsource/reconciler.go @@ -21,6 +21,7 @@ package pingsource import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } // Reconcile this copy of the resource and then write back any status @@ -176,7 +177,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go index 51a50204bac..a5890725ec2 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha2/apiserversource/reconciler.go @@ -21,6 +21,7 @@ package apiserversource import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go index ea36257bf13..dfe4cf08199 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha2/containersource/reconciler.go @@ -21,6 +21,7 @@ package containersource import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go b/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go index 845abd970e1..ace47ae7ef4 100644 --- a/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go +++ b/pkg/client/injection/reconciler/sources/v1alpha2/pingsource/reconciler.go @@ -21,6 +21,7 @@ package pingsource import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -161,7 +162,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } reconciler.PreProcessReconcile(ctx, resource) @@ -180,7 +181,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/pkg/leaderelection/leader_election.go b/pkg/leaderelection/leader_election.go index 23e3e4e3c03..5b2d72174b4 100644 --- a/pkg/leaderelection/leader_election.go +++ b/pkg/leaderelection/leader_election.go @@ -31,6 +31,7 @@ var ( "broker-controller", "inmemorychannel-dispatcher", "inmemorychannel-controller", + "webhook", ) ) diff --git a/pkg/leaderelection/leader_election_test.go b/pkg/leaderelection/leader_election_test.go index 6382be9c357..58ea7197be9 100644 --- a/pkg/leaderelection/leader_election_test.go +++ b/pkg/leaderelection/leader_election_test.go @@ -37,7 +37,7 @@ func okConfig() *kle.Config { LeaseDuration: 15 * time.Second, RenewDeadline: 10 * time.Second, RetryPeriod: 2 * time.Second, - EnabledComponents: sets.NewString("controller", "inmemorychannel-dispatcher", "inmemorychannel-controller", "broker-controller"), + EnabledComponents: sets.NewString("controller", "inmemorychannel-dispatcher", "inmemorychannel-controller", "broker-controller", "webhook"), } } @@ -50,7 +50,7 @@ func okData() map[string]string { "leaseDuration": "15s", "renewDeadline": "10s", "retryPeriod": "2s", - "enabledComponents": "controller,inmemorychannel-dispatcher,inmemorychannel-controller,broker-controller", + "enabledComponents": "controller,inmemorychannel-dispatcher,inmemorychannel-controller,broker-controller,webhook", } } @@ -69,7 +69,7 @@ func TestValidateConfig(t *testing.T) { data: kmeta.UnionMaps(okData(), map[string]string{ "enabledComponents": "controller,frobulator", }), - err: errors.New(`invalid enabledComponent "frobulator": valid values are ["broker-controller" "controller" "inmemorychannel-controller" "inmemorychannel-dispatcher"]`), + err: errors.New(`invalid enabledComponent "frobulator": valid values are ["broker-controller" "controller" "inmemorychannel-controller" "inmemorychannel-dispatcher" "webhook"]`), }, { name: "invalid config", data: kmeta.UnionMaps(okData(), map[string]string{ diff --git a/vendor/k8s.io/api/admission/v1beta1/doc.go b/vendor/k8s.io/api/admission/v1/doc.go similarity index 87% rename from vendor/k8s.io/api/admission/v1beta1/doc.go rename to vendor/k8s.io/api/admission/v1/doc.go index 92f7c19d26d..cbc6bb59dd9 100644 --- a/vendor/k8s.io/api/admission/v1beta1/doc.go +++ b/vendor/k8s.io/api/admission/v1/doc.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2019 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,4 +20,4 @@ limitations under the License. // +groupName=admission.k8s.io -package v1beta1 // import "k8s.io/api/admission/v1beta1" +package v1 // import "k8s.io/api/admission/v1" diff --git a/vendor/k8s.io/api/admission/v1beta1/generated.pb.go b/vendor/k8s.io/api/admission/v1/generated.pb.go similarity index 87% rename from vendor/k8s.io/api/admission/v1beta1/generated.pb.go rename to vendor/k8s.io/api/admission/v1/generated.pb.go index 10d3bead6f0..e6b4f7240ef 100644 --- a/vendor/k8s.io/api/admission/v1beta1/generated.pb.go +++ b/vendor/k8s.io/api/admission/v1/generated.pb.go @@ -15,9 +15,9 @@ limitations under the License. */ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: k8s.io/kubernetes/vendor/k8s.io/api/admission/v1beta1/generated.proto +// source: k8s.io/kubernetes/vendor/k8s.io/api/admission/v1/generated.proto -package v1beta1 +package v1 import ( fmt "fmt" @@ -50,7 +50,7 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package func (m *AdmissionRequest) Reset() { *m = AdmissionRequest{} } func (*AdmissionRequest) ProtoMessage() {} func (*AdmissionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_b87c2352de86eab9, []int{0} + return fileDescriptor_4b73421fd5edef9f, []int{0} } func (m *AdmissionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -78,7 +78,7 @@ var xxx_messageInfo_AdmissionRequest proto.InternalMessageInfo func (m *AdmissionResponse) Reset() { *m = AdmissionResponse{} } func (*AdmissionResponse) ProtoMessage() {} func (*AdmissionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_b87c2352de86eab9, []int{1} + return fileDescriptor_4b73421fd5edef9f, []int{1} } func (m *AdmissionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +106,7 @@ var xxx_messageInfo_AdmissionResponse proto.InternalMessageInfo func (m *AdmissionReview) Reset() { *m = AdmissionReview{} } func (*AdmissionReview) ProtoMessage() {} func (*AdmissionReview) Descriptor() ([]byte, []int) { - return fileDescriptor_b87c2352de86eab9, []int{2} + return fileDescriptor_4b73421fd5edef9f, []int{2} } func (m *AdmissionReview) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -132,75 +132,75 @@ func (m *AdmissionReview) XXX_DiscardUnknown() { var xxx_messageInfo_AdmissionReview proto.InternalMessageInfo func init() { - proto.RegisterType((*AdmissionRequest)(nil), "k8s.io.api.admission.v1beta1.AdmissionRequest") - proto.RegisterType((*AdmissionResponse)(nil), "k8s.io.api.admission.v1beta1.AdmissionResponse") - proto.RegisterMapType((map[string]string)(nil), "k8s.io.api.admission.v1beta1.AdmissionResponse.AuditAnnotationsEntry") - proto.RegisterType((*AdmissionReview)(nil), "k8s.io.api.admission.v1beta1.AdmissionReview") + proto.RegisterType((*AdmissionRequest)(nil), "k8s.io.api.admission.v1.AdmissionRequest") + proto.RegisterType((*AdmissionResponse)(nil), "k8s.io.api.admission.v1.AdmissionResponse") + proto.RegisterMapType((map[string]string)(nil), "k8s.io.api.admission.v1.AdmissionResponse.AuditAnnotationsEntry") + proto.RegisterType((*AdmissionReview)(nil), "k8s.io.api.admission.v1.AdmissionReview") } func init() { - proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/api/admission/v1beta1/generated.proto", fileDescriptor_b87c2352de86eab9) + proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/api/admission/v1/generated.proto", fileDescriptor_4b73421fd5edef9f) } -var fileDescriptor_b87c2352de86eab9 = []byte{ - // 902 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xf7, 0xd6, 0x8e, 0xed, 0x1d, 0x87, 0xda, 0x9d, 0x82, 0xb4, 0xb2, 0xd0, 0xda, 0xe4, 0x80, - 0x82, 0xd4, 0xcc, 0x92, 0x08, 0xaa, 0xa8, 0xe2, 0x92, 0x25, 0x11, 0x0a, 0x48, 0x4d, 0x34, 0xad, - 0x51, 0xe1, 0x80, 0x34, 0xf6, 0x4e, 0xed, 0xc5, 0xf6, 0xcc, 0xb2, 0x33, 0xeb, 0xe0, 0x1b, 0xe2, - 0xca, 0x85, 0x6f, 0xc0, 0x87, 0xe1, 0x92, 0x63, 0x8f, 0x3d, 0x59, 0xc4, 0x7c, 0x8b, 0x9c, 0xd0, - 0xcc, 0xce, 0x7a, 0xb7, 0x76, 0x02, 0xfd, 0xc3, 0xc9, 0xf3, 0xfe, 0xfc, 0x7e, 0xef, 0xf9, 0xf7, - 0x76, 0xde, 0x80, 0x93, 0xf1, 0xa1, 0x40, 0x21, 0xf7, 0xc6, 0x49, 0x9f, 0xc6, 0x8c, 0x4a, 0x2a, - 0xbc, 0x19, 0x65, 0x01, 0x8f, 0x3d, 0x13, 0x20, 0x51, 0xe8, 0x91, 0x60, 0x1a, 0x0a, 0x11, 0x72, - 0xe6, 0xcd, 0xf6, 0xfb, 0x54, 0x92, 0x7d, 0x6f, 0x48, 0x19, 0x8d, 0x89, 0xa4, 0x01, 0x8a, 0x62, - 0x2e, 0x39, 0xfc, 0x30, 0xcd, 0x46, 0x24, 0x0a, 0xd1, 0x2a, 0x1b, 0x99, 0xec, 0xf6, 0xde, 0x30, - 0x94, 0xa3, 0xa4, 0x8f, 0x06, 0x7c, 0xea, 0x0d, 0xf9, 0x90, 0x7b, 0x1a, 0xd4, 0x4f, 0x9e, 0x6b, - 0x4b, 0x1b, 0xfa, 0x94, 0x92, 0xb5, 0x1f, 0x14, 0x4b, 0x27, 0x72, 0x44, 0x99, 0x0c, 0x07, 0x44, - 0xa6, 0xf5, 0xd7, 0x4b, 0xb7, 0x3f, 0xcb, 0xb3, 0xa7, 0x64, 0x30, 0x0a, 0x19, 0x8d, 0xe7, 0x5e, - 0x34, 0x1e, 0x2a, 0x87, 0xf0, 0xa6, 0x54, 0x92, 0x9b, 0x50, 0xde, 0x6d, 0xa8, 0x38, 0x61, 0x32, - 0x9c, 0xd2, 0x0d, 0xc0, 0xc3, 0xff, 0x02, 0x88, 0xc1, 0x88, 0x4e, 0xc9, 0x3a, 0x6e, 0xe7, 0x0f, - 0x1b, 0xb4, 0x8e, 0x32, 0x45, 0x30, 0xfd, 0x29, 0xa1, 0x42, 0x42, 0x1f, 0x94, 0x93, 0x30, 0x70, - 0xac, 0xae, 0xb5, 0x6b, 0xfb, 0x9f, 0x5e, 0x2e, 0x3a, 0xa5, 0xe5, 0xa2, 0x53, 0xee, 0x9d, 0x1e, - 0x5f, 0x2f, 0x3a, 0x1f, 0xdd, 0x56, 0x48, 0xce, 0x23, 0x2a, 0x50, 0xef, 0xf4, 0x18, 0x2b, 0x30, - 0x7c, 0x06, 0x2a, 0xe3, 0x90, 0x05, 0xce, 0x9d, 0xae, 0xb5, 0xdb, 0x38, 0x78, 0x88, 0xf2, 0x09, - 0xac, 0x60, 0x28, 0x1a, 0x0f, 0x95, 0x43, 0x20, 0x25, 0x03, 0x9a, 0xed, 0xa3, 0xaf, 0x62, 0x9e, - 0x44, 0xdf, 0xd2, 0x58, 0x35, 0xf3, 0x4d, 0xc8, 0x02, 0x7f, 0xdb, 0x14, 0xaf, 0x28, 0x0b, 0x6b, - 0x46, 0x38, 0x02, 0xf5, 0x98, 0x0a, 0x9e, 0xc4, 0x03, 0xea, 0x94, 0x35, 0xfb, 0xa3, 0x37, 0x67, - 0xc7, 0x86, 0xc1, 0x6f, 0x99, 0x0a, 0xf5, 0xcc, 0x83, 0x57, 0xec, 0xf0, 0x73, 0xd0, 0x10, 0x49, - 0x3f, 0x0b, 0x38, 0x15, 0xad, 0xc7, 0x7d, 0x03, 0x68, 0x3c, 0xc9, 0x43, 0xb8, 0x98, 0x07, 0x43, - 0xd0, 0x88, 0x53, 0x25, 0x55, 0xd7, 0xce, 0x7b, 0xef, 0xa4, 0x40, 0x53, 0x95, 0xc2, 0x39, 0x1d, - 0x2e, 0x72, 0xc3, 0x39, 0x68, 0x1a, 0x73, 0xd5, 0xe5, 0xdd, 0x77, 0x96, 0xe4, 0xfe, 0x72, 0xd1, - 0x69, 0xe2, 0x57, 0x69, 0xf1, 0x7a, 0x1d, 0xf8, 0x35, 0x80, 0xc6, 0x55, 0x10, 0xc2, 0x69, 0x6a, - 0x8d, 0xda, 0x46, 0x23, 0x88, 0x37, 0x32, 0xf0, 0x0d, 0x28, 0xd8, 0x05, 0x15, 0x46, 0xa6, 0xd4, - 0xd9, 0xd2, 0xe8, 0xd5, 0xd0, 0x1f, 0x93, 0x29, 0xc5, 0x3a, 0x02, 0x3d, 0x60, 0xab, 0x5f, 0x11, - 0x91, 0x01, 0x75, 0xaa, 0x3a, 0xed, 0x9e, 0x49, 0xb3, 0x1f, 0x67, 0x01, 0x9c, 0xe7, 0xc0, 0x2f, - 0x80, 0xcd, 0x23, 0xf5, 0xa9, 0x87, 0x9c, 0x39, 0x35, 0x0d, 0x70, 0x33, 0xc0, 0x59, 0x16, 0xb8, - 0x2e, 0x1a, 0x38, 0x07, 0xc0, 0xa7, 0xa0, 0x9e, 0x08, 0x1a, 0x9f, 0xb2, 0xe7, 0xdc, 0xa9, 0x6b, - 0x41, 0x3f, 0x46, 0xc5, 0x1d, 0xf2, 0xca, 0xb5, 0x57, 0x42, 0xf6, 0x4c, 0x76, 0xfe, 0x3d, 0x65, - 0x1e, 0xbc, 0x62, 0x82, 0x3d, 0x50, 0xe5, 0xfd, 0x1f, 0xe9, 0x40, 0x3a, 0xb6, 0xe6, 0xdc, 0xbb, - 0x75, 0x48, 0xe6, 0xd6, 0x22, 0x4c, 0x2e, 0x4e, 0x7e, 0x96, 0x94, 0xa9, 0xf9, 0xf8, 0x77, 0x0d, - 0x75, 0xf5, 0x4c, 0x93, 0x60, 0x43, 0x06, 0x7f, 0x00, 0x36, 0x9f, 0x04, 0xa9, 0xd3, 0x01, 0x6f, - 0xc3, 0xbc, 0x92, 0xf2, 0x2c, 0xe3, 0xc1, 0x39, 0x25, 0xdc, 0x01, 0xd5, 0x20, 0x9e, 0xe3, 0x84, - 0x39, 0x8d, 0xae, 0xb5, 0x5b, 0xf7, 0x81, 0xea, 0xe1, 0x58, 0x7b, 0xb0, 0x89, 0xc0, 0x67, 0xa0, - 0xc6, 0x23, 0x25, 0x86, 0x70, 0xb6, 0xdf, 0xa6, 0x83, 0xa6, 0xe9, 0xa0, 0x76, 0x96, 0xb2, 0xe0, - 0x8c, 0x6e, 0xe7, 0xd7, 0x0a, 0xb8, 0x57, 0xd8, 0x50, 0x22, 0xe2, 0x4c, 0xd0, 0xff, 0x65, 0x45, - 0x7d, 0x02, 0x6a, 0x64, 0x32, 0xe1, 0x17, 0x34, 0xdd, 0x52, 0xf5, 0xbc, 0x89, 0xa3, 0xd4, 0x8d, - 0xb3, 0x38, 0x3c, 0x07, 0x55, 0x21, 0x89, 0x4c, 0x84, 0xd9, 0x38, 0x0f, 0x5e, 0xef, 0x7a, 0x3d, - 0xd1, 0x98, 0x54, 0x30, 0x4c, 0x45, 0x32, 0x91, 0xd8, 0xf0, 0xc0, 0x0e, 0xd8, 0x8a, 0x88, 0x1c, - 0x8c, 0xf4, 0x56, 0xd9, 0xf6, 0xed, 0xe5, 0xa2, 0xb3, 0x75, 0xae, 0x1c, 0x38, 0xf5, 0xc3, 0x43, - 0x60, 0xeb, 0xc3, 0xd3, 0x79, 0x94, 0x5d, 0x8c, 0xb6, 0x1a, 0xd1, 0x79, 0xe6, 0xbc, 0x2e, 0x1a, - 0x38, 0x4f, 0x86, 0xbf, 0x59, 0xa0, 0x45, 0x92, 0x20, 0x94, 0x47, 0x8c, 0x71, 0x49, 0xd2, 0xa9, - 0x54, 0xbb, 0xe5, 0xdd, 0xc6, 0xc1, 0x09, 0xfa, 0xb7, 0x97, 0x10, 0x6d, 0xe8, 0x8c, 0x8e, 0xd6, - 0x78, 0x4e, 0x98, 0x8c, 0xe7, 0xbe, 0x63, 0x84, 0x6a, 0xad, 0x87, 0xf1, 0x46, 0xe1, 0xf6, 0x97, - 0xe0, 0x83, 0x1b, 0x49, 0x60, 0x0b, 0x94, 0xc7, 0x74, 0x9e, 0x8e, 0x10, 0xab, 0x23, 0x7c, 0x1f, - 0x6c, 0xcd, 0xc8, 0x24, 0xa1, 0x7a, 0x1c, 0x36, 0x4e, 0x8d, 0x47, 0x77, 0x0e, 0xad, 0x9d, 0x3f, - 0x2d, 0xd0, 0x2c, 0x34, 0x37, 0x0b, 0xe9, 0x05, 0xec, 0x81, 0x9a, 0x59, 0x25, 0x9a, 0xa3, 0x71, - 0x80, 0x5e, 0xfb, 0xcf, 0x69, 0x94, 0xdf, 0x50, 0xa3, 0xce, 0xf6, 0x5c, 0xc6, 0x05, 0xbf, 0xd3, - 0xcf, 0x8b, 0xfe, 0xf7, 0xe6, 0xf1, 0xf2, 0xde, 0x50, 0x34, 0x7f, 0xdb, 0xbc, 0x27, 0xda, 0xc2, - 0x2b, 0x3a, 0x7f, 0xef, 0xf2, 0xca, 0x2d, 0xbd, 0xb8, 0x72, 0x4b, 0x2f, 0xaf, 0xdc, 0xd2, 0x2f, - 0x4b, 0xd7, 0xba, 0x5c, 0xba, 0xd6, 0x8b, 0xa5, 0x6b, 0xbd, 0x5c, 0xba, 0xd6, 0x5f, 0x4b, 0xd7, - 0xfa, 0xfd, 0x6f, 0xb7, 0xf4, 0x7d, 0xcd, 0x10, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0x8b, 0xd1, - 0x27, 0x74, 0xfd, 0x08, 0x00, 0x00, +var fileDescriptor_4b73421fd5edef9f = []byte{ + // 898 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4d, 0x6f, 0x1b, 0x45, + 0x18, 0xf6, 0xc6, 0x89, 0xed, 0x1d, 0x87, 0xda, 0x9d, 0x82, 0x58, 0xf9, 0xb0, 0x36, 0x39, 0x20, + 0x17, 0xb5, 0xb3, 0x24, 0x82, 0x2a, 0xaa, 0x38, 0x34, 0x4b, 0x2a, 0x14, 0x90, 0x9a, 0x68, 0xda, + 0xa0, 0x8a, 0x03, 0xd2, 0xd8, 0x3b, 0xb5, 0x17, 0xdb, 0x33, 0xcb, 0xce, 0xac, 0x83, 0x6f, 0x9c, + 0x38, 0xf3, 0x0f, 0xf8, 0x1d, 0xfc, 0x83, 0x1c, 0x7b, 0xec, 0xc9, 0x22, 0xe6, 0x5f, 0x44, 0x42, + 0x42, 0x33, 0x3b, 0xfb, 0xd1, 0x7c, 0x88, 0xd0, 0xf4, 0xe4, 0x79, 0x3f, 0x9e, 0xe7, 0x7d, 0xfd, + 0xbc, 0x3b, 0xef, 0x80, 0x27, 0x93, 0x5d, 0x81, 0x42, 0xee, 0x4d, 0x92, 0x01, 0x8d, 0x19, 0x95, + 0x54, 0x78, 0x73, 0xca, 0x02, 0x1e, 0x7b, 0x26, 0x40, 0xa2, 0xd0, 0x23, 0xc1, 0x2c, 0x14, 0x22, + 0xe4, 0xcc, 0x9b, 0x6f, 0x7b, 0x23, 0xca, 0x68, 0x4c, 0x24, 0x0d, 0x50, 0x14, 0x73, 0xc9, 0xe1, + 0xc7, 0x69, 0x22, 0x22, 0x51, 0x88, 0xf2, 0x44, 0x34, 0xdf, 0xee, 0x3c, 0x1c, 0x85, 0x72, 0x9c, + 0x0c, 0xd0, 0x90, 0xcf, 0xbc, 0x11, 0x1f, 0x71, 0x4f, 0xe7, 0x0f, 0x92, 0x57, 0xda, 0xd2, 0x86, + 0x3e, 0xa5, 0x3c, 0x9d, 0x07, 0xe5, 0x82, 0x89, 0x1c, 0x53, 0x26, 0xc3, 0x21, 0x91, 0x57, 0x57, + 0xed, 0x7c, 0x51, 0x64, 0xcf, 0xc8, 0x70, 0x1c, 0x32, 0x1a, 0x2f, 0xbc, 0x68, 0x32, 0x52, 0x0e, + 0xe1, 0xcd, 0xa8, 0x24, 0x57, 0xa1, 0xbc, 0xeb, 0x50, 0x71, 0xc2, 0x64, 0x38, 0xa3, 0x97, 0x00, + 0x8f, 0xfe, 0x0b, 0x20, 0x86, 0x63, 0x3a, 0x23, 0x17, 0x71, 0x5b, 0x7f, 0xd8, 0xa0, 0xbd, 0x97, + 0x89, 0x81, 0xe9, 0xcf, 0x09, 0x15, 0x12, 0xfa, 0xa0, 0x9a, 0x84, 0x81, 0x63, 0xf5, 0xac, 0xbe, + 0xed, 0x7f, 0x7e, 0xba, 0xec, 0x56, 0x56, 0xcb, 0x6e, 0xf5, 0xf8, 0x60, 0xff, 0x7c, 0xd9, 0xfd, + 0xe4, 0xba, 0x42, 0x72, 0x11, 0x51, 0x81, 0x8e, 0x0f, 0xf6, 0xb1, 0x02, 0xc3, 0x97, 0x60, 0x7d, + 0x12, 0xb2, 0xc0, 0x59, 0xeb, 0x59, 0xfd, 0xe6, 0xce, 0x23, 0x54, 0x88, 0x9f, 0xc3, 0x50, 0x34, + 0x19, 0x29, 0x87, 0x40, 0x4a, 0x06, 0x34, 0xdf, 0x46, 0xdf, 0xc4, 0x3c, 0x89, 0xbe, 0xa7, 0xb1, + 0x6a, 0xe6, 0xbb, 0x90, 0x05, 0xfe, 0xa6, 0x29, 0xbe, 0xae, 0x2c, 0xac, 0x19, 0xe1, 0x18, 0x34, + 0x62, 0x2a, 0x78, 0x12, 0x0f, 0xa9, 0x53, 0xd5, 0xec, 0x8f, 0xff, 0x3f, 0x3b, 0x36, 0x0c, 0x7e, + 0xdb, 0x54, 0x68, 0x64, 0x1e, 0x9c, 0xb3, 0xc3, 0x2f, 0x41, 0x53, 0x24, 0x83, 0x2c, 0xe0, 0xac, + 0x6b, 0x3d, 0xee, 0x19, 0x40, 0xf3, 0x79, 0x11, 0xc2, 0xe5, 0x3c, 0x18, 0x82, 0x66, 0x9c, 0x2a, + 0xa9, 0xba, 0x76, 0x3e, 0xb8, 0x95, 0x02, 0x2d, 0x55, 0x0a, 0x17, 0x74, 0xb8, 0xcc, 0x0d, 0x17, + 0xa0, 0x65, 0xcc, 0xbc, 0xcb, 0x3b, 0xb7, 0x96, 0xe4, 0xde, 0x6a, 0xd9, 0x6d, 0xe1, 0xb7, 0x69, + 0xf1, 0xc5, 0x3a, 0xf0, 0x5b, 0x00, 0x8d, 0xab, 0x24, 0x84, 0xd3, 0xd2, 0x1a, 0x75, 0x8c, 0x46, + 0x10, 0x5f, 0xca, 0xc0, 0x57, 0xa0, 0x60, 0x0f, 0xac, 0x33, 0x32, 0xa3, 0xce, 0x86, 0x46, 0xe7, + 0x43, 0x7f, 0x46, 0x66, 0x14, 0xeb, 0x08, 0xf4, 0x80, 0xad, 0x7e, 0x45, 0x44, 0x86, 0xd4, 0xa9, + 0xe9, 0xb4, 0xbb, 0x26, 0xcd, 0x7e, 0x96, 0x05, 0x70, 0x91, 0x03, 0xbf, 0x02, 0x36, 0x8f, 0xd4, + 0xa7, 0x1e, 0x72, 0xe6, 0xd4, 0x35, 0xc0, 0xcd, 0x00, 0x87, 0x59, 0xe0, 0xbc, 0x6c, 0xe0, 0x02, + 0x00, 0x5f, 0x80, 0x46, 0x22, 0x68, 0x7c, 0xc0, 0x5e, 0x71, 0xa7, 0xa1, 0x05, 0xfd, 0x14, 0x95, + 0xd7, 0xc7, 0x5b, 0xd7, 0x5e, 0x09, 0x79, 0x6c, 0xb2, 0x8b, 0xef, 0x29, 0xf3, 0xe0, 0x9c, 0x09, + 0x1e, 0x83, 0x1a, 0x1f, 0xfc, 0x44, 0x87, 0xd2, 0xb1, 0x35, 0xe7, 0xc3, 0x6b, 0x87, 0x64, 0x6e, + 0x2d, 0xc2, 0xe4, 0xe4, 0xe9, 0x2f, 0x92, 0x32, 0x35, 0x1f, 0xff, 0x8e, 0xa1, 0xae, 0x1d, 0x6a, + 0x12, 0x6c, 0xc8, 0xe0, 0x8f, 0xc0, 0xe6, 0xd3, 0x20, 0x75, 0x3a, 0xe0, 0x5d, 0x98, 0x73, 0x29, + 0x0f, 0x33, 0x1e, 0x5c, 0x50, 0xc2, 0x2d, 0x50, 0x0b, 0xe2, 0x05, 0x4e, 0x98, 0xd3, 0xec, 0x59, + 0xfd, 0x86, 0x0f, 0x54, 0x0f, 0xfb, 0xda, 0x83, 0x4d, 0x04, 0xbe, 0x04, 0x75, 0x1e, 0x29, 0x31, + 0x84, 0xb3, 0xf9, 0x2e, 0x1d, 0xb4, 0x4c, 0x07, 0xf5, 0xc3, 0x94, 0x05, 0x67, 0x74, 0x5b, 0xff, + 0x54, 0xc1, 0xdd, 0xd2, 0x86, 0x12, 0x11, 0x67, 0x82, 0xbe, 0x97, 0x15, 0x75, 0x1f, 0xd4, 0xc9, + 0x74, 0xca, 0x4f, 0x68, 0xba, 0xa5, 0x1a, 0x45, 0x13, 0x7b, 0xa9, 0x1b, 0x67, 0x71, 0x78, 0x04, + 0x6a, 0x42, 0x12, 0x99, 0x08, 0xb3, 0x71, 0x1e, 0xdc, 0xec, 0x7a, 0x3d, 0xd7, 0x98, 0x54, 0x30, + 0x4c, 0x45, 0x32, 0x95, 0xd8, 0xf0, 0xc0, 0x2e, 0xd8, 0x88, 0x88, 0x1c, 0x8e, 0xf5, 0x56, 0xd9, + 0xf4, 0xed, 0xd5, 0xb2, 0xbb, 0x71, 0xa4, 0x1c, 0x38, 0xf5, 0xc3, 0x5d, 0x60, 0xeb, 0xc3, 0x8b, + 0x45, 0x94, 0x5d, 0x8c, 0x8e, 0x1a, 0xd1, 0x51, 0xe6, 0x3c, 0x2f, 0x1b, 0xb8, 0x48, 0x86, 0xbf, + 0x59, 0xa0, 0x4d, 0x92, 0x20, 0x94, 0x7b, 0x8c, 0x71, 0x49, 0xd2, 0xa9, 0xd4, 0x7a, 0xd5, 0x7e, + 0x73, 0xe7, 0x09, 0xba, 0xe6, 0x11, 0x44, 0x97, 0x24, 0x46, 0x7b, 0x17, 0x28, 0x9e, 0x32, 0x19, + 0x2f, 0x7c, 0xc7, 0x68, 0xd4, 0xbe, 0x18, 0xc6, 0x97, 0x6a, 0x76, 0xbe, 0x06, 0x1f, 0x5d, 0x49, + 0x02, 0xdb, 0xa0, 0x3a, 0xa1, 0x8b, 0x74, 0x7a, 0x58, 0x1d, 0xe1, 0x87, 0x60, 0x63, 0x4e, 0xa6, + 0x09, 0xd5, 0x93, 0xb0, 0x71, 0x6a, 0x3c, 0x5e, 0xdb, 0xb5, 0xb6, 0xfe, 0xb4, 0x40, 0xab, 0xd4, + 0xdc, 0x3c, 0xa4, 0x27, 0xf0, 0x08, 0xd4, 0xcd, 0x16, 0xd1, 0x1c, 0xcd, 0x9d, 0xfb, 0x37, 0xf9, + 0x5f, 0x1a, 0xe0, 0x37, 0xd5, 0x80, 0xb3, 0xed, 0x96, 0xd1, 0xa8, 0x0b, 0x1f, 0x9b, 0x3f, 0x6e, + 0x9e, 0xac, 0xcf, 0x6e, 0x2e, 0x95, 0xbf, 0x69, 0x1e, 0x10, 0x6d, 0xe1, 0x9c, 0xc9, 0xef, 0x9f, + 0x9e, 0xb9, 0x95, 0xd7, 0x67, 0x6e, 0xe5, 0xcd, 0x99, 0x5b, 0xf9, 0x75, 0xe5, 0x5a, 0xa7, 0x2b, + 0xd7, 0x7a, 0xbd, 0x72, 0xad, 0x37, 0x2b, 0xd7, 0xfa, 0x6b, 0xe5, 0x5a, 0xbf, 0xff, 0xed, 0x56, + 0x7e, 0x58, 0x9b, 0x6f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x37, 0xc7, 0x3f, 0x71, 0xdf, 0x08, + 0x00, 0x00, } func (m *AdmissionRequest) Marshal() (dAtA []byte, err error) { diff --git a/vendor/k8s.io/api/admission/v1beta1/generated.proto b/vendor/k8s.io/api/admission/v1/generated.proto similarity index 98% rename from vendor/k8s.io/api/admission/v1beta1/generated.proto rename to vendor/k8s.io/api/admission/v1/generated.proto index 6999b80c27a..8d960a17d32 100644 --- a/vendor/k8s.io/api/admission/v1beta1/generated.proto +++ b/vendor/k8s.io/api/admission/v1/generated.proto @@ -19,7 +19,7 @@ limitations under the License. syntax = 'proto2'; -package k8s.io.api.admission.v1beta1; +package k8s.io.api.admission.v1; import "k8s.io/api/authentication/v1/generated.proto"; import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; @@ -27,7 +27,7 @@ import "k8s.io/apimachinery/pkg/runtime/generated.proto"; import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". -option go_package = "v1beta1"; +option go_package = "v1"; // AdmissionRequest describes the admission.Attributes for the admission request. message AdmissionRequest { @@ -120,7 +120,7 @@ message AdmissionRequest { // AdmissionResponse describes an admission response. message AdmissionResponse { // UID is an identifier for the individual request/response. - // This should be copied over from the corresponding AdmissionRequest. + // This must be copied over from the corresponding AdmissionRequest. optional string uid = 1; // Allowed indicates whether or not the admission request was permitted. diff --git a/vendor/k8s.io/api/admission/v1beta1/register.go b/vendor/k8s.io/api/admission/v1/register.go similarity index 95% rename from vendor/k8s.io/api/admission/v1beta1/register.go rename to vendor/k8s.io/api/admission/v1/register.go index 78d21a0c8a7..b548509ab32 100644 --- a/vendor/k8s.io/api/admission/v1beta1/register.go +++ b/vendor/k8s.io/api/admission/v1/register.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2019 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1beta1 +package v1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,7 +26,7 @@ import ( const GroupName = "admission.k8s.io" // SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} // Resource takes an unqualified resource and returns a Group qualified GroupResource func Resource(resource string) schema.GroupResource { diff --git a/vendor/k8s.io/api/admission/v1beta1/types.go b/vendor/k8s.io/api/admission/v1/types.go similarity index 98% rename from vendor/k8s.io/api/admission/v1beta1/types.go rename to vendor/k8s.io/api/admission/v1/types.go index 2cb9ea55a38..a40cb0d52e2 100644 --- a/vendor/k8s.io/api/admission/v1beta1/types.go +++ b/vendor/k8s.io/api/admission/v1/types.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2019 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1beta1 +package v1 import ( authenticationv1 "k8s.io/api/authentication/v1" @@ -115,7 +115,7 @@ type AdmissionRequest struct { // AdmissionResponse describes an admission response. type AdmissionResponse struct { // UID is an identifier for the individual request/response. - // This should be copied over from the corresponding AdmissionRequest. + // This must be copied over from the corresponding AdmissionRequest. UID types.UID `json:"uid" protobuf:"bytes,1,opt,name=uid"` // Allowed indicates whether or not the admission request was permitted. diff --git a/vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go b/vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go similarity index 98% rename from vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go rename to vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go index 2ef98db8729..62351b16177 100644 --- a/vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go +++ b/vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1beta1 +package v1 // This file contains a collection of methods that can be used from go-restful to // generate Swagger API documentation for its models. Please read this PR for more @@ -52,7 +52,7 @@ func (AdmissionRequest) SwaggerDoc() map[string]string { var map_AdmissionResponse = map[string]string{ "": "AdmissionResponse describes an admission response.", - "uid": "UID is an identifier for the individual request/response. This should be copied over from the corresponding AdmissionRequest.", + "uid": "UID is an identifier for the individual request/response. This must be copied over from the corresponding AdmissionRequest.", "allowed": "Allowed indicates whether or not the admission request was permitted.", "status": "Result contains extra details into why an admission request was denied. This field IS NOT consulted in any way if \"Allowed\" is \"true\".", "patch": "The patch body. Currently we only support \"JSONPatch\" which implements RFC 6902.", diff --git a/vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go b/vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go similarity index 95% rename from vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go rename to vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go index e4704c86dd3..42954ca4272 100644 --- a/vendor/k8s.io/api/admission/v1beta1/zz_generated.deepcopy.go +++ b/vendor/k8s.io/api/admission/v1/zz_generated.deepcopy.go @@ -18,10 +18,10 @@ limitations under the License. // Code generated by deepcopy-gen. DO NOT EDIT. -package v1beta1 +package v1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -32,12 +32,12 @@ func (in *AdmissionRequest) DeepCopyInto(out *AdmissionRequest) { out.Resource = in.Resource if in.RequestKind != nil { in, out := &in.RequestKind, &out.RequestKind - *out = new(v1.GroupVersionKind) + *out = new(metav1.GroupVersionKind) **out = **in } if in.RequestResource != nil { in, out := &in.RequestResource, &out.RequestResource - *out = new(v1.GroupVersionResource) + *out = new(metav1.GroupVersionResource) **out = **in } in.UserInfo.DeepCopyInto(&out.UserInfo) @@ -67,7 +67,7 @@ func (in *AdmissionResponse) DeepCopyInto(out *AdmissionResponse) { *out = *in if in.Result != nil { in, out := &in.Result, &out.Result - *out = new(v1.Status) + *out = new(metav1.Status) (*in).DeepCopyInto(*out) } if in.Patch != nil { diff --git a/vendor/knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1/customresourcedefinition/customresourcedefinition.go b/vendor/knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1/customresourcedefinition/customresourcedefinition.go new file mode 100644 index 00000000000..9c7757d3e46 --- /dev/null +++ b/vendor/knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1/customresourcedefinition/customresourcedefinition.go @@ -0,0 +1,52 @@ +/* +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 customresourcedefinition + +import ( + context "context" + + v1 "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1" + factory "knative.dev/pkg/client/injection/apiextensions/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Apiextensions().V1().CustomResourceDefinitions() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.CustomResourceDefinitionInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1.CustomResourceDefinitionInformer from context.") + } + return untyped.(v1.CustomResourceDefinitionInformer) +} diff --git a/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go b/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go similarity index 79% rename from vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go rename to vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go index 452bd44e210..27b95afa696 100644 --- a/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go +++ b/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration/mutatingwebhookconfiguration.go @@ -21,7 +21,7 @@ package mutatingwebhookconfiguration import ( context "context" - v1beta1 "k8s.io/client-go/informers/admissionregistration/v1beta1" + v1 "k8s.io/client-go/informers/admissionregistration/v1" factory "knative.dev/pkg/client/injection/kube/informers/factory" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" @@ -37,16 +37,16 @@ type Key struct{} func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := factory.Get(ctx) - inf := f.Admissionregistration().V1beta1().MutatingWebhookConfigurations() + inf := f.Admissionregistration().V1().MutatingWebhookConfigurations() return context.WithValue(ctx, Key{}, inf), inf.Informer() } // Get extracts the typed informer from the context. -func Get(ctx context.Context) v1beta1.MutatingWebhookConfigurationInformer { +func Get(ctx context.Context) v1.MutatingWebhookConfigurationInformer { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( - "Unable to fetch k8s.io/client-go/informers/admissionregistration/v1beta1.MutatingWebhookConfigurationInformer from context.") + "Unable to fetch k8s.io/client-go/informers/admissionregistration/v1.MutatingWebhookConfigurationInformer from context.") } - return untyped.(v1beta1.MutatingWebhookConfigurationInformer) + return untyped.(v1.MutatingWebhookConfigurationInformer) } diff --git a/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration/validatingwebhookconfiguration.go b/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration/validatingwebhookconfiguration.go similarity index 79% rename from vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration/validatingwebhookconfiguration.go rename to vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration/validatingwebhookconfiguration.go index 5ebe7b710ab..7cc5ac316ea 100644 --- a/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration/validatingwebhookconfiguration.go +++ b/vendor/knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration/validatingwebhookconfiguration.go @@ -21,7 +21,7 @@ package validatingwebhookconfiguration import ( context "context" - v1beta1 "k8s.io/client-go/informers/admissionregistration/v1beta1" + v1 "k8s.io/client-go/informers/admissionregistration/v1" factory "knative.dev/pkg/client/injection/kube/informers/factory" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" @@ -37,16 +37,16 @@ type Key struct{} func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := factory.Get(ctx) - inf := f.Admissionregistration().V1beta1().ValidatingWebhookConfigurations() + inf := f.Admissionregistration().V1().ValidatingWebhookConfigurations() return context.WithValue(ctx, Key{}, inf), inf.Informer() } // Get extracts the typed informer from the context. -func Get(ctx context.Context) v1beta1.ValidatingWebhookConfigurationInformer { +func Get(ctx context.Context) v1.ValidatingWebhookConfigurationInformer { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( - "Unable to fetch k8s.io/client-go/informers/admissionregistration/v1beta1.ValidatingWebhookConfigurationInformer from context.") + "Unable to fetch k8s.io/client-go/informers/admissionregistration/v1.ValidatingWebhookConfigurationInformer from context.") } - return untyped.(v1beta1.ValidatingWebhookConfigurationInformer) + return untyped.(v1.ValidatingWebhookConfigurationInformer) } diff --git a/vendor/knative.dev/pkg/client/injection/kube/reconciler/core/v1/namespace/reconciler.go b/vendor/knative.dev/pkg/client/injection/kube/reconciler/core/v1/namespace/reconciler.go index 4b7c037e310..00c761a1d76 100644 --- a/vendor/knative.dev/pkg/client/injection/kube/reconciler/core/v1/namespace/reconciler.go +++ b/vendor/knative.dev/pkg/client/injection/kube/reconciler/core/v1/namespace/reconciler.go @@ -21,6 +21,7 @@ package namespace import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -160,7 +161,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return fmt.Errorf("failed to set finalizers: %w", err) } // Reconcile this copy of the resource and then write back any status @@ -175,7 +176,7 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } } diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go index 8b4d0c73318..df4d595ab24 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/reconciler_reconciler.go @@ -147,6 +147,7 @@ func (g *reconcilerReconcilerGenerator) GenerateType(c *generator.Context, t *ty Package: "context", Name: "Context", }), + "fmtErrorf": c.Universe.Package("fmt").Function("Errorf"), "reflectDeepEqual": c.Universe.Package("reflect").Function("DeepEqual"), "equalitySemantic": c.Universe.Package("k8s.io/apimachinery/pkg/api/equality").Variable("Semantic"), "jsonMarshal": c.Universe.Package("encoding/json").Function("Marshal"), @@ -308,7 +309,7 @@ func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) erro // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) + return {{.fmtErrorf|raw}}("failed to set finalizers: %w", err) } {{if .isKRShaped}} @@ -330,7 +331,7 @@ func (r *reconcilerImpl) Reconcile(ctx {{.contextContext|raw}}, key string) erro // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return {{.fmtErrorf|raw}}("failed to clear finalizers: %w", err) } } diff --git a/vendor/knative.dev/pkg/hack/update-codegen.sh b/vendor/knative.dev/pkg/hack/update-codegen.sh index d049c42cbc2..1337f811001 100644 --- a/vendor/knative.dev/pkg/hack/update-codegen.sh +++ b/vendor/knative.dev/pkg/hack/update-codegen.sh @@ -41,7 +41,7 @@ EXTERNAL_INFORMER_PKG="k8s.io/client-go/informers" \ ${REPO_ROOT_DIR}/hack/generate-knative.sh "injection" \ k8s.io/client-go \ k8s.io/api \ - "admissionregistration:v1beta1 apps:v1 autoscaling:v1,v2beta1 batch:v1,v1beta1 core:v1 rbac:v1" \ + "admissionregistration:v1beta1,v1 apps:v1 autoscaling:v1,v2beta1 batch:v1,v1beta1 core:v1 rbac:v1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ --force-genreconciler-kinds "Namespace" @@ -50,7 +50,7 @@ VERSIONED_CLIENTSET_PKG="k8s.io/apiextensions-apiserver/pkg/client/clientset/cli ${REPO_ROOT_DIR}/hack/generate-knative.sh "injection" \ k8s.io/apiextensions-apiserver/pkg/client \ k8s.io/apiextensions-apiserver/pkg/apis \ - "apiextensions:v1beta1" \ + "apiextensions:v1beta1,v1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ --force-genreconciler-kinds "CustomResourceDefinition" diff --git a/vendor/knative.dev/pkg/injection/sharedmain/main.go b/vendor/knative.dev/pkg/injection/sharedmain/main.go index 5c2ba94a36c..fdc910ef034 100644 --- a/vendor/knative.dev/pkg/injection/sharedmain/main.go +++ b/vendor/knative.dev/pkg/injection/sharedmain/main.go @@ -232,6 +232,18 @@ func WebhookMainWithConfig(ctx context.Context, component string, cfg *rest.Conf CheckK8sClientMinimumVersionOrDie(ctx, logger) cmw := SetupConfigMapWatchOrDie(ctx, logger) + + // Set up leader election config + leaderElectionConfig, err := GetLeaderElectionConfig(ctx) + if err != nil { + logger.Fatalf("Error loading leader election configuration: %v", err) + } + leConfig := leaderElectionConfig.GetComponentConfig(component) + if leConfig.LeaderElect { + // Signal that we are executing in a context with leader election. + ctx = kle.WithStandardLeaderElectorBuilder(ctx, kubeclient.Get(ctx), leConfig) + } + controllers, webhooks := ControllersAndWebhooksFromCtors(ctx, cmw, ctors...) WatchLoggingConfigOrDie(ctx, cmw, logger, atomicLevel, component) WatchObservabilityConfigOrDie(ctx, cmw, profilingHandler, logger, component) @@ -242,7 +254,6 @@ func WebhookMainWithConfig(ctx context.Context, component string, cfg *rest.Conf // If we have one or more admission controllers, then start the webhook // and pass them in. var wh *webhook.Webhook - var err error if len(webhooks) > 0 { // Register webhook metrics webhook.RegisterMetrics() diff --git a/vendor/knative.dev/pkg/webhook/admission.go b/vendor/knative.dev/pkg/webhook/admission.go index da9c5263111..086f39dab14 100644 --- a/vendor/knative.dev/pkg/webhook/admission.go +++ b/vendor/knative.dev/pkg/webhook/admission.go @@ -24,7 +24,7 @@ import ( "time" "go.uber.org/zap" - admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionv1 "k8s.io/api/admission/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "knative.dev/pkg/logging" "knative.dev/pkg/logging/logkey" @@ -36,7 +36,7 @@ type AdmissionController interface { Path() string // Admit is the callback which is invoked when an HTTPS request comes in on Path(). - Admit(context.Context, *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse + Admit(context.Context, *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse } // StatelessAdmissionController is implemented by AdmissionControllers where Admit may be safely @@ -48,9 +48,9 @@ type StatelessAdmissionController interface { } // MakeErrorStatus creates an 'BadRequest' error AdmissionResponse -func MakeErrorStatus(reason string, args ...interface{}) *admissionv1beta1.AdmissionResponse { +func MakeErrorStatus(reason string, args ...interface{}) *admissionv1.AdmissionResponse { result := apierrors.NewBadRequest(fmt.Sprintf(reason, args...)).Status() - return &admissionv1beta1.AdmissionResponse{ + return &admissionv1.AdmissionResponse{ Result: &result, Allowed: false, } @@ -71,7 +71,7 @@ func admissionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c Admi logger := rootLogger logger.Infof("Webhook ServeHTTP request=%#v", r) - var review admissionv1beta1.AdmissionReview + var review admissionv1.AdmissionReview if err := json.NewDecoder(r.Body).Decode(&review); err != nil { http.Error(w, fmt.Sprintf("could not decode body: %v", err), http.StatusBadRequest) return @@ -88,7 +88,7 @@ func admissionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c Admi ctx := logging.WithLogger(r.Context(), logger) - var response admissionv1beta1.AdmissionReview + var response admissionv1.AdmissionReview reviewResponse := c.Admit(ctx, review.Request) var patchType string if reviewResponse.PatchType != nil { diff --git a/vendor/knative.dev/pkg/webhook/certificates/certificates.go b/vendor/knative.dev/pkg/webhook/certificates/certificates.go index 275bec9e396..5e698d762b3 100644 --- a/vendor/knative.dev/pkg/webhook/certificates/certificates.go +++ b/vendor/knative.dev/pkg/webhook/certificates/certificates.go @@ -23,11 +23,12 @@ import ( "time" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/controller" "knative.dev/pkg/logging" - "knative.dev/pkg/system" + pkgreconciler "knative.dev/pkg/reconciler" certresources "knative.dev/pkg/webhook/certificates/resources" ) @@ -37,39 +38,46 @@ const ( ) type reconciler struct { + pkgreconciler.LeaderAwareFuncs + client kubernetes.Interface secretlister corelisters.SecretLister - secretName string + key types.NamespacedName serviceName string } var _ controller.Reconciler = (*reconciler)(nil) +var _ pkgreconciler.LeaderAware = (*reconciler)(nil) // Reconcile implements controller.Reconciler func (r *reconciler) Reconcile(ctx context.Context, key string) error { - return r.reconcileCertificate(ctx) + if r.IsLeaderFor(r.key) { + // only reconciler the certificate when we are leader. + return r.reconcileCertificate(ctx) + } + return nil } func (r *reconciler) reconcileCertificate(ctx context.Context) error { logger := logging.FromContext(ctx) - secret, err := r.secretlister.Secrets(system.Namespace()).Get(r.secretName) + secret, err := r.secretlister.Secrets(r.key.Namespace).Get(r.key.Name) if apierrors.IsNotFound(err) { // The secret should be created explicitly by a higher-level system // that's responsible for install/updates. We simply populate the // secret information. return nil } else if err != nil { - logger.Errorf("Error accessing certificate secret %q: %v", r.secretName, err) + logger.Errorf("Error accessing certificate secret %q: %v", r.key.Name, err) return err } if _, haskey := secret.Data[certresources.ServerKey]; !haskey { - logger.Infof("Certificate secret %q is missing key %q", r.secretName, certresources.ServerKey) + logger.Infof("Certificate secret %q is missing key %q", r.key.Name, certresources.ServerKey) } else if _, haskey := secret.Data[certresources.ServerCert]; !haskey { - logger.Infof("Certificate secret %q is missing key %q", r.secretName, certresources.ServerCert) + logger.Infof("Certificate secret %q is missing key %q", r.key.Name, certresources.ServerCert) } else if _, haskey := secret.Data[certresources.CACert]; !haskey { - logger.Infof("Certificate secret %q is missing key %q", r.secretName, certresources.CACert) + logger.Infof("Certificate secret %q is missing key %q", r.key.Name, certresources.CACert) } else { // Check the expiration date of the certificate to see if it needs to be updated cert, err := tls.X509KeyPair(secret.Data[certresources.ServerCert], secret.Data[certresources.ServerKey]) @@ -88,7 +96,7 @@ func (r *reconciler) reconcileCertificate(ctx context.Context) error { secret = secret.DeepCopy() // One of the secret's keys is missing, so synthesize a new one and update the secret. - newSecret, err := certresources.MakeSecret(ctx, r.secretName, system.Namespace(), r.serviceName) + newSecret, err := certresources.MakeSecret(ctx, r.key.Name, r.key.Namespace, r.serviceName) if err != nil { return err } diff --git a/vendor/knative.dev/pkg/webhook/certificates/controller.go b/vendor/knative.dev/pkg/webhook/certificates/controller.go index b8f40811113..a50acb39abc 100644 --- a/vendor/knative.dev/pkg/webhook/certificates/controller.go +++ b/vendor/knative.dev/pkg/webhook/certificates/controller.go @@ -23,10 +23,12 @@ import ( kubeclient "knative.dev/pkg/client/injection/kube/client" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/cache" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" ) @@ -44,20 +46,31 @@ func NewController( secretInformer := secretinformer.Get(ctx) options := webhook.GetOptions(ctx) + key := types.NamespacedName{ + Namespace: system.Namespace(), + Name: options.SecretName, + } + wh := &reconciler{ - secretName: options.SecretName, + LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ + // Enqueue the key whenever we become leader. + PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { + enq(bkt, key) + return nil + }, + }, + key: key, serviceName: options.ServiceName, client: client, secretlister: secretInformer.Lister(), } - logger := logging.FromContext(ctx) - c := controller.NewImpl(wh, logger, "WebhookCertificates") + c := controller.NewImpl(wh, logging.FromContext(ctx), "WebhookCertificates") // Reconcile when the cert bundle changes. secretInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ - FilterFunc: controller.FilterWithNameAndNamespace(system.Namespace(), wh.secretName), + FilterFunc: controller.FilterWithNameAndNamespace(key.Namespace, key.Name), // It doesn't matter what we enqueue because we will always Reconcile // the named MWH resource. Handler: controller.HandleAll(c.Enqueue), diff --git a/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go b/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go index 62d213eb372..c2e7da0e6b1 100644 --- a/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go +++ b/vendor/knative.dev/pkg/webhook/configmaps/configmaps.go @@ -24,12 +24,13 @@ import ( "fmt" "reflect" - admissionv1beta1 "k8s.io/api/admission/v1beta1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + admissionv1 "k8s.io/api/admission/v1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - admissionlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" + admissionlisters "k8s.io/client-go/listers/admissionregistration/v1" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/configmap" @@ -37,6 +38,7 @@ import ( "knative.dev/pkg/kmp" "knative.dev/pkg/logging" "knative.dev/pkg/ptr" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" certresources "knative.dev/pkg/webhook/certificates/resources" @@ -45,8 +47,9 @@ import ( // reconciler implements the AdmissionController for ConfigMaps type reconciler struct { webhook.StatelessAdmissionImpl + pkgreconciler.LeaderAwareFuncs - name string + key types.NamespacedName path string constructors map[string]reflect.Value @@ -58,6 +61,7 @@ type reconciler struct { } var _ controller.Reconciler = (*reconciler)(nil) +var _ pkgreconciler.LeaderAware = (*reconciler)(nil) var _ webhook.AdmissionController = (*reconciler)(nil) var _ webhook.StatelessAdmissionController = (*reconciler)(nil) @@ -65,6 +69,11 @@ var _ webhook.StatelessAdmissionController = (*reconciler)(nil) func (ac *reconciler) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) + if !ac.IsLeaderFor(ac.key) { + logger.Debugf("Skipping key %q, not the leader.", ac.key) + return nil + } + secret, err := ac.secretlister.Secrets(system.Namespace()).Get(ac.secretName) if err != nil { logger.Errorf("Error fetching secret: %v", err) @@ -85,20 +94,20 @@ func (ac *reconciler) Path() string { } // Admit implements AdmissionController -func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse { +func (ac *reconciler) Admit(ctx context.Context, request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse { logger := logging.FromContext(ctx) switch request.Operation { - case admissionv1beta1.Create, admissionv1beta1.Update: + case admissionv1.Create, admissionv1.Update: default: logger.Infof("Unhandled webhook operation, letting it through %v", request.Operation) - return &admissionv1beta1.AdmissionResponse{Allowed: true} + return &admissionv1.AdmissionResponse{Allowed: true} } if err := ac.validate(ctx, request); err != nil { return webhook.MakeErrorStatus("validation failed: %v", err) } - return &admissionv1beta1.AdmissionResponse{ + return &admissionv1.AdmissionResponse{ Allowed: true, } } @@ -106,13 +115,13 @@ func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.Admis func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []byte) error { logger := logging.FromContext(ctx) - ruleScope := admissionregistrationv1beta1.NamespacedScope - rules := []admissionregistrationv1beta1.RuleWithOperations{{ - Operations: []admissionregistrationv1beta1.OperationType{ - admissionregistrationv1beta1.Create, - admissionregistrationv1beta1.Update, + ruleScope := admissionregistrationv1.NamespacedScope + rules := []admissionregistrationv1.RuleWithOperations{{ + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, }, - Rule: admissionregistrationv1beta1.Rule{ + Rule: admissionregistrationv1.Rule{ APIGroups: []string{""}, APIVersions: []string{"v1"}, Resources: []string{"configmaps/*"}, @@ -120,7 +129,7 @@ func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []b }, }} - configuredWebhook, err := ac.vwhlister.Get(ac.name) + configuredWebhook, err := ac.vwhlister.Get(ac.key.Name) if err != nil { return fmt.Errorf("error retrieving webhook: %w", err) } @@ -147,7 +156,7 @@ func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []b return fmt.Errorf("error diffing webhooks: %w", err) } else if !ok { logger.Info("Updating webhook") - vwhclient := ac.client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations() + vwhclient := ac.client.AdmissionregistrationV1().ValidatingWebhookConfigurations() if _, err := vwhclient.Update(webhook); err != nil { return fmt.Errorf("failed to update webhook: %w", err) } @@ -158,7 +167,7 @@ func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []b return nil } -func (ac *reconciler) validate(ctx context.Context, req *admissionv1beta1.AdmissionRequest) error { +func (ac *reconciler) validate(ctx context.Context, req *admissionv1.AdmissionRequest) error { logger := logging.FromContext(ctx) kind := req.Kind newBytes := req.Object.Raw diff --git a/vendor/knative.dev/pkg/webhook/configmaps/controller.go b/vendor/knative.dev/pkg/webhook/configmaps/controller.go index 1e62f58ecb8..895d07af72d 100644 --- a/vendor/knative.dev/pkg/webhook/configmaps/controller.go +++ b/vendor/knative.dev/pkg/webhook/configmaps/controller.go @@ -22,13 +22,15 @@ import ( // Injection stuff kubeclient "knative.dev/pkg/client/injection/kube/client" - vwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration" + vwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" + "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/cache" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" - "knative.dev/pkg/logging" "knative.dev/pkg/system" "knative.dev/pkg/webhook" ) @@ -45,8 +47,18 @@ func NewAdmissionController( secretInformer := secretinformer.Get(ctx) options := webhook.GetOptions(ctx) + key := types.NamespacedName{Name: name} + wh := &reconciler{ - name: name, + LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ + // Have this reconciler enqueue our singleton whenever it becomes leader. + PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { + enq(bkt, key) + return nil + }, + }, + + key: key, path: path, constructors: make(map[string]reflect.Value), @@ -61,8 +73,7 @@ func NewAdmissionController( wh.registerConfig(configName, constructor) } - logger := logging.FromContext(ctx) - c := controller.NewImpl(wh, logger, "ConfigMapWebhook") + c := controller.NewImpl(wh, logging.FromContext(ctx), "ConfigMapWebhook") // Reconcile when the named ValidatingWebhookConfiguration changes. vwhInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ diff --git a/vendor/knative.dev/pkg/webhook/conversion.go b/vendor/knative.dev/pkg/webhook/conversion.go index 59575c34f76..146ac259f95 100644 --- a/vendor/knative.dev/pkg/webhook/conversion.go +++ b/vendor/knative.dev/pkg/webhook/conversion.go @@ -23,7 +23,7 @@ import ( "net/http" "go.uber.org/zap" - apixv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "knative.dev/pkg/logging" ) @@ -33,7 +33,7 @@ type ConversionController interface { Path() string // Convert is the callback which is invoked when an HTTPS request comes in on Path(). - Convert(context.Context, *apixv1beta1.ConversionRequest) *apixv1beta1.ConversionResponse + Convert(context.Context, *apixv1.ConversionRequest) *apixv1.ConversionResponse } func conversionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c ConversionController) http.HandlerFunc { @@ -41,7 +41,7 @@ func conversionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c Con logger := rootLogger logger.Infof("Webhook ServeHTTP request=%#v", r) - var review apixv1beta1.ConversionReview + var review apixv1.ConversionReview if err := json.NewDecoder(r.Body).Decode(&review); err != nil { http.Error(w, fmt.Sprintf("could not decode body: %v", err), http.StatusBadRequest) return @@ -53,7 +53,7 @@ func conversionHandler(rootLogger *zap.SugaredLogger, stats StatsReporter, c Con ) ctx := logging.WithLogger(r.Context(), logger) - response := apixv1beta1.ConversionReview{ + response := apixv1.ConversionReview{ Response: c.Convert(ctx, review.Request), } diff --git a/vendor/knative.dev/pkg/webhook/psbinding/controller.go b/vendor/knative.dev/pkg/webhook/psbinding/controller.go index 76238d28b54..3967c053b18 100644 --- a/vendor/knative.dev/pkg/webhook/psbinding/controller.go +++ b/vendor/knative.dev/pkg/webhook/psbinding/controller.go @@ -21,7 +21,7 @@ import ( // Injection stuff kubeclient "knative.dev/pkg/client/injection/kube/client" - mwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration" + mwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" "k8s.io/apimachinery/pkg/types" @@ -30,6 +30,7 @@ import ( duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/controller" "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" ) @@ -66,6 +67,8 @@ type GetListAll func(context.Context, cache.ResourceEventHandler) ListAll // to NewAdmissionController and BaseReconciler. type BindableContext func(context.Context, Bindable) (context.Context, error) +var sentinel = types.NamespacedName{} + // NewAdmissionController constructs the webhook portion of the pair of // reconcilers that implement the semantics of our Binding. func NewAdmissionController( @@ -86,9 +89,15 @@ func NewAdmissionController( wh := NewReconciler(name, path, options.SecretName, client, mwhInformer.Lister(), secretInformer.Lister(), withContext, reconcilerOptions...) c := controller.NewImpl(wh, logging.FromContext(ctx), name) + // Enqueue a sentinel when we become leader. + wh.PromoteFunc = func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { + enq(bkt, sentinel) + return nil + } + // It doesn't matter what we enqueue because we will always Reconcile // the named MWH resource. - handler := controller.HandleAll(c.EnqueueSentinel(types.NamespacedName{})) + handler := controller.HandleAll(c.EnqueueSentinel(sentinel)) // Reconcile when the named MutatingWebhookConfiguration changes. mwhInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ diff --git a/vendor/knative.dev/pkg/webhook/psbinding/psbinding.go b/vendor/knative.dev/pkg/webhook/psbinding/psbinding.go index ce0fb7f963d..0b89705c7e0 100644 --- a/vendor/knative.dev/pkg/webhook/psbinding/psbinding.go +++ b/vendor/knative.dev/pkg/webhook/psbinding/psbinding.go @@ -26,21 +26,22 @@ import ( "sync" "github.com/markbates/inflect" - admissionv1beta1 "k8s.io/api/admission/v1beta1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + admissionv1 "k8s.io/api/admission/v1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/kubernetes" - admissionlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" + admissionlisters "k8s.io/client-go/listers/admissionregistration/v1" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/apis/duck" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/controller" "knative.dev/pkg/logging" "knative.dev/pkg/ptr" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" certresources "knative.dev/pkg/webhook/certificates/resources" @@ -97,6 +98,8 @@ func NewReconciler( // 2. Admit: which leverages the index built by the Reconciler to apply // mutations to resources. type Reconciler struct { + pkgreconciler.LeaderAwareFuncs + Name string HandlerPath string SecretName string @@ -120,6 +123,7 @@ type Reconciler struct { } var _ controller.Reconciler = (*Reconciler)(nil) +var _ pkgreconciler.LeaderAware = (*Reconciler)(nil) var _ webhook.AdmissionController = (*Reconciler)(nil) // We need to specifically exclude our deployment(s) from consideration, but this provides a way @@ -168,12 +172,12 @@ func (ac *Reconciler) Path() string { } // Admit implements AdmissionController -func (ac *Reconciler) Admit(ctx context.Context, request *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse { +func (ac *Reconciler) Admit(ctx context.Context, request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse { switch request.Operation { - case admissionv1beta1.Create, admissionv1beta1.Update: + case admissionv1.Create, admissionv1.Update: default: logging.FromContext(ctx).Infof("Unhandled webhook operation, letting it through %v", request.Operation) - return &admissionv1beta1.AdmissionResponse{Allowed: true} + return &admissionv1.AdmissionResponse{Allowed: true} } orig := &duckv1.WithPod{} @@ -209,7 +213,7 @@ func (ac *Reconciler) Admit(ctx context.Context, request *admissionv1beta1.Admis }() if fb == nil { // This doesn't apply! - return &admissionv1beta1.AdmissionResponse{Allowed: true} + return &admissionv1.AdmissionResponse{Allowed: true} } // Callback into the user's code to setup the context with additional @@ -235,11 +239,11 @@ func (ac *Reconciler) Admit(ctx context.Context, request *admissionv1beta1.Admis if err != nil { return webhook.MakeErrorStatus("unable to create patch with binding: %v", err) } - return &admissionv1beta1.AdmissionResponse{ + return &admissionv1.AdmissionResponse{ Patch: patchBytes, Allowed: true, - PatchType: func() *admissionv1beta1.PatchType { - pt := admissionv1beta1.PatchTypeJSONPatch + PatchType: func() *admissionv1.PatchType { + pt := admissionv1.PatchTypeJSONPatch return &pt }(), } @@ -302,16 +306,22 @@ func (ac *Reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt ac.inexact = inexact }() - rules := make([]admissionregistrationv1beta1.RuleWithOperations, 0, len(gks)) + // After we've updated our indices, bail out unless we are the leader. + // Only the leader should be mutating the webhook. + if !ac.IsLeaderFor(sentinel) { + return nil + } + + rules := make([]admissionregistrationv1.RuleWithOperations, 0, len(gks)) for gk, versions := range gks { plural := strings.ToLower(inflect.Pluralize(gk.Kind)) - rules = append(rules, admissionregistrationv1beta1.RuleWithOperations{ - Operations: []admissionregistrationv1beta1.OperationType{ - admissionregistrationv1beta1.Create, - admissionregistrationv1beta1.Update, + rules = append(rules, admissionregistrationv1.RuleWithOperations{ + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, }, - Rule: admissionregistrationv1beta1.Rule{ + Rule: admissionregistrationv1.Rule{ APIGroups: []string{gk.Group}, APIVersions: versions.List(), Resources: []string{plural + "/*"}, @@ -339,7 +349,7 @@ func (ac *Reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt // 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 := admissionregistrationv1beta1.Equivalent + matchPolicy := admissionregistrationv1.Equivalent for i, wh := range webhook.Webhooks { if wh.Name != webhook.Name { @@ -358,7 +368,7 @@ func (ac *Reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt if ok := equality.Semantic.DeepEqual(configuredWebhook, webhook); !ok { logging.FromContext(ctx).Info("Updating webhook") - mwhclient := ac.Client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations() + mwhclient := ac.Client.AdmissionregistrationV1().MutatingWebhookConfigurations() if _, err := mwhclient.Update(webhook); err != nil { return fmt.Errorf("failed to update webhook: %w", err) } diff --git a/vendor/knative.dev/pkg/webhook/psbinding/reconciler.go b/vendor/knative.dev/pkg/webhook/psbinding/reconciler.go index 28e2dd25894..eced30b4aeb 100644 --- a/vendor/knative.dev/pkg/webhook/psbinding/reconciler.go +++ b/vendor/knative.dev/pkg/webhook/psbinding/reconciler.go @@ -41,6 +41,7 @@ import ( "knative.dev/pkg/controller" "knative.dev/pkg/kmeta" "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/tracker" ) @@ -52,6 +53,8 @@ var jsonLabelPatch = map[string]interface{}{ // BaseReconciler helps implement controller.Reconciler for Binding resources. type BaseReconciler struct { + pkgreconciler.LeaderAwareFuncs + // The GVR of the "primary key" resource for this reconciler. // This is used along with the DynamicClient for updating the status // and managing finalizers of the resources being reconciled. @@ -89,6 +92,7 @@ type BaseReconciler struct { // Check that our Reconciler implements controller.Reconciler var _ controller.Reconciler = (*BaseReconciler)(nil) +var _ pkgreconciler.LeaderAware = (*BaseReconciler)(nil) // Reconcile implements controller.Reconciler func (r *BaseReconciler) Reconcile(ctx context.Context, key string) error { @@ -99,6 +103,15 @@ func (r *BaseReconciler) Reconcile(ctx context.Context, key string) error { return nil } + // Only the leader should reconcile binding resources. + if !r.IsLeaderFor(types.NamespacedName{ + Namespace: namespace, + Name: name, + }) { + logging.FromContext(ctx).Debugf("Skipping key %q, not the leader.", key) + return nil + } + // Get the resource with this namespace/name. original, err := r.Get(namespace, name) if apierrs.IsNotFound(err) { diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/controller.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/controller.go index 1d107aacf71..a53915a87ba 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/controller.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/controller.go @@ -25,10 +25,11 @@ import ( "k8s.io/client-go/tools/cache" "knative.dev/pkg/apis" apixclient "knative.dev/pkg/client/injection/apiextensions/client" - crdinformer "knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1beta1/customresourcedefinition" + crdinformer "knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1/customresourcedefinition" "knative.dev/pkg/controller" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" ) @@ -89,13 +90,23 @@ func NewConversionController( withContext func(context.Context) context.Context, ) *controller.Impl { - logger := logging.FromContext(ctx) secretInformer := secretinformer.Get(ctx) crdInformer := crdinformer.Get(ctx) client := apixclient.Get(ctx) options := webhook.GetOptions(ctx) r := &reconciler{ + LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ + // Have this reconciler enqueue our types whenever it becomes leader. + PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { + for _, gkc := range kinds { + name := gkc.DefinitionName + enq(bkt, types.NamespacedName{Name: name}) + } + return nil + }, + }, + kinds: kinds, path: path, secretName: options.SecretName, @@ -106,7 +117,7 @@ func NewConversionController( crdLister: crdInformer.Lister(), } - c := controller.NewImpl(r, logger, "ConversionWebhook") + c := controller.NewImpl(r, logging.FromContext(ctx), "ConversionWebhook") // Reconciler when the named CRDs change. for _, gkc := range kinds { diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/conversion.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/conversion.go index 3fab95bad02..5fa7beb9f1d 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/conversion.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/conversion.go @@ -23,7 +23,7 @@ import ( "go.uber.org/zap" - apixv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -37,14 +37,14 @@ import ( // Convert implements webhook.ConversionController func (r *reconciler) Convert( ctx context.Context, - req *apixv1beta1.ConversionRequest, -) *apixv1beta1.ConversionResponse { + req *apixv1.ConversionRequest, +) *apixv1.ConversionResponse { if r.withContext != nil { ctx = r.withContext(ctx) } - res := &apixv1beta1.ConversionResponse{ + res := &apixv1.ConversionResponse{ UID: req.UID, Result: metav1.Status{ Status: metav1.StatusSuccess, diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/reconciler.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/reconciler.go index ab8944620b2..e2709ee8003 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/reconciler.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/conversion/reconciler.go @@ -20,21 +20,25 @@ import ( "context" "fmt" - apixv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apixv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apixclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - apixlisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1" + apixlisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/controller" "knative.dev/pkg/kmp" "knative.dev/pkg/logging" "knative.dev/pkg/ptr" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" certresources "knative.dev/pkg/webhook/certificates/resources" ) type reconciler struct { + pkgreconciler.LeaderAwareFuncs + kinds map[schema.GroupKind]GroupKindConversion path string secretName string @@ -47,6 +51,7 @@ type reconciler struct { var _ webhook.ConversionController = (*reconciler)(nil) var _ controller.Reconciler = (*reconciler)(nil) +var _ pkgreconciler.LeaderAware = (*reconciler)(nil) // Path implements webhook.ConversionController func (r *reconciler) Path() string { @@ -57,6 +62,11 @@ func (r *reconciler) Path() string { func (r *reconciler) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) + if !r.IsLeaderFor(types.NamespacedName{Name: key}) { + logger.Debugf("Skipping key %q, not the leader.", key) + return nil + } + // Look up the webhook secret, and fetch the CA cert bundle. secret, err := r.secretLister.Secrets(system.Namespace()).Get(r.secretName) if err != nil { @@ -83,20 +93,20 @@ func (r *reconciler) reconcileCRD(ctx context.Context, cacert []byte, key string crd := configuredCRD.DeepCopy() if crd.Spec.Conversion == nil || - crd.Spec.Conversion.Strategy != apixv1beta1.WebhookConverter || - crd.Spec.Conversion.WebhookClientConfig == nil || - crd.Spec.Conversion.WebhookClientConfig.Service == nil { + crd.Spec.Conversion.Strategy != apixv1.WebhookConverter || + crd.Spec.Conversion.Webhook.ClientConfig == nil || + crd.Spec.Conversion.Webhook.ClientConfig.Service == nil { return fmt.Errorf("custom resource %q isn't configured for webhook conversion", key) } - crd.Spec.Conversion.WebhookClientConfig.CABundle = cacert - crd.Spec.Conversion.WebhookClientConfig.Service.Path = ptr.String(r.path) + crd.Spec.Conversion.Webhook.ClientConfig.CABundle = cacert + crd.Spec.Conversion.Webhook.ClientConfig.Service.Path = ptr.String(r.path) if ok, err := kmp.SafeEqual(configuredCRD, crd); err != nil { return fmt.Errorf("error diffing custom resource definitions: %w", err) } else if !ok { logger.Infof("updating CRD") - crdClient := r.client.ApiextensionsV1beta1().CustomResourceDefinitions() + crdClient := r.client.ApiextensionsV1().CustomResourceDefinitions() if _, err := crdClient.Update(crd); err != nil { return fmt.Errorf("failed to update webhook: %w", err) } diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go index 8d99732b52b..b331405880e 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go @@ -21,13 +21,15 @@ import ( // Injection stuff kubeclient "knative.dev/pkg/client/injection/kube/client" - mwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration" + mwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" + "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/cache" "knative.dev/pkg/controller" - "knative.dev/pkg/logging" "knative.dev/pkg/system" "knative.dev/pkg/webhook" "knative.dev/pkg/webhook/resourcesemantics" @@ -47,8 +49,18 @@ func NewAdmissionController( secretInformer := secretinformer.Get(ctx) options := webhook.GetOptions(ctx) + key := types.NamespacedName{Name: name} + wh := &reconciler{ - name: name, + LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ + // Have this reconciler enqueue our singleton whenever it becomes leader. + PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { + enq(bkt, key) + return nil + }, + }, + + key: key, path: path, handlers: handlers, diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go index d84e6ed9c8b..80d1dcc9adf 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go @@ -28,12 +28,13 @@ import ( "github.com/markbates/inflect" "go.uber.org/zap" jsonpatch "gomodules.xyz/jsonpatch/v2" - admissionv1beta1 "k8s.io/api/admission/v1beta1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + admissionv1 "k8s.io/api/admission/v1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - admissionlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" + admissionlisters "k8s.io/client-go/listers/admissionregistration/v1" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/apis" "knative.dev/pkg/apis/duck" @@ -41,6 +42,7 @@ import ( "knative.dev/pkg/kmp" "knative.dev/pkg/logging" "knative.dev/pkg/ptr" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" certresources "knative.dev/pkg/webhook/certificates/resources" @@ -52,8 +54,9 @@ var errMissingNewObject = errors.New("the new object may not be nil") // reconciler implements the AdmissionController for resources type reconciler struct { webhook.StatelessAdmissionImpl + pkgreconciler.LeaderAwareFuncs - name string + key types.NamespacedName path string handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD @@ -68,6 +71,7 @@ type reconciler struct { } var _ controller.Reconciler = (*reconciler)(nil) +var _ pkgreconciler.LeaderAware = (*reconciler)(nil) var _ webhook.AdmissionController = (*reconciler)(nil) var _ webhook.StatelessAdmissionController = (*reconciler)(nil) @@ -75,6 +79,11 @@ var _ webhook.StatelessAdmissionController = (*reconciler)(nil) func (ac *reconciler) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) + if !ac.IsLeaderFor(ac.key) { + logger.Debugf("Skipping key %q, not the leader.", ac.key) + return nil + } + // Look up the webhook secret, and fetch the CA cert bundle. secret, err := ac.secretlister.Secrets(system.Namespace()).Get(ac.secretName) if err != nil { @@ -96,17 +105,17 @@ func (ac *reconciler) Path() string { } // Admit implements AdmissionController -func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse { +func (ac *reconciler) Admit(ctx context.Context, request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse { if ac.withContext != nil { ctx = ac.withContext(ctx) } logger := logging.FromContext(ctx) switch request.Operation { - case admissionv1beta1.Create, admissionv1beta1.Update: + case admissionv1.Create, admissionv1.Update: default: logger.Infof("Unhandled webhook operation, letting it through %v", request.Operation) - return &admissionv1beta1.AdmissionResponse{Allowed: true} + return &admissionv1.AdmissionResponse{Allowed: true} } patchBytes, err := ac.mutate(ctx, request) @@ -115,11 +124,11 @@ func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.Admis } logger.Infof("Kind: %q PatchBytes: %v", request.Kind, string(patchBytes)) - return &admissionv1beta1.AdmissionResponse{ + return &admissionv1.AdmissionResponse{ Patch: patchBytes, Allowed: true, - PatchType: func() *admissionv1beta1.PatchType { - pt := admissionv1beta1.PatchTypeJSONPatch + PatchType: func() *admissionv1.PatchType { + pt := admissionv1.PatchTypeJSONPatch return &pt }(), } @@ -128,16 +137,16 @@ func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.Admis func (ac *reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byte) error { logger := logging.FromContext(ctx) - rules := make([]admissionregistrationv1beta1.RuleWithOperations, 0, len(ac.handlers)) + rules := make([]admissionregistrationv1.RuleWithOperations, 0, len(ac.handlers)) for gvk := range ac.handlers { plural := strings.ToLower(inflect.Pluralize(gvk.Kind)) - rules = append(rules, admissionregistrationv1beta1.RuleWithOperations{ - Operations: []admissionregistrationv1beta1.OperationType{ - admissionregistrationv1beta1.Create, - admissionregistrationv1beta1.Update, + rules = append(rules, admissionregistrationv1.RuleWithOperations{ + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, }, - Rule: admissionregistrationv1beta1.Rule{ + Rule: admissionregistrationv1.Rule{ APIGroups: []string{gvk.Group}, APIVersions: []string{gvk.Version}, Resources: []string{plural + "/*"}, @@ -157,7 +166,7 @@ func (ac *reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt return lhs.Resources[0] < rhs.Resources[0] }) - configuredWebhook, err := ac.mwhlister.Get(ac.name) + configuredWebhook, err := ac.mwhlister.Get(ac.key.Name) if err != nil { return fmt.Errorf("error retrieving webhook: %w", err) } @@ -190,7 +199,7 @@ func (ac *reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt return fmt.Errorf("error diffing webhooks: %w", err) } else if !ok { logger.Info("Updating webhook") - mwhclient := ac.client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations() + mwhclient := ac.client.AdmissionregistrationV1().MutatingWebhookConfigurations() if _, err := mwhclient.Update(webhook); err != nil { return fmt.Errorf("failed to update webhook: %w", err) } @@ -200,7 +209,7 @@ func (ac *reconciler) reconcileMutatingWebhook(ctx context.Context, caCert []byt return nil } -func (ac *reconciler) mutate(ctx context.Context, req *admissionv1beta1.AdmissionRequest) ([]byte, error) { +func (ac *reconciler) mutate(ctx context.Context, req *admissionv1.AdmissionRequest) ([]byte, error) { kind := req.Kind newBytes := req.Object.Raw oldBytes := req.OldObject.Raw diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go index cbaeaa5b290..14cf6dd73af 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go @@ -21,13 +21,15 @@ import ( // Injection stuff kubeclient "knative.dev/pkg/client/injection/kube/client" - vwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration" + vwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" + "knative.dev/pkg/logging" + pkgreconciler "knative.dev/pkg/reconciler" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/cache" "knative.dev/pkg/controller" - "knative.dev/pkg/logging" "knative.dev/pkg/system" "knative.dev/pkg/webhook" "knative.dev/pkg/webhook/resourcesemantics" @@ -62,7 +64,17 @@ func NewAdmissionController( } wh := &reconciler{ - name: name, + LeaderAwareFuncs: pkgreconciler.LeaderAwareFuncs{ + // Have this reconciler enqueue our singleton whenever it becomes leader. + PromoteFunc: func(bkt pkgreconciler.Bucket, enq func(pkgreconciler.Bucket, types.NamespacedName)) error { + enq(bkt, types.NamespacedName{Name: name}) + return nil + }, + }, + + key: types.NamespacedName{ + Name: name, + }, path: path, handlers: handlers, callbacks: unwrappedCallbacks, diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/reconcile_config.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/reconcile_config.go index c17db6281c4..1537adc7892 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/reconcile_config.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/reconcile_config.go @@ -24,16 +24,18 @@ import ( "github.com/markbates/inflect" "go.uber.org/zap" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" - admissionlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" + admissionlisters "k8s.io/client-go/listers/admissionregistration/v1" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/controller" "knative.dev/pkg/kmp" "knative.dev/pkg/logging" "knative.dev/pkg/ptr" + pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/webhook" certresources "knative.dev/pkg/webhook/certificates/resources" @@ -43,8 +45,9 @@ import ( // reconciler implements the AdmissionController for resources type reconciler struct { webhook.StatelessAdmissionImpl + pkgreconciler.LeaderAwareFuncs - name string + key types.NamespacedName path string handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD callbacks map[schema.GroupVersionKind]Callback @@ -60,6 +63,7 @@ type reconciler struct { } var _ controller.Reconciler = (*reconciler)(nil) +var _ pkgreconciler.LeaderAware = (*reconciler)(nil) var _ webhook.AdmissionController = (*reconciler)(nil) var _ webhook.StatelessAdmissionController = (*reconciler)(nil) @@ -72,6 +76,11 @@ func (ac *reconciler) Path() string { func (ac *reconciler) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) + if !ac.IsLeaderFor(ac.key) { + logger.Debugf("Skipping key %q, not the leader.", ac.key) + return nil + } + // Look up the webhook secret, and fetch the CA cert bundle. secret, err := ac.secretlister.Secrets(system.Namespace()).Get(ac.secretName) if err != nil { @@ -90,17 +99,17 @@ func (ac *reconciler) Reconcile(ctx context.Context, key string) error { func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []byte) error { logger := logging.FromContext(ctx) - rules := make([]admissionregistrationv1beta1.RuleWithOperations, 0, len(ac.handlers)) + rules := make([]admissionregistrationv1.RuleWithOperations, 0, len(ac.handlers)) for gvk := range ac.handlers { plural := strings.ToLower(inflect.Pluralize(gvk.Kind)) - rules = append(rules, admissionregistrationv1beta1.RuleWithOperations{ - Operations: []admissionregistrationv1beta1.OperationType{ - admissionregistrationv1beta1.Create, - admissionregistrationv1beta1.Update, - admissionregistrationv1beta1.Delete, + rules = append(rules, admissionregistrationv1.RuleWithOperations{ + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, + admissionregistrationv1.Delete, }, - Rule: admissionregistrationv1beta1.Rule{ + Rule: admissionregistrationv1.Rule{ APIGroups: []string{gvk.Group}, APIVersions: []string{gvk.Version}, Resources: []string{plural + "/*"}, @@ -120,7 +129,7 @@ func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []b return lhs.Resources[0] < rhs.Resources[0] }) - configuredWebhook, err := ac.vwhlister.Get(ac.name) + configuredWebhook, err := ac.vwhlister.Get(ac.key.Name) if err != nil { return fmt.Errorf("error retrieving webhook: %w", err) } @@ -153,7 +162,7 @@ func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []b return fmt.Errorf("error diffing webhooks: %w", err) } else if !ok { logger.Info("Updating webhook") - vwhclient := ac.client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations() + vwhclient := ac.client.AdmissionregistrationV1().ValidatingWebhookConfigurations() if _, err := vwhclient.Update(webhook); err != nil { return fmt.Errorf("failed to update webhook: %w", err) } diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation_admit.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation_admit.go index c547359ff9d..ad61de99745 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation_admit.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation_admit.go @@ -24,7 +24,7 @@ import ( "fmt" "go.uber.org/zap" - admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionv1 "k8s.io/api/admission/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" @@ -61,7 +61,7 @@ func NewCallback(function func(context.Context, *unstructured.Unstructured) erro var _ webhook.AdmissionController = (*reconciler)(nil) // Admit implements AdmissionController -func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse { +func (ac *reconciler) Admit(ctx context.Context, request *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse { if ac.withContext != nil { ctx = ac.withContext(ctx) } @@ -86,14 +86,14 @@ func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.Admis return webhook.MakeErrorStatus("validation callback failed: %v", err) } - return &admissionv1beta1.AdmissionResponse{Allowed: true} + return &admissionv1.AdmissionResponse{Allowed: true} } // decodeRequestAndPrepareContext deserializes the old and new GenericCrds from the incoming request and sets up the context. // nil oldObj or newObj denote absence of `old` (create) or `new` (delete) objects. func (ac *reconciler) decodeRequestAndPrepareContext( ctx context.Context, - req *admissionv1beta1.AdmissionRequest, + req *admissionv1.AdmissionRequest, gvk schema.GroupVersionKind) (context.Context, resourcesemantics.GenericCRD, error) { logger := logging.FromContext(ctx) @@ -142,11 +142,11 @@ func (ac *reconciler) decodeRequestAndPrepareContext( } switch req.Operation { - case admissionv1beta1.Update: + case admissionv1.Update: ctx = apis.WithinUpdate(ctx, oldObj) - case admissionv1beta1.Create: + case admissionv1.Create: ctx = apis.WithinCreate(ctx) - case admissionv1beta1.Delete: + case admissionv1.Delete: ctx = apis.WithinDelete(ctx) return ctx, oldObj, nil } @@ -154,14 +154,14 @@ func (ac *reconciler) decodeRequestAndPrepareContext( return ctx, newObj, nil } -func validate(ctx context.Context, resource resourcesemantics.GenericCRD, req *admissionv1beta1.AdmissionRequest) error { +func validate(ctx context.Context, resource resourcesemantics.GenericCRD, req *admissionv1.AdmissionRequest) error { logger := logging.FromContext(ctx) // Only run validation for supported create and update validaiton. switch req.Operation { - case admissionv1beta1.Create, admissionv1beta1.Update: + case admissionv1.Create, admissionv1.Update: // Supported verbs - case admissionv1beta1.Delete: + case admissionv1.Delete: return nil // Validation handled by optional Callback, but not validatable. default: logger.Infof("Unhandled webhook validation operation, letting it through %v", req.Operation) @@ -184,9 +184,9 @@ func validate(ctx context.Context, resource resourcesemantics.GenericCRD, req *a } // callback runs optional callbacks on admission -func (ac *reconciler) callback(ctx context.Context, req *admissionv1beta1.AdmissionRequest, gvk schema.GroupVersionKind) error { +func (ac *reconciler) callback(ctx context.Context, req *admissionv1.AdmissionRequest, gvk schema.GroupVersionKind) error { var toDecode []byte - if req.Operation == admissionv1beta1.Delete { + if req.Operation == admissionv1.Delete { toDecode = req.OldObject.Raw } else { toDecode = req.Object.Raw diff --git a/vendor/knative.dev/pkg/webhook/stats_reporter.go b/vendor/knative.dev/pkg/webhook/stats_reporter.go index 298bf499c9a..13293200c00 100644 --- a/vendor/knative.dev/pkg/webhook/stats_reporter.go +++ b/vendor/knative.dev/pkg/webhook/stats_reporter.go @@ -24,7 +24,7 @@ import ( "go.opencensus.io/stats" "go.opencensus.io/stats/view" "go.opencensus.io/tag" - admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionv1 "k8s.io/api/admission/v1" "knative.dev/pkg/metrics" ) @@ -62,7 +62,7 @@ var ( // StatsReporter reports webhook metrics type StatsReporter interface { - ReportRequest(request *admissionv1beta1.AdmissionRequest, response *admissionv1beta1.AdmissionResponse, d time.Duration) error + ReportRequest(request *admissionv1.AdmissionRequest, response *admissionv1.AdmissionResponse, d time.Duration) error } // reporter implements StatsReporter interface @@ -83,7 +83,7 @@ func NewStatsReporter() (StatsReporter, error) { } // Captures req count metric, recording the count and the duration -func (r *reporter) ReportRequest(req *admissionv1beta1.AdmissionRequest, resp *admissionv1beta1.AdmissionResponse, d time.Duration) error { +func (r *reporter) ReportRequest(req *admissionv1.AdmissionRequest, resp *admissionv1.AdmissionResponse, d time.Duration) error { ctx, err := tag.New( r.ctx, tag.Insert(requestOperationKey, string(req.Operation)), diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go index 869269b46d0..1a2988c1c71 100644 --- a/vendor/knative.dev/pkg/webhook/webhook.go +++ b/vendor/knative.dev/pkg/webhook/webhook.go @@ -30,7 +30,7 @@ import ( "go.uber.org/zap" "golang.org/x/sync/errgroup" - admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionv1 "k8s.io/api/admission/v1" "k8s.io/client-go/kubernetes" corelisters "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/logging" @@ -63,14 +63,14 @@ type Options struct { // Operation is the verb being operated on // it is aliasde in Validation from the k8s admission package -type Operation = admissionv1beta1.Operation +type Operation = admissionv1.Operation // Operation types const ( - Create Operation = admissionv1beta1.Create - Update Operation = admissionv1beta1.Update - Delete Operation = admissionv1beta1.Delete - Connect Operation = admissionv1beta1.Connect + Create Operation = admissionv1.Create + Update Operation = admissionv1.Update + Delete Operation = admissionv1.Delete + Connect Operation = admissionv1.Connect ) // Webhook implements the external webhook for validation of diff --git a/vendor/modules.txt b/vendor/modules.txt index d72b67efc06..8f7f3182649 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -556,7 +556,7 @@ honnef.co/go/tools/unused honnef.co/go/tools/version # k8s.io/api v0.17.6 => k8s.io/api v0.17.6 ## explicit -k8s.io/api/admission/v1beta1 +k8s.io/api/admission/v1 k8s.io/api/admissionregistration/v1 k8s.io/api/admissionregistration/v1beta1 k8s.io/api/apps/v1 @@ -943,7 +943,7 @@ k8s.io/utils/buffer k8s.io/utils/integer k8s.io/utils/pointer k8s.io/utils/trace -# knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743 +# knative.dev/pkg v0.0.0-20200619182625-b6a13e2894ee ## explicit knative.dev/pkg/apiextensions/storageversion knative.dev/pkg/apiextensions/storageversion/cmd/migrate @@ -955,6 +955,7 @@ knative.dev/pkg/apis/duck/v1beta1 knative.dev/pkg/changeset knative.dev/pkg/client/injection/apiextensions/client knative.dev/pkg/client/injection/apiextensions/client/fake +knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1/customresourcedefinition knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1beta1/customresourcedefinition knative.dev/pkg/client/injection/apiextensions/informers/apiextensions/v1beta1/customresourcedefinition/fake knative.dev/pkg/client/injection/apiextensions/informers/factory @@ -971,8 +972,8 @@ knative.dev/pkg/client/injection/ducks/duck/v1beta1/addressable knative.dev/pkg/client/injection/ducks/duck/v1beta1/addressable/fake knative.dev/pkg/client/injection/kube/client knative.dev/pkg/client/injection/kube/client/fake -knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration -knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration +knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/mutatingwebhookconfiguration +knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1/validatingwebhookconfiguration knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake knative.dev/pkg/client/injection/kube/informers/core/v1/configmap @@ -1056,7 +1057,7 @@ knative.dev/pkg/webhook/resourcesemantics knative.dev/pkg/webhook/resourcesemantics/conversion knative.dev/pkg/webhook/resourcesemantics/defaulting knative.dev/pkg/webhook/resourcesemantics/validation -# knative.dev/test-infra v0.0.0-20200618184825-a7b2980a8884 +# knative.dev/test-infra v0.0.0-20200619200026-0b0587234302 ## explicit knative.dev/test-infra/scripts # sigs.k8s.io/yaml v1.2.0 From 878fd0b5c728696dd4e6810e44dfb6c22e5ae1d7 Mon Sep 17 00:00:00 2001 From: Ali Ok Date: Mon, 22 Jun 2020 09:23:26 +0300 Subject: [PATCH 6/9] YAML desc for channel template spec (#3357) --- config/core/resources/channel.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/core/resources/channel.yaml b/config/core/resources/channel.yaml index 06524f64959..e547c79a217 100644 --- a/config/core/resources/channel.yaml +++ b/config/core/resources/channel.yaml @@ -82,6 +82,7 @@ spec: minLength: 1 spec: type: object + description: "Spec defines the Spec to use for each channel created. Passed in verbatim to the Channel CRD as Spec section." required: - apiVersion - kind From b2287df0abcc1cd083d625477ce7126181593e7b Mon Sep 17 00:00:00 2001 From: Ali Ok Date: Mon, 22 Jun 2020 15:14:51 +0300 Subject: [PATCH 7/9] v1 types for eventing.* --- hack/update-codegen.sh | 4 +- pkg/apis/eventing/v1/broker_defaults.go | 47 ++ pkg/apis/eventing/v1/broker_defaults_test.go | 249 ++++++++++ pkg/apis/eventing/v1/broker_lifecycle.go | 114 +++++ pkg/apis/eventing/v1/broker_lifecycle_test.go | 341 +++++++++++++ pkg/apis/eventing/v1/broker_types.go | 119 +++++ pkg/apis/eventing/v1/broker_types_test.go | 36 ++ pkg/apis/eventing/v1/broker_validation.go | 76 +++ .../eventing/v1/broker_validation_test.go | 205 ++++++++ pkg/apis/eventing/v1/doc.go | 20 + pkg/apis/eventing/v1/eventtype_defaults.go | 29 ++ .../eventing/v1/eventtype_defaults_test.go | 87 ++++ pkg/apis/eventing/v1/eventtype_lifecycle.go | 103 ++++ .../eventing/v1/eventtype_lifecycle_test.go | 257 ++++++++++ pkg/apis/eventing/v1/eventtype_types.go | 119 +++++ pkg/apis/eventing/v1/eventtype_types_test.go | 39 ++ pkg/apis/eventing/v1/eventtype_validation.go | 62 +++ .../eventing/v1/eventtype_validation_test.go | 258 ++++++++++ pkg/apis/eventing/v1/register.go | 57 +++ pkg/apis/eventing/v1/test_helper.go | 122 +++++ pkg/apis/eventing/v1/trigger_defaults.go | 52 ++ pkg/apis/eventing/v1/trigger_defaults_test.go | 122 +++++ pkg/apis/eventing/v1/trigger_lifecycle.go | 187 ++++++++ .../eventing/v1/trigger_lifecycle_test.go | 360 ++++++++++++++ pkg/apis/eventing/v1/trigger_types.go | 130 +++++ pkg/apis/eventing/v1/trigger_types_test.go | 37 ++ pkg/apis/eventing/v1/trigger_validation.go | 155 ++++++ .../eventing/v1/trigger_validation_test.go | 450 ++++++++++++++++++ pkg/apis/eventing/v1/zz_generated.deepcopy.go | 387 +++++++++++++++ pkg/client/clientset/versioned/clientset.go | 14 + .../versioned/fake/clientset_generated.go | 7 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../versioned/typed/eventing/v1/broker.go | 191 ++++++++ .../versioned/typed/eventing/v1/doc.go | 20 + .../typed/eventing/v1/eventing_client.go | 99 ++++ .../versioned/typed/eventing/v1/eventtype.go | 191 ++++++++ .../versioned/typed/eventing/v1/fake/doc.go | 20 + .../typed/eventing/v1/fake/fake_broker.go | 140 ++++++ .../eventing/v1/fake/fake_eventing_client.go | 48 ++ .../typed/eventing/v1/fake/fake_eventtype.go | 140 ++++++ .../typed/eventing/v1/fake/fake_trigger.go | 140 ++++++ .../typed/eventing/v1/generated_expansion.go | 25 + .../versioned/typed/eventing/v1/trigger.go | 191 ++++++++ .../externalversions/eventing/interface.go | 8 + .../externalversions/eventing/v1/broker.go | 89 ++++ .../externalversions/eventing/v1/eventtype.go | 89 ++++ .../externalversions/eventing/v1/interface.go | 59 +++ .../externalversions/eventing/v1/trigger.go | 89 ++++ .../informers/externalversions/generic.go | 9 + .../informers/eventing/v1/broker/broker.go | 52 ++ .../informers/eventing/v1/broker/fake/fake.go | 40 ++ .../eventing/v1/eventtype/eventtype.go | 52 ++ .../eventing/v1/eventtype/fake/fake.go | 40 ++ .../eventing/v1/trigger/fake/fake.go | 40 ++ .../informers/eventing/v1/trigger/trigger.go | 52 ++ .../eventing/v1/broker/controller.go | 122 +++++ .../eventing/v1/broker/reconciler.go | 369 ++++++++++++++ .../eventing/v1/broker/stub/controller.go | 63 +++ .../eventing/v1/broker/stub/reconciler.go | 66 +++ .../eventing/v1/eventtype/controller.go | 118 +++++ .../eventing/v1/eventtype/reconciler.go | 358 ++++++++++++++ .../eventing/v1/eventtype/stub/controller.go | 54 +++ .../eventing/v1/eventtype/stub/reconciler.go | 66 +++ .../eventing/v1/trigger/controller.go | 118 +++++ .../eventing/v1/trigger/reconciler.go | 358 ++++++++++++++ .../eventing/v1/trigger/stub/controller.go | 54 +++ .../eventing/v1/trigger/stub/reconciler.go | 66 +++ pkg/client/listers/eventing/v1/broker.go | 94 ++++ pkg/client/listers/eventing/v1/eventtype.go | 94 ++++ .../eventing/v1/expansion_generated.go | 43 ++ pkg/client/listers/eventing/v1/trigger.go | 94 ++++ .../helpers/channel_status_test_helper.go | 4 +- 73 files changed, 8210 insertions(+), 4 deletions(-) create mode 100644 pkg/apis/eventing/v1/broker_defaults.go create mode 100644 pkg/apis/eventing/v1/broker_defaults_test.go create mode 100644 pkg/apis/eventing/v1/broker_lifecycle.go create mode 100644 pkg/apis/eventing/v1/broker_lifecycle_test.go create mode 100644 pkg/apis/eventing/v1/broker_types.go create mode 100644 pkg/apis/eventing/v1/broker_types_test.go create mode 100644 pkg/apis/eventing/v1/broker_validation.go create mode 100644 pkg/apis/eventing/v1/broker_validation_test.go create mode 100644 pkg/apis/eventing/v1/doc.go create mode 100644 pkg/apis/eventing/v1/eventtype_defaults.go create mode 100644 pkg/apis/eventing/v1/eventtype_defaults_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_lifecycle.go create mode 100644 pkg/apis/eventing/v1/eventtype_lifecycle_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_types.go create mode 100644 pkg/apis/eventing/v1/eventtype_types_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_validation.go create mode 100644 pkg/apis/eventing/v1/eventtype_validation_test.go create mode 100644 pkg/apis/eventing/v1/register.go create mode 100644 pkg/apis/eventing/v1/test_helper.go create mode 100644 pkg/apis/eventing/v1/trigger_defaults.go create mode 100644 pkg/apis/eventing/v1/trigger_defaults_test.go create mode 100644 pkg/apis/eventing/v1/trigger_lifecycle.go create mode 100644 pkg/apis/eventing/v1/trigger_lifecycle_test.go create mode 100644 pkg/apis/eventing/v1/trigger_types.go create mode 100644 pkg/apis/eventing/v1/trigger_types_test.go create mode 100644 pkg/apis/eventing/v1/trigger_validation.go create mode 100644 pkg/apis/eventing/v1/trigger_validation_test.go create mode 100644 pkg/apis/eventing/v1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/broker.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/trigger.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/broker.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/eventtype.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/interface.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/trigger.go create mode 100644 pkg/client/injection/informers/eventing/v1/broker/broker.go create mode 100644 pkg/client/injection/informers/eventing/v1/broker/fake/fake.go create mode 100644 pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go create mode 100644 pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go create mode 100644 pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go create mode 100644 pkg/client/injection/informers/eventing/v1/trigger/trigger.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go create mode 100644 pkg/client/listers/eventing/v1/broker.go create mode 100644 pkg/client/listers/eventing/v1/eventtype.go create mode 100644 pkg/client/listers/eventing/v1/expansion_generated.go create mode 100644 pkg/client/listers/eventing/v1/trigger.go diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 50d7b7c174d..11304cfa1f6 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -45,7 +45,7 @@ chmod +x ${CODEGEN_PKG}/generate-groups.sh # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Deep copy config @@ -65,7 +65,7 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ chmod +x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/eventing/v1/broker_defaults.go b/pkg/apis/eventing/v1/broker_defaults.go new file mode 100644 index 00000000000..2ae42be8e7e --- /dev/null +++ b/pkg/apis/eventing/v1/broker_defaults.go @@ -0,0 +1,47 @@ +/* +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 ( + "context" + + "knative.dev/eventing/pkg/apis/config" + "knative.dev/eventing/pkg/apis/eventing" + "knative.dev/pkg/apis" +) + +func (b *Broker) SetDefaults(ctx context.Context) { + // Default Spec fields. + withNS := apis.WithinParent(ctx, b.ObjectMeta) + b.Spec.SetDefaults(withNS) + eventing.DefaultBrokerClassIfUnset(withNS, &b.ObjectMeta) +} + +func (bs *BrokerSpec) SetDefaults(ctx context.Context) { + if bs.Config != nil { + // Default the namespace if not given + bs.Config.SetDefaults(ctx) + return + } + + cfg := config.FromContextOrDefaults(ctx) + c, err := cfg.Defaults.GetBrokerConfig(apis.ParentMeta(ctx).Namespace) + if err == nil { + c.SetDefaults(ctx) + bs.Config = c + } +} diff --git a/pkg/apis/eventing/v1/broker_defaults_test.go b/pkg/apis/eventing/v1/broker_defaults_test.go new file mode 100644 index 00000000000..1d87225851e --- /dev/null +++ b/pkg/apis/eventing/v1/broker_defaults_test.go @@ -0,0 +1,249 @@ +/* +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 ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "knative.dev/eventing/pkg/apis/config" + "knative.dev/eventing/pkg/apis/eventing" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + defaultConfig = &config.Config{ + Defaults: &config.Defaults{ + // NamespaceDefaultsConfig are the default Broker Configs for each namespace. + // Namespace is the key, the value is the KReference to the config. + NamespaceDefaultsConfig: map[string]*config.ClassAndKRef{ + "mynamespace": { + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "kafka-channel", + }, + }, + "mynamespace2": { + BrokerClass: "mynamespace2class", + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "natss-channel", + }, + }, + "mynamespace3": { + BrokerClass: "mynamespace3class", + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Name: "natss-channel", + }, + }, + }, + ClusterDefault: &config.ClassAndKRef{ + BrokerClass: eventing.MTChannelBrokerClassValue, + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + } +) + +func TestBrokerSetDefaults(t *testing.T) { + testCases := map[string]struct { + initial Broker + expected Broker + }{ + "default everything from cluster": { + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + }, + "default annotation from cluster": { + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + initial: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + }, + "config already specified, adds annotation": { + initial: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + "no config, uses namespace broker config, cluster class": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Namespace: "mynamespace"}, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "mynamespace", + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "kafka-channel", + APIVersion: "v1", + }, + }, + }, + }, + "no config, uses namespace broker config, defaults namespace, cluster class": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Namespace: "mynamespace3"}, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "mynamespace3", + Annotations: map[string]string{ + eventing.BrokerClassKey: "mynamespace3class", + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "mynamespace3", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + }, + "no config, uses namespace broker config and class": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Namespace: "mynamespace2"}, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "mynamespace2", + Annotations: map[string]string{ + eventing.BrokerClassKey: "mynamespace2class", + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + }, + "config, missing namespace, defaulted": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Name: "rando", Namespace: "randons"}, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rando", + Namespace: "randons", + Annotations: map[string]string{ + eventing.BrokerClassKey: "MTChannelBasedBroker", + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "randons", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(config.ToContext(context.Background(), defaultConfig)) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/broker_lifecycle.go b/pkg/apis/eventing/v1/broker_lifecycle.go new file mode 100644 index 00000000000..92972d09992 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_lifecycle.go @@ -0,0 +1,114 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" + + "knative.dev/eventing/pkg/apis/duck" + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" +) + +var brokerCondSet = apis.NewLivingConditionSet( + BrokerConditionIngress, + BrokerConditionTriggerChannel, + BrokerConditionFilter, + BrokerConditionAddressable, +) + +const ( + BrokerConditionReady = apis.ConditionReady + BrokerConditionIngress apis.ConditionType = "IngressReady" + BrokerConditionTriggerChannel apis.ConditionType = "TriggerChannelReady" + BrokerConditionFilter apis.ConditionType = "FilterReady" + BrokerConditionAddressable apis.ConditionType = "Addressable" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Broker) GetConditionSet() apis.ConditionSet { + return brokerCondSet +} + +// GetTopLevelCondition returns the top level Condition. +func (bs *BrokerStatus) GetTopLevelCondition() *apis.Condition { + return brokerCondSet.Manage(bs).GetTopLevelCondition() +} + +// SetAddress makes this Broker addressable by setting the URI. It also +// sets the BrokerConditionAddressable to true. +func (bs *BrokerStatus) SetAddress(url *apis.URL) { + bs.Address.URL = url + if url != nil { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionAddressable) + } else { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionAddressable, "nil URL", "URL is nil") + } +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (bs *BrokerStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return brokerCondSet.Manage(bs).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (bs *BrokerStatus) IsReady() bool { + return brokerCondSet.Manage(bs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (bs *BrokerStatus) InitializeConditions() { + brokerCondSet.Manage(bs).InitializeConditions() +} + +func (bs *BrokerStatus) MarkIngressFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionIngress, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateIngressAvailability(ep *corev1.Endpoints) { + if duck.EndpointsAreAvailable(ep) { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionIngress) + } else { + bs.MarkIngressFailed("EndpointsUnavailable", "Endpoints %q are unavailable.", ep.Name) + } +} + +func (bs *BrokerStatus) MarkTriggerChannelFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionTriggerChannel, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *duckv1beta1.ChannelableStatus) { + // TODO: Once you can get a Ready status from Channelable in a generic way, use it here... + address := cs.AddressStatus.Address + if address != nil { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionTriggerChannel) + } else { + bs.MarkTriggerChannelFailed("ChannelNotReady", "trigger Channel is not ready: not addressable") + } +} + +func (bs *BrokerStatus) MarkFilterFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionFilter, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateFilterAvailability(ep *corev1.Endpoints) { + if duck.EndpointsAreAvailable(ep) { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionFilter) + } else { + bs.MarkFilterFailed("EndpointsUnavailable", "Endpoints %q are unavailable.", ep.Name) + } +} diff --git a/pkg/apis/eventing/v1/broker_lifecycle_test.go b/pkg/apis/eventing/v1/broker_lifecycle_test.go new file mode 100644 index 00000000000..9265a4f86ce --- /dev/null +++ b/pkg/apis/eventing/v1/broker_lifecycle_test.go @@ -0,0 +1,341 @@ +/* +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" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + trueVal = true + falseVal = false +) + +var ( + brokerConditionReady = apis.Condition{ + Type: BrokerConditionReady, + Status: corev1.ConditionTrue, + } + + brokerConditionIngress = apis.Condition{ + Type: BrokerConditionIngress, + Status: corev1.ConditionTrue, + } + + brokerConditionTriggerChannel = apis.Condition{ + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionTrue, + } + + brokerConditionFilter = apis.Condition{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + } + + brokerConditionAddressable = apis.Condition{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionFalse, + } +) + +func TestBrokerGetCondition(t *testing.T) { + tests := []struct { + name string + bs *BrokerStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &brokerConditionReady, + }, { + name: "multiple conditions", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionIngress, + brokerConditionTriggerChannel, + brokerConditionFilter, + }, + }, + }, + condQuery: BrokerConditionFilter, + want: &brokerConditionFilter, + }, { + name: "multiple conditions, condition false", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionTriggerChannel, + brokerConditionFilter, + brokerConditionAddressable, + }, + }, + }, + condQuery: BrokerConditionAddressable, + want: &brokerConditionAddressable, + }, { + name: "unknown condition", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionAddressable, + brokerConditionReady, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.bs.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestBrokerInitializeConditions(t *testing.T) { + tests := []struct { + name string + bs *BrokerStatus + want *BrokerStatus + }{{ + name: "empty", + bs: &BrokerStatus{}, + want: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one false", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionFalse, + }}, + }, + }, + }, { + name: "one true", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionUnknown, + }}, + }, + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.bs.InitializeConditions() + if diff := cmp.Diff(test.want, test.bs, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestBrokerIsReady(t *testing.T) { + tests := []struct { + name string + markIngressReady *bool + markTriggerChannelReady *bool + markFilterReady *bool + address *apis.URL + markIngressSubscriptionOwned bool + markIngressSubscriptionReady *bool + wantReady bool + }{{ + name: "all happy", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: true, + }, { + name: "all happy - deprecated", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: true, + }, { + name: "ingress sad", + markIngressReady: &falseVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "trigger channel sad", + markIngressReady: &trueVal, + markTriggerChannelReady: &falseVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "filter sad", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &falseVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "addressable sad", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: nil, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "all sad", + markIngressReady: &falseVal, + markTriggerChannelReady: &falseVal, + markFilterReady: &falseVal, + address: nil, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &falseVal, + wantReady: false, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + bs := &BrokerStatus{} + if test.markIngressReady != nil { + var ep *corev1.Endpoints + if *test.markIngressReady { + ep = TestHelper.AvailableEndpoints() + } else { + ep = TestHelper.UnavailableEndpoints() + } + bs.PropagateIngressAvailability(ep) + } + if test.markTriggerChannelReady != nil { + var c *duckv1beta1.ChannelableStatus + if *test.markTriggerChannelReady { + c = TestHelper.ReadyChannelStatus() + } else { + c = TestHelper.NotReadyChannelStatus() + } + bs.PropagateTriggerChannelReadiness(c) + } + if test.markFilterReady != nil { + var ep *corev1.Endpoints + if *test.markFilterReady { + ep = TestHelper.AvailableEndpoints() + } else { + ep = TestHelper.UnavailableEndpoints() + } + bs.PropagateFilterAvailability(ep) + } + bs.SetAddress(test.address) + + got := bs.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + + }) + } +} diff --git a/pkg/apis/eventing/v1/broker_types.go b/pkg/apis/eventing/v1/broker_types.go new file mode 100644 index 00000000000..fb1330f1004 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_types.go @@ -0,0 +1,119 @@ +/* + * 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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:class=eventing.knative.dev/broker.class,krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Broker collects a pool of events that are consumable using Triggers. Brokers +// provide a well-known endpoint for event delivery that senders can use with +// minimal knowledge of the event routing strategy. Receivers use Triggers to +// request delivery of events from a Broker's pool to a specific URL or +// Addressable endpoint. +type Broker struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Broker. + Spec BrokerSpec `json:"spec,omitempty"` + + // Status represents the current state of the Broker. This data may be out of + // date. + // +optional + Status BrokerStatus `json:"status,omitempty"` +} + +var ( + // Check that Broker can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Broker)(nil) + _ apis.Defaultable = (*Broker)(nil) + + // Check that Broker can return its spec untyped. + _ apis.HasSpec = (*Broker)(nil) + + _ runtime.Object = (*Broker)(nil) + + // Check that we can create OwnerReferences to a Broker. + _ kmeta.OwnerRefable = (*Broker)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Broker)(nil) +) + +type BrokerSpec struct { + // Config is a KReference to the configuration that specifies + // configuration options for this Broker. For example, this could be + // a pointer to a ConfigMap. + // +optional + Config *duckv1.KReference `json:"config,omitempty"` + + // Delivery is the delivery specification for Events within the Broker mesh. + // This includes things like retries, DLQ, etc. + // +optional + Delivery *eventingduckv1beta1.DeliverySpec `json:"delivery,omitempty"` +} + +// BrokerStatus represents the current state of a Broker. +type BrokerStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // Broker is Addressable. It exposes the endpoint as an URI to get events + // delivered into the Broker mesh. + Address duckv1.Addressable `json:"address,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// BrokerList is a collection of Brokers. +type BrokerList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []Broker `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for Brokers +func (t *Broker) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Broker") +} + +// GetUntypedSpec returns the spec of the Broker. +func (b *Broker) GetUntypedSpec() interface{} { + return b.Spec +} + +// GetStatus retrieves the status of the Broker. Implements the KRShaped interface. +func (t *Broker) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/eventing/v1/broker_types_test.go b/pkg/apis/eventing/v1/broker_types_test.go new file mode 100644 index 00000000000..ce6334cb02c --- /dev/null +++ b/pkg/apis/eventing/v1/broker_types_test.go @@ -0,0 +1,36 @@ +/* + * 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" + +func TestBrokerGetStatus(t *testing.T) { + r := &Broker{ + Status: BrokerStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestBroker_GetGroupVersionKind(t *testing.T) { + b := Broker{} + gvk := b.GetGroupVersionKind() + if gvk.Kind != "Broker" { + t.Errorf("Should be Broker.") + } +} diff --git a/pkg/apis/eventing/v1/broker_validation.go b/pkg/apis/eventing/v1/broker_validation.go new file mode 100644 index 00000000000..e7e0e8a3c46 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_validation.go @@ -0,0 +1,76 @@ +/* +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 ( + "context" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +const ( + BrokerClassAnnotationKey = "eventing.knative.dev/broker.class" +) + +func (b *Broker) Validate(ctx context.Context) *apis.FieldError { + withNS := apis.AllowDifferentNamespace(apis.WithinParent(ctx, b.ObjectMeta)) + return b.Spec.Validate(withNS).ViaField("spec") +} + +func (bs *BrokerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + // Validate the Config + if bs.Config != nil { + if ce := bs.Config.Validate(ctx); ce != nil { + errs = errs.Also(ce.ViaField("config")) + } + } + + if bs.Delivery != nil { + if de := bs.Delivery.Validate(ctx); de != nil { + errs = errs.Also(de.ViaField("delivery")) + } + } + return errs +} + +func (b *Broker) CheckImmutableFields(ctx context.Context, original *Broker) *apis.FieldError { + if original == nil { + return nil + } + + // Make sure you can't change the class annotation. + diff, err := kmp.ShortDiff(original.GetAnnotations()[BrokerClassAnnotationKey], b.GetAnnotations()[BrokerClassAnnotationKey]) + + if err != nil { + return &apis.FieldError{ + Message: "couldn't diff the Broker objects", + Details: err.Error(), + } + } + + if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"annotations"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1/broker_validation_test.go b/pkg/apis/eventing/v1/broker_validation_test.go new file mode 100644 index 00000000000..75535127f33 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_validation_test.go @@ -0,0 +1,205 @@ +/* +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 ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestBrokerImmutableFields(t *testing.T) { + original := &Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"eventing.knative.dev/broker.class": "original"}, + }, + } + current := &Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"eventing.knative.dev/broker.class": "current"}, + }, + } + + tests := map[string]struct { + og *Broker + wantErr *apis.FieldError + }{ + "nil original": { + wantErr: nil, + }, + "no ChannelTemplateSpec mutation": { + og: current, + wantErr: nil, + }, + "ChannelTemplateSpec mutated": { + og: original, + wantErr: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"annotations"}, + Details: `{string}: + -: "original" + +: "current" +`, + }, + }, + } + + for n, test := range tests { + t.Run(n, func(t *testing.T) { + gotErr := current.CheckImmutableFields(context.Background(), test.og) + if diff := cmp.Diff(test.wantErr.Error(), gotErr.Error()); diff != "" { + t.Errorf("Broker.CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} + +func TestValidate(t *testing.T) { + invalidString := "invalid time" + tests := []struct { + name string + b Broker + want *apis.FieldError + }{{ + name: "valid empty", + b: Broker{}, + }, { + name: "valid config", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, + }, { + name: "valid config, no namespace", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, + }, { + name: "invalid config, missing name", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, + want: apis.ErrMissingField("spec.config.name"), + }, { + name: "invalid config, missing apiVersion", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + }, + }, + }, + want: apis.ErrMissingField("spec.config.apiVersion"), + }, { + name: "invalid config, missing kind", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + APIVersion: "apiversion", + }, + }, + }, + want: apis.ErrMissingField("spec.config.kind"), + }, { + name: "invalid delivery, invalid delay string", + b: Broker{ + Spec: BrokerSpec{ + Delivery: &eventingduckv1beta1.DeliverySpec{ + BackoffDelay: &invalidString, + }, + }, + }, + want: apis.ErrInvalidValue(invalidString, "spec.delivery.backoffDelay"), + }, {}} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.b.Validate(context.Background()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("BrokerSpec.Validate (-want, +got) = %v", diff) + } + }) + } +} + +func TestValidSpec(t *testing.T) { + bop := eventingduckv1beta1.BackoffPolicyExponential + tests := []struct { + name string + spec BrokerSpec + want *apis.FieldError + }{{ + name: "valid empty", + spec: BrokerSpec{}, + }, { + name: "valid config", + spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, { + name: "valid delivery", + spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + Delivery: &eventingduckv1beta1.DeliverySpec{BackoffPolicy: &bop}, + }, + }, {}} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.spec.Validate(context.Background()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("BrokerSpec.Validate (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/doc.go b/pkg/apis/eventing/v1/doc.go new file mode 100644 index 00000000000..eba4c682603 --- /dev/null +++ b/pkg/apis/eventing/v1/doc.go @@ -0,0 +1,20 @@ +/* + * 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 is the v1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=eventing.knative.dev +package v1 diff --git a/pkg/apis/eventing/v1/eventtype_defaults.go b/pkg/apis/eventing/v1/eventtype_defaults.go new file mode 100644 index 00000000000..fa02a0d929c --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_defaults.go @@ -0,0 +1,29 @@ +/* +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 "context" + +func (et *EventType) SetDefaults(ctx context.Context) { + et.Spec.SetDefaults(ctx) +} + +func (ets *EventTypeSpec) SetDefaults(ctx context.Context) { + if ets.Broker == "" { + ets.Broker = "default" + } +} diff --git a/pkg/apis/eventing/v1/eventtype_defaults_test.go b/pkg/apis/eventing/v1/eventtype_defaults_test.go new file mode 100644 index 00000000000..3f73f59bf11 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_defaults_test.go @@ -0,0 +1,87 @@ +/* +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 ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + "knative.dev/pkg/apis" +) + +func TestEventTypeDefaults(t *testing.T) { + testSource := apis.HTTP("test-source") + testSchema := apis.HTTP("test-schema") + testCases := map[string]struct { + initial EventType + expected EventType + }{ + "nil spec": { + initial: EventType{}, + expected: EventType{ + Spec: EventTypeSpec{ + Broker: "default", + }, + }, + }, + "broker empty": { + initial: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "", + Schema: testSchema, + }, + }, + expected: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "default", + Schema: testSchema, + }, + }, + }, + "broker not set": { + initial: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Schema: testSchema, + }, + }, + expected: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "default", + Schema: testSchema, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.TODO()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_lifecycle.go b/pkg/apis/eventing/v1/eventtype_lifecycle.go new file mode 100644 index 00000000000..50f9758563b --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_lifecycle.go @@ -0,0 +1,103 @@ +/* +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 ( + corev1 "k8s.io/api/core/v1" + + "knative.dev/pkg/apis" +) + +var eventTypeCondSet = apis.NewLivingConditionSet(EventTypeConditionBrokerExists, EventTypeConditionBrokerReady) + +const ( + EventTypeConditionReady = apis.ConditionReady + EventTypeConditionBrokerExists apis.ConditionType = "BrokerExists" + EventTypeConditionBrokerReady apis.ConditionType = "BrokerReady" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*EventType) GetConditionSet() apis.ConditionSet { + return eventTypeCondSet +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (et *EventTypeStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return eventTypeCondSet.Manage(et).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (et *EventTypeStatus) IsReady() bool { + return eventTypeCondSet.Manage(et).IsHappy() +} + +// GetTopLevelCondition returns the top level Condition. +func (et *EventTypeStatus) GetTopLevelCondition() *apis.Condition { + return eventTypeCondSet.Manage(et).GetTopLevelCondition() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (et *EventTypeStatus) InitializeConditions() { + eventTypeCondSet.Manage(et).InitializeConditions() +} + +func (et *EventTypeStatus) MarkBrokerExists() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerExists) +} + +func (et *EventTypeStatus) MarkBrokerDoesNotExist() { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerExists, "BrokerDoesNotExist", "Broker does not exist") +} + +func (et *EventTypeStatus) MarkBrokerExistsUnknown(reason, messageFormat string, messageA ...interface{}) { + eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerExists, reason, messageFormat, messageA...) +} + +func (et *EventTypeStatus) MarkBrokerReady() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) +} + +func (et *EventTypeStatus) MarkBrokerFailed(reason, messageFormat string, messageA ...interface{}) { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, reason, messageFormat, messageA...) +} + +func (et *EventTypeStatus) MarkBrokerUnknown(reason, messageFormat string, messageA ...interface{}) { + eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerReady, reason, messageFormat, messageA...) +} + +func (et *EventTypeStatus) MarkBrokerNotConfigured() { + eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerReady, + "BrokerNotConfigured", "Broker has not yet been reconciled.") +} + +func (et *EventTypeStatus) PropagateBrokerStatus(bs *BrokerStatus) { + bc := brokerCondSet.Manage(bs).GetTopLevelCondition() + if bc == nil { + et.MarkBrokerNotConfigured() + return + } + switch { + case bc.Status == corev1.ConditionUnknown: + et.MarkBrokerUnknown(bc.Reason, bc.Message) + case bc.Status == corev1.ConditionTrue: + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) + case bc.Status == corev1.ConditionFalse: + et.MarkBrokerFailed(bc.Reason, bc.Message) + default: + et.MarkBrokerUnknown("BrokerUnknown", "The status of Broker is invalid: %v", bc.Status) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_lifecycle_test.go b/pkg/apis/eventing/v1/eventtype_lifecycle_test.go new file mode 100644 index 00000000000..426c08d1aec --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_lifecycle_test.go @@ -0,0 +1,257 @@ +/* +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" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + trueValue = true + falseValue = false +) + +var ( + eventTypeConditionReady = apis.Condition{ + Type: EventTypeConditionReady, + Status: corev1.ConditionTrue, + } + + eventTypeConditionBrokerExists = apis.Condition{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionTrue, + } + + eventTypeConditionBrokerReady = apis.Condition{ + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + } +) + +func TestEventTypeGetConditionSet(t *testing.T) { + r := &EventType{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestEventTypeGetCondition(t *testing.T) { + tests := []struct { + name string + ets *EventTypeStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &eventTypeConditionReady, + }, { + name: "broker exists condition", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionBrokerExists, + }, + }, + }, + condQuery: EventTypeConditionBrokerExists, + want: &eventTypeConditionBrokerExists, + }, { + name: "multiple conditions, condition true", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionBrokerExists, + eventTypeConditionBrokerReady, + }, + }, + }, + condQuery: EventTypeConditionBrokerReady, + want: &eventTypeConditionBrokerReady, + }, { + name: "unknown condition", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionBrokerReady, + eventTypeConditionReady, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ets.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestEventTypeInitializeConditions(t *testing.T) { + tests := []struct { + name string + ets *EventTypeStatus + want *EventTypeStatus + }{{ + name: "empty", + ets: &EventTypeStatus{}, + want: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one false", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionFalse, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ets.InitializeConditions() + if diff := cmp.Diff(test.want, test.ets, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestEventTypeConditionStatus(t *testing.T) { + tests := []struct { + name string + markBrokerExists *bool + brokerStatus *BrokerStatus + wantConditionStatus corev1.ConditionStatus + }{{ + name: "all happy", + markBrokerExists: &trueValue, + brokerStatus: TestHelper.ReadyBrokerStatus(), + wantConditionStatus: corev1.ConditionTrue, + }, { + name: "broker exist sad", + markBrokerExists: &falseValue, + brokerStatus: nil, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "broker ready sad", + markBrokerExists: &trueValue, + brokerStatus: TestHelper.FalseBrokerStatus(), + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "broker ready unknown", + markBrokerExists: &trueValue, + brokerStatus: TestHelper.UnknownBrokerStatus(), + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "all sad", + markBrokerExists: &falseValue, + brokerStatus: nil, + wantConditionStatus: corev1.ConditionFalse, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ets := &EventTypeStatus{} + if test.markBrokerExists != nil { + if *test.markBrokerExists { + ets.MarkBrokerExists() + } else { + ets.MarkBrokerDoesNotExist() + } + } + if test.brokerStatus != nil { + ets.PropagateBrokerStatus(test.brokerStatus) + } + + got := ets.GetTopLevelCondition().Status + if test.wantConditionStatus != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantConditionStatus, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_types.go b/pkg/apis/eventing/v1/eventtype_types.go new file mode 100644 index 00000000000..8686872fb01 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_types.go @@ -0,0 +1,119 @@ +/* + * 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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type EventType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the EventType. + Spec EventTypeSpec `json:"spec,omitempty"` + + // Status represents the current state of the EventType. + // This data may be out of date. + // +optional + // TODO might be removed https://github.com/knative/eventing/issues/2750 + Status EventTypeStatus `json:"status,omitempty"` +} + +var ( + // Check that EventType can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*EventType)(nil) + _ apis.Defaultable = (*EventType)(nil) + + // Check that EventType can return its spec untyped. + _ apis.HasSpec = (*EventType)(nil) + + _ runtime.Object = (*EventType)(nil) + + // Check that we can create OwnerReferences to an EventType. + _ kmeta.OwnerRefable = (*EventType)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*EventType)(nil) +) + +type EventTypeSpec struct { + // Type represents the CloudEvents type. It is authoritative. + Type string `json:"type"` + // Source is a URI, it represents the CloudEvents source. + // +optional + Source *apis.URL `json:"source,omitempty"` + // Schema is a URI, it represents the CloudEvents schemaurl extension attribute. + // It may be a JSON schema, a protobuf schema, etc. It is optional. + // +optional + Schema *apis.URL `json:"schema,omitempty"` + // SchemaData allows the CloudEvents schema to be stored directly in the + // EventType. Content is dependent on the encoding. Optional attribute. + // The contents are not validated or manipulated by the system. + // +optional + SchemaData string `json:"schemaData,omitempty"` + // TODO remove https://github.com/knative/eventing/issues/2750 + // Broker refers to the Broker that can provide the EventType. + // +optional + Broker string `json:"broker,omitempty"` + // Description is an optional field used to describe the EventType, in any meaningful way. + // +optional + Description string `json:"description,omitempty"` +} + +// EventTypeStatus represents the current state of a EventType. +type EventTypeStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// EventTypeList is a collection of EventTypes. +type EventTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []EventType `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for EventType +func (p *EventType) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("EventType") +} + +// GetUntypedSpec returns the spec of the EventType. +func (e *EventType) GetUntypedSpec() interface{} { + return e.Spec +} + +// GetStatus retrieves the status of the EventType. Implements the KRShaped interface. +func (t *EventType) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/eventing/v1/eventtype_types_test.go b/pkg/apis/eventing/v1/eventtype_types_test.go new file mode 100644 index 00000000000..09d5ac826a5 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_types_test.go @@ -0,0 +1,39 @@ +/* +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" +) + +func TestEventTypeGetStatus(t *testing.T) { + r := &EventType{ + Status: EventTypeStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestEventType_GetGroupVersionKind(t *testing.T) { + src := EventType{} + gvk := src.GetGroupVersionKind() + + if gvk.Kind != "EventType" { + t.Errorf("Should be EventType.") + } +} diff --git a/pkg/apis/eventing/v1/eventtype_validation.go b/pkg/apis/eventing/v1/eventtype_validation.go new file mode 100644 index 00000000000..46939f77e02 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_validation.go @@ -0,0 +1,62 @@ +/* +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 ( + "context" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +func (et *EventType) Validate(ctx context.Context) *apis.FieldError { + return et.Spec.Validate(ctx).ViaField("spec") +} + +func (ets *EventTypeSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if ets.Type == "" { + fe := apis.ErrMissingField("type") + errs = errs.Also(fe) + } + // TODO validate Source is a valid URI. + // TODO validate Schema is a valid URI. + // There is no validation of the SchemaData, it is application specific data. + return errs +} + +func (et *EventType) CheckImmutableFields(ctx context.Context, original *EventType) *apis.FieldError { + if original == nil { + return nil + } + + // All fields are immutable. + if diff, err := kmp.ShortDiff(original.Spec, et.Spec); err != nil { + return &apis.FieldError{ + Message: "Failed to diff EventType", + Paths: []string{"spec"}, + Details: err.Error(), + } + } else if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1/eventtype_validation_test.go b/pkg/apis/eventing/v1/eventtype_validation_test.go new file mode 100644 index 00000000000..ed1ce13050e --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_validation_test.go @@ -0,0 +1,258 @@ +/* +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 ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "knative.dev/pkg/apis" +) + +func TestEventTypeValidation(t *testing.T) { + name := "invalid type" + et := &EventType{Spec: EventTypeSpec{}} + + want := &apis.FieldError{ + Paths: []string{"spec.type"}, + Message: "missing field(s)", + } + + t.Run(name, func(t *testing.T) { + got := et.Validate(context.TODO()) + if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { + t.Errorf("EventType.Validate (-want, +got) = %v", diff) + } + }) +} + +func TestEventTypeSpecValidation(t *testing.T) { + testSource := apis.HTTP("test-source") + tests := []struct { + name string + ets *EventTypeSpec + want *apis.FieldError + }{{ + name: "invalid eventtype type", + ets: &EventTypeSpec{}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("type") + return fe + }(), + }, { + name: "valid eventtype", + ets: &EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ets.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate EventTypeSpec (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestEventTypeImmutableFields(t *testing.T) { + differentSource := apis.HTTP("original-source") + testSource := apis.HTTP("test-source") + testSchema := apis.HTTP("test-schema") + testSchemaData := `{"data": "awesome"}` + differentSchema := apis.HTTP("original-schema") + tests := []struct { + name string + current *EventType + original *EventType + want *apis.FieldError + }{{ + name: "good (no change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + SchemaData: testSchemaData, + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + SchemaData: testSchemaData, + }, + }, + want: nil, + }, { + name: "new nil is ok", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + }, + }, + original: nil, + want: nil, + }, { + name: "bad (broker change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "original-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1.EventTypeSpec}.Broker: + -: "original-broker" + +: "test-broker" +`, + }, + }, { + name: "bad (type change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "original-type", + Source: testSource, + Broker: "test-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1.EventTypeSpec}.Type: + -: "original-type" + +: "test-type" +`, + }, + }, { + name: "bad (source change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: differentSource, + Broker: "test-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1.EventTypeSpec}.Source.Host: + -: "original-source" + +: "test-source" +`, + }, + }, { + name: "bad (schema change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: differentSchema, + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1.EventTypeSpec}.Schema.Host: + -: "original-schema" + +: "test-schema" +`, + }, + }, { + name: "bad (description change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + Description: "test-description", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + Description: "original-description", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1.EventTypeSpec}.Description: + -: "original-description" + +: "test-description" +`, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.current.CheckImmutableFields(context.TODO(), test.original) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/register.go b/pkg/apis/eventing/v1/register.go new file mode 100644 index 00000000000..176bf23b31d --- /dev/null +++ b/pkg/apis/eventing/v1/register.go @@ -0,0 +1,57 @@ +/* + * 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 ( + "knative.dev/eventing/pkg/apis/eventing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: eventing.GroupName, Version: "v1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Broker{}, + &BrokerList{}, + &EventType{}, + &EventTypeList{}, + &Trigger{}, + &TriggerList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/eventing/v1/test_helper.go b/pkg/apis/eventing/v1/test_helper.go new file mode 100644 index 00000000000..49073aec4d9 --- /dev/null +++ b/pkg/apis/eventing/v1/test_helper.go @@ -0,0 +1,122 @@ +/* + * 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 ( + corev1 "k8s.io/api/core/v1" + + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +type testHelper struct{} + +// TestHelper contains helpers for unit tests. +var TestHelper = testHelper{} + +func (testHelper) ReadySubscriptionCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + Severity: apis.ConditionSeverityError, + } +} + +func (testHelper) FalseSubscriptionCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionFalse, + Severity: apis.ConditionSeverityError, + Message: "test induced failure condition", + } +} + +func (testHelper) ReadySubscriptionStatus() *messagingv1beta1.SubscriptionStatus { + ss := &messagingv1beta1.SubscriptionStatus{} + ss.MarkChannelReady() + ss.MarkReferencesResolved() + ss.MarkAddedToChannel() + return ss +} + +func (t testHelper) ReadyBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + bs.PropagateIngressAvailability(t.AvailableEndpoints()) + bs.PropagateTriggerChannelReadiness(t.ReadyChannelStatus()) + bs.PropagateFilterAvailability(t.AvailableEndpoints()) + bs.SetAddress(apis.HTTP("example.com")) + return bs +} + +func (testHelper) ReadyBrokerCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + Severity: apis.ConditionSeverityError, + } +} + +func (testHelper) UnknownBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + return bs +} + +func (testHelper) FalseBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + bs.SetAddress(nil) + return bs +} + +func (testHelper) UnavailableEndpoints() *corev1.Endpoints { + ep := &corev1.Endpoints{} + ep.Name = "unavailable" + ep.Subsets = []corev1.EndpointSubset{{ + NotReadyAddresses: []corev1.EndpointAddress{{ + IP: "127.0.0.1", + }}, + }} + return ep +} + +func (testHelper) AvailableEndpoints() *corev1.Endpoints { + ep := &corev1.Endpoints{} + ep.Name = "available" + ep.Subsets = []corev1.EndpointSubset{{ + Addresses: []corev1.EndpointAddress{{ + IP: "127.0.0.1", + }}, + }} + return ep +} + +func (testHelper) ReadyChannelStatus() *duckv1beta1.ChannelableStatus { + cs := &duckv1beta1.ChannelableStatus{ + Status: duckv1.Status{}, + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{Scheme: "http", Host: "foo"}, + }, + }, + SubscribableStatus: duckv1beta1.SubscribableStatus{}} + return cs +} + +func (t testHelper) NotReadyChannelStatus() *duckv1beta1.ChannelableStatus { + return &duckv1beta1.ChannelableStatus{} +} diff --git a/pkg/apis/eventing/v1/trigger_defaults.go b/pkg/apis/eventing/v1/trigger_defaults.go new file mode 100644 index 00000000000..6a2682d70f3 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_defaults.go @@ -0,0 +1,52 @@ +/* + * 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 ( + "context" + + "knative.dev/pkg/apis" +) + +const ( + brokerLabel = "eventing.knative.dev/broker" +) + +func (t *Trigger) SetDefaults(ctx context.Context) { + withNS := apis.WithinParent(ctx, t.ObjectMeta) + t.Spec.SetDefaults(withNS) + setLabels(t) +} + +func (ts *TriggerSpec) SetDefaults(ctx context.Context) { + if ts.Broker == "" { + ts.Broker = "default" + } + // Make a default filter that allows anything. + if ts.Filter == nil { + ts.Filter = &TriggerFilter{} + } + // Default the Subscriber namespace + ts.Subscriber.SetDefaults(ctx) +} + +func setLabels(t *Trigger) { + if len(t.Labels) == 0 { + t.Labels = map[string]string{} + } + t.Labels[brokerLabel] = t.Spec.Broker +} diff --git a/pkg/apis/eventing/v1/trigger_defaults_test.go b/pkg/apis/eventing/v1/trigger_defaults_test.go new file mode 100644 index 00000000000..3d844407692 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_defaults_test.go @@ -0,0 +1,122 @@ +/* + * 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 ( + "context" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" + + "github.com/google/go-cmp/cmp" +) + +var ( + defaultBroker = "default" + otherBroker = "other_broker" + namespace = "testnamespace" + emptyTriggerFilter = &TriggerFilter{} + defaultTrigger = Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{brokerLabel: defaultBroker}, + }, + Spec: TriggerSpec{ + Broker: defaultBroker, + Filter: emptyTriggerFilter, + }, + } +) + +func TestTriggerDefaults(t *testing.T) { + testCases := map[string]struct { + initial Trigger + expected Trigger + }{ + "nil broker": { + initial: Trigger{Spec: TriggerSpec{Filter: emptyTriggerFilter}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{brokerLabel: defaultBroker}, + }, + Spec: TriggerSpec{Broker: defaultBroker, Filter: emptyTriggerFilter}}, + }, + "nil filter": { + initial: Trigger{Spec: TriggerSpec{Broker: otherBroker}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{brokerLabel: otherBroker}, + }, + Spec: TriggerSpec{Broker: otherBroker, Filter: emptyTriggerFilter}}, + }, + "subscriber, ns defaulted": { + initial: Trigger{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: TriggerSpec{ + Broker: otherBroker, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: "foo", + }, + }}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: namespace, + Labels: map[string]string{brokerLabel: otherBroker}, + }, + Spec: TriggerSpec{ + Broker: otherBroker, + Filter: emptyTriggerFilter, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: "foo", + Namespace: namespace, + }, + }, + }}, + }, + "nil broker and nil filter": { + initial: Trigger{}, + expected: defaultTrigger, + }, + "with broker and label": { + initial: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{"otherLabel": "my-other-label"}, + }, + Spec: TriggerSpec{Broker: defaultBroker}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{ + "otherLabel": "my-other-label", + brokerLabel: defaultBroker}, + }, + Spec: TriggerSpec{Broker: defaultBroker, Filter: emptyTriggerFilter}}, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.TODO()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/trigger_lifecycle.go b/pkg/apis/eventing/v1/trigger_lifecycle.go new file mode 100644 index 00000000000..2ad85b219fa --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_lifecycle.go @@ -0,0 +1,187 @@ +/* + * 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 ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed, TriggerConditionDependency, TriggerConditionSubscriberResolved) + +const ( + // TriggerConditionReady has status True when all subconditions below have been set to True. + TriggerConditionReady = apis.ConditionReady + + TriggerConditionBroker apis.ConditionType = "BrokerReady" + + TriggerConditionSubscribed apis.ConditionType = "SubscriptionReady" + + TriggerConditionDependency apis.ConditionType = "DependencyReady" + + TriggerConditionSubscriberResolved apis.ConditionType = "SubscriberResolved" + + // TriggerAnyFilter Constant to represent that we should allow anything. + TriggerAnyFilter = "" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Trigger) GetConditionSet() apis.ConditionSet { + return triggerCondSet +} + +// GetGroupVersionKind returns GroupVersionKind for Triggers +func (t *Trigger) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Trigger") +} + +// GetUntypedSpec returns the spec of the Trigger. +func (t *Trigger) GetUntypedSpec() interface{} { + return t.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ts *TriggerStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return triggerCondSet.Manage(ts).GetCondition(t) +} + +// GetTopLevelCondition returns the top level Condition. +func (ts *TriggerStatus) GetTopLevelCondition() *apis.Condition { + return triggerCondSet.Manage(ts).GetTopLevelCondition() +} + +// IsReady returns true if the resource is ready overall. +func (ts *TriggerStatus) IsReady() bool { + return triggerCondSet.Manage(ts).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ts *TriggerStatus) InitializeConditions() { + triggerCondSet.Manage(ts).InitializeConditions() +} + +func (ts *TriggerStatus) PropagateBrokerCondition(bc *apis.Condition) { + if bc == nil { + ts.MarkBrokerNotConfigured() + return + } + + switch { + case bc.Status == corev1.ConditionUnknown: + ts.MarkBrokerUnknown(bc.Reason, bc.Message) + case bc.Status == corev1.ConditionTrue: + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionBroker) + case bc.Status == corev1.ConditionFalse: + ts.MarkBrokerFailed(bc.Reason, bc.Message) + default: + ts.MarkBrokerUnknown("BrokerUnknown", "The status of Broker is invalid: %v", bc.Status) + } +} + +func (ts *TriggerStatus) MarkBrokerFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBroker, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkBrokerUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionBroker, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkBrokerNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionBroker, + "BrokerNotConfigured", "Broker has not yet been reconciled.") +} + +func (ts *TriggerStatus) PropagateSubscriptionCondition(sc *apis.Condition) { + if sc == nil { + ts.MarkSubscriptionNotConfigured() + return + } + + switch { + case sc.Status == corev1.ConditionUnknown: + ts.MarkSubscribedUnknown(sc.Reason, sc.Message) + case sc.Status == corev1.ConditionTrue: + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscribed) + case sc.Status == corev1.ConditionFalse: + ts.MarkNotSubscribed(sc.Reason, sc.Message) + default: + ts.MarkSubscribedUnknown("SubscriptionUnknown", "The status of Subscription is invalid: %v", sc.Status) + } +} + +func (ts *TriggerStatus) MarkNotSubscribed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscribed, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscribedUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscribed, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscriptionNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscribed, + "SubscriptionNotConfigured", "Subscription has not yet been reconciled.") +} + +func (ts *TriggerStatus) MarkSubscriberResolvedSucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscriberResolved) +} + +func (ts *TriggerStatus) MarkSubscriberResolvedFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscriberResolved, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscriberResolvedUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscriberResolved, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencySucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionDependency) +} + +func (ts *TriggerStatus) MarkDependencyFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, + "DependencyNotConfigured", "Dependency has not yet been reconciled.") +} + +func (ts *TriggerStatus) PropagateDependencyStatus(ks *duckv1.KResource) { + kc := ks.Status.GetCondition(apis.ConditionReady) + if kc == nil { + ts.MarkDependencyNotConfigured() + return + } + + switch { + case kc.Status == corev1.ConditionUnknown: + ts.MarkDependencyUnknown(kc.Reason, kc.Message) + case kc.Status == corev1.ConditionTrue: + ts.MarkDependencySucceeded() + case kc.Status == corev1.ConditionFalse: + ts.MarkDependencyFailed(kc.Reason, kc.Message) + default: + ts.MarkDependencyUnknown("DependencyUnknown", "The status of Dependency is invalid: %v", kc.Status) + } +} diff --git a/pkg/apis/eventing/v1/trigger_lifecycle_test.go b/pkg/apis/eventing/v1/trigger_lifecycle_test.go new file mode 100644 index 00000000000..8a6bee1e531 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_lifecycle_test.go @@ -0,0 +1,360 @@ +/* + * 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" + + "knative.dev/pkg/apis" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + ignoreAllButTypeAndStatus = cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") + + triggerConditionReady = apis.Condition{ + Type: TriggerConditionReady, + Status: corev1.ConditionTrue, + } + + triggerConditionBroker = apis.Condition{ + Type: TriggerConditionBroker, + Status: corev1.ConditionTrue, + } + + triggerConditionDependency = apis.Condition{ + Type: TriggerConditionDependency, + Status: corev1.ConditionTrue, + } + + triggerConditionSubscriberResolved = apis.Condition{ + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionTrue, + } + + triggerConditionSubscribed = apis.Condition{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionFalse, + } +) + +func TestTriggerGetConditionSet(t *testing.T) { + r := &Trigger{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestTriggerGetCondition(t *testing.T) { + tests := []struct { + name string + ts *TriggerStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &triggerConditionReady, + }, { + name: "multiple conditions", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionBroker, + triggerConditionSubscribed, + triggerConditionDependency, + triggerConditionSubscriberResolved, + }, + }, + }, + condQuery: TriggerConditionSubscribed, + want: &triggerConditionSubscribed, + }, { + name: "multiple conditions, condition false", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionBroker, + triggerConditionSubscribed, + triggerConditionDependency, + triggerConditionSubscriberResolved, + }, + }, + }, + condQuery: TriggerConditionSubscribed, + want: &triggerConditionSubscribed, + }, { + name: "unknown condition", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionSubscribed, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ts.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerInitializeConditions(t *testing.T) { + tests := []struct { + name string + ts *TriggerStatus + want *TriggerStatus + }{{ + name: "empty", + ts: &TriggerStatus{}, + want: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one false", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionFalse, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, + }, + { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one true", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ts.InitializeConditions() + if diff := cmp.Diff(test.want, test.ts, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerConditionStatus(t *testing.T) { + tests := []struct { + name string + brokerStatus *BrokerStatus + markKubernetesServiceExists bool + markVirtualServiceExists bool + subscriptionCondition *apis.Condition + subscriberResolvedStatus bool + dependencyAnnotationExists bool + dependencyStatus corev1.ConditionStatus + wantConditionStatus corev1.ConditionStatus + }{{ + name: "all happy", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionTrue, + }, { + name: "broker status unknown", + brokerStatus: TestHelper.UnknownBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "broker status false", + brokerStatus: TestHelper.FalseBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "subscribed sad", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.FalseSubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "failed to resolve subscriber", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: false, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionTrue, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "dependency unknown", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionUnknown, + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "dependency false", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionFalse, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "all sad", + brokerStatus: TestHelper.FalseBrokerStatus(), + markKubernetesServiceExists: false, + markVirtualServiceExists: false, + subscriptionCondition: TestHelper.FalseSubscriptionCondition(), + subscriberResolvedStatus: false, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionFalse, + wantConditionStatus: corev1.ConditionFalse, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ts := &TriggerStatus{} + if test.brokerStatus != nil { + ts.PropagateBrokerCondition(test.brokerStatus.GetTopLevelCondition()) + } + if test.subscriptionCondition != nil { + ts.PropagateSubscriptionCondition(test.subscriptionCondition) + } + if test.subscriberResolvedStatus { + ts.MarkSubscriberResolvedSucceeded() + } else { + ts.MarkSubscriberResolvedFailed("Unable to get the Subscriber's URI", "subscriber not found") + } + if !test.dependencyAnnotationExists { + ts.MarkDependencySucceeded() + } else { + if test.dependencyStatus == corev1.ConditionTrue { + ts.MarkDependencySucceeded() + } else if test.dependencyStatus == corev1.ConditionUnknown { + ts.MarkDependencyUnknown("The status of dependency is unknown", "The status of dependency is unknown: nil") + } else { + ts.MarkDependencyFailed("The status of dependency is false", "The status of dependency is unknown: nil") + } + } + got := ts.GetTopLevelCondition().Status + if test.wantConditionStatus != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantConditionStatus, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/trigger_types.go b/pkg/apis/eventing/v1/trigger_types.go new file mode 100644 index 00000000000..21bb847a814 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_types.go @@ -0,0 +1,130 @@ +/* + * 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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +const ( + // DependencyAnnotation is the annotation key used to mark the sources that the Trigger depends on. + // This will be used when the kn client creates a source and trigger pair for the user such that the trigger only receives events produced by the paired source. + DependencyAnnotation = "knative.dev/dependency" + // InjectionAnnotation is the annotation key used to enable knative eventing injection for a namespace and automatically create a default broker. + // This will be used when the client creates a trigger paired with default broker and the default broker doesn't exist in the namespace + InjectionAnnotation = "knative-eventing-injection" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Trigger represents a request to have events delivered to a consumer from a +// Broker's event pool. +type Trigger struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Trigger. + Spec TriggerSpec `json:"spec,omitempty"` + + // Status represents the current state of the Trigger. This data may be out of + // date. + // +optional + Status TriggerStatus `json:"status,omitempty"` +} + +var ( + // Check that Trigger can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Trigger)(nil) + _ apis.Defaultable = (*Trigger)(nil) + + // Check that Trigger can return its spec untyped. + _ apis.HasSpec = (*Trigger)(nil) + + _ runtime.Object = (*Trigger)(nil) + + // Check that we can create OwnerReferences to a Trigger. + _ kmeta.OwnerRefable = (*Trigger)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Trigger)(nil) +) + +type TriggerSpec struct { + // Broker is the broker that this trigger receives events from. If not specified, will default + // to 'default'. + Broker string `json:"broker,omitempty"` + + // Filter is the filter to apply against all events from the Broker. Only events that pass this + // filter will be sent to the Subscriber. If not specified, will default to allowing all events. + // + // +optional + Filter *TriggerFilter `json:"filter,omitempty"` + + // Subscriber is the addressable that receives events from the Broker that pass the Filter. It + // is required. + Subscriber duckv1.Destination `json:"subscriber"` +} + +type TriggerFilter struct { + // Attributes filters events by exact match on event context attributes. + // Each key in the map is compared with the equivalent key in the event + // context. An event passes the filter if all values are equal to the + // specified values. + // + // Nested context attributes are not supported as keys. Only string values are supported. + // + // +optional + Attributes TriggerFilterAttributes `json:"attributes,omitempty"` +} + +// TriggerFilterAttributes is a map of context attribute names to values for +// filtering by equality. Only exact matches will pass the filter. You can use the value '' +// to indicate all strings match. +type TriggerFilterAttributes map[string]string + +// TriggerStatus represents the current state of a Trigger. +type TriggerStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // SubscriberURI is the resolved URI of the receiver for this Trigger. + SubscriberURI *apis.URL `json:"subscriberUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TriggerList is a collection of Triggers. +type TriggerList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Trigger `json:"items"` +} + +// GetStatus retrieves the status of the Trigger. Implements the KRShaped interface. +func (t *Trigger) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/eventing/v1/trigger_types_test.go b/pkg/apis/eventing/v1/trigger_types_test.go new file mode 100644 index 00000000000..12e2cfbae41 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_types_test.go @@ -0,0 +1,37 @@ +/* +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" + +func TestTriggerGetStatus(t *testing.T) { + r := &Trigger{ + Status: TriggerStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestTrigger_GetGroupVersionKind(t *testing.T) { + + tr := Trigger{} + gvk := tr.GetGroupVersionKind() + if gvk.Kind != "Trigger" { + t.Errorf("Should be Trigger.") + } +} diff --git a/pkg/apis/eventing/v1/trigger_validation.go b/pkg/apis/eventing/v1/trigger_validation.go new file mode 100644 index 00000000000..8a18a89e182 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_validation.go @@ -0,0 +1,155 @@ +/* + * 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 ( + "context" + "encoding/json" + "fmt" + "regexp" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" + + corev1 "k8s.io/api/core/v1" +) + +var ( + // Only allow lowercase alphanumeric, starting with letters. + validAttributeName = regexp.MustCompile(`^[a-z][a-z0-9]*$`) +) + +// Validate the Trigger. +func (t *Trigger) Validate(ctx context.Context) *apis.FieldError { + errs := t.Spec.Validate(ctx).ViaField("spec") + errs = t.validateAnnotation(errs, DependencyAnnotation, t.validateDependencyAnnotation) + errs = t.validateAnnotation(errs, InjectionAnnotation, t.validateInjectionAnnotation) + return errs +} + +// Validate the TriggerSpec. +func (ts *TriggerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if ts.Broker == "" { + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + } + + if ts.Filter != nil { + for attr := range map[string]string(ts.Filter.Attributes) { + if !validAttributeName.MatchString(attr) { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Invalid attribute name: %q", attr), + Paths: []string{"filter.attributes"}, + } + errs = errs.Also(fe) + } + } + } + + if fe := ts.Subscriber.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("subscriber")) + } + + return errs +} + +// CheckImmutableFields checks that any immutable fields were not changed. +func (t *Trigger) CheckImmutableFields(ctx context.Context, original *Trigger) *apis.FieldError { + if original == nil { + return nil + } + + if diff, err := kmp.ShortDiff(original.Spec.Broker, t.Spec.Broker); err != nil { + return &apis.FieldError{ + Message: "Failed to diff Trigger", + Paths: []string{"spec"}, + Details: err.Error(), + } + } else if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "broker"}, + Details: diff, + } + } + return nil +} + +func GetObjRefFromDependencyAnnotation(dependencyAnnotation string) (corev1.ObjectReference, error) { + var objectRef corev1.ObjectReference + if err := json.Unmarshal([]byte(dependencyAnnotation), &objectRef); err != nil { + return objectRef, err + } + return objectRef, nil +} + +func (t *Trigger) validateAnnotation(errs *apis.FieldError, annotation string, function func(string) *apis.FieldError) *apis.FieldError { + if annotationValue, ok := t.GetAnnotations()[annotation]; ok { + annotationPrefix := fmt.Sprintf("metadata.annotations[%s]", annotation) + errs = errs.Also(function(annotationValue).ViaField(annotationPrefix)) + } + return errs +} + +func (t *Trigger) validateDependencyAnnotation(dependencyAnnotation string) *apis.FieldError { + depObjRef, err := GetObjRefFromDependencyAnnotation(dependencyAnnotation) + if err != nil { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided annotation was not a corev1.ObjectReference: %q", dependencyAnnotation), + Details: err.Error(), + Paths: []string{""}, + } + } + var errs *apis.FieldError + if depObjRef.Namespace != "" && depObjRef.Namespace != t.GetNamespace() { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Namespace must be empty or equal to the trigger namespace %q", t.GetNamespace()), + Paths: []string{"namespace"}, + } + errs = errs.Also(fe) + } + if depObjRef.Kind == "" { + fe := apis.ErrMissingField("kind") + errs = errs.Also(fe) + } + if depObjRef.Name == "" { + fe := apis.ErrMissingField("name") + errs = errs.Also(fe) + } + if depObjRef.APIVersion == "" { + fe := apis.ErrMissingField("apiVersion") + errs = errs.Also(fe) + } + return errs +} + +func (t *Trigger) validateInjectionAnnotation(injectionAnnotation string) *apis.FieldError { + if injectionAnnotation != "enabled" { + return &apis.FieldError{ + Message: fmt.Sprintf(`The provided injection annotation value can only be "enabled", not %q`, injectionAnnotation), + Paths: []string{""}, + } + } + if t.Spec.Broker != "default" { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided injection annotation is only used for default broker, but non-default broker specified here: %q", t.Spec.Broker), + Paths: []string{""}, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1/trigger_validation_test.go b/pkg/apis/eventing/v1/trigger_validation_test.go new file mode 100644 index 00000000000..59e4b266bc6 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_validation_test.go @@ -0,0 +1,450 @@ +/* + * 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 ( + "context" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + validEmptyFilter = &TriggerFilter{} + validAttributesFilter = &TriggerFilter{ + Attributes: TriggerFilterAttributes{ + "type": "other_type", + "source": "other_source", + }, + } + validSubscriber = duckv1.Destination{ + Ref: &duckv1.KReference{ + Namespace: "namespace", + Name: "subscriber_test", + Kind: "Service", + APIVersion: "serving.knative.dev/v1alpha1", + }, + } + invalidSubscriber = duckv1.Destination{ + Ref: &duckv1.KReference{ + Namespace: "namespace", + Kind: "Service", + APIVersion: "serving.knative.dev/v1alpha1", + }, + } + // Dependency annotation + invalidDependencyAnnotation = "invalid dependency annotation" + dependencyAnnotationPath = fmt.Sprintf("metadata.annotations[%s]", DependencyAnnotation) + // Create default broker annotation + validInjectionAnnotation = "enabled" + invalidInjectionAnnotation = "disabled" + injectionAnnotationPath = fmt.Sprintf("metadata.annotations[%s]", InjectionAnnotation) +) + +func TestTriggerValidation(t *testing.T) { + tests := []struct { + name string + t *Trigger + want *apis.FieldError + }{{ + name: "invalid trigger spec", + t: &Trigger{Spec: TriggerSpec{}}, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("spec.broker") + errs = errs.Also(fe) + fe = apis.ErrGeneric("expected at least one, got none", "spec.subscriber.ref", "spec.subscriber.uri") + errs = errs.Also(fe) + return errs + }(), + }, { + name: "invalid dependency annotation, not a corev1.ObjectReference", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Annotations: map[string]string{ + DependencyAnnotation: invalidDependencyAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath}, + Message: "The provided annotation was not a corev1.ObjectReference: \"invalid dependency annotation\"", + Details: "invalid character 'i' looking for beginning of value", + }, + }, { + name: "invalid dependency annotation, trigger namespace is not equal to dependency namespace)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns-1", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"PingSource\",\"namespace\":\"test-ns-2\", \"name\":\"test-ping-source\",\"apiVersion\":\"sources.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "namespace"}, + Message: "Namespace must be empty or equal to the trigger namespace \"test-ns-1\"", + }, + }, + { + name: "invalid dependency annotation, missing kind)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"name\":\"test-ping-source\",\"apiVersion\":\"sources.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "kind"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing name", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"PingSource\",\"apiVersion\":\"sources.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "name"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing apiVersion", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"CronJobSource\",\"name\":\"test-cronjob-source\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing kind, name, apiVersion", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{ + dependencyAnnotationPath + "." + "kind", + dependencyAnnotationPath + "." + "name", + dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, + { + name: "invalid trigger spec, invalid dependency annotation(missing kind, name, apiVersion)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{}", + }}, + Spec: TriggerSpec{Subscriber: validSubscriber}}, + want: &apis.FieldError{ + Paths: []string{ + "spec.broker", + dependencyAnnotationPath + "." + "kind", + dependencyAnnotationPath + "." + "name", + dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, + { + name: "invalid injection annotation value", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + InjectionAnnotation: invalidInjectionAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "default", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{injectionAnnotationPath}, + Message: "The provided injection annotation value can only be \"enabled\", not \"disabled\"", + }, + }, + { + name: "valid injection annotation value, non-default broker specified", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + InjectionAnnotation: validInjectionAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "test-broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{injectionAnnotationPath}, + Message: "The provided injection annotation is only used for default broker, but non-default broker specified here: \"test-broker\"", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.t.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("Trigger.Validate (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerSpecValidation(t *testing.T) { + tests := []struct { + name string + ts *TriggerSpec + want *apis.FieldError + }{{ + name: "invalid trigger spec", + ts: &TriggerSpec{}, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + fe = apis.ErrGeneric("expected at least one, got none", "subscriber.ref", "subscriber.uri") + errs = errs.Also(fe) + return errs + + }(), + }, { + name: "missing broker", + ts: &TriggerSpec{ + Broker: "", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("broker") + return fe + }(), + }, { + name: "missing attributes keys, match all", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{ + Attributes: TriggerFilterAttributes{}, + }, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }, { + name: "invalid attribute name, start with number", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{ + Attributes: TriggerFilterAttributes{ + "0invalid": "my-value", + }, + }, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{ + Message: "Invalid attribute name: \"0invalid\"", + Paths: []string{"filter.attributes"}, + }, + }, { + name: "invalid attribute name, capital letters", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{ + Attributes: TriggerFilterAttributes{ + "invALID": "my-value", + }, + }, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{ + Message: "Invalid attribute name: \"invALID\"", + Paths: []string{"filter.attributes"}, + }, + }, { + name: "missing subscriber", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + }, + want: apis.ErrGeneric("expected at least one, got none", "subscriber.ref", "subscriber.uri"), + }, { + name: "missing subscriber.ref.name", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + Subscriber: invalidSubscriber, + }, + want: apis.ErrMissingField("subscriber.ref.name"), + }, { + name: "missing broker", + ts: &TriggerSpec{ + Broker: "", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: apis.ErrMissingField("broker"), + }, { + name: "valid empty filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }, { + name: "valid SourceAndType filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }, { + name: "valid Attributes filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ts.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate TriggerSpec (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestTriggerImmutableFields(t *testing.T) { + tests := []struct { + name string + current *Trigger + original *Trigger + want *apis.FieldError + }{{ + name: "good (no change)", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + want: nil, + }, { + name: "new nil is ok", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: nil, + want: nil, + }, { + name: "good (filter change)", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + Filter: validAttributesFilter, + }, + }, + want: nil, + }, { + name: "bad (broker change)", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Trigger{ + Spec: TriggerSpec{ + Broker: "original_broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "broker"}, + Details: `{string}: + -: "original_broker" + +: "broker" +`, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.current.CheckImmutableFields(context.TODO(), test.original) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..dcda76b4000 --- /dev/null +++ b/pkg/apis/eventing/v1/zz_generated.deepcopy.go @@ -0,0 +1,387 @@ +// +build !ignore_autogenerated + +/* +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 deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + v1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + apis "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Broker) DeepCopyInto(out *Broker) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Broker. +func (in *Broker) DeepCopy() *Broker { + if in == nil { + return nil + } + out := new(Broker) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Broker) 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 *BrokerList) DeepCopyInto(out *BrokerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Broker, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerList. +func (in *BrokerList) DeepCopy() *BrokerList { + if in == nil { + return nil + } + out := new(BrokerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BrokerList) 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 *BrokerSpec) DeepCopyInto(out *BrokerSpec) { + *out = *in + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(duckv1.KReference) + **out = **in + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(v1beta1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerSpec. +func (in *BrokerSpec) DeepCopy() *BrokerSpec { + if in == nil { + return nil + } + out := new(BrokerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerStatus) DeepCopyInto(out *BrokerStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.Address.DeepCopyInto(&out.Address) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerStatus. +func (in *BrokerStatus) DeepCopy() *BrokerStatus { + if in == nil { + return nil + } + out := new(BrokerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventType) DeepCopyInto(out *EventType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventType. +func (in *EventType) DeepCopy() *EventType { + if in == nil { + return nil + } + out := new(EventType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EventType) 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 *EventTypeList) DeepCopyInto(out *EventTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]EventType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeList. +func (in *EventTypeList) DeepCopy() *EventTypeList { + if in == nil { + return nil + } + out := new(EventTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EventTypeList) 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 *EventTypeSpec) DeepCopyInto(out *EventTypeSpec) { + *out = *in + if in.Source != nil { + in, out := &in.Source, &out.Source + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + if in.Schema != nil { + in, out := &in.Schema, &out.Schema + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeSpec. +func (in *EventTypeSpec) DeepCopy() *EventTypeSpec { + if in == nil { + return nil + } + out := new(EventTypeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventTypeStatus) DeepCopyInto(out *EventTypeStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeStatus. +func (in *EventTypeStatus) DeepCopy() *EventTypeStatus { + if in == nil { + return nil + } + out := new(EventTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Trigger) DeepCopyInto(out *Trigger) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trigger. +func (in *Trigger) DeepCopy() *Trigger { + if in == nil { + return nil + } + out := new(Trigger) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Trigger) 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 *TriggerFilter) DeepCopyInto(out *TriggerFilter) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(TriggerFilterAttributes, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilter. +func (in *TriggerFilter) DeepCopy() *TriggerFilter { + if in == nil { + return nil + } + out := new(TriggerFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in TriggerFilterAttributes) DeepCopyInto(out *TriggerFilterAttributes) { + { + in := &in + *out = make(TriggerFilterAttributes, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilterAttributes. +func (in TriggerFilterAttributes) DeepCopy() TriggerFilterAttributes { + if in == nil { + return nil + } + out := new(TriggerFilterAttributes) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerList) DeepCopyInto(out *TriggerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Trigger, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerList. +func (in *TriggerList) DeepCopy() *TriggerList { + if in == nil { + return nil + } + out := new(TriggerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TriggerList) 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 *TriggerSpec) DeepCopyInto(out *TriggerSpec) { + *out = *in + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(TriggerFilter) + (*in).DeepCopyInto(*out) + } + in.Subscriber.DeepCopyInto(&out.Subscriber) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerSpec. +func (in *TriggerSpec) DeepCopy() *TriggerSpec { + if in == nil { + return nil + } + out := new(TriggerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerStatus) DeepCopyInto(out *TriggerStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + if in.SubscriberURI != nil { + in, out := &in.SubscriberURI, &out.SubscriberURI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerStatus. +func (in *TriggerStatus) DeepCopy() *TriggerStatus { + if in == nil { + return nil + } + out := new(TriggerStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 7b5f994fcd5..21897073e17 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -25,6 +25,7 @@ import ( rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" @@ -36,6 +37,7 @@ type Interface interface { Discovery() discovery.DiscoveryInterface ConfigsV1alpha1() configsv1alpha1.ConfigsV1alpha1Interface EventingV1beta1() eventingv1beta1.EventingV1beta1Interface + EventingV1() eventingv1.EventingV1Interface FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface @@ -48,6 +50,7 @@ type Clientset struct { *discovery.DiscoveryClient configsV1alpha1 *configsv1alpha1.ConfigsV1alpha1Client eventingV1beta1 *eventingv1beta1.EventingV1beta1Client + eventingV1 *eventingv1.EventingV1Client flowsV1beta1 *flowsv1beta1.FlowsV1beta1Client messagingV1beta1 *messagingv1beta1.MessagingV1beta1Client sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client @@ -64,6 +67,11 @@ func (c *Clientset) EventingV1beta1() eventingv1beta1.EventingV1beta1Interface { return c.eventingV1beta1 } +// EventingV1 retrieves the EventingV1Client +func (c *Clientset) EventingV1() eventingv1.EventingV1Interface { + return c.eventingV1 +} + // FlowsV1beta1 retrieves the FlowsV1beta1Client func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return c.flowsV1beta1 @@ -113,6 +121,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.eventingV1, err = eventingv1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.flowsV1beta1, err = flowsv1beta1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -143,6 +155,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset cs.configsV1alpha1 = configsv1alpha1.NewForConfigOrDie(c) cs.eventingV1beta1 = eventingv1beta1.NewForConfigOrDie(c) + cs.eventingV1 = eventingv1.NewForConfigOrDie(c) cs.flowsV1beta1 = flowsv1beta1.NewForConfigOrDie(c) cs.messagingV1beta1 = messagingv1beta1.NewForConfigOrDie(c) cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) @@ -157,6 +170,7 @@ func New(c rest.Interface) *Clientset { var cs Clientset cs.configsV1alpha1 = configsv1alpha1.New(c) cs.eventingV1beta1 = eventingv1beta1.New(c) + cs.eventingV1 = eventingv1.New(c) cs.flowsV1beta1 = flowsv1beta1.New(c) cs.messagingV1beta1 = messagingv1beta1.New(c) cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 5f55ecc9095..a3c066cafe7 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -27,6 +27,8 @@ import ( clientset "knative.dev/eventing/pkg/client/clientset/versioned" configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" fakeconfigsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake" + eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" + fakeeventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" fakeeventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" @@ -96,6 +98,11 @@ func (c *Clientset) EventingV1beta1() eventingv1beta1.EventingV1beta1Interface { return &fakeeventingv1beta1.FakeEventingV1beta1{Fake: &c.Fake} } +// EventingV1 retrieves the EventingV1Client +func (c *Clientset) EventingV1() eventingv1.EventingV1Interface { + return &fakeeventingv1.FakeEventingV1{Fake: &c.Fake} +} + // FlowsV1beta1 retrieves the FlowsV1beta1Client func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return &fakeflowsv1beta1.FakeFlowsV1beta1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 6b46a004e41..d767c435481 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -38,6 +39,7 @@ var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ configsv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, + eventingv1.AddToScheme, flowsv1beta1.AddToScheme, messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 76c104bc5bc..a6cb9e4ac2d 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -38,6 +39,7 @@ var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ configsv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, + eventingv1.AddToScheme, flowsv1beta1.AddToScheme, messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/broker.go b/pkg/client/clientset/versioned/typed/eventing/v1/broker.go new file mode 100644 index 00000000000..f7309d95a94 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/broker.go @@ -0,0 +1,191 @@ +/* +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// BrokersGetter has a method to return a BrokerInterface. +// A group's client should implement this interface. +type BrokersGetter interface { + Brokers(namespace string) BrokerInterface +} + +// BrokerInterface has methods to work with Broker resources. +type BrokerInterface interface { + Create(*v1.Broker) (*v1.Broker, error) + Update(*v1.Broker) (*v1.Broker, error) + UpdateStatus(*v1.Broker) (*v1.Broker, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Broker, error) + List(opts metav1.ListOptions) (*v1.BrokerList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Broker, err error) + BrokerExpansion +} + +// brokers implements BrokerInterface +type brokers struct { + client rest.Interface + ns string +} + +// newBrokers returns a Brokers +func newBrokers(c *EventingV1Client, namespace string) *brokers { + return &brokers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the broker, and returns the corresponding broker object, and an error if there is any. +func (c *brokers) Get(name string, options metav1.GetOptions) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Brokers that match those selectors. +func (c *brokers) List(opts metav1.ListOptions) (result *v1.BrokerList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.BrokerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *brokers) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a broker and creates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *brokers) Create(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Post(). + Namespace(c.ns). + Resource("brokers"). + Body(broker). + Do(). + Into(result) + return +} + +// Update takes the representation of a broker and updates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *brokers) Update(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Put(). + Namespace(c.ns). + Resource("brokers"). + Name(broker.Name). + Body(broker). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *brokers) UpdateStatus(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Put(). + Namespace(c.ns). + Resource("brokers"). + Name(broker.Name). + SubResource("status"). + Body(broker). + Do(). + Into(result) + return +} + +// Delete takes name of the broker and deletes it. Returns an error if one occurs. +func (c *brokers) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *brokers) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched broker. +func (c *brokers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("brokers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/doc.go b/pkg/client/clientset/versioned/typed/eventing/v1/doc.go new file mode 100644 index 00000000000..5b83bd1f41a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/doc.go @@ -0,0 +1,20 @@ +/* +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 client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go new file mode 100644 index 00000000000..33f0a284138 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go @@ -0,0 +1,99 @@ +/* +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type EventingV1Interface interface { + RESTClient() rest.Interface + BrokersGetter + EventTypesGetter + TriggersGetter +} + +// EventingV1Client is used to interact with features provided by the eventing.knative.dev group. +type EventingV1Client struct { + restClient rest.Interface +} + +func (c *EventingV1Client) Brokers(namespace string) BrokerInterface { + return newBrokers(c, namespace) +} + +func (c *EventingV1Client) EventTypes(namespace string) EventTypeInterface { + return newEventTypes(c, namespace) +} + +func (c *EventingV1Client) Triggers(namespace string) TriggerInterface { + return newTriggers(c, namespace) +} + +// NewForConfig creates a new EventingV1Client for the given config. +func NewForConfig(c *rest.Config) (*EventingV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &EventingV1Client{client}, nil +} + +// NewForConfigOrDie creates a new EventingV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *EventingV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new EventingV1Client for the given RESTClient. +func New(c rest.Interface) *EventingV1Client { + return &EventingV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *EventingV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go new file mode 100644 index 00000000000..ae2ff540429 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go @@ -0,0 +1,191 @@ +/* +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// EventTypesGetter has a method to return a EventTypeInterface. +// A group's client should implement this interface. +type EventTypesGetter interface { + EventTypes(namespace string) EventTypeInterface +} + +// EventTypeInterface has methods to work with EventType resources. +type EventTypeInterface interface { + Create(*v1.EventType) (*v1.EventType, error) + Update(*v1.EventType) (*v1.EventType, error) + UpdateStatus(*v1.EventType) (*v1.EventType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.EventType, error) + List(opts metav1.ListOptions) (*v1.EventTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.EventType, err error) + EventTypeExpansion +} + +// eventTypes implements EventTypeInterface +type eventTypes struct { + client rest.Interface + ns string +} + +// newEventTypes returns a EventTypes +func newEventTypes(c *EventingV1Client, namespace string) *eventTypes { + return &eventTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any. +func (c *eventTypes) Get(name string, options metav1.GetOptions) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of EventTypes that match those selectors. +func (c *eventTypes) List(opts metav1.ListOptions) (result *v1.EventTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.EventTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested eventTypes. +func (c *eventTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *eventTypes) Create(eventType *v1.EventType) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("eventtypes"). + Body(eventType). + Do(). + Into(result) + return +} + +// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *eventTypes) Update(eventType *v1.EventType) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("eventtypes"). + Name(eventType.Name). + Body(eventType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *eventTypes) UpdateStatus(eventType *v1.EventType) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("eventtypes"). + Name(eventType.Name). + SubResource("status"). + Body(eventType). + Do(). + Into(result) + return +} + +// Delete takes name of the eventType and deletes it. Returns an error if one occurs. +func (c *eventTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("eventtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *eventTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched eventType. +func (c *eventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("eventtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go new file mode 100644 index 00000000000..c7f6e65cab8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +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 client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go new file mode 100644 index 00000000000..fff607109c6 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go @@ -0,0 +1,140 @@ +/* +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 client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeBrokers implements BrokerInterface +type FakeBrokers struct { + Fake *FakeEventingV1 + ns string +} + +var brokersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "brokers"} + +var brokersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "Broker"} + +// Get takes name of the broker, and returns the corresponding broker object, and an error if there is any. +func (c *FakeBrokers) Get(name string, options v1.GetOptions) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(brokersResource, c.ns, name), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// List takes label and field selectors, and returns the list of Brokers that match those selectors. +func (c *FakeBrokers) List(opts v1.ListOptions) (result *eventingv1.BrokerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(brokersResource, brokersKind, c.ns, opts), &eventingv1.BrokerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.BrokerList{ListMeta: obj.(*eventingv1.BrokerList).ListMeta} + for _, item := range obj.(*eventingv1.BrokerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *FakeBrokers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(brokersResource, c.ns, opts)) + +} + +// Create takes the representation of a broker and creates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *FakeBrokers) Create(broker *eventingv1.Broker) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(brokersResource, c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// Update takes the representation of a broker and updates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *FakeBrokers) Update(broker *eventingv1.Broker) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(brokersResource, c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeBrokers) UpdateStatus(broker *eventingv1.Broker) (*eventingv1.Broker, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(brokersResource, "status", c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// Delete takes name of the broker and deletes it. Returns an error if one occurs. +func (c *FakeBrokers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(brokersResource, c.ns, name), &eventingv1.Broker{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBrokers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(brokersResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.BrokerList{}) + return err +} + +// Patch applies the patch and returns the patched broker. +func (c *FakeBrokers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(brokersResource, c.ns, name, pt, data, subresources...), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go new file mode 100644 index 00000000000..ce798a54a83 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go @@ -0,0 +1,48 @@ +/* +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 client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" +) + +type FakeEventingV1 struct { + *testing.Fake +} + +func (c *FakeEventingV1) Brokers(namespace string) v1.BrokerInterface { + return &FakeBrokers{c, namespace} +} + +func (c *FakeEventingV1) EventTypes(namespace string) v1.EventTypeInterface { + return &FakeEventTypes{c, namespace} +} + +func (c *FakeEventingV1) Triggers(namespace string) v1.TriggerInterface { + return &FakeTriggers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeEventingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go new file mode 100644 index 00000000000..05936641b19 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go @@ -0,0 +1,140 @@ +/* +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 client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeEventTypes implements EventTypeInterface +type FakeEventTypes struct { + Fake *FakeEventingV1 + ns string +} + +var eventtypesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "eventtypes"} + +var eventtypesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "EventType"} + +// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any. +func (c *FakeEventTypes) Get(name string, options v1.GetOptions) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// List takes label and field selectors, and returns the list of EventTypes that match those selectors. +func (c *FakeEventTypes) List(opts v1.ListOptions) (result *eventingv1.EventTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &eventingv1.EventTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.EventTypeList{ListMeta: obj.(*eventingv1.EventTypeList).ListMeta} + for _, item := range obj.(*eventingv1.EventTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested eventTypes. +func (c *FakeEventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(eventtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *FakeEventTypes) Create(eventType *eventingv1.EventType) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *FakeEventTypes) Update(eventType *eventingv1.EventType) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeEventTypes) UpdateStatus(eventType *eventingv1.EventType) (*eventingv1.EventType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// Delete takes name of the eventType and deletes it. Returns an error if one occurs. +func (c *FakeEventTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(eventtypesResource, c.ns, name), &eventingv1.EventType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(eventtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.EventTypeList{}) + return err +} + +// Patch applies the patch and returns the patched eventType. +func (c *FakeEventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, pt, data, subresources...), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go new file mode 100644 index 00000000000..6b3795b6fbb --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go @@ -0,0 +1,140 @@ +/* +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 client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeTriggers implements TriggerInterface +type FakeTriggers struct { + Fake *FakeEventingV1 + ns string +} + +var triggersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "triggers"} + +var triggersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "Trigger"} + +// Get takes name of the trigger, and returns the corresponding trigger object, and an error if there is any. +func (c *FakeTriggers) Get(name string, options v1.GetOptions) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(triggersResource, c.ns, name), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// List takes label and field selectors, and returns the list of Triggers that match those selectors. +func (c *FakeTriggers) List(opts v1.ListOptions) (result *eventingv1.TriggerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(triggersResource, triggersKind, c.ns, opts), &eventingv1.TriggerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.TriggerList{ListMeta: obj.(*eventingv1.TriggerList).ListMeta} + for _, item := range obj.(*eventingv1.TriggerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *FakeTriggers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(triggersResource, c.ns, opts)) + +} + +// Create takes the representation of a trigger and creates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *FakeTriggers) Create(trigger *eventingv1.Trigger) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(triggersResource, c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// Update takes the representation of a trigger and updates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *FakeTriggers) Update(trigger *eventingv1.Trigger) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(triggersResource, c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTriggers) UpdateStatus(trigger *eventingv1.Trigger) (*eventingv1.Trigger, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(triggersResource, "status", c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// Delete takes name of the trigger and deletes it. Returns an error if one occurs. +func (c *FakeTriggers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(triggersResource, c.ns, name), &eventingv1.Trigger{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTriggers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(triggersResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.TriggerList{}) + return err +} + +// Patch applies the patch and returns the patched trigger. +func (c *FakeTriggers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(triggersResource, c.ns, name, pt, data, subresources...), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go new file mode 100644 index 00000000000..9dbe76ef962 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go @@ -0,0 +1,25 @@ +/* +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 client-gen. DO NOT EDIT. + +package v1 + +type BrokerExpansion interface{} + +type EventTypeExpansion interface{} + +type TriggerExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go b/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go new file mode 100644 index 00000000000..9726e4e3c8f --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go @@ -0,0 +1,191 @@ +/* +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// TriggersGetter has a method to return a TriggerInterface. +// A group's client should implement this interface. +type TriggersGetter interface { + Triggers(namespace string) TriggerInterface +} + +// TriggerInterface has methods to work with Trigger resources. +type TriggerInterface interface { + Create(*v1.Trigger) (*v1.Trigger, error) + Update(*v1.Trigger) (*v1.Trigger, error) + UpdateStatus(*v1.Trigger) (*v1.Trigger, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Trigger, error) + List(opts metav1.ListOptions) (*v1.TriggerList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Trigger, err error) + TriggerExpansion +} + +// triggers implements TriggerInterface +type triggers struct { + client rest.Interface + ns string +} + +// newTriggers returns a Triggers +func newTriggers(c *EventingV1Client, namespace string) *triggers { + return &triggers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the trigger, and returns the corresponding trigger object, and an error if there is any. +func (c *triggers) Get(name string, options metav1.GetOptions) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Triggers that match those selectors. +func (c *triggers) List(opts metav1.ListOptions) (result *v1.TriggerList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TriggerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *triggers) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a trigger and creates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *triggers) Create(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Post(). + Namespace(c.ns). + Resource("triggers"). + Body(trigger). + Do(). + Into(result) + return +} + +// Update takes the representation of a trigger and updates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *triggers) Update(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Put(). + Namespace(c.ns). + Resource("triggers"). + Name(trigger.Name). + Body(trigger). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *triggers) UpdateStatus(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Put(). + Namespace(c.ns). + Resource("triggers"). + Name(trigger.Name). + SubResource("status"). + Body(trigger). + Do(). + Into(result) + return +} + +// Delete takes name of the trigger and deletes it. Returns an error if one occurs. +func (c *triggers) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *triggers) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched trigger. +func (c *triggers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("triggers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/eventing/interface.go b/pkg/client/informers/externalversions/eventing/interface.go index c4e662bafbf..531a3c77218 100644 --- a/pkg/client/informers/externalversions/eventing/interface.go +++ b/pkg/client/informers/externalversions/eventing/interface.go @@ -19,6 +19,7 @@ limitations under the License. package eventing import ( + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1beta1" internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" ) @@ -27,6 +28,8 @@ import ( type Interface interface { // V1beta1 provides access to shared informers for resources in V1beta1. V1beta1() v1beta1.Interface + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1beta1() v1beta1.Interface { return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/eventing/v1/broker.go b/pkg/client/informers/externalversions/eventing/v1/broker.go new file mode 100644 index 00000000000..b35aa4ee2fa --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/broker.go @@ -0,0 +1,89 @@ +/* +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// BrokerInformer provides access to a shared informer and lister for +// Brokers. +type BrokerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.BrokerLister +} + +type brokerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewBrokerInformer constructs a new informer for Broker type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBrokerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBrokerInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredBrokerInformer constructs a new informer for Broker type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBrokerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Brokers(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Brokers(namespace).Watch(options) + }, + }, + &eventingv1.Broker{}, + resyncPeriod, + indexers, + ) +} + +func (f *brokerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBrokerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *brokerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.Broker{}, f.defaultInformer) +} + +func (f *brokerInformer) Lister() v1.BrokerLister { + return v1.NewBrokerLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/eventing/v1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1/eventtype.go new file mode 100644 index 00000000000..7c9034c5a5d --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/eventtype.go @@ -0,0 +1,89 @@ +/* +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// EventTypeInformer provides access to a shared informer and lister for +// EventTypes. +type EventTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.EventTypeLister +} + +type eventTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewEventTypeInformer constructs a new informer for EventType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredEventTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredEventTypeInformer constructs a new informer for EventType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().EventTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().EventTypes(namespace).Watch(options) + }, + }, + &eventingv1.EventType{}, + resyncPeriod, + indexers, + ) +} + +func (f *eventTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredEventTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *eventTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.EventType{}, f.defaultInformer) +} + +func (f *eventTypeInformer) Lister() v1.EventTypeLister { + return v1.NewEventTypeLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/eventing/v1/interface.go b/pkg/client/informers/externalversions/eventing/v1/interface.go new file mode 100644 index 00000000000..b152e717d0f --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/interface.go @@ -0,0 +1,59 @@ +/* +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Brokers returns a BrokerInformer. + Brokers() BrokerInformer + // EventTypes returns a EventTypeInformer. + EventTypes() EventTypeInformer + // Triggers returns a TriggerInformer. + Triggers() TriggerInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Brokers returns a BrokerInformer. +func (v *version) Brokers() BrokerInformer { + return &brokerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// EventTypes returns a EventTypeInformer. +func (v *version) EventTypes() EventTypeInformer { + return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Triggers returns a TriggerInformer. +func (v *version) Triggers() TriggerInformer { + return &triggerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/eventing/v1/trigger.go b/pkg/client/informers/externalversions/eventing/v1/trigger.go new file mode 100644 index 00000000000..6f99981bf74 --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/trigger.go @@ -0,0 +1,89 @@ +/* +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// TriggerInformer provides access to a shared informer and lister for +// Triggers. +type TriggerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TriggerLister +} + +type triggerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTriggerInformer constructs a new informer for Trigger type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTriggerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTriggerInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTriggerInformer constructs a new informer for Trigger type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTriggerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Triggers(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Triggers(namespace).Watch(options) + }, + }, + &eventingv1.Trigger{}, + resyncPeriod, + indexers, + ) +} + +func (f *triggerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTriggerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *triggerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.Trigger{}, f.defaultInformer) +} + +func (f *triggerInformer) Lister() v1.TriggerLister { + return v1.NewTriggerLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index c91f5c47581..b264f0f489e 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -61,6 +62,14 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("configmappropagations"): return &genericInformer{resource: resource.GroupResource(), informer: f.Configs().V1alpha1().ConfigMapPropagations().Informer()}, nil + // Group=eventing.knative.dev, Version=v1 + case v1.SchemeGroupVersion.WithResource("brokers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Brokers().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("eventtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().EventTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("triggers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Triggers().Informer()}, nil + // Group=eventing.knative.dev, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithResource("brokers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1beta1().Brokers().Informer()}, nil diff --git a/pkg/client/injection/informers/eventing/v1/broker/broker.go b/pkg/client/injection/informers/eventing/v1/broker/broker.go new file mode 100644 index 00000000000..61f646f0941 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/broker/broker.go @@ -0,0 +1,52 @@ +/* +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 broker + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1().Brokers() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.BrokerInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.BrokerInformer from context.") + } + return untyped.(v1.BrokerInformer) +} diff --git a/pkg/client/injection/informers/eventing/v1/broker/fake/fake.go b/pkg/client/injection/informers/eventing/v1/broker/fake/fake.go new file mode 100644 index 00000000000..5dc3b1c768a --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/broker/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + broker "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = broker.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1().Brokers() + return context.WithValue(ctx, broker.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go b/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go new file mode 100644 index 00000000000..838fa4db171 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go @@ -0,0 +1,52 @@ +/* +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 eventtype + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1().EventTypes() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.EventTypeInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.EventTypeInformer from context.") + } + return untyped.(v1.EventTypeInformer) +} diff --git a/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go b/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go new file mode 100644 index 00000000000..6cda229bf31 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = eventtype.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1().EventTypes() + return context.WithValue(ctx, eventtype.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go b/pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go new file mode 100644 index 00000000000..bf33f84f0ee --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/trigger/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + trigger "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = trigger.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1().Triggers() + return context.WithValue(ctx, trigger.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1/trigger/trigger.go b/pkg/client/injection/informers/eventing/v1/trigger/trigger.go new file mode 100644 index 00000000000..3bd2d81ed3d --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/trigger/trigger.go @@ -0,0 +1,52 @@ +/* +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 trigger + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1().Triggers() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.TriggerInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.TriggerInformer from context.") + } + return untyped.(v1.TriggerInformer) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/controller.go b/pkg/client/injection/reconciler/eventing/v1/broker/controller.go new file mode 100644 index 00000000000..5fc2915d5c4 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/controller.go @@ -0,0 +1,122 @@ +/* +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 broker + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + broker "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "broker-controller" + defaultFinalizerName = "brokers.eventing.knative.dev" + + // ClassAnnotationKey points to the annotation for the class of this resource. + ClassAnnotationKey = "eventing.knative.dev/broker.class" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, classValue string, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + brokerInformer := broker.Get(ctx) + + rec := &reconcilerImpl{ + Client: client.Get(ctx), + Lister: brokerInformer.Lister(), + reconciler: r, + finalizerName: defaultFinalizerName, + classValue: classValue, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go new file mode 100644 index 00000000000..7e44be64ba0 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go @@ -0,0 +1,369 @@ +/* +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 broker + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Broker. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.Broker. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.Broker) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Broker. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.Broker. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.Broker) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.Broker resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister eventingv1.BrokerLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string + + // classValue is the resource annotation[eventing.knative.dev/broker.class] instance value this reconciler instance filters on. + classValue string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventingv1.BrokerLister, recorder record.EventRecorder, r Interface, classValue string, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + classValue: classValue, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.Brokers(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + if classValue, found := original.GetAnnotations()[ClassAnnotationKey]; !found || classValue != r.classValue { + logger.Debugw("Skip reconciling resource, class annotation value does not match reconciler instance value.", + zap.String("classKey", ClassAnnotationKey), + zap.String("issue", classValue+"!="+r.classValue)) + return nil + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + reconciler.PreProcessReconcile(ctx, resource) + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + reconciler.PostProcessReconcile(ctx, resource, original) + + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.Broker, desired *v1.Broker) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1().Brokers(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1().Brokers(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Broker) (*v1.Broker, error) { + + getter := r.Lister.Brokers(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1().Brokers(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Broker) (*v1.Broker, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Broker, reconcileEvent reconciler.Event) (*v1.Broker, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go new file mode 100644 index 00000000000..8d6a39a0ba3 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go @@ -0,0 +1,63 @@ +/* +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 broker + +import ( + context "context" + + cache "k8s.io/client-go/tools/cache" + broker "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker" + v1broker "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/broker" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Broker and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + brokerInformer := broker.Get(ctx) + + classValue := "default" // TODO: update this to the appropriate value. + classFilter := reconciler.AnnotationFilterFunc(v1broker.ClassAnnotationKey, classValue, false /*allowUnset*/) + + // TODO: setup additional informers here. + // TODO: remember to use the classFilter from above to filter appropriately. + + r := &Reconciler{} + impl := v1broker.NewImpl(ctx, r, classValue) + + logger.Info("Setting up event handlers.") + + brokerInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: classFilter, + Handler: controller.HandleAll(impl.Enqueue), + }) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go new file mode 100644 index 00000000000..4af7c0a978a --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +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 broker + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + broker "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/broker" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason BrokerReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "BrokerReconciled", "Broker reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Broker resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ broker.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ broker.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.Broker) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.Broker) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go new file mode 100644 index 00000000000..4b8baabc07a --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go @@ -0,0 +1,118 @@ +/* +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 eventtype + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "eventtype-controller" + defaultFinalizerName = "eventtypes.eventing.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + eventtypeInformer := eventtype.Get(ctx) + + rec := &reconcilerImpl{ + Client: client.Get(ctx), + Lister: eventtypeInformer.Lister(), + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go new file mode 100644 index 00000000000..c16bafe9b9a --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go @@ -0,0 +1,358 @@ +/* +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 eventtype + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.EventType. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.EventType. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.EventType) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.EventType. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.EventType. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.EventType) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.EventType resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister eventingv1.EventTypeLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventingv1.EventTypeLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.EventTypes(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + reconciler.PreProcessReconcile(ctx, resource) + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + reconciler.PostProcessReconcile(ctx, resource, original) + + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.EventType, desired *v1.EventType) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1().EventTypes(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1().EventTypes(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.EventType) (*v1.EventType, error) { + + getter := r.Lister.EventTypes(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1().EventTypes(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.EventType) (*v1.EventType, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.EventType, reconcileEvent reconciler.Event) (*v1.EventType, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go new file mode 100644 index 00000000000..287c617e9cd --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go @@ -0,0 +1,54 @@ +/* +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 eventtype + +import ( + context "context" + + eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" + v1eventtype "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/eventtype" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for EventType and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + eventtypeInformer := eventtype.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1eventtype.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + eventtypeInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go new file mode 100644 index 00000000000..dd6b073d2ae --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +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 eventtype + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + eventtype "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/eventtype" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason EventTypeReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "EventTypeReconciled", "EventType reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for EventType resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ eventtype.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ eventtype.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/controller.go b/pkg/client/injection/reconciler/eventing/v1/trigger/controller.go new file mode 100644 index 00000000000..075c88405d4 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/controller.go @@ -0,0 +1,118 @@ +/* +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 trigger + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + trigger "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "trigger-controller" + defaultFinalizerName = "triggers.eventing.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + triggerInformer := trigger.Get(ctx) + + rec := &reconcilerImpl{ + Client: client.Get(ctx), + Lister: triggerInformer.Lister(), + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/trigger/reconciler.go new file mode 100644 index 00000000000..6a3f530e078 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/reconciler.go @@ -0,0 +1,358 @@ +/* +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 trigger + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Trigger. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.Trigger. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.Trigger) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Trigger. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.Trigger. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.Trigger) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.Trigger resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister eventingv1.TriggerLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventingv1.TriggerLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.Triggers(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + reconciler.PreProcessReconcile(ctx, resource) + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + reconciler.PostProcessReconcile(ctx, resource, original) + + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.Trigger, desired *v1.Trigger) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1().Triggers(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1().Triggers(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Trigger) (*v1.Trigger, error) { + + getter := r.Lister.Triggers(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1().Triggers(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Trigger) (*v1.Trigger, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Trigger, reconcileEvent reconciler.Event) (*v1.Trigger, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go new file mode 100644 index 00000000000..763d680a2b9 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go @@ -0,0 +1,54 @@ +/* +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 trigger + +import ( + context "context" + + trigger "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger" + v1trigger "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/trigger" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Trigger and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + triggerInformer := trigger.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1trigger.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + triggerInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go new file mode 100644 index 00000000000..e94291d5242 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +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 trigger + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + trigger "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/trigger" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason TriggerReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "TriggerReconciled", "Trigger reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Trigger resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ trigger.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ trigger.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.Trigger) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.Trigger) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/listers/eventing/v1/broker.go b/pkg/client/listers/eventing/v1/broker.go new file mode 100644 index 00000000000..c6dca9da079 --- /dev/null +++ b/pkg/client/listers/eventing/v1/broker.go @@ -0,0 +1,94 @@ +/* +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 lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// BrokerLister helps list Brokers. +type BrokerLister interface { + // List lists all Brokers in the indexer. + List(selector labels.Selector) (ret []*v1.Broker, err error) + // Brokers returns an object that can list and get Brokers. + Brokers(namespace string) BrokerNamespaceLister + BrokerListerExpansion +} + +// brokerLister implements the BrokerLister interface. +type brokerLister struct { + indexer cache.Indexer +} + +// NewBrokerLister returns a new BrokerLister. +func NewBrokerLister(indexer cache.Indexer) BrokerLister { + return &brokerLister{indexer: indexer} +} + +// List lists all Brokers in the indexer. +func (s *brokerLister) List(selector labels.Selector) (ret []*v1.Broker, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Broker)) + }) + return ret, err +} + +// Brokers returns an object that can list and get Brokers. +func (s *brokerLister) Brokers(namespace string) BrokerNamespaceLister { + return brokerNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// BrokerNamespaceLister helps list and get Brokers. +type BrokerNamespaceLister interface { + // List lists all Brokers in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Broker, err error) + // Get retrieves the Broker from the indexer for a given namespace and name. + Get(name string) (*v1.Broker, error) + BrokerNamespaceListerExpansion +} + +// brokerNamespaceLister implements the BrokerNamespaceLister +// interface. +type brokerNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Brokers in the indexer for a given namespace. +func (s brokerNamespaceLister) List(selector labels.Selector) (ret []*v1.Broker, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Broker)) + }) + return ret, err +} + +// Get retrieves the Broker from the indexer for a given namespace and name. +func (s brokerNamespaceLister) Get(name string) (*v1.Broker, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("broker"), name) + } + return obj.(*v1.Broker), nil +} diff --git a/pkg/client/listers/eventing/v1/eventtype.go b/pkg/client/listers/eventing/v1/eventtype.go new file mode 100644 index 00000000000..260b3ff14fd --- /dev/null +++ b/pkg/client/listers/eventing/v1/eventtype.go @@ -0,0 +1,94 @@ +/* +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 lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// EventTypeLister helps list EventTypes. +type EventTypeLister interface { + // List lists all EventTypes in the indexer. + List(selector labels.Selector) (ret []*v1.EventType, err error) + // EventTypes returns an object that can list and get EventTypes. + EventTypes(namespace string) EventTypeNamespaceLister + EventTypeListerExpansion +} + +// eventTypeLister implements the EventTypeLister interface. +type eventTypeLister struct { + indexer cache.Indexer +} + +// NewEventTypeLister returns a new EventTypeLister. +func NewEventTypeLister(indexer cache.Indexer) EventTypeLister { + return &eventTypeLister{indexer: indexer} +} + +// List lists all EventTypes in the indexer. +func (s *eventTypeLister) List(selector labels.Selector) (ret []*v1.EventType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.EventType)) + }) + return ret, err +} + +// EventTypes returns an object that can list and get EventTypes. +func (s *eventTypeLister) EventTypes(namespace string) EventTypeNamespaceLister { + return eventTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// EventTypeNamespaceLister helps list and get EventTypes. +type EventTypeNamespaceLister interface { + // List lists all EventTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.EventType, err error) + // Get retrieves the EventType from the indexer for a given namespace and name. + Get(name string) (*v1.EventType, error) + EventTypeNamespaceListerExpansion +} + +// eventTypeNamespaceLister implements the EventTypeNamespaceLister +// interface. +type eventTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all EventTypes in the indexer for a given namespace. +func (s eventTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.EventType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.EventType)) + }) + return ret, err +} + +// Get retrieves the EventType from the indexer for a given namespace and name. +func (s eventTypeNamespaceLister) Get(name string) (*v1.EventType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("eventtype"), name) + } + return obj.(*v1.EventType), nil +} diff --git a/pkg/client/listers/eventing/v1/expansion_generated.go b/pkg/client/listers/eventing/v1/expansion_generated.go new file mode 100644 index 00000000000..08088029b1e --- /dev/null +++ b/pkg/client/listers/eventing/v1/expansion_generated.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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// BrokerListerExpansion allows custom methods to be added to +// BrokerLister. +type BrokerListerExpansion interface{} + +// BrokerNamespaceListerExpansion allows custom methods to be added to +// BrokerNamespaceLister. +type BrokerNamespaceListerExpansion interface{} + +// EventTypeListerExpansion allows custom methods to be added to +// EventTypeLister. +type EventTypeListerExpansion interface{} + +// EventTypeNamespaceListerExpansion allows custom methods to be added to +// EventTypeNamespaceLister. +type EventTypeNamespaceListerExpansion interface{} + +// TriggerListerExpansion allows custom methods to be added to +// TriggerLister. +type TriggerListerExpansion interface{} + +// TriggerNamespaceListerExpansion allows custom methods to be added to +// TriggerNamespaceLister. +type TriggerNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/eventing/v1/trigger.go b/pkg/client/listers/eventing/v1/trigger.go new file mode 100644 index 00000000000..bd362b5c5fc --- /dev/null +++ b/pkg/client/listers/eventing/v1/trigger.go @@ -0,0 +1,94 @@ +/* +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 lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// TriggerLister helps list Triggers. +type TriggerLister interface { + // List lists all Triggers in the indexer. + List(selector labels.Selector) (ret []*v1.Trigger, err error) + // Triggers returns an object that can list and get Triggers. + Triggers(namespace string) TriggerNamespaceLister + TriggerListerExpansion +} + +// triggerLister implements the TriggerLister interface. +type triggerLister struct { + indexer cache.Indexer +} + +// NewTriggerLister returns a new TriggerLister. +func NewTriggerLister(indexer cache.Indexer) TriggerLister { + return &triggerLister{indexer: indexer} +} + +// List lists all Triggers in the indexer. +func (s *triggerLister) List(selector labels.Selector) (ret []*v1.Trigger, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Trigger)) + }) + return ret, err +} + +// Triggers returns an object that can list and get Triggers. +func (s *triggerLister) Triggers(namespace string) TriggerNamespaceLister { + return triggerNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TriggerNamespaceLister helps list and get Triggers. +type TriggerNamespaceLister interface { + // List lists all Triggers in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Trigger, err error) + // Get retrieves the Trigger from the indexer for a given namespace and name. + Get(name string) (*v1.Trigger, error) + TriggerNamespaceListerExpansion +} + +// triggerNamespaceLister implements the TriggerNamespaceLister +// interface. +type triggerNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Triggers in the indexer for a given namespace. +func (s triggerNamespaceLister) List(selector labels.Selector) (ret []*v1.Trigger, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Trigger)) + }) + return ret, err +} + +// Get retrieves the Trigger from the indexer for a given namespace and name. +func (s triggerNamespaceLister) Get(name string) (*v1.Trigger, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("trigger"), name) + } + return obj.(*v1.Trigger), nil +} diff --git a/test/conformance/helpers/channel_status_test_helper.go b/test/conformance/helpers/channel_status_test_helper.go index 0b767c62e81..fbe755bf58f 100644 --- a/test/conformance/helpers/channel_status_test_helper.go +++ b/test/conformance/helpers/channel_status_test_helper.go @@ -74,7 +74,7 @@ func channelHasRequiredStatus(st *testing.T, client *testlib.Client, channel met st.Fatalf("No hostname found for %q", channel) } if channelable.Status.AddressStatus.Address.URL.IsEmpty() { - st.Fatalf("No hostname found for %q", channel) + st.Fatalf("No URL found for %q", channel) } } else if dtsv == "v1beta1" { channelable, err := getChannelAsV1Beta1Channelable(channelName, client, channel) @@ -90,7 +90,7 @@ func channelHasRequiredStatus(st *testing.T, client *testlib.Client, channel met // SPEC: When the channel instance is ready to receive events status.address.hostname and // status.address.url MUST be populated if channelable.Status.Address.URL.IsEmpty() { - st.Fatalf("No hostname found for %q", channel) + st.Fatalf("No URL found for %q", channel) } } else { st.Fatalf("Channel doesn't support v1alpha1 nor v1beta1 Channel duck types: %q", channel) From 0ce4c74cc8b266b4128cc27c9cd334aa4fbb12b9 Mon Sep 17 00:00:00 2001 From: Ali Ok Date: Mon, 22 Jun 2020 15:44:15 +0300 Subject: [PATCH 8/9] TMP v1 conversion for eventing.* --- pkg/apis/eventing/v1/broker_conversion.go | 34 +++++++++++++++++++ .../eventing/v1/broker_conversion_test.go | 34 +++++++++++++++++++ pkg/apis/eventing/v1/eventtype_conversion.go | 34 +++++++++++++++++++ .../eventing/v1/eventtype_conversion_test.go | 34 +++++++++++++++++++ pkg/apis/eventing/v1/trigger_conversion.go | 34 +++++++++++++++++++ .../eventing/v1/trigger_conversion_test.go | 34 +++++++++++++++++++ 6 files changed, 204 insertions(+) create mode 100644 pkg/apis/eventing/v1/broker_conversion.go create mode 100644 pkg/apis/eventing/v1/broker_conversion_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_conversion.go create mode 100644 pkg/apis/eventing/v1/eventtype_conversion_test.go create mode 100644 pkg/apis/eventing/v1/trigger_conversion.go create mode 100644 pkg/apis/eventing/v1/trigger_conversion_test.go diff --git a/pkg/apis/eventing/v1/broker_conversion.go b/pkg/apis/eventing/v1/broker_conversion.go new file mode 100644 index 00000000000..0f7d820ed94 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_conversion.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/eventing/v1/broker_conversion_test.go b/pkg/apis/eventing/v1/broker_conversion_test.go new file mode 100644 index 00000000000..311c51fdf9c --- /dev/null +++ b/pkg/apis/eventing/v1/broker_conversion_test.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "testing" +) + +func TestBrokerConversionBadType(t *testing.T) { + good, bad := &Broker{}, &Broker{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_conversion.go b/pkg/apis/eventing/v1/eventtype_conversion.go new file mode 100644 index 00000000000..3b36fca9774 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_conversion.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/eventing/v1/eventtype_conversion_test.go b/pkg/apis/eventing/v1/eventtype_conversion_test.go new file mode 100644 index 00000000000..39145489459 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_conversion_test.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "testing" +) + +func TestEventTypeConversionBadType(t *testing.T) { + good, bad := &EventType{}, &EventType{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/eventing/v1/trigger_conversion.go b/pkg/apis/eventing/v1/trigger_conversion.go new file mode 100644 index 00000000000..e856396e321 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_conversion.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/eventing/v1/trigger_conversion_test.go b/pkg/apis/eventing/v1/trigger_conversion_test.go new file mode 100644 index 00000000000..27ff6e46e16 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_conversion_test.go @@ -0,0 +1,34 @@ +/* +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 ( + "context" + "testing" +) + +func TestTriggerConversionBadType(t *testing.T) { + good, bad := &Trigger{}, &Trigger{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} From fc0008b7ad5baf25bab39b76842fdd769d1b75d8 Mon Sep 17 00:00:00 2001 From: Ali Ok Date: Mon, 22 Jun 2020 17:23:29 +0300 Subject: [PATCH 9/9] use eventing/duck.* and messaging.* v1 --- pkg/apis/eventing/v1/broker_conversion.go | 2 ++ pkg/apis/eventing/v1/broker_lifecycle.go | 4 ++-- pkg/apis/eventing/v1/broker_lifecycle_test.go | 4 ++-- pkg/apis/eventing/v1/broker_types.go | 4 ++-- pkg/apis/eventing/v1/broker_validation_test.go | 8 ++++---- pkg/apis/eventing/v1/eventtype_conversion.go | 2 ++ pkg/apis/eventing/v1/test_helper.go | 18 +++++++++--------- pkg/apis/eventing/v1/trigger_conversion.go | 2 ++ pkg/apis/eventing/v1/zz_generated.deepcopy.go | 4 ++-- 9 files changed, 27 insertions(+), 21 deletions(-) diff --git a/pkg/apis/eventing/v1/broker_conversion.go b/pkg/apis/eventing/v1/broker_conversion.go index 0f7d820ed94..ca12f9c5091 100644 --- a/pkg/apis/eventing/v1/broker_conversion.go +++ b/pkg/apis/eventing/v1/broker_conversion.go @@ -25,10 +25,12 @@ import ( // ConvertTo implements apis.Convertible func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { + // TODO: return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) } // ConvertFrom implements apis.Convertible func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { + // TODO: return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) } diff --git a/pkg/apis/eventing/v1/broker_lifecycle.go b/pkg/apis/eventing/v1/broker_lifecycle.go index 92972d09992..7d94467392f 100644 --- a/pkg/apis/eventing/v1/broker_lifecycle.go +++ b/pkg/apis/eventing/v1/broker_lifecycle.go @@ -20,7 +20,7 @@ import ( corev1 "k8s.io/api/core/v1" "knative.dev/eventing/pkg/apis/duck" - duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" ) @@ -91,7 +91,7 @@ func (bs *BrokerStatus) MarkTriggerChannelFailed(reason, format string, args ... brokerCondSet.Manage(bs).MarkFalse(BrokerConditionTriggerChannel, reason, format, args...) } -func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *duckv1beta1.ChannelableStatus) { +func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *eventingduckv1.ChannelableStatus) { // TODO: Once you can get a Ready status from Channelable in a generic way, use it here... address := cs.AddressStatus.Address if address != nil { diff --git a/pkg/apis/eventing/v1/broker_lifecycle_test.go b/pkg/apis/eventing/v1/broker_lifecycle_test.go index 9265a4f86ce..5c6fd43c112 100644 --- a/pkg/apis/eventing/v1/broker_lifecycle_test.go +++ b/pkg/apis/eventing/v1/broker_lifecycle_test.go @@ -19,7 +19,7 @@ import ( "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" - duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" @@ -312,7 +312,7 @@ func TestBrokerIsReady(t *testing.T) { bs.PropagateIngressAvailability(ep) } if test.markTriggerChannelReady != nil { - var c *duckv1beta1.ChannelableStatus + var c *eventingduckv1.ChannelableStatus if *test.markTriggerChannelReady { c = TestHelper.ReadyChannelStatus() } else { diff --git a/pkg/apis/eventing/v1/broker_types.go b/pkg/apis/eventing/v1/broker_types.go index fb1330f1004..7621f0971bb 100644 --- a/pkg/apis/eventing/v1/broker_types.go +++ b/pkg/apis/eventing/v1/broker_types.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" @@ -77,7 +77,7 @@ type BrokerSpec struct { // Delivery is the delivery specification for Events within the Broker mesh. // This includes things like retries, DLQ, etc. // +optional - Delivery *eventingduckv1beta1.DeliverySpec `json:"delivery,omitempty"` + Delivery *eventingduckv1.DeliverySpec `json:"delivery,omitempty"` } // BrokerStatus represents the current state of a Broker. diff --git a/pkg/apis/eventing/v1/broker_validation_test.go b/pkg/apis/eventing/v1/broker_validation_test.go index 75535127f33..774d55fd27a 100644 --- a/pkg/apis/eventing/v1/broker_validation_test.go +++ b/pkg/apis/eventing/v1/broker_validation_test.go @@ -22,7 +22,7 @@ import ( "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -145,7 +145,7 @@ func TestValidate(t *testing.T) { name: "invalid delivery, invalid delay string", b: Broker{ Spec: BrokerSpec{ - Delivery: &eventingduckv1beta1.DeliverySpec{ + Delivery: &eventingduckv1.DeliverySpec{ BackoffDelay: &invalidString, }, }, @@ -163,7 +163,7 @@ func TestValidate(t *testing.T) { } func TestValidSpec(t *testing.T) { - bop := eventingduckv1beta1.BackoffPolicyExponential + bop := eventingduckv1.BackoffPolicyExponential tests := []struct { name string spec BrokerSpec @@ -190,7 +190,7 @@ func TestValidSpec(t *testing.T) { Kind: "kind", APIVersion: "apiversion", }, - Delivery: &eventingduckv1beta1.DeliverySpec{BackoffPolicy: &bop}, + Delivery: &eventingduckv1.DeliverySpec{BackoffPolicy: &bop}, }, }, {}} diff --git a/pkg/apis/eventing/v1/eventtype_conversion.go b/pkg/apis/eventing/v1/eventtype_conversion.go index 3b36fca9774..5b010c224c3 100644 --- a/pkg/apis/eventing/v1/eventtype_conversion.go +++ b/pkg/apis/eventing/v1/eventtype_conversion.go @@ -25,10 +25,12 @@ import ( // ConvertTo implements apis.Convertible func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { + // TODO return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) } // ConvertFrom implements apis.Convertible func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { + // TODO return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) } diff --git a/pkg/apis/eventing/v1/test_helper.go b/pkg/apis/eventing/v1/test_helper.go index 49073aec4d9..50e773b144d 100644 --- a/pkg/apis/eventing/v1/test_helper.go +++ b/pkg/apis/eventing/v1/test_helper.go @@ -19,8 +19,8 @@ package v1 import ( corev1 "k8s.io/api/core/v1" - duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" - messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -47,8 +47,8 @@ func (testHelper) FalseSubscriptionCondition() *apis.Condition { } } -func (testHelper) ReadySubscriptionStatus() *messagingv1beta1.SubscriptionStatus { - ss := &messagingv1beta1.SubscriptionStatus{} +func (testHelper) ReadySubscriptionStatus() *messagingv1.SubscriptionStatus { + ss := &messagingv1.SubscriptionStatus{} ss.MarkChannelReady() ss.MarkReferencesResolved() ss.MarkAddedToChannel() @@ -105,18 +105,18 @@ func (testHelper) AvailableEndpoints() *corev1.Endpoints { return ep } -func (testHelper) ReadyChannelStatus() *duckv1beta1.ChannelableStatus { - cs := &duckv1beta1.ChannelableStatus{ +func (testHelper) ReadyChannelStatus() *eventingduckv1.ChannelableStatus { + cs := &eventingduckv1.ChannelableStatus{ Status: duckv1.Status{}, AddressStatus: duckv1.AddressStatus{ Address: &duckv1.Addressable{ URL: &apis.URL{Scheme: "http", Host: "foo"}, }, }, - SubscribableStatus: duckv1beta1.SubscribableStatus{}} + SubscribableStatus: eventingduckv1.SubscribableStatus{}} return cs } -func (t testHelper) NotReadyChannelStatus() *duckv1beta1.ChannelableStatus { - return &duckv1beta1.ChannelableStatus{} +func (t testHelper) NotReadyChannelStatus() *eventingduckv1.ChannelableStatus { + return &eventingduckv1.ChannelableStatus{} } diff --git a/pkg/apis/eventing/v1/trigger_conversion.go b/pkg/apis/eventing/v1/trigger_conversion.go index e856396e321..96590e6d976 100644 --- a/pkg/apis/eventing/v1/trigger_conversion.go +++ b/pkg/apis/eventing/v1/trigger_conversion.go @@ -25,10 +25,12 @@ import ( // ConvertTo implements apis.Convertible func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { + // TODO return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) } // ConvertFrom implements apis.Convertible func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { + // TODO return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) } diff --git a/pkg/apis/eventing/v1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1/zz_generated.deepcopy.go index dcda76b4000..70c532fbe33 100644 --- a/pkg/apis/eventing/v1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ package v1 import ( runtime "k8s.io/apimachinery/pkg/runtime" - v1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + apisduckv1 "knative.dev/eventing/pkg/apis/duck/v1" apis "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -98,7 +98,7 @@ func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { } if in.Delivery != nil { in, out := &in.Delivery, &out.Delivery - *out = new(v1beta1.DeliverySpec) + *out = new(apisduckv1.DeliverySpec) (*in).DeepCopyInto(*out) } return