From ef479cf11d976f3f86bb804c99a0cea4e96be3e4 Mon Sep 17 00:00:00 2001
From: Cali0707
-(Appears on:ChannelableStatus, BrokerStatus, ParallelStatus, SequenceStatus, JobSinkStatus)
+(Appears on:ChannelableStatus, BrokerStatus, RequestReplyStatus, ParallelStatus, SequenceStatus, JobSinkStatus)
AppliedEventPoliciesStatus contains the list of policies which apply to a resource.
@@ -393,7 +393,7 @@ AppliedEventPoliciesStatus
-(Appears on:ChannelableSpec, SubscriberSpec, BrokerSpec, TriggerSpec, ParallelBranch, SequenceStep, SubscriptionSpec)
+(Appears on:ChannelableSpec, SubscriberSpec, BrokerSpec, TriggerSpec, RequestReplySpec, ParallelBranch, SequenceStep, SubscriptionSpec)
DeliverySpec contains the delivery options for event senders,
@@ -2648,6 +2648,8 @@ knative.dev/pkg/apis/duck/v1.AuthStatus
Resource Types:
AppliedEventPoliciesStatus
DeliverySpec
EventPolicy
@@ -2776,6 +2778,150 @@ This data may be out of date.
+
RequestRepluy represents synchronous interface to sending and receiving events from a Broker.
+ +Field | +Description | +||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+apiVersion +string |
+
+
+eventing.knative.dev/v1alpha1
+
+ |
+||||||||||||
+kind +string + |
+RequestReply |
+||||||||||||
+metadata + + +Kubernetes meta/v1.ObjectMeta + + + |
+
+(Optional)
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||||||
+spec + + +RequestReplySpec + + + |
+
+ Spec defines the desired state of the EventPolicy. ++ +
|
+||||||||||||
+status + + +RequestReplyStatus + + + |
+
+(Optional)
+ Status represents the current state of the EventPolicy. +This data may be out of date. + |
+
@@ -3127,6 +3273,159 @@ More info: RequestReplySpec
+
+
+(Appears on:RequestReply)
+
+
Field | +Description | +
---|---|
+brokerRef + + +knative.dev/pkg/apis/duck/v1.KReference + + + |
+
+ BrokerRef contains the reference to the broker the RequestReply sends events to. + |
+
+correlationAttribute + +string + + |
++ | +
+replyAttribute + +string + + |
++ | +
+timeout + +string + + |
++ | +
+delivery + + +DeliverySpec + + + |
++ | +
+secrets + +[]string + + |
++ | +
+(Appears on:RequestReply) +
++
RequestReplyStatus represents the current state of a RequestReply.
+ +Field | +Description | +
---|---|
+Status + + +knative.dev/pkg/apis/duck/v1.Status + + + |
+
+
+(Members of 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. + |
+
+AddressStatus + + +knative.dev/pkg/apis/duck/v1.AddressStatus + + + |
+
+
+(Members of AddressStatus is the part where the RequestReply fulfills the Addressable contract. +It exposes the endpoint as an URI to get events delivered. + |
+
+AppliedEventPoliciesStatus + + +AppliedEventPoliciesStatus + + + |
+
+
+(Members of AppliedEventPoliciesStatus contains the list of EventPolicies which apply to this Broker. + |
+
diff --git a/pkg/apis/eventing/v1alpha1/register.go b/pkg/apis/eventing/v1alpha1/register.go index c6f3e98cd0b..c891f7c7b18 100644 --- a/pkg/apis/eventing/v1alpha1/register.go +++ b/pkg/apis/eventing/v1alpha1/register.go @@ -47,6 +47,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &EventPolicy{}, &EventPolicyList{}, + &RequestReply{}, + &RequestReplyList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/eventing/v1alpha1/requestreply_conversion.go b/pkg/apis/eventing/v1alpha1/requestreply_conversion.go new file mode 100644 index 00000000000..739e922ca42 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (ep *RequestReply) ConvertTo(ctx context.Context, obj apis.Convertible) error { + return fmt.Errorf("v1alpha1 is the highest known version, got: %T", obj) +} + +// ConvertFrom implements apis.Convertible +func (ep *RequestReply) ConvertFrom(ctx context.Context, obj apis.Convertible) error { + return fmt.Errorf("v1alpha1 is the highest known version, got: %T", obj) +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_conversion_test.go b/pkg/apis/eventing/v1alpha1/requestreply_conversion_test.go new file mode 100644 index 00000000000..96e1136da50 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "testing" +) + +func TestRequestReplyConversionHighestVersion(t *testing.T) { + good, bad := &RequestReply{}, &RequestReply{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_defaults.go b/pkg/apis/eventing/v1alpha1/requestreply_defaults.go new file mode 100644 index 00000000000..ee73d0d6a7c --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_defaults.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 v1alpha1 + +import ( + "context" + + "k8s.io/utils/ptr" + "knative.dev/pkg/apis" +) + +func (rr *RequestReply) SetDefaults(ctx context.Context) { + ctx = apis.WithinParent(ctx, rr.ObjectMeta) + rr.Spec.SetDefaults(ctx) +} + +func (rrs *RequestReplySpec) SetDefaults(ctx context.Context) { + if rrs.Timeout == nil || *rrs.Timeout == "" { + rrs.Timeout = ptr.To("30s") + } + + if rrs.CorrelationAttribute == "" { + rrs.CorrelationAttribute = "correlationid" + } + + if rrs.ReplyAttribute == "" { + rrs.ReplyAttribute = "replyid" + } +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_defaults_test.go b/pkg/apis/eventing/v1alpha1/requestreply_defaults_test.go new file mode 100644 index 00000000000..9dda159130c --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_defaults_test.go @@ -0,0 +1,68 @@ +/* +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 v1alpha1 + +import ( + "context" + "testing" + + "k8s.io/utils/ptr" + + "github.com/google/go-cmp/cmp" +) + +func TestRequestReplyDefaults(t *testing.T) { + testCases := map[string]struct { + initial RequestReply + expected RequestReply + }{ + "nil spec": { + initial: RequestReply{}, + expected: RequestReply{ + Spec: RequestReplySpec{ + Timeout: ptr.To("30s"), + CorrelationAttribute: "correlationid", + ReplyAttribute: "replyid", + }, + }, + }, + "does not override existing values": { + initial: RequestReply{ + Spec: RequestReplySpec{ + Timeout: ptr.To("40s"), + CorrelationAttribute: "othercorrelationid", + ReplyAttribute: "otherreplyid", + }, + }, + expected: RequestReply{ + Spec: RequestReplySpec{ + Timeout: ptr.To("40s"), + CorrelationAttribute: "othercorrelationid", + ReplyAttribute: "otherreplyid", + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.TODO()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatal("Unexpected defaults (-want, +got):", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_lifecycle.go b/pkg/apis/eventing/v1alpha1/requestreply_lifecycle.go new file mode 100644 index 00000000000..67014229088 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_lifecycle.go @@ -0,0 +1,106 @@ +/* +Copyright 2024 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 v1alpha1 + +import ( + "knative.dev/pkg/apis" + v1 "knative.dev/pkg/apis/duck/v1" +) + +var requestReplyCondSet = apis.NewLivingConditionSet(RequestReplyConditionIngress, RequestReplyConditionTriggers, RequestReplyConditionAddressable, RequestReplyConditionEventPoliciesReady) + +const ( + RequestReplyConditionReady = apis.ConditionReady + RequestReplyConditionIngress apis.ConditionType = "IngressReady" + RequestReplyConditionTriggers apis.ConditionType = "TriggersReady" + RequestReplyConditionAddressable apis.ConditionType = "Addressable" + RequestReplyConditionEventPoliciesReady apis.ConditionType = "EventPoliciesReady" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*RequestReply) GetConditionSet() apis.ConditionSet { + return requestReplyCondSet +} + +func (*RequestReplyStatus) GetConditionSet() apis.ConditionSet { + return requestReplyCondSet +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (rr *RequestReplyStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return requestReplyCondSet.Manage(rr).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (rr *RequestReplyStatus) IsReady() bool { + return rr.GetTopLevelCondition().IsTrue() +} + +// GetTopLevelCondition returns the top level Condition. +func (rr *RequestReplyStatus) GetTopLevelCondition() *apis.Condition { + return requestReplyCondSet.Manage(rr).GetTopLevelCondition() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (rr *RequestReplyStatus) InitializeConditions() { + requestReplyCondSet.Manage(rr).InitializeConditions() +} + +func (rr *RequestReplyStatus) SetAddress(address *v1.Addressable) { + rr.AddressStatus = v1.AddressStatus{ + Address: address, + } + + if address != nil && address.URL != nil { + rr.GetConditionSet().Manage(rr).MarkTrue(RequestReplyConditionAddressable) + rr.AddressStatus.Address.Name = &address.URL.Scheme + } else { + rr.GetConditionSet().Manage(rr).MarkFalse(RequestReplyConditionAddressable, "nil URL", "URL is nil") + } +} + +func (rr *RequestReplyStatus) MarkTriggersReady() { + rr.GetConditionSet().Manage(rr).MarkTrue(RequestReplyConditionTriggers) +} + +func (rr *RequestReplyStatus) MarkTriggersNotReadyWithReason(reason, messageFormat string, messageA ...interface{}) { + rr.GetConditionSet().Manage(rr).MarkUnknown(RequestReplyConditionTriggers, reason, messageFormat, messageA...) +} + +func (rr *RequestReplyStatus) MarkIngressReady() { + rr.GetConditionSet().Manage(rr).MarkTrue(RequestReplyConditionIngress) +} + +func (rr *RequestReplyStatus) MarkIngressNotReadyWithReason(reason, messageFormat string, messageA ...interface{}) { + rr.GetConditionSet().Manage(rr).MarkUnknown(RequestReplyConditionIngress, reason, messageFormat, messageA...) +} + +func (rr *RequestReplyStatus) MarkEventPoliciesTrue() { + rr.GetConditionSet().Manage(rr).MarkTrue(RequestReplyConditionEventPoliciesReady) +} + +func (rr *RequestReplyStatus) MarkEventPoliciesTrueWithReason(reason, messageFormat string, messageA ...interface{}) { + rr.GetConditionSet().Manage(rr).MarkTrueWithReason(RequestReplyConditionEventPoliciesReady, reason, messageFormat, messageA...) +} + +func (rr *RequestReplyStatus) MarkEventPoliciesFailed(reason, messageFormat string, messageA ...interface{}) { + rr.GetConditionSet().Manage(rr).MarkFalse(RequestReplyConditionEventPoliciesReady, reason, messageFormat, messageA...) +} + +func (rr *RequestReplyStatus) MarkEventPoliciesUnknown(reason, messageFormat string, messageA ...interface{}) { + rr.GetConditionSet().Manage(rr).MarkUnknown(RequestReplyConditionEventPoliciesReady, reason, messageFormat, messageA...) +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_lifecycle_test.go b/pkg/apis/eventing/v1alpha1/requestreply_lifecycle_test.go new file mode 100644 index 00000000000..75540cb88c1 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_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 v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + requestReplyConditionReady = apis.Condition{ + Type: RequestReplyConditionReady, + Status: corev1.ConditionTrue, + } +) + +func TestRequestReplyGetConditionSet(t *testing.T) { + r := &RequestReply{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestRequestReplyGetCondition(t *testing.T) { + tests := []struct { + name string + rrs *RequestReplyStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + rrs: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + requestReplyConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &eventPolicyConditionReady, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.rrs.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Error("unexpected condition (-want, +got) =", diff) + } + }) + } +} + +func TestRequestReplyInitializeConditions(t *testing.T) { + tests := []struct { + name string + rrs *RequestReplyStatus + want *RequestReplyStatus + }{ + { + name: "empty status", + rrs: &RequestReplyStatus{}, + want: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + { + Type: RequestReplyConditionAddressable, + Status: corev1.ConditionUnknown, + }, + { + Type: RequestReplyConditionEventPoliciesReady, + Status: corev1.ConditionUnknown, + }, + { + Type: RequestReplyConditionIngress, + Status: corev1.ConditionUnknown, + }, + { + Type: RequestReplyConditionReady, + Status: corev1.ConditionUnknown, + }, + { + Type: RequestReplyConditionTriggers, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.rrs.InitializeConditions() + if diff := cmp.Diff(test.want, test.rrs, ignoreAllButTypeAndStatus); diff != "" { + t.Error("unexpected conditions (-want, +got) =", diff) + } + }) + } +} + +func TestRequestReplyReadyCondition(t *testing.T) { + tests := []struct { + name string + rrs *RequestReplyStatus + markAddresableSucceeded *bool + markIngressReadySucceeded *bool + markTriggersReadySucceeded *bool + markEventPoliciesReadySucceeded *bool + wantReady bool + }{ + { + name: "Initially everything is Unknown, Auth&SubjectsResolved marked as true, EP should become Ready", + rrs: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + {Type: RequestReplyConditionReady, Status: corev1.ConditionUnknown}, + {Type: RequestReplyConditionAddressable, Status: corev1.ConditionUnknown}, + {Type: RequestReplyConditionIngress, Status: corev1.ConditionUnknown}, + {Type: RequestReplyConditionTriggers, Status: corev1.ConditionUnknown}, + {Type: RequestReplyConditionEventPoliciesReady, Status: corev1.ConditionUnknown}, + }, + }, + }, + markAddresableSucceeded: ptr.To(true), + markIngressReadySucceeded: ptr.To(true), + markTriggersReadySucceeded: ptr.To(true), + markEventPoliciesReadySucceeded: ptr.To(true), + wantReady: true, + }, + { + name: "Initially everything is Ready, Addressable set to false, RR should become False", + rrs: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + {Type: RequestReplyConditionReady, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionAddressable, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionIngress, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionTriggers, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionEventPoliciesReady, Status: corev1.ConditionTrue}, + }, + }, + }, + markAddresableSucceeded: ptr.To(false), + markIngressReadySucceeded: ptr.To(true), + markTriggersReadySucceeded: ptr.To(true), + markEventPoliciesReadySucceeded: ptr.To(true), + wantReady: false, + }, + { + name: "Initially everything is Ready, Ingress set to false, RR should become False", + rrs: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + {Type: RequestReplyConditionReady, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionAddressable, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionIngress, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionTriggers, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionEventPoliciesReady, Status: corev1.ConditionTrue}, + }, + }, + }, + markAddresableSucceeded: ptr.To(true), + markIngressReadySucceeded: ptr.To(false), + markTriggersReadySucceeded: ptr.To(true), + markEventPoliciesReadySucceeded: ptr.To(true), + wantReady: false, + }, + { + name: "Initially everything is Ready, Trigger set to false, RR should become False", + rrs: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + {Type: RequestReplyConditionReady, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionAddressable, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionIngress, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionTriggers, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionEventPoliciesReady, Status: corev1.ConditionTrue}, + }, + }, + }, + markAddresableSucceeded: ptr.To(true), + markIngressReadySucceeded: ptr.To(true), + markTriggersReadySucceeded: ptr.To(false), + markEventPoliciesReadySucceeded: ptr.To(true), + wantReady: false, + }, + { + name: "Initially everything is Ready, EPs set to false, RR should become False", + rrs: &RequestReplyStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + {Type: RequestReplyConditionReady, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionAddressable, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionIngress, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionTriggers, Status: corev1.ConditionTrue}, + {Type: RequestReplyConditionEventPoliciesReady, Status: corev1.ConditionTrue}, + }, + }, + }, + markAddresableSucceeded: ptr.To(true), + markIngressReadySucceeded: ptr.To(true), + markTriggersReadySucceeded: ptr.To(true), + markEventPoliciesReadySucceeded: ptr.To(false), + wantReady: false, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.markAddresableSucceeded != nil { + if *test.markAddresableSucceeded { + url, _ := apis.ParseURL("http://localhost:8080") + test.rrs.SetAddress(&duckv1.Addressable{URL: url}) + } else { + test.rrs.SetAddress(nil) + + } + } + if test.markIngressReadySucceeded != nil { + if *test.markIngressReadySucceeded { + test.rrs.MarkIngressReady() + } else { + test.rrs.MarkIngressNotReadyWithReason("", "") + } + } + if test.markTriggersReadySucceeded != nil { + if *test.markTriggersReadySucceeded { + test.rrs.MarkTriggersReady() + } else { + test.rrs.MarkTriggersNotReadyWithReason("", "") + } + } + if test.markEventPoliciesReadySucceeded != nil { + if *test.markEventPoliciesReadySucceeded { + test.rrs.MarkEventPoliciesTrue() + } else { + test.rrs.MarkEventPoliciesFailed("", "") + } + } + rr := RequestReply{Status: *test.rrs} + got := rr.GetConditionSet().Manage(test.rrs).IsHappy() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_types.go b/pkg/apis/eventing/v1alpha1/requestreply_types.go new file mode 100644 index 00000000000..3cb37e11b89 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_types.go @@ -0,0 +1,122 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" +) + +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RequestRepluy represents synchronous interface to sending and receiving events from a Broker. +type RequestReply struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the EventPolicy. + Spec RequestReplySpec `json:"spec,omitempty"` + + // Status represents the current state of the EventPolicy. + // This data may be out of date. + // +optional + Status RequestReplyStatus `json:"status,omitempty"` +} + +var ( + // Check that EventPolicy can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*RequestReply)(nil) + _ apis.Defaultable = (*RequestReply)(nil) + + // Check that EventPolicy can return its spec untyped. + _ apis.HasSpec = (*RequestReply)(nil) + + _ runtime.Object = (*RequestReply)(nil) + + // Check that we can create OwnerReferences to an EventPolicy. + _ kmeta.OwnerRefable = (*RequestReply)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*RequestReply)(nil) +) + +type RequestReplySpec struct { + // BrokerRef contains the reference to the broker the RequestReply sends events to. + BrokerRef duckv1.KReference `json:"brokerRef"` + + CorrelationAttribute string `json:"correlationAttribute"` + + ReplyAttribute string `json:"replyAttribute"` + + Timeout *string `json:"timeout,omitempty"` + + Delivery *eventingduckv1.DeliverySpec `json:"delivery,omitempty"` + + Secrets []string `json:"secrets"` +} + +// RequestReplyStatus represents the current state of a RequestReply. +type RequestReplyStatus 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 RequestReply fulfills the Addressable contract. + // It exposes the endpoint as an URI to get events delivered. + // +optional + duckv1.AddressStatus `json:",inline"` + + // AppliedEventPoliciesStatus contains the list of EventPolicies which apply to this Broker. + // +optional + eventingduckv1.AppliedEventPoliciesStatus `json:",inline"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RequestReplyList is a collection of RequestReplies. +type RequestReplyList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []RequestReply `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for EventPolicy +func (rr *RequestReply) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("RequestReply") +} + +// GetUntypedSpec returns the spec of the EventPolicy. +func (rr *RequestReply) GetUntypedSpec() interface{} { + return rr.Spec +} + +// GetStatus retrieves the status of the EventPolicy. Implements the KRShaped interface. +func (rr *RequestReply) GetStatus() *duckv1.Status { + return &rr.Status.Status +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_types_test.go b/pkg/apis/eventing/v1alpha1/requestreply_types_test.go new file mode 100644 index 00000000000..c4137f85f0b --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_types_test.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "testing" +) + +func TestRequestReplyGetStatus(t *testing.T) { + r := &RequestReply{ + Status: RequestReplyStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestRequestReply_GetGroupVersionKind(t *testing.T) { + src := RequestReply{} + gvk := src.GetGroupVersionKind() + + if gvk.Kind != "RequestReply" { + t.Errorf("Should be RequestReply, got %s.", gvk.Kind) + } +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_validation.go b/pkg/apis/eventing/v1alpha1/requestreply_validation.go new file mode 100644 index 00000000000..693c5a789d4 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_validation.go @@ -0,0 +1,83 @@ +/* +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 v1alpha1 + +import ( + "context" + "strings" + + "github.com/rickb777/date/period" + + "knative.dev/pkg/apis" +) + +func (rr *RequestReply) Validate(ctx context.Context) *apis.FieldError { + ctx = apis.WithinParent(ctx, rr.ObjectMeta) + return rr.Spec.Validate(ctx).ViaField("spec") +} + +func (rrs *RequestReplySpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + if ke := rrs.BrokerRef.Validate(ctx); ke != nil { + errs = errs.Also(ke.ViaField("brokerRef")) + } + + if !strings.EqualFold(rrs.BrokerRef.Kind, "broker") { + errs = errs.Also(apis.ErrInvalidValue(rrs.BrokerRef.Kind, ".kind", "brokerRef kind must be Broker").ViaField("brokerRef")) + } + + if rrs.BrokerRef.Namespace != "" { + errs = errs.Also(apis.ErrDisallowedFields("namespace").ViaField("brokerRef")) + } + + if rrs.Delivery != nil { + if de := rrs.Delivery.Validate(ctx); de != nil { + errs = errs.Also(de.ViaField("delivery")) + } + } + + if rrs.Timeout != nil { + timeout, err := period.Parse(*rrs.Timeout) + if err != nil || timeout.IsZero() || timeout.IsNegative() { + errs = errs.Also(apis.ErrInvalidValue(*rrs.Timeout, "timeout")) + } + + } + + if len(rrs.Secrets) == 0 { + errs = errs.Also(apis.ErrInvalidValue(rrs.Secrets, "secrets", "one or more secrets must be provided")) + } + + if rrs.CorrelationAttribute == "" || + rrs.CorrelationAttribute == "id" || + rrs.CorrelationAttribute == "course" || + rrs.CorrelationAttribute == "specversion" || + rrs.CorrelationAttribute == "type" { + errs = errs.Also(apis.ErrInvalidValue(rrs.CorrelationAttribute, "correlationattribute", "correlationattribute must be non-empty and cannot be a core cloudevent attribute (id, type, specversion, source)")) + } + + if rrs.ReplyAttribute == "" || + rrs.ReplyAttribute == "id" || + rrs.ReplyAttribute == "course" || + rrs.ReplyAttribute == "specversion" || + rrs.ReplyAttribute == "type" { + errs = errs.Also(apis.ErrInvalidValue(rrs.ReplyAttribute, "replyattribute", "replyattribute must be non-empty and cannot be a core cloudevent attribute (id, type, specversion, source)")) + } + + return errs +} diff --git a/pkg/apis/eventing/v1alpha1/requestreply_validation_test.go b/pkg/apis/eventing/v1alpha1/requestreply_validation_test.go new file mode 100644 index 00000000000..7b0e4861437 --- /dev/null +++ b/pkg/apis/eventing/v1alpha1/requestreply_validation_test.go @@ -0,0 +1,63 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestRequestReplyValidation(t *testing.T) { + tests := []struct { + name string + rr *RequestReply + want *apis.FieldError + }{ + { + name: "valid, all required fields set", + rr: &RequestReply{ + Spec: RequestReplySpec{ + ReplyAttribute: "reply", + CorrelationAttribute: "correlate", + Secrets: []string{"secret1"}, + BrokerRef: duckv1.KReference{ + APIVersion: "eventing.knative.dev/v1", + Kind: "Broker", + Name: "broker", + }, + }, + }, + want: func() *apis.FieldError { + return nil + }(), + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ctx := apis.WithinCreate(context.Background()) + got := test.rr.Validate(ctx) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate EventPolicySpec (-want, +got) = %v", test.name, diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go index 068369c53ba..4a30bba4840 100644 --- a/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ package v1alpha1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + duckv1 "knative.dev/eventing/pkg/apis/duck/v1" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" ) @@ -256,3 +257,115 @@ func (in *EventPolicyToReference) DeepCopy() *EventPolicyToReference { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestReply) DeepCopyInto(out *RequestReply) { + *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 RequestReply. +func (in *RequestReply) DeepCopy() *RequestReply { + if in == nil { + return nil + } + out := new(RequestReply) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RequestReply) 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 *RequestReplyList) DeepCopyInto(out *RequestReplyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RequestReply, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestReplyList. +func (in *RequestReplyList) DeepCopy() *RequestReplyList { + if in == nil { + return nil + } + out := new(RequestReplyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RequestReplyList) 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 *RequestReplySpec) DeepCopyInto(out *RequestReplySpec) { + *out = *in + in.BrokerRef.DeepCopyInto(&out.BrokerRef) + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(string) + **out = **in + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(duckv1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestReplySpec. +func (in *RequestReplySpec) DeepCopy() *RequestReplySpec { + if in == nil { + return nil + } + out := new(RequestReplySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestReplyStatus) DeepCopyInto(out *RequestReplyStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.AddressStatus.DeepCopyInto(&out.AddressStatus) + in.AppliedEventPoliciesStatus.DeepCopyInto(&out.AppliedEventPoliciesStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestReplyStatus. +func (in *RequestReplyStatus) DeepCopy() *RequestReplyStatus { + if in == nil { + return nil + } + out := new(RequestReplyStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go index e901caf43a4..5ffd41edd36 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/eventing_client.go @@ -29,6 +29,7 @@ import ( type EventingV1alpha1Interface interface { RESTClient() rest.Interface EventPoliciesGetter + RequestRepliesGetter } // EventingV1alpha1Client is used to interact with features provided by the eventing.knative.dev group. @@ -40,6 +41,10 @@ func (c *EventingV1alpha1Client) EventPolicies(namespace string) EventPolicyInte return newEventPolicies(c, namespace) } +func (c *EventingV1alpha1Client) RequestReplies(namespace string) RequestReplyInterface { + return newRequestReplies(c, namespace) +} + // NewForConfig creates a new EventingV1alpha1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go index 958cd866140..5d628625ca8 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_eventing_client.go @@ -32,6 +32,10 @@ func (c *FakeEventingV1alpha1) EventPolicies(namespace string) v1alpha1.EventPol return &FakeEventPolicies{c, namespace} } +func (c *FakeEventingV1alpha1) RequestReplies(namespace string) v1alpha1.RequestReplyInterface { + return &FakeRequestReplies{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeEventingV1alpha1) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_requestreply.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_requestreply.go new file mode 100644 index 00000000000..a1b6fdc6a21 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake/fake_requestreply.go @@ -0,0 +1,141 @@ +/* +Copyright 2021 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 ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" +) + +// FakeRequestReplies implements RequestReplyInterface +type FakeRequestReplies struct { + Fake *FakeEventingV1alpha1 + ns string +} + +var requestrepliesResource = v1alpha1.SchemeGroupVersion.WithResource("requestreplies") + +var requestrepliesKind = v1alpha1.SchemeGroupVersion.WithKind("RequestReply") + +// Get takes name of the requestReply, and returns the corresponding requestReply object, and an error if there is any. +func (c *FakeRequestReplies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RequestReply, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(requestrepliesResource, c.ns, name), &v1alpha1.RequestReply{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RequestReply), err +} + +// List takes label and field selectors, and returns the list of RequestReplies that match those selectors. +func (c *FakeRequestReplies) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RequestReplyList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(requestrepliesResource, requestrepliesKind, c.ns, opts), &v1alpha1.RequestReplyList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.RequestReplyList{ListMeta: obj.(*v1alpha1.RequestReplyList).ListMeta} + for _, item := range obj.(*v1alpha1.RequestReplyList).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 requestReplies. +func (c *FakeRequestReplies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(requestrepliesResource, c.ns, opts)) + +} + +// Create takes the representation of a requestReply and creates it. Returns the server's representation of the requestReply, and an error, if there is any. +func (c *FakeRequestReplies) Create(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.CreateOptions) (result *v1alpha1.RequestReply, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(requestrepliesResource, c.ns, requestReply), &v1alpha1.RequestReply{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RequestReply), err +} + +// Update takes the representation of a requestReply and updates it. Returns the server's representation of the requestReply, and an error, if there is any. +func (c *FakeRequestReplies) Update(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.UpdateOptions) (result *v1alpha1.RequestReply, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(requestrepliesResource, c.ns, requestReply), &v1alpha1.RequestReply{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RequestReply), 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 *FakeRequestReplies) UpdateStatus(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.UpdateOptions) (*v1alpha1.RequestReply, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(requestrepliesResource, "status", c.ns, requestReply), &v1alpha1.RequestReply{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RequestReply), err +} + +// Delete takes name of the requestReply and deletes it. Returns an error if one occurs. +func (c *FakeRequestReplies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(requestrepliesResource, c.ns, name, opts), &v1alpha1.RequestReply{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRequestReplies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(requestrepliesResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.RequestReplyList{}) + return err +} + +// Patch applies the patch and returns the patched requestReply. +func (c *FakeRequestReplies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RequestReply, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(requestrepliesResource, c.ns, name, pt, data, subresources...), &v1alpha1.RequestReply{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.RequestReply), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go index d5bd1a045d9..96c08942a55 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/generated_expansion.go @@ -19,3 +19,5 @@ limitations under the License. package v1alpha1 type EventPolicyExpansion interface{} + +type RequestReplyExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1alpha1/requestreply.go b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/requestreply.go new file mode 100644 index 00000000000..01742674fcc --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1alpha1/requestreply.go @@ -0,0 +1,195 @@ +/* +Copyright 2021 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 v1alpha1 + +import ( + "context" + "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" + v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// RequestRepliesGetter has a method to return a RequestReplyInterface. +// A group's client should implement this interface. +type RequestRepliesGetter interface { + RequestReplies(namespace string) RequestReplyInterface +} + +// RequestReplyInterface has methods to work with RequestReply resources. +type RequestReplyInterface interface { + Create(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.CreateOptions) (*v1alpha1.RequestReply, error) + Update(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.UpdateOptions) (*v1alpha1.RequestReply, error) + UpdateStatus(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.UpdateOptions) (*v1alpha1.RequestReply, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.RequestReply, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.RequestReplyList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RequestReply, err error) + RequestReplyExpansion +} + +// requestReplies implements RequestReplyInterface +type requestReplies struct { + client rest.Interface + ns string +} + +// newRequestReplies returns a RequestReplies +func newRequestReplies(c *EventingV1alpha1Client, namespace string) *requestReplies { + return &requestReplies{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the requestReply, and returns the corresponding requestReply object, and an error if there is any. +func (c *requestReplies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.RequestReply, err error) { + result = &v1alpha1.RequestReply{} + err = c.client.Get(). + Namespace(c.ns). + Resource("requestreplies"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of RequestReplies that match those selectors. +func (c *requestReplies) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.RequestReplyList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.RequestReplyList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("requestreplies"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested requestReplies. +func (c *requestReplies) Watch(ctx context.Context, 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("requestreplies"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a requestReply and creates it. Returns the server's representation of the requestReply, and an error, if there is any. +func (c *requestReplies) Create(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.CreateOptions) (result *v1alpha1.RequestReply, err error) { + result = &v1alpha1.RequestReply{} + err = c.client.Post(). + Namespace(c.ns). + Resource("requestreplies"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(requestReply). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a requestReply and updates it. Returns the server's representation of the requestReply, and an error, if there is any. +func (c *requestReplies) Update(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.UpdateOptions) (result *v1alpha1.RequestReply, err error) { + result = &v1alpha1.RequestReply{} + err = c.client.Put(). + Namespace(c.ns). + Resource("requestreplies"). + Name(requestReply.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(requestReply). + Do(ctx). + 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 *requestReplies) UpdateStatus(ctx context.Context, requestReply *v1alpha1.RequestReply, opts v1.UpdateOptions) (result *v1alpha1.RequestReply, err error) { + result = &v1alpha1.RequestReply{} + err = c.client.Put(). + Namespace(c.ns). + Resource("requestreplies"). + Name(requestReply.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(requestReply). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the requestReply and deletes it. Returns an error if one occurs. +func (c *requestReplies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("requestreplies"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *requestReplies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("requestreplies"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched requestReply. +func (c *requestReplies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.RequestReply, err error) { + result = &v1alpha1.RequestReply{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("requestreplies"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go index 89263c25853..4ae2f7faa04 100644 --- a/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // EventPolicies returns a EventPolicyInformer. EventPolicies() EventPolicyInformer + // RequestReplies returns a RequestReplyInformer. + RequestReplies() RequestReplyInformer } type version struct { @@ -43,3 +45,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (v *version) EventPolicies() EventPolicyInformer { return &eventPolicyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } + +// RequestReplies returns a RequestReplyInformer. +func (v *version) RequestReplies() RequestReplyInformer { + return &requestReplyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/eventing/v1alpha1/requestreply.go b/pkg/client/informers/externalversions/eventing/v1alpha1/requestreply.go new file mode 100644 index 00000000000..d2960b6e795 --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1alpha1/requestreply.go @@ -0,0 +1,90 @@ +/* +Copyright 2021 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 v1alpha1 + +import ( + "context" + 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" + eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "knative.dev/eventing/pkg/client/listers/eventing/v1alpha1" +) + +// RequestReplyInformer provides access to a shared informer and lister for +// RequestReplies. +type RequestReplyInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.RequestReplyLister +} + +type requestReplyInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewRequestReplyInformer constructs a new informer for RequestReply 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 NewRequestReplyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRequestReplyInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredRequestReplyInformer constructs a new informer for RequestReply 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 NewFilteredRequestReplyInformer(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.EventingV1alpha1().RequestReplies(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1alpha1().RequestReplies(namespace).Watch(context.TODO(), options) + }, + }, + &eventingv1alpha1.RequestReply{}, + resyncPeriod, + indexers, + ) +} + +func (f *requestReplyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRequestReplyInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *requestReplyInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1alpha1.RequestReply{}, f.defaultInformer) +} + +func (f *requestReplyInformer) Lister() v1alpha1.RequestReplyLister { + return v1alpha1.NewRequestReplyLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index cf7e4cf4896..c53cfc57753 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -71,6 +71,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=eventing.knative.dev, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithResource("eventpolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().EventPolicies().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("requestreplies"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().RequestReplies().Informer()}, nil // Group=eventing.knative.dev, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithResource("eventtypes"): diff --git a/pkg/client/injection/informers/eventing/v1alpha1/requestreply/fake/fake.go b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/fake/fake.go new file mode 100644 index 00000000000..7b62bc9ad0c --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2021 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + requestreply "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/requestreply" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = requestreply.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1alpha1().RequestReplies() + return context.WithValue(ctx, requestreply.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered/fake/fake.go b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered/fake/fake.go new file mode 100644 index 00000000000..fddc7ba448d --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered/fake/fake.go @@ -0,0 +1,52 @@ +/* +Copyright 2021 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + filtered "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered" + factoryfiltered "knative.dev/eventing/pkg/client/injection/informers/factory/filtered" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +var Get = filtered.Get + +func init() { + injection.Fake.RegisterFilteredInformers(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, []controller.Informer) { + untyped := ctx.Value(factoryfiltered.LabelKey{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch labelkey from context.") + } + labelSelectors := untyped.([]string) + infs := []controller.Informer{} + for _, selector := range labelSelectors { + f := factoryfiltered.Get(ctx, selector) + inf := f.Eventing().V1alpha1().RequestReplies() + ctx = context.WithValue(ctx, filtered.Key{Selector: selector}, inf) + infs = append(infs, inf.Informer()) + } + return ctx, infs +} diff --git a/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered/requestreply.go b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered/requestreply.go new file mode 100644 index 00000000000..8c20285e1ea --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/filtered/requestreply.go @@ -0,0 +1,65 @@ +/* +Copyright 2021 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 filtered + +import ( + context "context" + + v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1alpha1" + filtered "knative.dev/eventing/pkg/client/injection/informers/factory/filtered" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterFilteredInformers(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct { + Selector string +} + +func withInformer(ctx context.Context) (context.Context, []controller.Informer) { + untyped := ctx.Value(filtered.LabelKey{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch labelkey from context.") + } + labelSelectors := untyped.([]string) + infs := []controller.Informer{} + for _, selector := range labelSelectors { + f := filtered.Get(ctx, selector) + inf := f.Eventing().V1alpha1().RequestReplies() + ctx = context.WithValue(ctx, Key{Selector: selector}, inf) + infs = append(infs, inf.Informer()) + } + return ctx, infs +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context, selector string) v1alpha1.RequestReplyInformer { + untyped := ctx.Value(Key{Selector: selector}) + if untyped == nil { + logging.FromContext(ctx).Panicf( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1alpha1.RequestReplyInformer with selector %s from context.", selector) + } + return untyped.(v1alpha1.RequestReplyInformer) +} diff --git a/pkg/client/injection/informers/eventing/v1alpha1/requestreply/requestreply.go b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/requestreply.go new file mode 100644 index 00000000000..bbf14918169 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1alpha1/requestreply/requestreply.go @@ -0,0 +1,52 @@ +/* +Copyright 2021 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 requestreply + +import ( + context "context" + + v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1alpha1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1alpha1().RequestReplies() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha1.RequestReplyInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1alpha1.RequestReplyInformer from context.") + } + return untyped.(v1alpha1.RequestReplyInformer) +} diff --git a/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/controller.go b/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/controller.go new file mode 100644 index 00000000000..91d21edb7a7 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/controller.go @@ -0,0 +1,170 @@ +/* +Copyright 2021 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 requestreply + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + requestreply "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/requestreply" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + logkey "knative.dev/pkg/logging/logkey" + reconciler "knative.dev/pkg/reconciler" +) + +const ( + defaultControllerAgentName = "requestreply-controller" + defaultFinalizerName = "requestreplies.eventing.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.ControllerOptions to be used by the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatal("Up to one options function is supported, found: ", len(optionsFns)) + } + + requestreplyInformer := requestreply.Get(ctx) + + lister := requestreplyInformer.Lister() + + var promoteFilterFunc func(obj interface{}) bool + var promoteFunc = func(bkt reconciler.Bucket) {} + + rec := &reconcilerImpl{ + LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ + PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { + + // Signal promotion event + promoteFunc(bkt) + + all, err := lister.List(labels.Everything()) + if err != nil { + return err + } + for _, elt := range all { + if promoteFilterFunc != nil { + if ok := promoteFilterFunc(elt); !ok { + continue + } + } + enq(bkt, types.NamespacedName{ + Namespace: elt.GetNamespace(), + Name: elt.GetName(), + }) + } + return nil + }, + }, + Client: client.Get(ctx), + Lister: lister, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + ctrType := reflect.TypeOf(r).Elem() + ctrTypeName := fmt.Sprintf("%s.%s", ctrType.PkgPath(), ctrType.Name()) + ctrTypeName = strings.ReplaceAll(ctrTypeName, "/", ".") + + logger = logger.With( + zap.String(logkey.ControllerType, ctrTypeName), + zap.String(logkey.Kind, "eventing.knative.dev.RequestReply"), + ) + + impl := controller.NewContext(ctx, rec, controller.ControllerOptions{WorkQueueName: ctrTypeName, Logger: logger}) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + if opts.SkipStatusUpdates { + rec.skipStatusUpdates = true + } + if opts.DemoteFunc != nil { + rec.DemoteFunc = opts.DemoteFunc + } + if opts.PromoteFilterFunc != nil { + promoteFilterFunc = opts.PromoteFilterFunc + } + if opts.PromoteFunc != nil { + promoteFunc = opts.PromoteFunc + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/reconciler.go b/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/reconciler.go new file mode 100644 index 00000000000..2546e85a47f --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/reconciler.go @@ -0,0 +1,440 @@ +/* +Copyright 2021 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 requestreply + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + zap "go.uber.org/zap" + "go.uber.org/zap/zapcore" + v1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + record "k8s.io/client-go/tools/record" + v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1alpha1 "knative.dev/eventing/pkg/client/listers/eventing/v1alpha1" + controller "knative.dev/pkg/controller" + kmp "knative.dev/pkg/kmp" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1alpha1.RequestReply. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1alpha1.RequestReply. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1alpha1.RequestReply) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1alpha1.RequestReply. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1alpha1.RequestReply. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1alpha1.RequestReply) reconciler.Event +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1alpha1.RequestReply if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1alpha1.RequestReply. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1alpha1.RequestReply) reconciler.Event +} + +type doReconcile func(ctx context.Context, o *v1alpha1.RequestReply) reconciler.Event + +// reconcilerImpl implements controller.Reconciler for v1alpha1.RequestReply resources. +type reconcilerImpl struct { + // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware. + reconciler.LeaderAwareFuncs + + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources. + Lister eventingv1alpha1.RequestReplyLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string + + // skipStatusUpdates configures whether or not this reconciler automatically updates + // the status of the reconciled resource. + skipStatusUpdates bool +} + +// Check that our Reconciler implements controller.Reconciler. +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +// Check that our generated Reconciler is always LeaderAware. +var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventingv1alpha1.RequestReplyLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatal("Up to one options struct is supported, found: ", len(options)) + } + + // Fail fast when users inadvertently implement the other LeaderAware interface. + // For the typed reconcilers, Promote shouldn't take any arguments. + if _, ok := r.(reconciler.LeaderAware); ok { + logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) + } + + rec := &reconcilerImpl{ + LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ + PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { + all, err := lister.List(labels.Everything()) + if err != nil { + return err + } + for _, elt := range all { + // TODO: Consider letting users specify a filter in options. + enq(bkt, types.NamespacedName{ + Namespace: elt.GetNamespace(), + Name: elt.GetName(), + }) + } + return nil + }, + }, + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.SkipStatusUpdates { + rec.skipStatusUpdates = true + } + if opts.DemoteFunc != nil { + rec.DemoteFunc = opts.DemoteFunc + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // Initialize the reconciler state. This will convert the namespace/name + // string into a distinct namespace and name, determine if this instance of + // the reconciler is the leader, and any additional interfaces implemented + // by the reconciler. Returns an error is the resource key is invalid. + s, err := newState(key, r) + if err != nil { + logger.Error("Invalid resource key: ", key) + return nil + } + + // If we are not the leader, and we don't implement either ReadOnly + // observer interfaces, then take a fast-path out. + if s.isNotLeaderNorObserver() { + return controller.NewSkipKey(key) + } + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Get the resource with this namespace/name. + + getter := r.Lister.RequestReplies(s.namespace) + + original, err := getter.Get(s.name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing and call + // the ObserveDeletion handler if appropriate. + logger.Debugf("Resource %q no longer exists", key) + if del, ok := r.reconciler.(reconciler.OnDeletionInterface); ok { + return del.ObserveDeletion(ctx, types.NamespacedName{ + Namespace: s.namespace, + Name: s.name, + }) + } + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + + name, do := s.reconcileMethodFor(resource) + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", name)) + switch name { + case reconciler.DoReconcileKind: + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + if !r.skipStatusUpdates { + reconciler.PreProcessReconcile(ctx, resource) + } + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = do(ctx, resource) + + if !r.skipStatusUpdates { + reconciler.PostProcessReconcile(ctx, resource, original) + } + + case reconciler.DoFinalizeKind: + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = do(ctx, resource) + + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + + case reconciler.DoObserveKind: + // Observe any changes to this resource, since we are not the leader. + reconcileEvent = do(ctx, resource) + + } + + // Synchronize the status. + switch { + case r.skipStatusUpdates: + // This reconciler implementation is configured to skip resource updates. + // This may mean this reconciler does not observe spec, but reconciles external changes. + case equality.Semantic.DeepEqual(original.Status, resource.Status): + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + case !s.isLeader: + // High-availability reconcilers may have many replicas watching the resource, but only + // the elected leader is expected to write modifications. + logger.Warn("Saw status changes when we aren't the leader!") + default: + if err = r.updateStatus(ctx, logger, original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Event(resource, event.EventType, event.Reason, event.Error()) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + if controller.IsSkipKey(reconcileEvent) { + // This is a wrapped error, don't emit an event. + } else if ok, _ := controller.IsRequeueKey(reconcileEvent); ok { + // This is a wrapped error, don't emit an event. + } else { + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + } + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(ctx context.Context, logger *zap.SugaredLogger, existing *v1alpha1.RequestReply, desired *v1alpha1.RequestReply) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1alpha1().RequestReplies(desired.Namespace) + + existing, err = getter.Get(ctx, desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if equality.Semantic.DeepEqual(existing.Status, desired.Status) { + return nil + } + + if logger.Desugar().Core().Enabled(zapcore.DebugLevel) { + if diff, err := kmp.SafeDiff(existing.Status, desired.Status); err == nil && diff != "" { + logger.Debug("Updating status with: ", diff) + } + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1alpha1().RequestReplies(existing.Namespace) + + _, err = updater.UpdateStatus(ctx, existing, metav1.UpdateOptions{}) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.RequestReply, desiredFinalizers sets.Set[string]) (*v1alpha1.RequestReply, error) { + // Don't modify the informers copy. + existing := resource.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.New[string](existing.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = sets.List(existingFinalizers) + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1alpha1().RequestReplies(resource.Namespace) + + resourceName := resource.Name + updated, err := patcher.Patch(ctx, resourceName, types.MergePatchType, patch, metav1.PatchOptions{}) + if err != nil { + r.Recorder.Eventf(existing, v1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(updated, v1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return updated, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.RequestReply) (*v1alpha1.RequestReply, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.New[string](resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource, finalizers) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.RequestReply, reconcileEvent reconciler.Event) (*v1alpha1.RequestReply, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.New[string](resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == v1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource, finalizers) +} diff --git a/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/state.go b/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/state.go new file mode 100644 index 00000000000..f87bea232fb --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1alpha1/requestreply/state.go @@ -0,0 +1,97 @@ +/* +Copyright 2021 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 requestreply + +import ( + fmt "fmt" + + types "k8s.io/apimachinery/pkg/types" + cache "k8s.io/client-go/tools/cache" + v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + reconciler "knative.dev/pkg/reconciler" +) + +// state is used to track the state of a reconciler in a single run. +type state struct { + // key is the original reconciliation key from the queue. + key string + // namespace is the namespace split from the reconciliation key. + namespace string + // name is the name split from the reconciliation key. + name string + // reconciler is the reconciler. + reconciler Interface + // roi is the read only interface cast of the reconciler. + roi ReadOnlyInterface + // isROI (Read Only Interface) the reconciler only observes reconciliation. + isROI bool + // isLeader the instance of the reconciler is the elected leader. + isLeader bool +} + +func newState(key string, r *reconcilerImpl) (*state, error) { + // Convert the namespace/name string into a distinct namespace and name. + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + return nil, fmt.Errorf("invalid resource key: %s", key) + } + + roi, isROI := r.reconciler.(ReadOnlyInterface) + + isLeader := r.IsLeaderFor(types.NamespacedName{ + Namespace: namespace, + Name: name, + }) + + return &state{ + key: key, + namespace: namespace, + name: name, + reconciler: r.reconciler, + roi: roi, + isROI: isROI, + isLeader: isLeader, + }, nil +} + +// isNotLeaderNorObserver checks to see if this reconciler with the current +// state is enabled to do any work or not. +// isNotLeaderNorObserver returns true when there is no work possible for the +// reconciler. +func (s *state) isNotLeaderNorObserver() bool { + if !s.isLeader && !s.isROI { + // If we are not the leader, and we don't implement the ReadOnly + // interface, then take a fast-path out. + return true + } + return false +} + +func (s *state) reconcileMethodFor(o *v1alpha1.RequestReply) (string, doReconcile) { + if o.GetDeletionTimestamp().IsZero() { + if s.isLeader { + return reconciler.DoReconcileKind, s.reconciler.ReconcileKind + } else if s.isROI { + return reconciler.DoObserveKind, s.roi.ObserveKind + } + } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { + return reconciler.DoFinalizeKind, fin.FinalizeKind + } + return "unknown", nil +} diff --git a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go index e3f601930d7..1d021242be1 100644 --- a/pkg/client/listers/eventing/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1alpha1/expansion_generated.go @@ -25,3 +25,11 @@ type EventPolicyListerExpansion interface{} // EventPolicyNamespaceListerExpansion allows custom methods to be added to // EventPolicyNamespaceLister. type EventPolicyNamespaceListerExpansion interface{} + +// RequestReplyListerExpansion allows custom methods to be added to +// RequestReplyLister. +type RequestReplyListerExpansion interface{} + +// RequestReplyNamespaceListerExpansion allows custom methods to be added to +// RequestReplyNamespaceLister. +type RequestReplyNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/eventing/v1alpha1/requestreply.go b/pkg/client/listers/eventing/v1alpha1/requestreply.go new file mode 100644 index 00000000000..fdfe4d17e94 --- /dev/null +++ b/pkg/client/listers/eventing/v1alpha1/requestreply.go @@ -0,0 +1,99 @@ +/* +Copyright 2021 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 v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" +) + +// RequestReplyLister helps list RequestReplies. +// All objects returned here must be treated as read-only. +type RequestReplyLister interface { + // List lists all RequestReplies in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.RequestReply, err error) + // RequestReplies returns an object that can list and get RequestReplies. + RequestReplies(namespace string) RequestReplyNamespaceLister + RequestReplyListerExpansion +} + +// requestReplyLister implements the RequestReplyLister interface. +type requestReplyLister struct { + indexer cache.Indexer +} + +// NewRequestReplyLister returns a new RequestReplyLister. +func NewRequestReplyLister(indexer cache.Indexer) RequestReplyLister { + return &requestReplyLister{indexer: indexer} +} + +// List lists all RequestReplies in the indexer. +func (s *requestReplyLister) List(selector labels.Selector) (ret []*v1alpha1.RequestReply, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.RequestReply)) + }) + return ret, err +} + +// RequestReplies returns an object that can list and get RequestReplies. +func (s *requestReplyLister) RequestReplies(namespace string) RequestReplyNamespaceLister { + return requestReplyNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// RequestReplyNamespaceLister helps list and get RequestReplies. +// All objects returned here must be treated as read-only. +type RequestReplyNamespaceLister interface { + // List lists all RequestReplies in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.RequestReply, err error) + // Get retrieves the RequestReply from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.RequestReply, error) + RequestReplyNamespaceListerExpansion +} + +// requestReplyNamespaceLister implements the RequestReplyNamespaceLister +// interface. +type requestReplyNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all RequestReplies in the indexer for a given namespace. +func (s requestReplyNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.RequestReply, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.RequestReply)) + }) + return ret, err +} + +// Get retrieves the RequestReply from the indexer for a given namespace and name. +func (s requestReplyNamespaceLister) Get(name string) (*v1alpha1.RequestReply, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("requestreply"), name) + } + return obj.(*v1alpha1.RequestReply), nil +}