diff --git a/Gopkg.lock b/Gopkg.lock index 86972108eb6..0f8509f903f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1423,6 +1423,7 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ + "contrib.go.opencensus.io/exporter/ocagent", "github.com/cloudevents/sdk-go", "github.com/cloudevents/sdk-go/pkg/cloudevents", "github.com/cloudevents/sdk-go/pkg/cloudevents/client", diff --git a/Gopkg.toml b/Gopkg.toml index f47361f1822..e5b7a459d10 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -12,6 +12,7 @@ required = [ "knative.dev/pkg/testutils/clustermanager/perf-tests", "knative.dev/test-infra/scripts", "knative.dev/test-infra/tools/dep-collector", + "contrib.go.opencensus.io/exporter/ocagent", ] [prune] @@ -79,6 +80,10 @@ required = [ # https://github.com/kubernetes/kubernetes/blob/v1.16.4/go.mod#L81 version = "v1.1.7" +[[override]] + name = "contrib.go.opencensus.io/exporter/ocagent" + version = "v0.6.0" + # TODO why is this overridden? [[override]] name = "github.com/Shopify/sarama" @@ -116,3 +121,7 @@ required = [ [[constraint]] name = "github.com/tsenart/vegeta" version = "12.7.0" + +[[constraint]] + name = "contrib.go.opencensus.io/exporter/ocagent" + version = "0.6.0" diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 4a5b1af4d0d..b6f57248a20 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -30,7 +30,7 @@ KNATIVE_CODEGEN_PKG=${KNATIVE_CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 $(dir # 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:v1alpha1 messaging:v1alpha1 flows:v1alpha1 sources:v1alpha1" \ + "eventing:v1alpha1 messaging:v1alpha1 messaging:v1beta1 flows:v1alpha1 sources:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # TODO(#2312): Remove this after v0.13. @@ -42,13 +42,13 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ # 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:v1alpha1 duck:v1beta1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Knative Injection ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1alpha1 messaging:v1alpha1 flows:v1alpha1 sources:v1alpha1 duck:v1alpha1" \ + "eventing:v1alpha1 messaging:v1alpha1 messaging:v1beta1 flows:v1alpha1 sources:v1alpha1 duck:v1alpha1 duck:v1beta1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # TODO(#2312): Remove this after v0.13. diff --git a/pkg/apis/duck/v1beta1/channelable_types.go b/pkg/apis/duck/v1beta1/channelable_types.go new file mode 100644 index 00000000000..a97df00a6b6 --- /dev/null +++ b/pkg/apis/duck/v1beta1/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 v1beta1 + +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 set by the channel when it supports native error handling via a channel + // Failed messages are delivered here. + // +optional + DeadLetterChannel *corev1.ObjectReference `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: &corev1.ObjectReference{ + 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/v1beta1/channelable_types_test.go b/pkg/apis/duck/v1beta1/channelable_types_test.go new file mode 100644 index 00000000000..6e56caf71c8 --- /dev/null +++ b/pkg/apis/duck/v1beta1/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 v1beta1 + +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: &corev1.ObjectReference{ + 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/v1beta1/delivery_types.go b/pkg/apis/duck/v1beta1/delivery_types.go new file mode 100644 index 00000000000..ed9103e9b1b --- /dev/null +++ b/pkg/apis/duck/v1beta1/delivery_types.go @@ -0,0 +1,67 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + 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 couldn't 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"` +} + +// 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 the reference to the native, platform specific channel + // where failed events are sent to. + // +optional + DeadLetterChannel *corev1.ObjectReference `json:"deadLetterChannel,omitempty"` +} diff --git a/pkg/apis/duck/v1beta1/doc.go b/pkg/apis/duck/v1beta1/doc.go new file mode 100644 index 00000000000..08ba5444902 --- /dev/null +++ b/pkg/apis/duck/v1beta1/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 v1beta1 is the v1beta1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=duck.knative.dev +package v1beta1 diff --git a/pkg/apis/duck/v1beta1/subscribable_types.go b/pkg/apis/duck/v1beta1/subscribable_types.go new file mode 100644 index 00000000000..242901888a4 --- /dev/null +++ b/pkg/apis/duck/v1beta1/subscribable_types.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 v1beta1 + +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) +) + +// 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/duck/v1beta1/subscribable_types_test.go b/pkg/apis/duck/v1beta1/subscribable_types_test.go new file mode 100644 index 00000000000..d203d91e463 --- /dev/null +++ b/pkg/apis/duck/v1beta1/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 v1beta1 + +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/v1beta1/zz_generated.deepcopy.go b/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..902b5cbcc50 --- /dev/null +++ b/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,344 @@ +// +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 v1beta1 + +import ( + v1 "k8s.io/api/core/v1" + 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(v1.ObjectReference) + **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(v1.ObjectReference) + **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/messaging/v1beta1/channel_defaults.go b/pkg/apis/messaging/v1beta1/channel_defaults.go new file mode 100644 index 00000000000..f210d5a2d36 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_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 v1beta1 + +import ( + "context" +) + +var ( + // ChannelDefaulterSingleton is the global singleton used to default Channels that do not + // specify a Channel CRD. + ChannelDefaulterSingleton ChannelDefaulter +) + +func (c *Channel) SetDefaults(ctx context.Context) { + if c != nil && c.Spec.ChannelTemplate == nil { + // The singleton may not have been set, if so ignore it and validation will reject the + // Channel. + if cd := ChannelDefaulterSingleton; cd != nil { + c.Spec.ChannelTemplate = cd.GetDefault(c.Namespace) + } + } + c.Spec.SetDefaults(ctx) +} + +func (cs *ChannelSpec) SetDefaults(ctx context.Context) {} + +// ChannelDefaulter sets the default Channel CRD and Arguments on Channels that do not +// specify any implementation. +type ChannelDefaulter interface { + // GetDefault determines the default Channel CRD for the given namespace. + GetDefault(namespace string) *ChannelTemplateSpec +} diff --git a/pkg/apis/messaging/v1beta1/channel_defaults_test.go b/pkg/apis/messaging/v1beta1/channel_defaults_test.go new file mode 100644 index 00000000000..d99328d483f --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_defaults_test.go @@ -0,0 +1,105 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "testing" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/google/go-cmp/cmp" +) + +var ( + defaultChannelTemplate = &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "InMemoryChannel", + }, + } +) + +func TestChannelSetDefaults(t *testing.T) { + testCases := map[string]struct { + nilChannelDefaulter bool + channelTemplate *ChannelTemplateSpec + initial Channel + expected Channel + }{ + "nil ChannelDefaulter": { + nilChannelDefaulter: true, + expected: Channel{}, + }, + "unset ChannelDefaulter": { + expected: Channel{}, + }, + "set ChannelDefaulter": { + channelTemplate: defaultChannelTemplate, + expected: Channel{ + Spec: ChannelSpec{ + ChannelTemplate: defaultChannelTemplate, + }, + }, + }, + "template already specified": { + channelTemplate: defaultChannelTemplate, + initial: Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + expected: Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + if !tc.nilChannelDefaulter { + ChannelDefaulterSingleton = &channelDefaulter{ + channelTemplate: tc.channelTemplate, + } + defer func() { ChannelDefaulterSingleton = nil }() + } + tc.initial.SetDefaults(context.TODO()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} + +type channelDefaulter struct { + channelTemplate *ChannelTemplateSpec +} + +func (cd *channelDefaulter) GetDefault(_ string) *ChannelTemplateSpec { + return cd.channelTemplate +} diff --git a/pkg/apis/messaging/v1beta1/channel_lifecycle.go b/pkg/apis/messaging/v1beta1/channel_lifecycle.go new file mode 100644 index 00000000000..5bdc25a8d67 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_lifecycle.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 v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + eventingduck "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var chCondSet = apis.NewLivingConditionSet(ChannelConditionBackingChannelReady, ChannelConditionAddressable) + +const ( + // ChannelConditionReady has status True when all subconditions below have been set to True. + ChannelConditionReady = apis.ConditionReady + + // ChannelConditionBackingChannelReady has status True when the backing Channel CRD is ready. + ChannelConditionBackingChannelReady apis.ConditionType = "BackingChannelReady" + + // ChannelConditionAddressable has status true when this Channel meets + // the Addressable contract and has a non-empty hostname. + ChannelConditionAddressable apis.ConditionType = "Addressable" +) + +// GetGroupVersionKind returns GroupVersionKind for Channels. +func (dc *Channel) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Channel") +} + +// GetUntypedSpec returns the spec of the Channel. +func (c *Channel) GetUntypedSpec() interface{} { + return c.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (cs *ChannelStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return chCondSet.Manage(cs).GetCondition(t) +} + +// GetTopLevelCondition returns the top level Condition. +func (cs *ChannelStatus) GetTopLevelCondition() *apis.Condition { + return chCondSet.Manage(cs).GetTopLevelCondition() +} + +// IsReady returns true if the resource is ready overall. +func (cs *ChannelStatus) IsReady() bool { + return chCondSet.Manage(cs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (cs *ChannelStatus) InitializeConditions() { + chCondSet.Manage(cs).InitializeConditions() +} + +func (cs *ChannelStatus) SetAddress(address *duckv1.Addressable) { + cs.Address = address + if address == nil || address.URL.IsEmpty() { + chCondSet.Manage(cs).MarkFalse(ChannelConditionAddressable, "EmptyHostname", "hostname is the empty string") + } else { + chCondSet.Manage(cs).MarkTrue(ChannelConditionAddressable) + + } +} + +func (cs *ChannelStatus) MarkBackingChannelFailed(reason, messageFormat string, messageA ...interface{}) { + chCondSet.Manage(cs).MarkFalse(ChannelConditionBackingChannelReady, reason, messageFormat, messageA...) +} + +func (cs *ChannelStatus) MarkBackingChannelUnknown(reason, messageFormat string, messageA ...interface{}) { + chCondSet.Manage(cs).MarkUnknown(ChannelConditionBackingChannelReady, reason, messageFormat, messageA...) +} + +func (cs *ChannelStatus) MarkBackingChannelNotConfigured() { + chCondSet.Manage(cs).MarkUnknown(ChannelConditionBackingChannelReady, + "BackingChannelNotConfigured", "BackingChannel has not yet been reconciled.") +} + +func (cs *ChannelStatus) MarkBackingChannelReady() { + chCondSet.Manage(cs).MarkTrue(ChannelConditionBackingChannelReady) +} + +func (cs *ChannelStatus) PropagateStatuses(chs *eventingduck.ChannelableStatus) { + // TODO: Once you can get a Ready status from Channelable in a generic way, use it here. + readyCondition := chs.Status.GetCondition(apis.ConditionReady) + if readyCondition == nil { + cs.MarkBackingChannelNotConfigured() + } else { + switch { + case readyCondition.Status == corev1.ConditionUnknown: + cs.MarkBackingChannelUnknown(readyCondition.Reason, readyCondition.Message) + case readyCondition.Status == corev1.ConditionTrue: + cs.MarkBackingChannelReady() + case readyCondition.Status == corev1.ConditionFalse: + cs.MarkBackingChannelFailed(readyCondition.Reason, readyCondition.Message) + default: + cs.MarkBackingChannelUnknown("BackingChannelUnknown", "The status of BackingChannel is invalid: %v", readyCondition.Status) + } + } + // Set the address and update the Addressable conditions. + cs.SetAddress(chs.AddressStatus.Address) + // Set the subscribable status. + cs.SubscribableStatus = chs.SubscribableStatus +} diff --git a/pkg/apis/messaging/v1beta1/channel_lifecycle_test.go b/pkg/apis/messaging/v1beta1/channel_lifecycle_test.go new file mode 100644 index 00000000000..bb38805a3bc --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_lifecycle_test.go @@ -0,0 +1,399 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" + "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + validAddress = &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "test-domain", + }, + } +) + +func TestChannelGetCondition(t *testing.T) { + tests := []struct { + name string + cs *ChannelStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + cs: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + condReady, + }, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &condReady, + }, { + name: "unknown condition", + cs: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + condReady, + }, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cs.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestChannelInitializeConditions(t *testing.T) { + tests := []struct { + name string + cs *ChannelStatus + want *ChannelStatus + }{{ + name: "empty", + cs: &ChannelStatus{}, + want: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ChannelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: ChannelConditionBackingChannelReady, + Status: corev1.ConditionUnknown, + }, { + Type: ChannelConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, + }, { + name: "one false", + cs: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ChannelConditionAddressable, + Status: corev1.ConditionFalse, + }}, + }, + }, + }, + want: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ChannelConditionAddressable, + Status: corev1.ConditionFalse, + }, { + Type: ChannelConditionBackingChannelReady, + Status: corev1.ConditionUnknown, + }, { + Type: ChannelConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, + }, { + name: "one true", + cs: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ChannelConditionBackingChannelReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + }, + want: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ChannelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: ChannelConditionBackingChannelReady, + Status: corev1.ConditionTrue, + }, { + Type: ChannelConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.cs.InitializeConditions() + ignore := cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") + if diff := cmp.Diff(test.want, test.cs, ignore); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestChannelConditionStatus(t *testing.T) { + tests := []struct { + name string + address *duckv1.Addressable + backingChannelStatus corev1.ConditionStatus + wantConditionStatus corev1.ConditionStatus + }{{ + name: "all happy", + address: validAddress, + backingChannelStatus: corev1.ConditionTrue, + wantConditionStatus: corev1.ConditionTrue, + }, { + name: "address not set", + address: &duckv1.Addressable{}, + backingChannelStatus: corev1.ConditionTrue, + wantConditionStatus: corev1.ConditionFalse, + }, + { + name: "nil address", + address: nil, + backingChannelStatus: corev1.ConditionTrue, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "backing channel with unknown status", + address: validAddress, + backingChannelStatus: corev1.ConditionUnknown, + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "backing channel with false status", + address: validAddress, + backingChannelStatus: corev1.ConditionFalse, + wantConditionStatus: corev1.ConditionFalse, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cs := &ChannelStatus{} + cs.InitializeConditions() + cs.SetAddress(test.address) + if test.backingChannelStatus == corev1.ConditionTrue { + cs.MarkBackingChannelReady() + } else if test.backingChannelStatus == corev1.ConditionFalse { + cs.MarkBackingChannelFailed("ChannelFailure", "testing") + } else { + cs.MarkBackingChannelUnknown("ChannelUnknown", "testing") + } + got := cs.GetTopLevelCondition().Status + if test.wantConditionStatus != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantConditionStatus, got) + } + }) + } +} + +func TestChannelSetAddressable(t *testing.T) { + testCases := map[string]struct { + address *duckv1.Addressable + want *ChannelStatus + }{ + "nil url": { + want: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: ChannelConditionAddressable, + Status: corev1.ConditionFalse, + }, + // Note that Ready is here because when the condition is marked False, duck + // automatically sets Ready to false. + { + Type: ChannelConditionReady, + Status: corev1.ConditionFalse, + }, + }, + }, + AddressStatus: duckv1.AddressStatus{}, + }, + }, + }, + "has domain": { + address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "test-domain", + }, + }, + want: &ChannelStatus{ + ChannelableStatus: v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "test-domain", + }, + }, + }, + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: ChannelConditionAddressable, + Status: corev1.ConditionTrue, + }}, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + cs := &ChannelStatus{} + cs.SetAddress(tc.address) + ignore := cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") + if diff := cmp.Diff(tc.want, cs, ignore); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestChannelPropagateStatuses(t *testing.T) { + testCases := map[string]struct { + channelableStatus *v1beta1.ChannelableStatus + wantConditionStatus corev1.ConditionStatus + }{ + "address set": { + channelableStatus: &v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: validAddress, + }, + }, + wantConditionStatus: corev1.ConditionUnknown, + }, + "address not set": { + channelableStatus: &v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{}, + }, + }, + wantConditionStatus: corev1.ConditionFalse, + }, + "url nil": { + channelableStatus: &v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: nil, + }, + }, + wantConditionStatus: corev1.ConditionFalse, + }, + "all set": { + channelableStatus: &v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: validAddress, + }, + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + wantConditionStatus: corev1.ConditionTrue, + }, + "backing channel with unknown status": { + channelableStatus: &v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: validAddress, + }, + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + wantConditionStatus: corev1.ConditionUnknown, + }, + "no condition ready in backing channel": { + channelableStatus: &v1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: validAddress, + }, + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }}, + }, + }, + wantConditionStatus: corev1.ConditionUnknown, + }, + "test subscribableTypeStatus is set": { + channelableStatus: &v1beta1.ChannelableStatus{ + SubscribableStatus: v1beta1.SubscribableStatus{ + // Populate ALL fields + Subscribers: []v1beta1.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", + }}, + }, + }, + wantConditionStatus: corev1.ConditionFalse, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + cs := &ChannelStatus{} + cs.PropagateStatuses(tc.channelableStatus) + got := cs.GetTopLevelCondition().Status + if tc.wantConditionStatus != got { + t.Errorf("unexpected readiness: want %v, got %v", tc.wantConditionStatus, got) + } + }) + } +} diff --git a/pkg/apis/messaging/v1beta1/channel_template_types.go b/pkg/apis/messaging/v1beta1/channel_template_types.go new file mode 100644 index 00000000000..02a5581b14e --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_template_types.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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ChannelTemplateSpec struct { + metav1.TypeMeta `json:",inline"` + + // Spec defines the Spec to use for each channel created. Passed + // in verbatim to the Channel CRD as Spec section. + // +optional + Spec *runtime.RawExtension `json:"spec,omitempty"` +} + +// ChannelTemplateSpecInternal is an internal only version that includes ObjectMeta so that +// we can easily create new Channels off of it. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ChannelTemplateSpecInternal struct { + metav1.TypeMeta `json:",inline"` + + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the Spec to use for each channel created. Passed + // in verbatim to the Channel CRD as Spec section. + // +optional + Spec *runtime.RawExtension `json:"spec,omitempty"` +} diff --git a/pkg/apis/messaging/v1beta1/channel_types.go b/pkg/apis/messaging/v1beta1/channel_types.go new file mode 100644 index 00000000000..2f49a9c2c88 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_types.go @@ -0,0 +1,88 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + eventingduck "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +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) +) + +// 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 ObjectReference to the Channel CRD backing this Channel. + Channel *corev1.ObjectReference `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"` +} diff --git a/pkg/apis/messaging/v1beta1/channel_types_test.go b/pkg/apis/messaging/v1beta1/channel_types_test.go new file mode 100644 index 00000000000..13dba4291a0 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_types_test.go @@ -0,0 +1,27 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import "testing" + +func TestChannel_GetGroupVersionKind(t *testing.T) { + c := Channel{} + gvk := c.GetGroupVersionKind() + if gvk.Kind != "Channel" { + t.Errorf("Should be Channel.") + } +} diff --git a/pkg/apis/messaging/v1beta1/channel_validation.go b/pkg/apis/messaging/v1beta1/channel_validation.go new file mode 100644 index 00000000000..a48cd5906df --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_validation.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 v1beta1 + +import ( + "context" + "fmt" + + "github.com/google/go-cmp/cmp/cmpopts" + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +func (c *Channel) Validate(ctx context.Context) *apis.FieldError { + return c.Spec.Validate(ctx).ViaField("spec") +} + +func (cs *ChannelSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + if cs.ChannelTemplate == nil { + // The Channel defaulter is expected to set this, not the users. + errs = errs.Also(apis.ErrMissingField("channelTemplate")) + } else { + if cte := isValidChannelTemplate(cs.ChannelTemplate); cte != nil { + errs = errs.Also(cte.ViaField("channelTemplate")) + } + } + + for i, subscriber := range cs.SubscribableSpec.Subscribers { + if subscriber.ReplyURI == nil && subscriber.SubscriberURI == nil { + fe := apis.ErrMissingField("replyURI", "subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe.ViaField(fmt.Sprintf("subscriber[%d]", i)).ViaField("subscribable")) + } + } + + return errs +} + +func isValidChannelTemplate(ct *ChannelTemplateSpec) *apis.FieldError { + var errs *apis.FieldError + if ct.Kind == "" { + errs = errs.Also(apis.ErrMissingField("kind")) + } + if ct.APIVersion == "" { + errs = errs.Also(apis.ErrMissingField("apiVersion")) + } + return errs +} + +func (c *Channel) CheckImmutableFields(ctx context.Context, original *Channel) *apis.FieldError { + if original == nil { + return nil + } + + ignoreArguments := cmpopts.IgnoreFields(ChannelSpec{}, "SubscribableSpec") + if diff, err := kmp.ShortDiff(original.Spec, c.Spec, ignoreArguments); err != nil { + return &apis.FieldError{ + Message: "Failed to diff Channel", + 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/messaging/v1beta1/channel_validation_test.go b/pkg/apis/messaging/v1beta1/channel_validation_test.go new file mode 100644 index 00000000000..7b49f01becc --- /dev/null +++ b/pkg/apis/messaging/v1beta1/channel_validation_test.go @@ -0,0 +1,295 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + eventingduck "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" +) + +func TestChannelValidation(t *testing.T) { + tests := []CRDTest{{ + name: "empty", + cr: &Channel{ + Spec: ChannelSpec{}, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("spec.channelTemplate") + return fe + }(), + }, { + name: "channel template with no kind", + cr: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + }, + }}, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("spec.channelTemplate.kind") + return fe + }(), + }, { + name: "channel template with no apiVersion", + cr: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + }, + }}, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("spec.channelTemplate.apiVersion") + return fe + }(), + }, { + name: "valid subscribers array", + cr: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + }, + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{ + SubscriberURI: apis.HTTP("subscriberendpoint"), + ReplyURI: apis.HTTP("resultendpoint"), + }}, + }}, + }}, + want: nil, + }, { + name: "empty subscriber at index 1", + cr: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + }, + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{ + SubscriberURI: apis.HTTP("subscriberendpoint"), + ReplyURI: apis.HTTP("replyendpoint"), + }, {}}, + }}, + }, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("spec.subscribable.subscriber[1].replyURI", "spec.subscribable.subscriber[1].subscriberURI") + fe.Details = "expected at least one of, got none" + return fe + }(), + }, { + name: "nil channelTemplate and empty subscriber at index 1", + cr: &Channel{ + Spec: ChannelSpec{ + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{ + SubscriberURI: apis.HTTP("subscriberendpoint"), + ReplyURI: apis.HTTP("replyendpoint"), + }, {}}, + }}, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("spec.channelTemplate") + errs = errs.Also(fe) + fe = apis.ErrMissingField("spec.subscribable.subscriber[1].replyURI", "spec.subscribable.subscriber[1].subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe) + return errs + }(), + }, { + name: "2 empty subscribers", + cr: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + }, + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{}, {}}, + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("spec.subscribable.subscriber[0].replyURI", "spec.subscribable.subscriber[0].subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe) + fe = apis.ErrMissingField("spec.subscribable.subscriber[1].replyURI", "spec.subscribable.subscriber[1].subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe) + return errs + }(), + }} + + doValidateTest(t, tests) +} + +func TestChannelImmutableFields(t *testing.T) { + tests := []struct { + name string + current *Channel + original *Channel + want *apis.FieldError + }{{ + name: "good (no change)", + current: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + Spec: &runtime.RawExtension{ + Raw: []byte(`"foo":"baz"`), + }, + }, + }, + }, + original: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + Spec: &runtime.RawExtension{ + Raw: []byte(`"foo":"baz"`), + }, + }, + }, + }, + want: nil, + }, { + name: "new nil is ok", + current: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + Spec: &runtime.RawExtension{ + Raw: []byte(`"foo":"baz"`), + }, + }, + }, + }, + original: nil, + want: nil, + }, { + name: "bad (channelTemplate change)", + current: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "OtherChannel", + APIVersion: SchemeGroupVersion.String(), + }, + Spec: &runtime.RawExtension{ + Raw: []byte(`"foo":"baz"`), + }, + }, + }, + }, + original: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + Spec: &runtime.RawExtension{ + Raw: []byte(`"foo":"baz"`), + }, + }, + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.ChannelSpec}.ChannelTemplate.TypeMeta.Kind: + -: "InMemoryChannel" + +: "OtherChannel" +`, + }, + }, { + name: "good (subscribable change)", + current: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + }, + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{ + SubscriberURI: apis.HTTP("subscriberendpoint"), + ReplyURI: apis.HTTP("replyendpoint"), + }}, + }, + }, + }, + }, + original: &Channel{ + Spec: ChannelSpec{ + ChannelTemplate: &ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + Kind: "InMemoryChannel", + APIVersion: SchemeGroupVersion.String(), + }, + }, + }, + }, + want: nil, + }} + + 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/messaging/v1beta1/crd_validation_test.go b/pkg/apis/messaging/v1beta1/crd_validation_test.go new file mode 100644 index 00000000000..1daeee4c0de --- /dev/null +++ b/pkg/apis/messaging/v1beta1/crd_validation_test.go @@ -0,0 +1,43 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "knative.dev/pkg/apis" + "knative.dev/pkg/webhook/resourcesemantics" +) + +type CRDTest struct { + name string + cr resourcesemantics.GenericCRD + want *apis.FieldError +} + +func doValidateTest(t *testing.T, tests []CRDTest) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cr.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: validate (-want, +got) = %v", test.name, diff) + } + }) + } +} diff --git a/pkg/apis/messaging/v1beta1/doc.go b/pkg/apis/messaging/v1beta1/doc.go new file mode 100644 index 00000000000..82d5675cc90 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/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 v1beta1 is the v1beta1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=messaging.knative.dev +package v1beta1 diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_defaults.go b/pkg/apis/messaging/v1beta1/in_memory_channel_defaults.go new file mode 100644 index 00000000000..49e65618fdb --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_defaults.go @@ -0,0 +1,27 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import "context" + +func (imc *InMemoryChannel) SetDefaults(ctx context.Context) { + imc.Spec.SetDefaults(ctx) +} + +func (imcs *InMemoryChannelSpec) SetDefaults(ctx context.Context) { + // TODO: Nothing to default here... +} diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_lifecycle.go b/pkg/apis/messaging/v1beta1/in_memory_channel_lifecycle.go new file mode 100644 index 00000000000..ad719924c69 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_lifecycle.go @@ -0,0 +1,147 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import ( + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + v1 "knative.dev/pkg/apis/duck/v1" +) + +var imcCondSet = apis.NewLivingConditionSet(InMemoryChannelConditionDispatcherReady, InMemoryChannelConditionServiceReady, InMemoryChannelConditionEndpointsReady, InMemoryChannelConditionAddressable, InMemoryChannelConditionChannelServiceReady) + +const ( + // InMemoryChannelConditionReady has status True when all subconditions below have been set to True. + InMemoryChannelConditionReady = apis.ConditionReady + + // InMemoryChannelConditionDispatcherReady has status True when a Dispatcher deployment is ready + // Keyed off appsv1.DeploymentAvaialble, which means minimum available replicas required are up + // and running for at least minReadySeconds. + InMemoryChannelConditionDispatcherReady apis.ConditionType = "DispatcherReady" + + // InMemoryChannelConditionServiceReady has status True when a k8s Service is ready. This + // basically just means it exists because there's no meaningful status in Service. See Endpoints + // below. + InMemoryChannelConditionServiceReady apis.ConditionType = "ServiceReady" + + // InMemoryChannelConditionEndpointsReady has status True when a k8s Service Endpoints are backed + // by at least one endpoint. + InMemoryChannelConditionEndpointsReady apis.ConditionType = "EndpointsReady" + + // InMemoryChannelConditionAddressable has status true when this InMemoryChannel meets + // the Addressable contract and has a non-empty hostname. + InMemoryChannelConditionAddressable apis.ConditionType = "Addressable" + + // InMemoryChannelConditionServiceReady has status True when a k8s Service representing the channel is ready. + // Because this uses ExternalName, there are no endpoints to check. + InMemoryChannelConditionChannelServiceReady apis.ConditionType = "ChannelServiceReady" +) + +// GetGroupVersionKind returns GroupVersionKind for InMemoryChannels +func (imc *InMemoryChannel) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("InMemoryChannel") +} + +// GetUntypedSpec returns the spec of the InMemoryChannel. +func (i *InMemoryChannel) GetUntypedSpec() interface{} { + return i.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (imcs *InMemoryChannelStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return imcCondSet.Manage(imcs).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (imcs *InMemoryChannelStatus) IsReady() bool { + return imcCondSet.Manage(imcs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (imcs *InMemoryChannelStatus) InitializeConditions() { + imcCondSet.Manage(imcs).InitializeConditions() +} + +func (imcs *InMemoryChannelStatus) SetAddress(url *apis.URL) { + imcs.Address = &v1.Addressable{URL: url} + if url != nil { + imcCondSet.Manage(imcs).MarkTrue(InMemoryChannelConditionAddressable) + } else { + imcCondSet.Manage(imcs).MarkFalse(InMemoryChannelConditionAddressable, "emptyHostname", "hostname is the empty string") + } +} + +func (imcs *InMemoryChannelStatus) MarkDispatcherFailed(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkFalse(InMemoryChannelConditionDispatcherReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkDispatcherUnknown(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkUnknown(InMemoryChannelConditionDispatcherReady, reason, messageFormat, messageA...) +} + +// TODO: Unify this with the ones from Eventing. Say: Broker, Trigger. +func (imcs *InMemoryChannelStatus) PropagateDispatcherStatus(ds *appsv1.DeploymentStatus) { + for _, cond := range ds.Conditions { + if cond.Type == appsv1.DeploymentAvailable { + if cond.Status == corev1.ConditionTrue { + imcCondSet.Manage(imcs).MarkTrue(InMemoryChannelConditionDispatcherReady) + } else if cond.Status == corev1.ConditionFalse { + imcs.MarkDispatcherFailed("DispatcherDeploymentFalse", "The status of Dispatcher Deployment is False: %s : %s", cond.Reason, cond.Message) + } else if cond.Status == corev1.ConditionUnknown { + imcs.MarkDispatcherUnknown("DispatcherDeploymentUnknown", "The status of Dispatcher Deployment is Unknown: %s : %s", cond.Reason, cond.Message) + } + } + } +} + +func (imcs *InMemoryChannelStatus) MarkServiceFailed(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkFalse(InMemoryChannelConditionServiceReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkServiceUnknown(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkUnknown(InMemoryChannelConditionServiceReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkServiceTrue() { + imcCondSet.Manage(imcs).MarkTrue(InMemoryChannelConditionServiceReady) +} + +func (imcs *InMemoryChannelStatus) MarkChannelServiceFailed(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkFalse(InMemoryChannelConditionChannelServiceReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkChannelServiceUnknown(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkUnknown(InMemoryChannelConditionChannelServiceReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkChannelServiceTrue() { + imcCondSet.Manage(imcs).MarkTrue(InMemoryChannelConditionChannelServiceReady) +} + +func (imcs *InMemoryChannelStatus) MarkEndpointsFailed(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkFalse(InMemoryChannelConditionEndpointsReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkEndpointsUnknown(reason, messageFormat string, messageA ...interface{}) { + imcCondSet.Manage(imcs).MarkUnknown(InMemoryChannelConditionEndpointsReady, reason, messageFormat, messageA...) +} + +func (imcs *InMemoryChannelStatus) MarkEndpointsTrue() { + imcCondSet.Manage(imcs).MarkTrue(InMemoryChannelConditionEndpointsReady) +} diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_lifecycle_test.go b/pkg/apis/messaging/v1beta1/in_memory_channel_lifecycle_test.go new file mode 100644 index 00000000000..30215529f8f --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_lifecycle_test.go @@ -0,0 +1,393 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var condReady = apis.Condition{ + Type: InMemoryChannelConditionReady, + Status: corev1.ConditionTrue, +} + +var condDispatcherReady = apis.Condition{ + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionTrue, +} + +var condDispatcherNotReady = apis.Condition{ + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionFalse, +} + +var condDispatcherServiceReady = apis.Condition{ + Type: InMemoryChannelConditionServiceReady, + Status: corev1.ConditionTrue, +} + +var condDispatcherEndpointsReady = apis.Condition{ + Type: InMemoryChannelConditionEndpointsReady, + Status: corev1.ConditionTrue, +} + +var condDispatcherAddressable = apis.Condition{ + Type: InMemoryChannelConditionAddressable, + Status: corev1.ConditionTrue, +} + +var deploymentConditionReady = appsv1.DeploymentCondition{ + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, +} + +var deploymentConditionNotReady = appsv1.DeploymentCondition{ + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionFalse, +} + +var deploymentStatusReady = &appsv1.DeploymentStatus{Conditions: []appsv1.DeploymentCondition{deploymentConditionReady}} +var deploymentStatusNotReady = &appsv1.DeploymentStatus{Conditions: []appsv1.DeploymentCondition{deploymentConditionNotReady}} + +var ignoreAllButTypeAndStatus = cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") + +var ignoreLastTransitionTime = cmpopts.IgnoreFields(apis.Condition{}, "LastTransitionTime") + +func TestInMemoryChannelGetCondition(t *testing.T) { + tests := []struct { + name string + cs *InMemoryChannelStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + cs: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + condReady, + }, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &condReady, + }, { + name: "unknown condition", + cs: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + condReady, + condDispatcherNotReady, + }, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cs.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestInMemoryChannelInitializeConditions(t *testing.T) { + tests := []struct { + name string + cs *InMemoryChannelStatus + want *InMemoryChannelStatus + }{{ + name: "empty", + cs: &InMemoryChannelStatus{}, + want: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: InMemoryChannelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionChannelServiceReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionEndpointsReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionServiceReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, + }, { + name: "one false", + cs: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionFalse, + }}, + }, + }, + }, + want: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: InMemoryChannelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionChannelServiceReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionFalse, + }, { + Type: InMemoryChannelConditionEndpointsReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionServiceReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, + }, { + name: "one true", + cs: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + }, + want: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: InMemoryChannelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionChannelServiceReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionDispatcherReady, + Status: corev1.ConditionTrue, + }, { + Type: InMemoryChannelConditionEndpointsReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: InMemoryChannelConditionServiceReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.cs.InitializeConditions() + if diff := cmp.Diff(test.want, test.cs, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestInMemoryChannelIsReady(t *testing.T) { + tests := []struct { + name string + markServiceReady bool + markChannelServiceReady bool + setAddress bool + markEndpointsReady bool + wantReady bool + dispatcherStatus *appsv1.DeploymentStatus + }{{ + name: "all happy", + markServiceReady: true, + markChannelServiceReady: true, + markEndpointsReady: true, + dispatcherStatus: deploymentStatusReady, + setAddress: true, + wantReady: true, + }, { + name: "service not ready", + markServiceReady: false, + markChannelServiceReady: false, + markEndpointsReady: true, + dispatcherStatus: deploymentStatusReady, + setAddress: true, + wantReady: false, + }, { + name: "endpoints not ready", + markServiceReady: true, + markChannelServiceReady: false, + markEndpointsReady: false, + dispatcherStatus: deploymentStatusReady, + setAddress: true, + wantReady: false, + }, { + name: "deployment not ready", + markServiceReady: true, + markEndpointsReady: true, + markChannelServiceReady: false, + dispatcherStatus: deploymentStatusNotReady, + setAddress: true, + wantReady: false, + }, { + name: "address not set", + markServiceReady: true, + markChannelServiceReady: false, + markEndpointsReady: true, + dispatcherStatus: deploymentStatusReady, + setAddress: false, + wantReady: false, + }, { + name: "channel service not ready", + markServiceReady: true, + markChannelServiceReady: false, + markEndpointsReady: true, + dispatcherStatus: deploymentStatusReady, + setAddress: true, + wantReady: false, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cs := &InMemoryChannelStatus{} + cs.InitializeConditions() + if test.markServiceReady { + cs.MarkServiceTrue() + } else { + cs.MarkServiceFailed("NotReadyService", "testing") + } + if test.markChannelServiceReady { + cs.MarkChannelServiceTrue() + } else { + cs.MarkChannelServiceFailed("NotReadyChannelService", "testing") + } + if test.setAddress { + cs.SetAddress(&apis.URL{Scheme: "http", Host: "foo.bar"}) + } + if test.markEndpointsReady { + cs.MarkEndpointsTrue() + } else { + cs.MarkEndpointsFailed("NotReadyEndpoints", "testing") + } + if test.dispatcherStatus != nil { + cs.PropagateDispatcherStatus(test.dispatcherStatus) + } else { + cs.MarkDispatcherFailed("NotReadyDispatcher", "testing") + } + got := cs.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} + +func TestInMemoryChannelStatus_SetAddressable(t *testing.T) { + testCases := map[string]struct { + url *apis.URL + want *InMemoryChannelStatus + }{ + "empty string": { + want: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: InMemoryChannelConditionAddressable, + Status: corev1.ConditionFalse, + }, + // Note that Ready is here because when the condition is marked False, duck + // automatically sets Ready to false. + { + Type: InMemoryChannelConditionReady, + Status: corev1.ConditionFalse, + }, + }, + }, + AddressStatus: duckv1.AddressStatus{Address: &duckv1.Addressable{}}, + }, + }, + }, + "has domain": { + url: &apis.URL{Scheme: "http", Host: "test-domain"}, + want: &InMemoryChannelStatus{ + ChannelableStatus: eventingduckv1beta1.ChannelableStatus{ + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{ + Scheme: "http", + Host: "test-domain", + }, + }, + }, + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: InMemoryChannelConditionAddressable, + Status: corev1.ConditionTrue, + }}, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + cs := &InMemoryChannelStatus{} + cs.SetAddress(tc.url) + if diff := cmp.Diff(tc.want, cs, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_types.go b/pkg/apis/messaging/v1beta1/in_memory_channel_types.go new file mode 100644 index 00000000000..66f19f2dba0 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_types.go @@ -0,0 +1,81 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +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) +) + +// 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. + eventingduckv1beta1.ChannelableSpec `json:",inline"` +} + +// ChannelStatus represents the current state of a Channel. +type InMemoryChannelStatus struct { + // Channel conforms to Duck type Channelable. + eventingduckv1beta1.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"` +} diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_types_test.go b/pkg/apis/messaging/v1beta1/in_memory_channel_types_test.go new file mode 100644 index 00000000000..3cf1b135d87 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_types_test.go @@ -0,0 +1,27 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import "testing" + +func TestInMemoryChannel_GetGroupVersionKind(t *testing.T) { + imc := InMemoryChannel{} + gvk := imc.GetGroupVersionKind() + if gvk.Kind != "InMemoryChannel" { + t.Errorf("Should be InMemoryChannel.") + } +} diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_validation.go b/pkg/apis/messaging/v1beta1/in_memory_channel_validation.go new file mode 100644 index 00000000000..50fb8db2f32 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_validation.go @@ -0,0 +1,42 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +func (imc *InMemoryChannel) Validate(ctx context.Context) *apis.FieldError { + return imc.Spec.Validate(ctx).ViaField("spec") +} + +func (imcs *InMemoryChannelSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + for i, subscriber := range imcs.SubscribableSpec.Subscribers { + if subscriber.ReplyURI == nil && subscriber.SubscriberURI == nil { + fe := apis.ErrMissingField("replyURI", "subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe.ViaField(fmt.Sprintf("subscriber[%d]", i)).ViaField("subscribable")) + } + } + + return errs +} diff --git a/pkg/apis/messaging/v1beta1/in_memory_channel_validation_test.go b/pkg/apis/messaging/v1beta1/in_memory_channel_validation_test.go new file mode 100644 index 00000000000..17d79aad1b1 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/in_memory_channel_validation_test.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. +*/ + +package v1beta1 + +import ( + "testing" + + eventingduck "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" +) + +func TestInMemoryChannelValidation(t *testing.T) { + tests := []CRDTest{{ + name: "empty", + cr: &InMemoryChannel{ + Spec: InMemoryChannelSpec{}, + }, + want: nil, + }, { + name: "valid subscribers array", + cr: &InMemoryChannel{ + Spec: InMemoryChannelSpec{ + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{ + SubscriberURI: apis.HTTP("subscriberendpoint"), + ReplyURI: apis.HTTP("resultendpoint"), + }}, + }}, + }, + }, + want: nil, + }, { + name: "empty subscriber at index 1", + cr: &InMemoryChannel{ + Spec: InMemoryChannelSpec{ + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{ + SubscriberURI: apis.HTTP("subscriberendpoint"), + ReplyURI: apis.HTTP("replyendpoint"), + }, {}}, + }}, + }, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("spec.subscribable.subscriber[1].replyURI", "spec.subscribable.subscriber[1].subscriberURI") + fe.Details = "expected at least one of, got none" + return fe + }(), + }, { + name: "2 empty subscribers", + cr: &InMemoryChannel{ + Spec: InMemoryChannelSpec{ + ChannelableSpec: eventingduck.ChannelableSpec{ + SubscribableSpec: eventingduck.SubscribableSpec{ + Subscribers: []eventingduck.SubscriberSpec{{}, {}}, + }, + }, + }, + }, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("spec.subscribable.subscriber[0].replyURI", "spec.subscribable.subscriber[0].subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe) + fe = apis.ErrMissingField("spec.subscribable.subscriber[1].replyURI", "spec.subscribable.subscriber[1].subscriberURI") + fe.Details = "expected at least one of, got none" + errs = errs.Also(fe) + return errs + }(), + }} + + doValidateTest(t, tests) +} diff --git a/pkg/apis/messaging/v1beta1/register.go b/pkg/apis/messaging/v1beta1/register.go new file mode 100644 index 00000000000..9c3b54f60ec --- /dev/null +++ b/pkg/apis/messaging/v1beta1/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 v1beta1 + +import ( + "knative.dev/eventing/pkg/apis/messaging" + + 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: messaging.GroupName, Version: "v1beta1"} + +// 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, + &InMemoryChannel{}, + &InMemoryChannelList{}, + &Subscription{}, + &SubscriptionList{}, + &Channel{}, + &ChannelList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/messaging/v1beta1/subscribable_channelable_validation.go b/pkg/apis/messaging/v1beta1/subscribable_channelable_validation.go new file mode 100644 index 00000000000..6429fbc72b0 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscribable_channelable_validation.go @@ -0,0 +1,85 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "reflect" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "knative.dev/pkg/apis" +) + +func isChannelEmpty(f corev1.ObjectReference) bool { + return equality.Semantic.DeepEqual(f, corev1.ObjectReference{}) +} + +// Valid if it is a valid object reference. +func isValidChannel(f corev1.ObjectReference) *apis.FieldError { + return IsValidObjectReference(f) +} + +func IsValidObjectReference(f corev1.ObjectReference) *apis.FieldError { + return checkRequiredObjectReferenceFields(f). + Also(checkDisallowedObjectReferenceFields(f)) +} + +// Check the corev1.ObjectReference to make sure it has the required fields. They +// are not checked for anything more except that they are set. +func checkRequiredObjectReferenceFields(f corev1.ObjectReference) *apis.FieldError { + var errs *apis.FieldError + if f.Name == "" { + errs = errs.Also(apis.ErrMissingField("name")) + } + if f.APIVersion == "" { + errs = errs.Also(apis.ErrMissingField("apiVersion")) + } + if f.Kind == "" { + errs = errs.Also(apis.ErrMissingField("kind")) + } + return errs +} + +// Check the corev1.ObjectReference to make sure it only has the following fields set: +// Name, Kind, APIVersion +// If any other fields are set and is not the Zero value, returns an apis.FieldError +// with the fieldpaths for all those fields. +func checkDisallowedObjectReferenceFields(f corev1.ObjectReference) *apis.FieldError { + disallowedFields := []string{} + // See if there are any fields that have been set that should not be. + // TODO: Hoist this kind of stuff into pkg repository. + s := reflect.ValueOf(f) + typeOf := s.Type() + for i := 0; i < s.NumField(); i++ { + field := s.Field(i) + fieldName := typeOf.Field(i).Name + if fieldName == "Name" || fieldName == "Kind" || fieldName == "APIVersion" { + continue + } + if !cmp.Equal(field.Interface(), reflect.Zero(field.Type()).Interface()) { + disallowedFields = append(disallowedFields, fieldName) + } + } + if len(disallowedFields) > 0 { + fe := apis.ErrDisallowedFields(disallowedFields...) + fe.Details = "only name, apiVersion and kind are supported fields" + return fe + } + return nil + +} diff --git a/pkg/apis/messaging/v1beta1/subscribable_channelable_validation_test.go b/pkg/apis/messaging/v1beta1/subscribable_channelable_validation_test.go new file mode 100644 index 00000000000..c306217e21a --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscribable_channelable_validation_test.go @@ -0,0 +1,150 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +var validationTests = []struct { + name string + ref corev1.ObjectReference + want *apis.FieldError +}{ + { + name: "valid object ref", + ref: corev1.ObjectReference{ + Name: "boaty-mcboatface", + APIVersion: "messaging.knative.dev/v1alpha1", + Kind: "MyChannel", + }, + want: nil, + }, + { + name: "invalid object ref", + ref: corev1.ObjectReference{ + Name: "boaty-mcboatface", + APIVersion: "messaging.knative.dev/v1alpha1", + Kind: "", + }, + want: apis.ErrMissingField("kind"), + }, +} + +func TestIsChannelEmpty(t *testing.T) { + name := "non empty" + t.Run(name, func(t *testing.T) { + r := corev1.ObjectReference{ + Name: "boaty-mcboatface", + APIVersion: "messaging.knative.dev/v1alpha1", + Kind: "Channel", + } + if isChannelEmpty(r) { + t.Errorf("%s: isChannelEmpty(%s) should be false", name, r) + } + }) + + name = "empty" + t.Run(name, func(t *testing.T) { + r := corev1.ObjectReference{} + if !isChannelEmpty(r) { + t.Errorf("%s: isChannelEmpty(%s) should be true", name, r) + } + }) +} + +func TestIsValidChannel(t *testing.T) { + for _, test := range validationTests { + t.Run(test.name, func(t *testing.T) { + got := isValidChannel(test.ref) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: validation (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestIsValidObjectReference(t *testing.T) { + tests := []struct { + name string + ref corev1.ObjectReference + want []*apis.FieldError + }{ + { + name: "missing api version and kind", + ref: corev1.ObjectReference{ + Name: "boaty-mcboatface", + APIVersion: "", + Kind: "", + }, + want: []*apis.FieldError{ + apis.ErrMissingField("apiVersion"), + apis.ErrMissingField("kind"), + }, + }, + { + name: "missing name", + ref: corev1.ObjectReference{ + Name: "", + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Strait", + }, + want: []*apis.FieldError{ + apis.ErrMissingField("name"), + }, + }, + { + name: "missing all", + ref: corev1.ObjectReference{ + Name: "", + APIVersion: "", + Kind: "", + }, + want: []*apis.FieldError{ + apis.ErrMissingField("name"), + apis.ErrMissingField("apiVersion"), + apis.ErrMissingField("kind"), + }, + }, + { + name: "missing none", + ref: corev1.ObjectReference{ + Name: "kind", + APIVersion: "messaging.knative.dev/v1alpha1", + Kind: "Channel", + }, + want: []*apis.FieldError{}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + allWanted := &apis.FieldError{} + for _, fe := range test.want { + allWanted = allWanted.Also(fe) + } + got := IsValidObjectReference(test.ref) + if diff := cmp.Diff(allWanted.Error(), got.Error()); diff != "" { + t.Errorf("%s: validation (-want, +got) = %v", test.name, diff) + } + }) + } +} diff --git a/pkg/apis/messaging/v1beta1/subscription_defaults.go b/pkg/apis/messaging/v1beta1/subscription_defaults.go new file mode 100644 index 00000000000..16fd42ea588 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_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 v1beta1 + +import ( + "context" +) + +func (s *Subscription) SetDefaults(ctx context.Context) { + s.Spec.SetDefaults(ctx) +} + +func (ss *SubscriptionSpec) SetDefaults(ctx context.Context) { + // TODO anything? +} diff --git a/pkg/apis/messaging/v1beta1/subscription_defaults_test.go b/pkg/apis/messaging/v1beta1/subscription_defaults_test.go new file mode 100644 index 00000000000..8e30351f70a --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_defaults_test.go @@ -0,0 +1,28 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "testing" +) + +// No-op test because method does nothing. +func TestSubscriptionDefaults(t *testing.T) { + s := Subscription{} + s.SetDefaults(context.TODO()) +} diff --git a/pkg/apis/messaging/v1beta1/subscription_lifecycle.go b/pkg/apis/messaging/v1beta1/subscription_lifecycle.go new file mode 100644 index 00000000000..2b8c43e8bd8 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_lifecycle.go @@ -0,0 +1,105 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import ( + "knative.dev/pkg/apis" +) + +// subCondSet is a condition set with Ready as the happy condition and +// ReferencesResolved and ChannelReady as the dependent conditions. +var SubCondSet = apis.NewLivingConditionSet(SubscriptionConditionReferencesResolved, SubscriptionConditionAddedToChannel, SubscriptionConditionChannelReady) + +const ( + // SubscriptionConditionReady has status True when all subconditions below have been set to True. + SubscriptionConditionReady = apis.ConditionReady + // SubscriptionConditionReferencesResolved has status True when all the specified references have been successfully + // resolved. + SubscriptionConditionReferencesResolved apis.ConditionType = "Resolved" + + // SubscriptionConditionAddedToChannel has status True when controller has successfully added a + // subscription to the spec.channel resource. + SubscriptionConditionAddedToChannel apis.ConditionType = "AddedToChannel" + + // SubscriptionConditionChannelReady has status True when the channel has marked the subscriber as 'ready' + SubscriptionConditionChannelReady apis.ConditionType = "ChannelReady" +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ss *SubscriptionStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return SubCondSet.Manage(ss).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (ss *SubscriptionStatus) IsReady() bool { + return SubCondSet.Manage(ss).IsHappy() +} + +// IsAddedToChannel returns true if SubscriptionConditionAddedToChannel is true +func (ss *SubscriptionStatus) IsAddedToChannel() bool { + return ss.GetCondition(SubscriptionConditionAddedToChannel).IsTrue() +} + +// AreReferencesResolved returns true if SubscriptionConditionReferencesResolved is true +func (ss *SubscriptionStatus) AreReferencesResolved() bool { + return ss.GetCondition(SubscriptionConditionReferencesResolved).IsTrue() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ss *SubscriptionStatus) InitializeConditions() { + SubCondSet.Manage(ss).InitializeConditions() +} + +// MarkReferencesResolved sets the ReferencesResolved condition to True state. +func (ss *SubscriptionStatus) MarkReferencesResolved() { + SubCondSet.Manage(ss).MarkTrue(SubscriptionConditionReferencesResolved) +} + +// MarkChannelReady sets the ChannelReady condition to True state. +func (ss *SubscriptionStatus) MarkChannelReady() { + SubCondSet.Manage(ss).MarkTrue(SubscriptionConditionChannelReady) +} + +// MarkAddedToChannel sets the AddedToChannel condition to True state. +func (ss *SubscriptionStatus) MarkAddedToChannel() { + SubCondSet.Manage(ss).MarkTrue(SubscriptionConditionAddedToChannel) +} + +// MarkReferencesNotResolved sets the ReferencesResolved condition to False state. +func (ss *SubscriptionStatus) MarkReferencesNotResolved(reason, messageFormat string, messageA ...interface{}) { + SubCondSet.Manage(ss).MarkFalse(SubscriptionConditionReferencesResolved, reason, messageFormat, messageA...) +} + +// MarkReferencesResolvedUnknown sets the ReferencesResolved condition to Unknown state. +func (ss *SubscriptionStatus) MarkReferencesResolvedUnknown(reason, messageFormat string, messageA ...interface{}) { + SubCondSet.Manage(ss).MarkUnknown(SubscriptionConditionReferencesResolved, reason, messageFormat, messageA...) +} + +// MarkChannelFailed sets the ChannelReady condition to False state. +func (ss *SubscriptionStatus) MarkChannelFailed(reason, messageFormat string, messageA ...interface{}) { + SubCondSet.Manage(ss).MarkFalse(SubscriptionConditionChannelReady, reason, messageFormat, messageA) +} + +// MarkChannelUnknown sets the ChannelReady condition to Unknown state. +func (ss *SubscriptionStatus) MarkChannelUnknown(reason, messageFormat string, messageA ...interface{}) { + SubCondSet.Manage(ss).MarkUnknown(SubscriptionConditionChannelReady, reason, messageFormat, messageA) +} + +// MarkNotAddedToChannel sets the AddedToChannel condition to False state. +func (ss *SubscriptionStatus) MarkNotAddedToChannel(reason, messageFormat string, messageA ...interface{}) { + SubCondSet.Manage(ss).MarkFalse(SubscriptionConditionAddedToChannel, reason, messageFormat, messageA) +} diff --git a/pkg/apis/messaging/v1beta1/subscription_lifecycle_test.go b/pkg/apis/messaging/v1beta1/subscription_lifecycle_test.go new file mode 100644 index 00000000000..97fb7471fac --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_lifecycle_test.go @@ -0,0 +1,267 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "testing" + + "knative.dev/pkg/apis" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var subscriptionConditionReady = apis.Condition{ + Type: SubscriptionConditionReady, + Status: corev1.ConditionTrue, +} + +var subscriptionConditionReferencesResolved = apis.Condition{ + Type: SubscriptionConditionReferencesResolved, + Status: corev1.ConditionFalse, +} + +var subscriptionConditionChannelReady = apis.Condition{ + Type: SubscriptionConditionChannelReady, + Status: corev1.ConditionTrue, +} + +func TestSubscriptionGetCondition(t *testing.T) { + tests := []struct { + name string + ss *SubscriptionStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ss: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + subscriptionConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &subscriptionConditionReady, + }, { + name: "multiple conditions", + ss: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + subscriptionConditionReady, + subscriptionConditionReferencesResolved, + }, + }, + }, + condQuery: SubscriptionConditionReferencesResolved, + want: &subscriptionConditionReferencesResolved, + }, { + name: "multiple conditions, condition true", + ss: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + subscriptionConditionReady, + subscriptionConditionChannelReady, + }, + }, + }, + condQuery: SubscriptionConditionChannelReady, + want: &subscriptionConditionChannelReady, + }, { + name: "unknown condition", + ss: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + subscriptionConditionReady, + subscriptionConditionReferencesResolved, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ss.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestSubscriptionInitializeConditions(t *testing.T) { + tests := []struct { + name string + ss *SubscriptionStatus + want *SubscriptionStatus + }{{ + name: "empty", + ss: &SubscriptionStatus{}, + want: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SubscriptionConditionAddedToChannel, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionChannelReady, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionReferencesResolved, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one false", + ss: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SubscriptionConditionChannelReady, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SubscriptionConditionAddedToChannel, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionChannelReady, + Status: corev1.ConditionFalse, + }, { + Type: SubscriptionConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionReferencesResolved, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + ss: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SubscriptionConditionReferencesResolved, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &SubscriptionStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SubscriptionConditionAddedToChannel, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionChannelReady, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: SubscriptionConditionReferencesResolved, + Status: corev1.ConditionTrue, + }}, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ss.InitializeConditions() + if diff := cmp.Diff(test.want, test.ss, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestSubscriptionIsReady(t *testing.T) { + tests := []struct { + name string + markResolved bool + markChannelReady bool + wantReady bool + markAddedToChannel bool + }{{ + name: "all happy", + markResolved: true, + markChannelReady: true, + markAddedToChannel: true, + wantReady: true, + }, { + name: "one sad - markResolved", + markResolved: false, + markChannelReady: true, + markAddedToChannel: true, + wantReady: false, + }, { + name: "one sad - markChannelReady", + markResolved: true, + markChannelReady: false, + markAddedToChannel: true, + wantReady: false, + }, { + name: "one sad - markAddedToChannel", + markResolved: true, + markChannelReady: true, + markAddedToChannel: false, + wantReady: false, + }, { + name: "other sad", + markResolved: true, + markChannelReady: false, + wantReady: false, + }, { + name: "all sad", + markResolved: false, + markChannelReady: false, + markAddedToChannel: false, + wantReady: false, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ss := &SubscriptionStatus{} + if test.markResolved { + ss.MarkReferencesResolved() + if !ss.AreReferencesResolved() { + t.Errorf("References marked resolved, but not reflected in AreReferencesResolved") + } + } + if test.markChannelReady { + ss.MarkChannelReady() + } + if test.markAddedToChannel { + ss.MarkAddedToChannel() + if !ss.IsAddedToChannel() { + t.Errorf("Channel added, but not reflected in IsAddedToChannel") + } + } + got := ss.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} diff --git a/pkg/apis/messaging/v1beta1/subscription_types.go b/pkg/apis/messaging/v1beta1/subscription_types.go new file mode 100644 index 00000000000..36fa1db5af4 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_types.go @@ -0,0 +1,147 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import ( + 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" + + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" +) + +// +genclient +// +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) +) + +// 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 *eventingduckv1beta1.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 (t *Subscription) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Subscription") +} + +// GetUntypedSpec returns the spec of the Subscription. +func (s *Subscription) GetUntypedSpec() interface{} { + return s.Spec +} diff --git a/pkg/apis/messaging/v1beta1/subscription_types_test.go b/pkg/apis/messaging/v1beta1/subscription_types_test.go new file mode 100644 index 00000000000..8ae03372b92 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_types_test.go @@ -0,0 +1,27 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1beta1 + +import "testing" + +func TestSubscription_GetGroupVersionKind(t *testing.T) { + c := Subscription{} + gvk := c.GetGroupVersionKind() + if gvk.Kind != "Subscription" { + t.Errorf("Should be Subscription.") + } +} diff --git a/pkg/apis/messaging/v1beta1/subscription_validation.go b/pkg/apis/messaging/v1beta1/subscription_validation.go new file mode 100644 index 00000000000..5cf8c2e8515 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_validation.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. +*/ + +package v1beta1 + +import ( + "context" + + "github.com/google/go-cmp/cmp/cmpopts" + "k8s.io/apimachinery/pkg/api/equality" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmp" +) + +func (s *Subscription) Validate(ctx context.Context) *apis.FieldError { + return s.Spec.Validate(ctx).ViaField("spec") +} + +func (ss *SubscriptionSpec) Validate(ctx context.Context) *apis.FieldError { + // We require always Channel. + // Also at least one of 'subscriber' and 'reply' must be defined (non-nil and non-empty). + + var errs *apis.FieldError + if isChannelEmpty(ss.Channel) { + fe := apis.ErrMissingField("channel") + fe.Details = "the Subscription must reference a channel" + return fe + } else if fe := isValidChannel(ss.Channel); fe != nil { + errs = errs.Also(fe.ViaField("channel")) + } + + missingSubscriber := isDestinationNilOrEmpty(ss.Subscriber) + missingReply := isDestinationNilOrEmpty(ss.Reply) + if missingSubscriber && missingReply { + fe := apis.ErrMissingField("reply", "subscriber") + fe.Details = "the Subscription must reference at least one of (reply or a subscriber)" + errs = errs.Also(fe) + } + + if !missingSubscriber { + if fe := ss.Subscriber.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("subscriber")) + } + } + + if !missingReply { + if fe := ss.Reply.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("reply")) + } + } + + return errs +} + +func isDestinationNilOrEmpty(d *duckv1.Destination) bool { + return d == nil || equality.Semantic.DeepEqual(d, &duckv1.Destination{}) +} + +func (s *Subscription) CheckImmutableFields(ctx context.Context, original *Subscription) *apis.FieldError { + if original == nil { + return nil + } + + // Only Subscriber and Reply are mutable. + ignoreArguments := cmpopts.IgnoreFields(SubscriptionSpec{}, "Subscriber", "Reply") + if diff, err := kmp.ShortDiff(original.Spec, s.Spec, ignoreArguments); err != nil { + return &apis.FieldError{ + Message: "Failed to diff Subscription", + 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/messaging/v1beta1/subscription_validation_test.go b/pkg/apis/messaging/v1beta1/subscription_validation_test.go new file mode 100644 index 00000000000..9eaab2d5042 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/subscription_validation_test.go @@ -0,0 +1,440 @@ +/* +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 v1beta1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +const ( + channelKind = "MyChannel" + channelAPIVersion = "eventing.knative.dev/v1alpha1" + routeKind = "Route" + routeAPIVersion = "serving.knative.dev/v1alpha1" + channelName = "subscribedChannel" + replyChannelName = "toChannel" + subscriberName = "subscriber" +) + +func getValidChannelRef() corev1.ObjectReference { + return corev1.ObjectReference{ + Name: channelName, + Kind: channelKind, + APIVersion: channelAPIVersion, + } +} + +func getValidReply() *duckv1.Destination { + return &duckv1.Destination{ + Ref: &corev1.ObjectReference{ + Name: replyChannelName, + Kind: channelKind, + APIVersion: channelAPIVersion, + }, + } +} + +func getValidDestination() *duckv1.Destination { + return &duckv1.Destination{ + Ref: &corev1.ObjectReference{ + Name: subscriberName, + Kind: routeKind, + APIVersion: routeAPIVersion, + }, + } +} + +func TestSubscriptionValidation(t *testing.T) { + name := "empty channel" + c := &Subscription{ + Spec: SubscriptionSpec{ + Channel: corev1.ObjectReference{}, + }, + } + want := &apis.FieldError{ + Paths: []string{"spec.channel"}, + Message: "missing field(s)", + Details: "the Subscription must reference a channel", + } + + t.Run(name, func(t *testing.T) { + got := c.Validate(context.TODO()) + if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { + t.Errorf("Subscription.Validate (-want, +got) = %v", diff) + } + }) + +} + +func TestSubscriptionSpecValidation(t *testing.T) { + tests := []struct { + name string + c *SubscriptionSpec + want *apis.FieldError + }{{ + name: "valid", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + }, + want: nil, + }, { + name: "valid with reply", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + Reply: getValidReply(), + }, + want: nil, + }, { + name: "empty Channel", + c: &SubscriptionSpec{ + Channel: corev1.ObjectReference{}, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("channel") + fe.Details = "the Subscription must reference a channel" + return fe + }(), + }, { + name: "missing name in Channel", + c: &SubscriptionSpec{ + Channel: corev1.ObjectReference{ + Kind: channelKind, + APIVersion: channelAPIVersion, + }, + Subscriber: getValidDestination(), + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("channel.name") + return fe + }(), + }, { + name: "missing Subscriber and Reply", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("reply", "subscriber") + fe.Details = "the Subscription must reference at least one of (reply or a subscriber)" + return fe + }(), + }, { + name: "empty Subscriber and Reply", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: &duckv1.Destination{}, + Reply: &duckv1.Destination{}, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("reply", "subscriber") + fe.Details = "the Subscription must reference at least one of (reply or a subscriber)" + return fe + }(), + }, { + name: "missing Reply", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + }, + want: nil, + }, { + name: "empty Reply", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + Reply: &duckv1.Destination{}, + }, + want: nil, + }, { + name: "missing Subscriber", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Reply: getValidReply(), + }, + want: nil, + }, { + name: "empty Subscriber", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: &duckv1.Destination{}, + Reply: getValidReply(), + }, + want: nil, + }, { + name: "missing name in channel, and missing subscriber, reply", + c: &SubscriptionSpec{ + Channel: corev1.ObjectReference{ + Kind: channelKind, + APIVersion: channelAPIVersion, + }, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("reply", "subscriber") + fe.Details = "the Subscription must reference at least one of (reply or a subscriber)" + return apis.ErrMissingField("channel.name").Also(fe) + }(), + }, { + name: "empty", + c: &SubscriptionSpec{}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("channel") + fe.Details = "the Subscription must reference a channel" + return fe + }(), + }, { + name: "missing name in Subscriber.Ref", + c: &SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: &duckv1.Destination{ + Ref: &corev1.ObjectReference{ + Kind: channelKind, + APIVersion: channelAPIVersion, + }, + }, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("subscriber.ref.name") + return fe + }(), + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.c.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: validateChannel (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestSubscriptionImmutable(t *testing.T) { + newChannel := getValidChannelRef() + newChannel.Name = "newChannel" + + newSubscriber := getValidDestination() + newSubscriber.Ref.Name = "newSubscriber" + + newReply := getValidReply() + newReply.Ref.Name = "newReplyChannel" + + tests := []struct { + name string + c *Subscription + og *Subscription + want *apis.FieldError + }{{ + name: "valid", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + }, + }, + og: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + }, + }, + want: nil, + }, { + name: "new nil is ok", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + }, + }, + og: nil, + want: nil, + }, { + name: "valid, new Subscriber", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + }, + }, + og: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: newSubscriber, + }, + }, + want: nil, + }, { + name: "valid, new Reply", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Reply: getValidReply(), + }, + }, + og: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Reply: newReply, + }, + }, + want: nil, + }, { + name: "valid, have Reply, remove and replace with Subscriber", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Reply: getValidReply(), + }, + }, + og: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + }, + }, + want: nil, + }, { + name: "valid, have Subscriber, remove and replace with Reply", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Subscriber: getValidDestination(), + }, + }, + og: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + Reply: getValidReply(), + }, + }, + want: nil, + }, { + name: "Channel changed", + c: &Subscription{ + Spec: SubscriptionSpec{ + Channel: getValidChannelRef(), + }, + }, + og: &Subscription{ + Spec: SubscriptionSpec{ + Channel: newChannel, + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.SubscriptionSpec}.Channel.Name: + -: "newChannel" + +: "subscribedChannel" +`, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.c.CheckImmutableFields(context.TODO(), test.og) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} + +func TestValidChannel(t *testing.T) { + tests := []struct { + name string + c corev1.ObjectReference + want *apis.FieldError + }{{ + name: "valid", + c: corev1.ObjectReference{ + Name: channelName, + APIVersion: channelAPIVersion, + Kind: channelKind, + }, + want: nil, + }, { + name: "missing name", + c: corev1.ObjectReference{ + APIVersion: channelAPIVersion, + Kind: channelKind, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("name") + return fe + }(), + }, { + name: "missing apiVersion", + c: corev1.ObjectReference{ + Name: channelName, + Kind: channelKind, + }, + want: func() *apis.FieldError { + return apis.ErrMissingField("apiVersion") + }(), + }, { + name: "extra field, namespace", + c: corev1.ObjectReference{ + Name: channelName, + APIVersion: channelAPIVersion, + Kind: channelKind, + Namespace: "secretnamespace", + }, + want: func() *apis.FieldError { + fe := apis.ErrDisallowedFields("Namespace") + fe.Details = "only name, apiVersion and kind are supported fields" + return fe + }(), + }, { + name: "extra field, namespace and resourceVersion", + c: corev1.ObjectReference{ + Name: channelName, + APIVersion: channelAPIVersion, + Kind: channelKind, + Namespace: "secretnamespace", + ResourceVersion: "myresourceversion", + }, + want: func() *apis.FieldError { + fe := apis.ErrDisallowedFields("Namespace", "ResourceVersion") + fe.Details = "only name, apiVersion and kind are supported fields" + return fe + }(), + }, { + // Make sure that if an empty field for namespace is given, it's treated as not there. + name: "valid extra field, namespace empty", + c: corev1.ObjectReference{ + Name: channelName, + APIVersion: channelAPIVersion, + Kind: channelKind, + Namespace: "", + }, + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := isValidChannel(test.c) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("isValidChannel (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/messaging/v1beta1/zz_generated.deepcopy.go b/pkg/apis/messaging/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..c5e8fdad2b2 --- /dev/null +++ b/pkg/apis/messaging/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,432 @@ +// +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 v1beta1 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + duckv1beta1 "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 *Channel) DeepCopyInto(out *Channel) { + *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 Channel. +func (in *Channel) DeepCopy() *Channel { + if in == nil { + return nil + } + out := new(Channel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Channel) 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 *ChannelList) DeepCopyInto(out *ChannelList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Channel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelList. +func (in *ChannelList) DeepCopy() *ChannelList { + if in == nil { + return nil + } + out := new(ChannelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ChannelList) 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 *ChannelSpec) DeepCopyInto(out *ChannelSpec) { + *out = *in + if in.ChannelTemplate != nil { + in, out := &in.ChannelTemplate, &out.ChannelTemplate + *out = new(ChannelTemplateSpec) + (*in).DeepCopyInto(*out) + } + in.ChannelableSpec.DeepCopyInto(&out.ChannelableSpec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelSpec. +func (in *ChannelSpec) DeepCopy() *ChannelSpec { + if in == nil { + return nil + } + out := new(ChannelSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelStatus) DeepCopyInto(out *ChannelStatus) { + *out = *in + in.ChannelableStatus.DeepCopyInto(&out.ChannelableStatus) + if in.Channel != nil { + in, out := &in.Channel, &out.Channel + *out = new(v1.ObjectReference) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelStatus. +func (in *ChannelStatus) DeepCopy() *ChannelStatus { + if in == nil { + return nil + } + out := new(ChannelStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChannelTemplateSpec) DeepCopyInto(out *ChannelTemplateSpec) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelTemplateSpec. +func (in *ChannelTemplateSpec) DeepCopy() *ChannelTemplateSpec { + if in == nil { + return nil + } + out := new(ChannelTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ChannelTemplateSpec) 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 *ChannelTemplateSpecInternal) DeepCopyInto(out *ChannelTemplateSpecInternal) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChannelTemplateSpecInternal. +func (in *ChannelTemplateSpecInternal) DeepCopy() *ChannelTemplateSpecInternal { + if in == nil { + return nil + } + out := new(ChannelTemplateSpecInternal) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ChannelTemplateSpecInternal) 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 *InMemoryChannel) DeepCopyInto(out *InMemoryChannel) { + *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 InMemoryChannel. +func (in *InMemoryChannel) DeepCopy() *InMemoryChannel { + if in == nil { + return nil + } + out := new(InMemoryChannel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InMemoryChannel) 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 *InMemoryChannelList) DeepCopyInto(out *InMemoryChannelList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]InMemoryChannel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InMemoryChannelList. +func (in *InMemoryChannelList) DeepCopy() *InMemoryChannelList { + if in == nil { + return nil + } + out := new(InMemoryChannelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InMemoryChannelList) 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 *InMemoryChannelSpec) DeepCopyInto(out *InMemoryChannelSpec) { + *out = *in + in.ChannelableSpec.DeepCopyInto(&out.ChannelableSpec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InMemoryChannelSpec. +func (in *InMemoryChannelSpec) DeepCopy() *InMemoryChannelSpec { + if in == nil { + return nil + } + out := new(InMemoryChannelSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InMemoryChannelStatus) DeepCopyInto(out *InMemoryChannelStatus) { + *out = *in + in.ChannelableStatus.DeepCopyInto(&out.ChannelableStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InMemoryChannelStatus. +func (in *InMemoryChannelStatus) DeepCopy() *InMemoryChannelStatus { + if in == nil { + return nil + } + out := new(InMemoryChannelStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Subscription) DeepCopyInto(out *Subscription) { + *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 Subscription. +func (in *Subscription) DeepCopy() *Subscription { + if in == nil { + return nil + } + out := new(Subscription) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Subscription) 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 *SubscriptionList) DeepCopyInto(out *SubscriptionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Subscription, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionList. +func (in *SubscriptionList) DeepCopy() *SubscriptionList { + if in == nil { + return nil + } + out := new(SubscriptionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SubscriptionList) 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 *SubscriptionSpec) DeepCopyInto(out *SubscriptionSpec) { + *out = *in + out.Channel = in.Channel + if in.Subscriber != nil { + in, out := &in.Subscriber, &out.Subscriber + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + if in.Reply != nil { + in, out := &in.Reply, &out.Reply + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(duckv1beta1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionSpec. +func (in *SubscriptionSpec) DeepCopy() *SubscriptionSpec { + if in == nil { + return nil + } + out := new(SubscriptionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriptionStatus) DeepCopyInto(out *SubscriptionStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.PhysicalSubscription.DeepCopyInto(&out.PhysicalSubscription) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionStatus. +func (in *SubscriptionStatus) DeepCopy() *SubscriptionStatus { + if in == nil { + return nil + } + out := new(SubscriptionStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SubscriptionStatusPhysicalSubscription) DeepCopyInto(out *SubscriptionStatusPhysicalSubscription) { + *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.DeadLetterSinkURI != nil { + in, out := &in.DeadLetterSinkURI, &out.DeadLetterSinkURI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubscriptionStatusPhysicalSubscription. +func (in *SubscriptionStatusPhysicalSubscription) DeepCopy() *SubscriptionStatusPhysicalSubscription { + if in == nil { + return nil + } + out := new(SubscriptionStatusPhysicalSubscription) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 32afeaaf93f..5f4a22a0a59 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -27,6 +27,7 @@ import ( eventingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1alpha1" + messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" sourcesv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" ) @@ -35,6 +36,7 @@ type Interface interface { EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface FlowsV1alpha1() flowsv1alpha1.FlowsV1alpha1Interface MessagingV1alpha1() messagingv1alpha1.MessagingV1alpha1Interface + MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface } @@ -45,6 +47,7 @@ type Clientset struct { eventingV1alpha1 *eventingv1alpha1.EventingV1alpha1Client flowsV1alpha1 *flowsv1alpha1.FlowsV1alpha1Client messagingV1alpha1 *messagingv1alpha1.MessagingV1alpha1Client + messagingV1beta1 *messagingv1beta1.MessagingV1beta1Client sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client } @@ -63,6 +66,11 @@ func (c *Clientset) MessagingV1alpha1() messagingv1alpha1.MessagingV1alpha1Inter return c.messagingV1alpha1 } +// MessagingV1beta1 retrieves the MessagingV1beta1Client +func (c *Clientset) MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface { + return c.messagingV1beta1 +} + // SourcesV1alpha1 retrieves the SourcesV1alpha1Client func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { return c.sourcesV1alpha1 @@ -101,6 +109,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.messagingV1beta1, err = messagingv1beta1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.sourcesV1alpha1, err = sourcesv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -120,6 +132,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { cs.eventingV1alpha1 = eventingv1alpha1.NewForConfigOrDie(c) cs.flowsV1alpha1 = flowsv1alpha1.NewForConfigOrDie(c) cs.messagingV1alpha1 = messagingv1alpha1.NewForConfigOrDie(c) + cs.messagingV1beta1 = messagingv1beta1.NewForConfigOrDie(c) cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) @@ -132,6 +145,7 @@ func New(c rest.Interface) *Clientset { cs.eventingV1alpha1 = eventingv1alpha1.New(c) cs.flowsV1alpha1 = flowsv1alpha1.New(c) cs.messagingV1alpha1 = messagingv1alpha1.New(c) + cs.messagingV1beta1 = messagingv1beta1.New(c) cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 8dae4a33376..74fa682d0fc 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -31,6 +31,8 @@ import ( fakeflowsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1alpha1/fake" messagingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1alpha1" fakemessagingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1alpha1/fake" + messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" + fakemessagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake" sourcesv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1" fakesourcesv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1/fake" ) @@ -97,6 +99,11 @@ func (c *Clientset) MessagingV1alpha1() messagingv1alpha1.MessagingV1alpha1Inter return &fakemessagingv1alpha1.FakeMessagingV1alpha1{Fake: &c.Fake} } +// MessagingV1beta1 retrieves the MessagingV1beta1Client +func (c *Clientset) MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface { + return &fakemessagingv1beta1.FakeMessagingV1beta1{Fake: &c.Fake} +} + // SourcesV1alpha1 retrieves the SourcesV1alpha1Client func (c *Clientset) SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface { return &fakesourcesv1alpha1.FakeSourcesV1alpha1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index dde81aa1581..8bc0390bdd1 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -27,6 +27,7 @@ import ( eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" ) @@ -37,6 +38,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ eventingv1alpha1.AddToScheme, flowsv1alpha1.AddToScheme, messagingv1alpha1.AddToScheme, + messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, } diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 29291713a64..e65a7eb6c6c 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -27,6 +27,7 @@ import ( eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" ) @@ -37,6 +38,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ eventingv1alpha1.AddToScheme, flowsv1alpha1.AddToScheme, messagingv1alpha1.AddToScheme, + messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, } diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/channel.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/channel.go new file mode 100644 index 00000000000..4538453f83a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/channel.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 v1beta1 + +import ( + "time" + + v1 "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" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// ChannelsGetter has a method to return a ChannelInterface. +// A group's client should implement this interface. +type ChannelsGetter interface { + Channels(namespace string) ChannelInterface +} + +// ChannelInterface has methods to work with Channel resources. +type ChannelInterface interface { + Create(*v1beta1.Channel) (*v1beta1.Channel, error) + Update(*v1beta1.Channel) (*v1beta1.Channel, error) + UpdateStatus(*v1beta1.Channel) (*v1beta1.Channel, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.Channel, error) + List(opts v1.ListOptions) (*v1beta1.ChannelList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Channel, err error) + ChannelExpansion +} + +// channels implements ChannelInterface +type channels struct { + client rest.Interface + ns string +} + +// newChannels returns a Channels +func newChannels(c *MessagingV1beta1Client, namespace string) *channels { + return &channels{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the channel, and returns the corresponding channel object, and an error if there is any. +func (c *channels) Get(name string, options v1.GetOptions) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Get(). + Namespace(c.ns). + Resource("channels"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Channels that match those selectors. +func (c *channels) List(opts v1.ListOptions) (result *v1beta1.ChannelList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.ChannelList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("channels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested channels. +func (c *channels) Watch(opts v1.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("channels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a channel and creates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *channels) Create(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Post(). + Namespace(c.ns). + Resource("channels"). + Body(channel). + Do(). + Into(result) + return +} + +// Update takes the representation of a channel and updates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *channels) Update(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("channels"). + Name(channel.Name). + Body(channel). + 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 *channels) UpdateStatus(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("channels"). + Name(channel.Name). + SubResource("status"). + Body(channel). + Do(). + Into(result) + return +} + +// Delete takes name of the channel and deletes it. Returns an error if one occurs. +func (c *channels) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("channels"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *channels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.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("channels"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched channel. +func (c *channels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Channel, err error) { + result = &v1beta1.Channel{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("channels"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/doc.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/doc.go new file mode 100644 index 00000000000..b641cb37309 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/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 v1beta1 diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/doc.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/doc.go new file mode 100644 index 00000000000..c7f6e65cab8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/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/messaging/v1beta1/fake/fake_channel.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_channel.go new file mode 100644 index 00000000000..b81e0314a92 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_channel.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" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// FakeChannels implements ChannelInterface +type FakeChannels struct { + Fake *FakeMessagingV1beta1 + ns string +} + +var channelsResource = schema.GroupVersionResource{Group: "messaging.knative.dev", Version: "v1beta1", Resource: "channels"} + +var channelsKind = schema.GroupVersionKind{Group: "messaging.knative.dev", Version: "v1beta1", Kind: "Channel"} + +// Get takes name of the channel, and returns the corresponding channel object, and an error if there is any. +func (c *FakeChannels) Get(name string, options v1.GetOptions) (result *v1beta1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(channelsResource, c.ns, name), &v1beta1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Channel), err +} + +// List takes label and field selectors, and returns the list of Channels that match those selectors. +func (c *FakeChannels) List(opts v1.ListOptions) (result *v1beta1.ChannelList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(channelsResource, channelsKind, c.ns, opts), &v1beta1.ChannelList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.ChannelList{ListMeta: obj.(*v1beta1.ChannelList).ListMeta} + for _, item := range obj.(*v1beta1.ChannelList).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 channels. +func (c *FakeChannels) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(channelsResource, c.ns, opts)) + +} + +// Create takes the representation of a channel and creates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *FakeChannels) Create(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(channelsResource, c.ns, channel), &v1beta1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Channel), err +} + +// Update takes the representation of a channel and updates it. Returns the server's representation of the channel, and an error, if there is any. +func (c *FakeChannels) Update(channel *v1beta1.Channel) (result *v1beta1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(channelsResource, c.ns, channel), &v1beta1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Channel), 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 *FakeChannels) UpdateStatus(channel *v1beta1.Channel) (*v1beta1.Channel, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(channelsResource, "status", c.ns, channel), &v1beta1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Channel), err +} + +// Delete takes name of the channel and deletes it. Returns an error if one occurs. +func (c *FakeChannels) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(channelsResource, c.ns, name), &v1beta1.Channel{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeChannels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(channelsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.ChannelList{}) + return err +} + +// Patch applies the patch and returns the patched channel. +func (c *FakeChannels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Channel, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(channelsResource, c.ns, name, pt, data, subresources...), &v1beta1.Channel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Channel), err +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_inmemorychannel.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_inmemorychannel.go new file mode 100644 index 00000000000..1542ff5bf80 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_inmemorychannel.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" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// FakeInMemoryChannels implements InMemoryChannelInterface +type FakeInMemoryChannels struct { + Fake *FakeMessagingV1beta1 + ns string +} + +var inmemorychannelsResource = schema.GroupVersionResource{Group: "messaging.knative.dev", Version: "v1beta1", Resource: "inmemorychannels"} + +var inmemorychannelsKind = schema.GroupVersionKind{Group: "messaging.knative.dev", Version: "v1beta1", Kind: "InMemoryChannel"} + +// Get takes name of the inMemoryChannel, and returns the corresponding inMemoryChannel object, and an error if there is any. +func (c *FakeInMemoryChannels) Get(name string, options v1.GetOptions) (result *v1beta1.InMemoryChannel, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(inmemorychannelsResource, c.ns, name), &v1beta1.InMemoryChannel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.InMemoryChannel), err +} + +// List takes label and field selectors, and returns the list of InMemoryChannels that match those selectors. +func (c *FakeInMemoryChannels) List(opts v1.ListOptions) (result *v1beta1.InMemoryChannelList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(inmemorychannelsResource, inmemorychannelsKind, c.ns, opts), &v1beta1.InMemoryChannelList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.InMemoryChannelList{ListMeta: obj.(*v1beta1.InMemoryChannelList).ListMeta} + for _, item := range obj.(*v1beta1.InMemoryChannelList).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 inMemoryChannels. +func (c *FakeInMemoryChannels) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(inmemorychannelsResource, c.ns, opts)) + +} + +// Create takes the representation of a inMemoryChannel and creates it. Returns the server's representation of the inMemoryChannel, and an error, if there is any. +func (c *FakeInMemoryChannels) Create(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(inmemorychannelsResource, c.ns, inMemoryChannel), &v1beta1.InMemoryChannel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.InMemoryChannel), err +} + +// Update takes the representation of a inMemoryChannel and updates it. Returns the server's representation of the inMemoryChannel, and an error, if there is any. +func (c *FakeInMemoryChannels) Update(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(inmemorychannelsResource, c.ns, inMemoryChannel), &v1beta1.InMemoryChannel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.InMemoryChannel), 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 *FakeInMemoryChannels) UpdateStatus(inMemoryChannel *v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(inmemorychannelsResource, "status", c.ns, inMemoryChannel), &v1beta1.InMemoryChannel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.InMemoryChannel), err +} + +// Delete takes name of the inMemoryChannel and deletes it. Returns an error if one occurs. +func (c *FakeInMemoryChannels) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(inmemorychannelsResource, c.ns, name), &v1beta1.InMemoryChannel{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeInMemoryChannels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(inmemorychannelsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.InMemoryChannelList{}) + return err +} + +// Patch applies the patch and returns the patched inMemoryChannel. +func (c *FakeInMemoryChannels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.InMemoryChannel, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(inmemorychannelsResource, c.ns, name, pt, data, subresources...), &v1beta1.InMemoryChannel{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.InMemoryChannel), err +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_messaging_client.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_messaging_client.go new file mode 100644 index 00000000000..e2c712afd83 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_messaging_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" + v1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" +) + +type FakeMessagingV1beta1 struct { + *testing.Fake +} + +func (c *FakeMessagingV1beta1) Channels(namespace string) v1beta1.ChannelInterface { + return &FakeChannels{c, namespace} +} + +func (c *FakeMessagingV1beta1) InMemoryChannels(namespace string) v1beta1.InMemoryChannelInterface { + return &FakeInMemoryChannels{c, namespace} +} + +func (c *FakeMessagingV1beta1) Subscriptions(namespace string) v1beta1.SubscriptionInterface { + return &FakeSubscriptions{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeMessagingV1beta1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_subscription.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_subscription.go new file mode 100644 index 00000000000..6c3a3d592a3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/fake/fake_subscription.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" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// FakeSubscriptions implements SubscriptionInterface +type FakeSubscriptions struct { + Fake *FakeMessagingV1beta1 + ns string +} + +var subscriptionsResource = schema.GroupVersionResource{Group: "messaging.knative.dev", Version: "v1beta1", Resource: "subscriptions"} + +var subscriptionsKind = schema.GroupVersionKind{Group: "messaging.knative.dev", Version: "v1beta1", Kind: "Subscription"} + +// Get takes name of the subscription, and returns the corresponding subscription object, and an error if there is any. +func (c *FakeSubscriptions) Get(name string, options v1.GetOptions) (result *v1beta1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(subscriptionsResource, c.ns, name), &v1beta1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Subscription), err +} + +// List takes label and field selectors, and returns the list of Subscriptions that match those selectors. +func (c *FakeSubscriptions) List(opts v1.ListOptions) (result *v1beta1.SubscriptionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(subscriptionsResource, subscriptionsKind, c.ns, opts), &v1beta1.SubscriptionList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.SubscriptionList{ListMeta: obj.(*v1beta1.SubscriptionList).ListMeta} + for _, item := range obj.(*v1beta1.SubscriptionList).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 subscriptions. +func (c *FakeSubscriptions) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(subscriptionsResource, c.ns, opts)) + +} + +// Create takes the representation of a subscription and creates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *FakeSubscriptions) Create(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(subscriptionsResource, c.ns, subscription), &v1beta1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Subscription), err +} + +// Update takes the representation of a subscription and updates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *FakeSubscriptions) Update(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(subscriptionsResource, c.ns, subscription), &v1beta1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Subscription), 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 *FakeSubscriptions) UpdateStatus(subscription *v1beta1.Subscription) (*v1beta1.Subscription, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(subscriptionsResource, "status", c.ns, subscription), &v1beta1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Subscription), err +} + +// Delete takes name of the subscription and deletes it. Returns an error if one occurs. +func (c *FakeSubscriptions) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(subscriptionsResource, c.ns, name), &v1beta1.Subscription{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSubscriptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(subscriptionsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.SubscriptionList{}) + return err +} + +// Patch applies the patch and returns the patched subscription. +func (c *FakeSubscriptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Subscription, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(subscriptionsResource, c.ns, name, pt, data, subresources...), &v1beta1.Subscription{}) + + if obj == nil { + return nil, err + } + return obj.(*v1beta1.Subscription), err +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/generated_expansion.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/generated_expansion.go new file mode 100644 index 00000000000..219ca637ac3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/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 v1beta1 + +type ChannelExpansion interface{} + +type InMemoryChannelExpansion interface{} + +type SubscriptionExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/inmemorychannel.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/inmemorychannel.go new file mode 100644 index 00000000000..cc3541fe8e3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/inmemorychannel.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 v1beta1 + +import ( + "time" + + v1 "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" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// InMemoryChannelsGetter has a method to return a InMemoryChannelInterface. +// A group's client should implement this interface. +type InMemoryChannelsGetter interface { + InMemoryChannels(namespace string) InMemoryChannelInterface +} + +// InMemoryChannelInterface has methods to work with InMemoryChannel resources. +type InMemoryChannelInterface interface { + Create(*v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) + Update(*v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) + UpdateStatus(*v1beta1.InMemoryChannel) (*v1beta1.InMemoryChannel, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.InMemoryChannel, error) + List(opts v1.ListOptions) (*v1beta1.InMemoryChannelList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.InMemoryChannel, err error) + InMemoryChannelExpansion +} + +// inMemoryChannels implements InMemoryChannelInterface +type inMemoryChannels struct { + client rest.Interface + ns string +} + +// newInMemoryChannels returns a InMemoryChannels +func newInMemoryChannels(c *MessagingV1beta1Client, namespace string) *inMemoryChannels { + return &inMemoryChannels{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the inMemoryChannel, and returns the corresponding inMemoryChannel object, and an error if there is any. +func (c *inMemoryChannels) Get(name string, options v1.GetOptions) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Get(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of InMemoryChannels that match those selectors. +func (c *inMemoryChannels) List(opts v1.ListOptions) (result *v1beta1.InMemoryChannelList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.InMemoryChannelList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("inmemorychannels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested inMemoryChannels. +func (c *inMemoryChannels) Watch(opts v1.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("inmemorychannels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a inMemoryChannel and creates it. Returns the server's representation of the inMemoryChannel, and an error, if there is any. +func (c *inMemoryChannels) Create(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Post(). + Namespace(c.ns). + Resource("inmemorychannels"). + Body(inMemoryChannel). + Do(). + Into(result) + return +} + +// Update takes the representation of a inMemoryChannel and updates it. Returns the server's representation of the inMemoryChannel, and an error, if there is any. +func (c *inMemoryChannels) Update(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(inMemoryChannel.Name). + Body(inMemoryChannel). + 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 *inMemoryChannels) UpdateStatus(inMemoryChannel *v1beta1.InMemoryChannel) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(inMemoryChannel.Name). + SubResource("status"). + Body(inMemoryChannel). + Do(). + Into(result) + return +} + +// Delete takes name of the inMemoryChannel and deletes it. Returns an error if one occurs. +func (c *inMemoryChannels) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("inmemorychannels"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *inMemoryChannels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.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("inmemorychannels"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched inMemoryChannel. +func (c *inMemoryChannels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.InMemoryChannel, err error) { + result = &v1beta1.InMemoryChannel{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("inmemorychannels"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/messaging_client.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/messaging_client.go new file mode 100644 index 00000000000..f1199efa9e3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/messaging_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 v1beta1 + +import ( + rest "k8s.io/client-go/rest" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type MessagingV1beta1Interface interface { + RESTClient() rest.Interface + ChannelsGetter + InMemoryChannelsGetter + SubscriptionsGetter +} + +// MessagingV1beta1Client is used to interact with features provided by the messaging.knative.dev group. +type MessagingV1beta1Client struct { + restClient rest.Interface +} + +func (c *MessagingV1beta1Client) Channels(namespace string) ChannelInterface { + return newChannels(c, namespace) +} + +func (c *MessagingV1beta1Client) InMemoryChannels(namespace string) InMemoryChannelInterface { + return newInMemoryChannels(c, namespace) +} + +func (c *MessagingV1beta1Client) Subscriptions(namespace string) SubscriptionInterface { + return newSubscriptions(c, namespace) +} + +// NewForConfig creates a new MessagingV1beta1Client for the given config. +func NewForConfig(c *rest.Config) (*MessagingV1beta1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &MessagingV1beta1Client{client}, nil +} + +// NewForConfigOrDie creates a new MessagingV1beta1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *MessagingV1beta1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new MessagingV1beta1Client for the given RESTClient. +func New(c rest.Interface) *MessagingV1beta1Client { + return &MessagingV1beta1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1beta1.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 *MessagingV1beta1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/messaging/v1beta1/subscription.go b/pkg/client/clientset/versioned/typed/messaging/v1beta1/subscription.go new file mode 100644 index 00000000000..a610b08522e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/messaging/v1beta1/subscription.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 v1beta1 + +import ( + "time" + + v1 "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" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// SubscriptionsGetter has a method to return a SubscriptionInterface. +// A group's client should implement this interface. +type SubscriptionsGetter interface { + Subscriptions(namespace string) SubscriptionInterface +} + +// SubscriptionInterface has methods to work with Subscription resources. +type SubscriptionInterface interface { + Create(*v1beta1.Subscription) (*v1beta1.Subscription, error) + Update(*v1beta1.Subscription) (*v1beta1.Subscription, error) + UpdateStatus(*v1beta1.Subscription) (*v1beta1.Subscription, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.Subscription, error) + List(opts v1.ListOptions) (*v1beta1.SubscriptionList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Subscription, err error) + SubscriptionExpansion +} + +// subscriptions implements SubscriptionInterface +type subscriptions struct { + client rest.Interface + ns string +} + +// newSubscriptions returns a Subscriptions +func newSubscriptions(c *MessagingV1beta1Client, namespace string) *subscriptions { + return &subscriptions{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the subscription, and returns the corresponding subscription object, and an error if there is any. +func (c *subscriptions) Get(name string, options v1.GetOptions) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Subscriptions that match those selectors. +func (c *subscriptions) List(opts v1.ListOptions) (result *v1beta1.SubscriptionList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.SubscriptionList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("subscriptions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested subscriptions. +func (c *subscriptions) Watch(opts v1.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("subscriptions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a subscription and creates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *subscriptions) Create(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Post(). + Namespace(c.ns). + Resource("subscriptions"). + Body(subscription). + Do(). + Into(result) + return +} + +// Update takes the representation of a subscription and updates it. Returns the server's representation of the subscription, and an error, if there is any. +func (c *subscriptions) Update(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Put(). + Namespace(c.ns). + Resource("subscriptions"). + Name(subscription.Name). + Body(subscription). + 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 *subscriptions) UpdateStatus(subscription *v1beta1.Subscription) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Put(). + Namespace(c.ns). + Resource("subscriptions"). + Name(subscription.Name). + SubResource("status"). + Body(subscription). + Do(). + Into(result) + return +} + +// Delete takes name of the subscription and deletes it. Returns an error if one occurs. +func (c *subscriptions) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("subscriptions"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *subscriptions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.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("subscriptions"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched subscription. +func (c *subscriptions) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Subscription, err error) { + result = &v1beta1.Subscription{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("subscriptions"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index d2f35b1aa44..7eacaab1074 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -26,6 +26,7 @@ import ( v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" ) @@ -81,6 +82,14 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case messagingv1alpha1.SchemeGroupVersion.WithResource("subscriptions"): return &genericInformer{resource: resource.GroupResource(), informer: f.Messaging().V1alpha1().Subscriptions().Informer()}, nil + // Group=messaging.knative.dev, Version=v1beta1 + case v1beta1.SchemeGroupVersion.WithResource("channels"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Messaging().V1beta1().Channels().Informer()}, nil + case v1beta1.SchemeGroupVersion.WithResource("inmemorychannels"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Messaging().V1beta1().InMemoryChannels().Informer()}, nil + case v1beta1.SchemeGroupVersion.WithResource("subscriptions"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Messaging().V1beta1().Subscriptions().Informer()}, nil + // Group=sources.knative.dev, Version=v1alpha1 case sourcesv1alpha1.SchemeGroupVersion.WithResource("apiserversources"): return &genericInformer{resource: resource.GroupResource(), informer: f.Sources().V1alpha1().ApiServerSources().Informer()}, nil diff --git a/pkg/client/informers/externalversions/messaging/interface.go b/pkg/client/informers/externalversions/messaging/interface.go index cb50d2009ad..f821e966e03 100644 --- a/pkg/client/informers/externalversions/messaging/interface.go +++ b/pkg/client/informers/externalversions/messaging/interface.go @@ -21,12 +21,15 @@ package messaging import ( internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1alpha1" + v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1" ) // Interface provides access to each of this group's versions. type Interface interface { // V1alpha1 provides access to shared informers for resources in V1alpha1. V1alpha1() v1alpha1.Interface + // V1beta1 provides access to shared informers for resources in V1beta1. + V1beta1() v1beta1.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1alpha1() v1alpha1.Interface { return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1beta1 returns a new v1beta1.Interface. +func (g *group) V1beta1() v1beta1.Interface { + return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/messaging/v1beta1/channel.go b/pkg/client/informers/externalversions/messaging/v1beta1/channel.go new file mode 100644 index 00000000000..5a176043b0c --- /dev/null +++ b/pkg/client/informers/externalversions/messaging/v1beta1/channel.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 v1beta1 + +import ( + time "time" + + v1 "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" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1beta1 "knative.dev/eventing/pkg/client/listers/messaging/v1beta1" +) + +// ChannelInformer provides access to a shared informer and lister for +// Channels. +type ChannelInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.ChannelLister +} + +type channelInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewChannelInformer constructs a new informer for Channel 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 NewChannelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredChannelInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredChannelInformer constructs a new informer for Channel 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 NewFilteredChannelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MessagingV1beta1().Channels(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MessagingV1beta1().Channels(namespace).Watch(options) + }, + }, + &messagingv1beta1.Channel{}, + resyncPeriod, + indexers, + ) +} + +func (f *channelInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredChannelInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *channelInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&messagingv1beta1.Channel{}, f.defaultInformer) +} + +func (f *channelInformer) Lister() v1beta1.ChannelLister { + return v1beta1.NewChannelLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/messaging/v1beta1/inmemorychannel.go b/pkg/client/informers/externalversions/messaging/v1beta1/inmemorychannel.go new file mode 100644 index 00000000000..c6c3cd0eeba --- /dev/null +++ b/pkg/client/informers/externalversions/messaging/v1beta1/inmemorychannel.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 v1beta1 + +import ( + time "time" + + v1 "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" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1beta1 "knative.dev/eventing/pkg/client/listers/messaging/v1beta1" +) + +// InMemoryChannelInformer provides access to a shared informer and lister for +// InMemoryChannels. +type InMemoryChannelInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.InMemoryChannelLister +} + +type inMemoryChannelInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewInMemoryChannelInformer constructs a new informer for InMemoryChannel 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 NewInMemoryChannelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredInMemoryChannelInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredInMemoryChannelInformer constructs a new informer for InMemoryChannel 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 NewFilteredInMemoryChannelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MessagingV1beta1().InMemoryChannels(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MessagingV1beta1().InMemoryChannels(namespace).Watch(options) + }, + }, + &messagingv1beta1.InMemoryChannel{}, + resyncPeriod, + indexers, + ) +} + +func (f *inMemoryChannelInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredInMemoryChannelInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *inMemoryChannelInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&messagingv1beta1.InMemoryChannel{}, f.defaultInformer) +} + +func (f *inMemoryChannelInformer) Lister() v1beta1.InMemoryChannelLister { + return v1beta1.NewInMemoryChannelLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/messaging/v1beta1/interface.go b/pkg/client/informers/externalversions/messaging/v1beta1/interface.go new file mode 100644 index 00000000000..43da3e1c273 --- /dev/null +++ b/pkg/client/informers/externalversions/messaging/v1beta1/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 v1beta1 + +import ( + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Channels returns a ChannelInformer. + Channels() ChannelInformer + // InMemoryChannels returns a InMemoryChannelInformer. + InMemoryChannels() InMemoryChannelInformer + // Subscriptions returns a SubscriptionInformer. + Subscriptions() SubscriptionInformer +} + +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} +} + +// Channels returns a ChannelInformer. +func (v *version) Channels() ChannelInformer { + return &channelInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// InMemoryChannels returns a InMemoryChannelInformer. +func (v *version) InMemoryChannels() InMemoryChannelInformer { + return &inMemoryChannelInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Subscriptions returns a SubscriptionInformer. +func (v *version) Subscriptions() SubscriptionInformer { + return &subscriptionInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/messaging/v1beta1/subscription.go b/pkg/client/informers/externalversions/messaging/v1beta1/subscription.go new file mode 100644 index 00000000000..6900efde646 --- /dev/null +++ b/pkg/client/informers/externalversions/messaging/v1beta1/subscription.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 v1beta1 + +import ( + time "time" + + v1 "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" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1beta1 "knative.dev/eventing/pkg/client/listers/messaging/v1beta1" +) + +// SubscriptionInformer provides access to a shared informer and lister for +// Subscriptions. +type SubscriptionInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.SubscriptionLister +} + +type subscriptionInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewSubscriptionInformer constructs a new informer for Subscription 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 NewSubscriptionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredSubscriptionInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredSubscriptionInformer constructs a new informer for Subscription 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 NewFilteredSubscriptionInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MessagingV1beta1().Subscriptions(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MessagingV1beta1().Subscriptions(namespace).Watch(options) + }, + }, + &messagingv1beta1.Subscription{}, + resyncPeriod, + indexers, + ) +} + +func (f *subscriptionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredSubscriptionInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *subscriptionInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&messagingv1beta1.Subscription{}, f.defaultInformer) +} + +func (f *subscriptionInformer) Lister() v1beta1.SubscriptionLister { + return v1beta1.NewSubscriptionLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/injection/ducks/duck/v1beta1/channelable/channelable.go b/pkg/client/injection/ducks/duck/v1beta1/channelable/channelable.go new file mode 100644 index 00000000000..4526074320d --- /dev/null +++ b/pkg/client/injection/ducks/duck/v1beta1/channelable/channelable.go @@ -0,0 +1,60 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package channelable + +import ( + "context" + + v1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + duck "knative.dev/pkg/apis/duck" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + dynamicclient "knative.dev/pkg/injection/clients/dynamicclient" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterDuck(WithDuck) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func WithDuck(ctx context.Context) context.Context { + dc := dynamicclient.Get(ctx) + dif := &duck.CachedInformerFactory{ + Delegate: &duck.TypedInformerFactory{ + Client: dc, + Type: (&v1beta1.Channelable{}).GetFullType(), + ResyncPeriod: controller.GetResyncPeriod(ctx), + StopChannel: ctx.Done(), + }, + } + return context.WithValue(ctx, Key{}, dif) +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) duck.InformerFactory { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/pkg/apis/duck.InformerFactory from context.") + } + return untyped.(duck.InformerFactory) +} diff --git a/pkg/client/injection/ducks/duck/v1beta1/channelable/fake/fake.go b/pkg/client/injection/ducks/duck/v1beta1/channelable/fake/fake.go new file mode 100644 index 00000000000..a86c1940019 --- /dev/null +++ b/pkg/client/injection/ducks/duck/v1beta1/channelable/fake/fake.go @@ -0,0 +1,30 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + channelable "knative.dev/eventing/pkg/client/injection/ducks/duck/v1beta1/channelable" + injection "knative.dev/pkg/injection" +) + +var Get = channelable.Get + +func init() { + injection.Fake.RegisterDuck(channelable.WithDuck) +} diff --git a/pkg/client/injection/ducks/duck/v1beta1/subscribable/fake/fake.go b/pkg/client/injection/ducks/duck/v1beta1/subscribable/fake/fake.go new file mode 100644 index 00000000000..89105cb1ddb --- /dev/null +++ b/pkg/client/injection/ducks/duck/v1beta1/subscribable/fake/fake.go @@ -0,0 +1,30 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + subscribable "knative.dev/eventing/pkg/client/injection/ducks/duck/v1beta1/subscribable" + injection "knative.dev/pkg/injection" +) + +var Get = subscribable.Get + +func init() { + injection.Fake.RegisterDuck(subscribable.WithDuck) +} diff --git a/pkg/client/injection/ducks/duck/v1beta1/subscribable/subscribable.go b/pkg/client/injection/ducks/duck/v1beta1/subscribable/subscribable.go new file mode 100644 index 00000000000..461b5f0a713 --- /dev/null +++ b/pkg/client/injection/ducks/duck/v1beta1/subscribable/subscribable.go @@ -0,0 +1,60 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package subscribable + +import ( + "context" + + v1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + duck "knative.dev/pkg/apis/duck" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + dynamicclient "knative.dev/pkg/injection/clients/dynamicclient" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterDuck(WithDuck) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func WithDuck(ctx context.Context) context.Context { + dc := dynamicclient.Get(ctx) + dif := &duck.CachedInformerFactory{ + Delegate: &duck.TypedInformerFactory{ + Client: dc, + Type: (&v1beta1.Subscribable{}).GetFullType(), + ResyncPeriod: controller.GetResyncPeriod(ctx), + StopChannel: ctx.Done(), + }, + } + return context.WithValue(ctx, Key{}, dif) +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) duck.InformerFactory { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/pkg/apis/duck.InformerFactory from context.") + } + return untyped.(duck.InformerFactory) +} diff --git a/pkg/client/injection/informers/messaging/v1beta1/channel/channel.go b/pkg/client/injection/informers/messaging/v1beta1/channel/channel.go new file mode 100644 index 00000000000..90c255c7d4d --- /dev/null +++ b/pkg/client/injection/informers/messaging/v1beta1/channel/channel.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 channel + +import ( + "context" + + v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1" + 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.Messaging().V1beta1().Channels() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1beta1.ChannelInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1.ChannelInformer from context.") + } + return untyped.(v1beta1.ChannelInformer) +} diff --git a/pkg/client/injection/informers/messaging/v1beta1/channel/fake/fake.go b/pkg/client/injection/informers/messaging/v1beta1/channel/fake/fake.go new file mode 100644 index 00000000000..69c78fcf2de --- /dev/null +++ b/pkg/client/injection/informers/messaging/v1beta1/channel/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" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + channel "knative.dev/eventing/pkg/client/injection/informers/messaging/v1beta1/channel" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = channel.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Messaging().V1beta1().Channels() + return context.WithValue(ctx, channel.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel/fake/fake.go b/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel/fake/fake.go new file mode 100644 index 00000000000..3772b9f6f6c --- /dev/null +++ b/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel/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" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + inmemorychannel "knative.dev/eventing/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = inmemorychannel.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Messaging().V1beta1().InMemoryChannels() + return context.WithValue(ctx, inmemorychannel.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel/inmemorychannel.go b/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel/inmemorychannel.go new file mode 100644 index 00000000000..3813d5a8013 --- /dev/null +++ b/pkg/client/injection/informers/messaging/v1beta1/inmemorychannel/inmemorychannel.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 inmemorychannel + +import ( + "context" + + v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1" + 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.Messaging().V1beta1().InMemoryChannels() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1beta1.InMemoryChannelInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1.InMemoryChannelInformer from context.") + } + return untyped.(v1beta1.InMemoryChannelInformer) +} diff --git a/pkg/client/injection/informers/messaging/v1beta1/subscription/fake/fake.go b/pkg/client/injection/informers/messaging/v1beta1/subscription/fake/fake.go new file mode 100644 index 00000000000..2e888e48f34 --- /dev/null +++ b/pkg/client/injection/informers/messaging/v1beta1/subscription/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" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + subscription "knative.dev/eventing/pkg/client/injection/informers/messaging/v1beta1/subscription" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = subscription.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Messaging().V1beta1().Subscriptions() + return context.WithValue(ctx, subscription.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/messaging/v1beta1/subscription/subscription.go b/pkg/client/injection/informers/messaging/v1beta1/subscription/subscription.go new file mode 100644 index 00000000000..d04435f3336 --- /dev/null +++ b/pkg/client/injection/informers/messaging/v1beta1/subscription/subscription.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 subscription + +import ( + "context" + + v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1" + 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.Messaging().V1beta1().Subscriptions() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1beta1.SubscriptionInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/messaging/v1beta1.SubscriptionInformer from context.") + } + return untyped.(v1beta1.SubscriptionInformer) +} diff --git a/pkg/client/listers/messaging/v1beta1/channel.go b/pkg/client/listers/messaging/v1beta1/channel.go new file mode 100644 index 00000000000..b092ae1c7ae --- /dev/null +++ b/pkg/client/listers/messaging/v1beta1/channel.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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// ChannelLister helps list Channels. +type ChannelLister interface { + // List lists all Channels in the indexer. + List(selector labels.Selector) (ret []*v1beta1.Channel, err error) + // Channels returns an object that can list and get Channels. + Channels(namespace string) ChannelNamespaceLister + ChannelListerExpansion +} + +// channelLister implements the ChannelLister interface. +type channelLister struct { + indexer cache.Indexer +} + +// NewChannelLister returns a new ChannelLister. +func NewChannelLister(indexer cache.Indexer) ChannelLister { + return &channelLister{indexer: indexer} +} + +// List lists all Channels in the indexer. +func (s *channelLister) List(selector labels.Selector) (ret []*v1beta1.Channel, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.Channel)) + }) + return ret, err +} + +// Channels returns an object that can list and get Channels. +func (s *channelLister) Channels(namespace string) ChannelNamespaceLister { + return channelNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ChannelNamespaceLister helps list and get Channels. +type ChannelNamespaceLister interface { + // List lists all Channels in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1beta1.Channel, err error) + // Get retrieves the Channel from the indexer for a given namespace and name. + Get(name string) (*v1beta1.Channel, error) + ChannelNamespaceListerExpansion +} + +// channelNamespaceLister implements the ChannelNamespaceLister +// interface. +type channelNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Channels in the indexer for a given namespace. +func (s channelNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.Channel, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.Channel)) + }) + return ret, err +} + +// Get retrieves the Channel from the indexer for a given namespace and name. +func (s channelNamespaceLister) Get(name string) (*v1beta1.Channel, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("channel"), name) + } + return obj.(*v1beta1.Channel), nil +} diff --git a/pkg/client/listers/messaging/v1beta1/expansion_generated.go b/pkg/client/listers/messaging/v1beta1/expansion_generated.go new file mode 100644 index 00000000000..86e075351dc --- /dev/null +++ b/pkg/client/listers/messaging/v1beta1/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 v1beta1 + +// ChannelListerExpansion allows custom methods to be added to +// ChannelLister. +type ChannelListerExpansion interface{} + +// ChannelNamespaceListerExpansion allows custom methods to be added to +// ChannelNamespaceLister. +type ChannelNamespaceListerExpansion interface{} + +// InMemoryChannelListerExpansion allows custom methods to be added to +// InMemoryChannelLister. +type InMemoryChannelListerExpansion interface{} + +// InMemoryChannelNamespaceListerExpansion allows custom methods to be added to +// InMemoryChannelNamespaceLister. +type InMemoryChannelNamespaceListerExpansion interface{} + +// SubscriptionListerExpansion allows custom methods to be added to +// SubscriptionLister. +type SubscriptionListerExpansion interface{} + +// SubscriptionNamespaceListerExpansion allows custom methods to be added to +// SubscriptionNamespaceLister. +type SubscriptionNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/messaging/v1beta1/inmemorychannel.go b/pkg/client/listers/messaging/v1beta1/inmemorychannel.go new file mode 100644 index 00000000000..9a2a9cdc307 --- /dev/null +++ b/pkg/client/listers/messaging/v1beta1/inmemorychannel.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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// InMemoryChannelLister helps list InMemoryChannels. +type InMemoryChannelLister interface { + // List lists all InMemoryChannels in the indexer. + List(selector labels.Selector) (ret []*v1beta1.InMemoryChannel, err error) + // InMemoryChannels returns an object that can list and get InMemoryChannels. + InMemoryChannels(namespace string) InMemoryChannelNamespaceLister + InMemoryChannelListerExpansion +} + +// inMemoryChannelLister implements the InMemoryChannelLister interface. +type inMemoryChannelLister struct { + indexer cache.Indexer +} + +// NewInMemoryChannelLister returns a new InMemoryChannelLister. +func NewInMemoryChannelLister(indexer cache.Indexer) InMemoryChannelLister { + return &inMemoryChannelLister{indexer: indexer} +} + +// List lists all InMemoryChannels in the indexer. +func (s *inMemoryChannelLister) List(selector labels.Selector) (ret []*v1beta1.InMemoryChannel, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.InMemoryChannel)) + }) + return ret, err +} + +// InMemoryChannels returns an object that can list and get InMemoryChannels. +func (s *inMemoryChannelLister) InMemoryChannels(namespace string) InMemoryChannelNamespaceLister { + return inMemoryChannelNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// InMemoryChannelNamespaceLister helps list and get InMemoryChannels. +type InMemoryChannelNamespaceLister interface { + // List lists all InMemoryChannels in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1beta1.InMemoryChannel, err error) + // Get retrieves the InMemoryChannel from the indexer for a given namespace and name. + Get(name string) (*v1beta1.InMemoryChannel, error) + InMemoryChannelNamespaceListerExpansion +} + +// inMemoryChannelNamespaceLister implements the InMemoryChannelNamespaceLister +// interface. +type inMemoryChannelNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all InMemoryChannels in the indexer for a given namespace. +func (s inMemoryChannelNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.InMemoryChannel, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.InMemoryChannel)) + }) + return ret, err +} + +// Get retrieves the InMemoryChannel from the indexer for a given namespace and name. +func (s inMemoryChannelNamespaceLister) Get(name string) (*v1beta1.InMemoryChannel, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("inmemorychannel"), name) + } + return obj.(*v1beta1.InMemoryChannel), nil +} diff --git a/pkg/client/listers/messaging/v1beta1/subscription.go b/pkg/client/listers/messaging/v1beta1/subscription.go new file mode 100644 index 00000000000..878eb987730 --- /dev/null +++ b/pkg/client/listers/messaging/v1beta1/subscription.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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" +) + +// SubscriptionLister helps list Subscriptions. +type SubscriptionLister interface { + // List lists all Subscriptions in the indexer. + List(selector labels.Selector) (ret []*v1beta1.Subscription, err error) + // Subscriptions returns an object that can list and get Subscriptions. + Subscriptions(namespace string) SubscriptionNamespaceLister + SubscriptionListerExpansion +} + +// subscriptionLister implements the SubscriptionLister interface. +type subscriptionLister struct { + indexer cache.Indexer +} + +// NewSubscriptionLister returns a new SubscriptionLister. +func NewSubscriptionLister(indexer cache.Indexer) SubscriptionLister { + return &subscriptionLister{indexer: indexer} +} + +// List lists all Subscriptions in the indexer. +func (s *subscriptionLister) List(selector labels.Selector) (ret []*v1beta1.Subscription, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.Subscription)) + }) + return ret, err +} + +// Subscriptions returns an object that can list and get Subscriptions. +func (s *subscriptionLister) Subscriptions(namespace string) SubscriptionNamespaceLister { + return subscriptionNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// SubscriptionNamespaceLister helps list and get Subscriptions. +type SubscriptionNamespaceLister interface { + // List lists all Subscriptions in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1beta1.Subscription, err error) + // Get retrieves the Subscription from the indexer for a given namespace and name. + Get(name string) (*v1beta1.Subscription, error) + SubscriptionNamespaceListerExpansion +} + +// subscriptionNamespaceLister implements the SubscriptionNamespaceLister +// interface. +type subscriptionNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Subscriptions in the indexer for a given namespace. +func (s subscriptionNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.Subscription, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.Subscription)) + }) + return ret, err +} + +// Get retrieves the Subscription from the indexer for a given namespace and name. +func (s subscriptionNamespaceLister) Get(name string) (*v1beta1.Subscription, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("subscription"), name) + } + return obj.(*v1beta1.Subscription), nil +}