From 20f313a38c98e88997f289773f25fac843d24189 Mon Sep 17 00:00:00 2001 From: Lionel Villard Date: Fri, 19 Jun 2020 14:59:44 -0400 Subject: [PATCH 1/2] add flow v1 types --- hack/update-codegen.sh | 4 +- pkg/apis/flows/v1/doc.go | 20 + pkg/apis/flows/v1/implements_test.go | 41 ++ pkg/apis/flows/v1/parallel_conversion.go | 34 ++ pkg/apis/flows/v1/parallel_conversion_test.go | 34 ++ pkg/apis/flows/v1/parallel_defaults.go | 56 +++ pkg/apis/flows/v1/parallel_defaults_test.go | 153 ++++++ pkg/apis/flows/v1/parallel_lifecycle.go | 205 +++++++++ pkg/apis/flows/v1/parallel_lifecycle_test.go | 433 +++++++++++++++++ pkg/apis/flows/v1/parallel_types.go | 165 +++++++ pkg/apis/flows/v1/parallel_types_test.go | 35 ++ pkg/apis/flows/v1/parallel_validation.go | 68 +++ pkg/apis/flows/v1/register.go | 55 +++ pkg/apis/flows/v1/sequence_conversion.go | 34 ++ pkg/apis/flows/v1/sequence_conversion_test.go | 34 ++ pkg/apis/flows/v1/sequence_defaults.go | 58 +++ pkg/apis/flows/v1/sequence_defaults_test.go | 139 ++++++ pkg/apis/flows/v1/sequence_lifecycle.go | 174 +++++++ pkg/apis/flows/v1/sequence_lifecycle_test.go | 402 ++++++++++++++++ pkg/apis/flows/v1/sequence_types.go | 146 ++++++ pkg/apis/flows/v1/sequence_types_test.go | 43 ++ pkg/apis/flows/v1/sequence_validation.go | 72 +++ pkg/apis/flows/v1/test_helpers.go | 37 ++ pkg/apis/flows/v1/zz_generated.deepcopy.go | 419 +++++++++++++++++ pkg/client/clientset/versioned/clientset.go | 14 + .../versioned/fake/clientset_generated.go | 7 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../clientset/versioned/typed/flows/v1/doc.go | 20 + .../versioned/typed/flows/v1/fake/doc.go | 20 + .../typed/flows/v1/fake/fake_flows_client.go | 44 ++ .../typed/flows/v1/fake/fake_parallel.go | 140 ++++++ .../typed/flows/v1/fake/fake_sequence.go | 140 ++++++ .../versioned/typed/flows/v1/flows_client.go | 94 ++++ .../typed/flows/v1/generated_expansion.go | 23 + .../versioned/typed/flows/v1/parallel.go | 191 ++++++++ .../versioned/typed/flows/v1/sequence.go | 191 ++++++++ .../externalversions/flows/interface.go | 8 + .../externalversions/flows/v1/interface.go | 52 +++ .../externalversions/flows/v1/parallel.go | 89 ++++ .../externalversions/flows/v1/sequence.go | 89 ++++ .../informers/externalversions/generic.go | 7 + .../informers/flows/v1/parallel/fake/fake.go | 40 ++ .../informers/flows/v1/parallel/parallel.go | 52 +++ .../informers/flows/v1/sequence/fake/fake.go | 40 ++ .../informers/flows/v1/sequence/sequence.go | 52 +++ .../flows/v1/parallel/controller.go | 139 ++++++ .../flows/v1/parallel/reconciler.go | 434 ++++++++++++++++++ .../flows/v1/parallel/stub/controller.go | 54 +++ .../flows/v1/parallel/stub/reconciler.go | 87 ++++ .../flows/v1/sequence/controller.go | 139 ++++++ .../flows/v1/sequence/reconciler.go | 434 ++++++++++++++++++ .../flows/v1/sequence/stub/controller.go | 54 +++ .../flows/v1/sequence/stub/reconciler.go | 87 ++++ .../listers/flows/v1/expansion_generated.go | 35 ++ pkg/client/listers/flows/v1/parallel.go | 94 ++++ pkg/client/listers/flows/v1/sequence.go | 94 ++++ 57 files changed, 5827 insertions(+), 2 deletions(-) create mode 100644 pkg/apis/flows/v1/doc.go create mode 100644 pkg/apis/flows/v1/implements_test.go create mode 100644 pkg/apis/flows/v1/parallel_conversion.go create mode 100644 pkg/apis/flows/v1/parallel_conversion_test.go create mode 100644 pkg/apis/flows/v1/parallel_defaults.go create mode 100644 pkg/apis/flows/v1/parallel_defaults_test.go create mode 100644 pkg/apis/flows/v1/parallel_lifecycle.go create mode 100644 pkg/apis/flows/v1/parallel_lifecycle_test.go create mode 100644 pkg/apis/flows/v1/parallel_types.go create mode 100644 pkg/apis/flows/v1/parallel_types_test.go create mode 100644 pkg/apis/flows/v1/parallel_validation.go create mode 100644 pkg/apis/flows/v1/register.go create mode 100644 pkg/apis/flows/v1/sequence_conversion.go create mode 100644 pkg/apis/flows/v1/sequence_conversion_test.go create mode 100644 pkg/apis/flows/v1/sequence_defaults.go create mode 100644 pkg/apis/flows/v1/sequence_defaults_test.go create mode 100644 pkg/apis/flows/v1/sequence_lifecycle.go create mode 100644 pkg/apis/flows/v1/sequence_lifecycle_test.go create mode 100644 pkg/apis/flows/v1/sequence_types.go create mode 100644 pkg/apis/flows/v1/sequence_types_test.go create mode 100644 pkg/apis/flows/v1/sequence_validation.go create mode 100644 pkg/apis/flows/v1/test_helpers.go create mode 100644 pkg/apis/flows/v1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/fake/fake_flows_client.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/fake/fake_parallel.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/fake/fake_sequence.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/flows_client.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/parallel.go create mode 100644 pkg/client/clientset/versioned/typed/flows/v1/sequence.go create mode 100644 pkg/client/informers/externalversions/flows/v1/interface.go create mode 100644 pkg/client/informers/externalversions/flows/v1/parallel.go create mode 100644 pkg/client/informers/externalversions/flows/v1/sequence.go create mode 100644 pkg/client/injection/informers/flows/v1/parallel/fake/fake.go create mode 100644 pkg/client/injection/informers/flows/v1/parallel/parallel.go create mode 100644 pkg/client/injection/informers/flows/v1/sequence/fake/fake.go create mode 100644 pkg/client/injection/informers/flows/v1/sequence/sequence.go create mode 100644 pkg/client/injection/reconciler/flows/v1/parallel/controller.go create mode 100644 pkg/client/injection/reconciler/flows/v1/parallel/reconciler.go create mode 100644 pkg/client/injection/reconciler/flows/v1/parallel/stub/controller.go create mode 100644 pkg/client/injection/reconciler/flows/v1/parallel/stub/reconciler.go create mode 100644 pkg/client/injection/reconciler/flows/v1/sequence/controller.go create mode 100644 pkg/client/injection/reconciler/flows/v1/sequence/reconciler.go create mode 100644 pkg/client/injection/reconciler/flows/v1/sequence/stub/controller.go create mode 100644 pkg/client/injection/reconciler/flows/v1/sequence/stub/reconciler.go create mode 100644 pkg/client/listers/flows/v1/expansion_generated.go create mode 100644 pkg/client/listers/flows/v1/parallel.go create mode 100644 pkg/client/listers/flows/v1/sequence.go diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 5e0280bb834..89080ed776b 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -45,7 +45,7 @@ chmod +x ${CODEGEN_PKG}/generate-groups.sh # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 eventing:v1 messaging:v1beta1 messaging:v1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 messaging:v1 flows:v1beta1 flows:v1 sources:v1alpha1 sources:v1alpha2 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Deep copy config @@ -65,7 +65,7 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ chmod +x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 eventing:v1 messaging:v1beta1 messaging:v1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 messaging:v1 flows:v1beta1 flows:v1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/flows/v1/doc.go b/pkg/apis/flows/v1/doc.go new file mode 100644 index 00000000000..ab319b35b3f --- /dev/null +++ b/pkg/apis/flows/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1 is the v1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=flows.knative.dev +package v1 diff --git a/pkg/apis/flows/v1/implements_test.go b/pkg/apis/flows/v1/implements_test.go new file mode 100644 index 00000000000..2a893f184f2 --- /dev/null +++ b/pkg/apis/flows/v1/implements_test.go @@ -0,0 +1,41 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "testing" + + "knative.dev/pkg/apis/duck" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestTypesImplements(t *testing.T) { + testCases := []struct { + instance interface{} + iface duck.Implementable + }{ + // Sequence + {instance: &Sequence{}, iface: &duckv1.Conditions{}}, + // Parallel + {instance: &Parallel{}, iface: &duckv1.Conditions{}}, + } + for _, tc := range testCases { + if err := duck.VerifyType(tc.instance, tc.iface); err != nil { + t.Error(err) + } + } +} diff --git a/pkg/apis/flows/v1/parallel_conversion.go b/pkg/apis/flows/v1/parallel_conversion.go new file mode 100644 index 00000000000..3b0f9f85cdf --- /dev/null +++ b/pkg/apis/flows/v1/parallel_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Parallel) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Parallel) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/flows/v1/parallel_conversion_test.go b/pkg/apis/flows/v1/parallel_conversion_test.go new file mode 100644 index 00000000000..9dab7af196a --- /dev/null +++ b/pkg/apis/flows/v1/parallel_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" +) + +func TestParallelConversionBadType(t *testing.T) { + good, bad := &Parallel{}, &Parallel{} + + 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/flows/v1/parallel_defaults.go b/pkg/apis/flows/v1/parallel_defaults.go new file mode 100644 index 00000000000..9f19c3b5a25 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_defaults.go @@ -0,0 +1,56 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + + "knative.dev/eventing/pkg/apis/messaging/config" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + "knative.dev/pkg/apis" +) + +func (p *Parallel) SetDefaults(ctx context.Context) { + withNS := apis.WithinParent(ctx, p.ObjectMeta) + if p != nil && p.Spec.ChannelTemplate == nil { + cfg := config.FromContextOrDefaults(ctx) + c, err := cfg.ChannelDefaults.GetChannelConfig(apis.ParentMeta(ctx).Namespace) + + if err == nil { + p.Spec.ChannelTemplate = &messagingv1.ChannelTemplateSpec{ + TypeMeta: c.TypeMeta, + Spec: c.Spec, + } + } + } + p.Spec.SetDefaults(withNS) +} + +func (ps *ParallelSpec) SetDefaults(ctx context.Context) { + for _, branch := range ps.Branches { + if branch.Filter != nil { + branch.Filter.SetDefaults(ctx) + } + branch.Subscriber.SetDefaults(ctx) + if branch.Reply != nil { + branch.Reply.SetDefaults(ctx) + } + } + if ps.Reply != nil { + ps.Reply.SetDefaults(ctx) + } +} diff --git a/pkg/apis/flows/v1/parallel_defaults_test.go b/pkg/apis/flows/v1/parallel_defaults_test.go new file mode 100644 index 00000000000..1a25546fe13 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_defaults_test.go @@ -0,0 +1,153 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/google/go-cmp/cmp" + "knative.dev/eventing/pkg/apis/messaging/config" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestParallelSetDefaults(t *testing.T) { + testCases := map[string]struct { + nilChannelDefaulter bool + channelTemplate *config.ChannelTemplateSpec + initial Parallel + expected Parallel + }{ + "nil ChannelDefaulter": { + nilChannelDefaulter: true, + expected: Parallel{}, + }, + "unset ChannelDefaulter": { + expected: Parallel{}, + }, + "set ChannelDefaulter": { + channelTemplate: configDefaultChannelTemplate, + expected: Parallel{ + Spec: ParallelSpec{ + ChannelTemplate: defaultChannelTemplate, + }, + }, + }, + "branches namespace defaulted": { + channelTemplate: configDefaultChannelTemplate, + initial: Parallel{ + ObjectMeta: metav1.ObjectMeta{Namespace: testNS}, + Spec: ParallelSpec{ + Branches: []ParallelBranch{ + { + Filter: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "firstfilter"}, + }, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{Name: "firstsub"}, + }, + Reply: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "firstreply"}, + }, + }, { + Filter: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "secondfilter"}, + }, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{Name: "secondsub"}, + }, + Reply: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "secondreply"}, + }, + }}, + Reply: &duckv1.Destination{Ref: &duckv1.KReference{Name: "reply"}}}, + }, + expected: Parallel{ + ObjectMeta: metav1.ObjectMeta{Namespace: testNS}, + Spec: ParallelSpec{ + ChannelTemplate: defaultChannelTemplate, + Branches: []ParallelBranch{ + { + Filter: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "firstfilter", Namespace: testNS}, + }, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{Name: "firstsub", Namespace: testNS}, + }, + Reply: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "firstreply", Namespace: testNS}, + }, + }, { + Filter: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "secondfilter", Namespace: testNS}, + }, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{Name: "secondsub", Namespace: testNS}, + }, + Reply: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "secondreply", Namespace: testNS}, + }, + }}, + Reply: &duckv1.Destination{Ref: &duckv1.KReference{Name: "reply", Namespace: testNS}}, + }, + }, + }, + "template already specified": { + channelTemplate: configDefaultChannelTemplate, + initial: Parallel{ + Spec: ParallelSpec{ + ChannelTemplate: &messagingv1.ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + expected: Parallel{ + Spec: ParallelSpec{ + ChannelTemplate: &messagingv1.ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + ctx := context.Background() + if !tc.nilChannelDefaulter { + ctx = config.ToContext(ctx, &config.Config{ + ChannelDefaults: &config.ChannelDefaults{ + ClusterDefault: tc.channelTemplate, + }, + }) + } + tc.initial.SetDefaults(ctx) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/flows/v1/parallel_lifecycle.go b/pkg/apis/flows/v1/parallel_lifecycle.go new file mode 100644 index 00000000000..18857479ab3 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_lifecycle.go @@ -0,0 +1,205 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + duckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + "knative.dev/pkg/apis" + pkgduckv1 "knative.dev/pkg/apis/duck/v1" +) + +var pCondSet = apis.NewLivingConditionSet(ParallelConditionReady, ParallelConditionChannelsReady, ParallelConditionSubscriptionsReady, ParallelConditionAddressable) + +const ( + // ParallelConditionReady has status True when all subconditions below have been set to True. + ParallelConditionReady = apis.ConditionReady + + // ParallelConditionChannelsReady has status True when all the channels created as part of + // this parallel are ready. + ParallelConditionChannelsReady apis.ConditionType = "ChannelsReady" + + // ParallelConditionSubscriptionsReady has status True when all the subscriptions created as part of + // this parallel are ready. + ParallelConditionSubscriptionsReady apis.ConditionType = "SubscriptionsReady" + + // ParallelConditionAddressable has status true when this Parallel meets + // the Addressable contract and has a non-empty hostname. + ParallelConditionAddressable apis.ConditionType = "Addressable" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Parallel) GetConditionSet() apis.ConditionSet { + return pCondSet +} + +// GetGroupVersionKind returns GroupVersionKind for Parallel +func (*Parallel) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Parallel") +} + +// GetUntypedSpec returns the spec of the Parallel. +func (p *Parallel) GetUntypedSpec() interface{} { + return p.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ps *ParallelStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return pCondSet.Manage(ps).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (ps *ParallelStatus) IsReady() bool { + return pCondSet.Manage(ps).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ps *ParallelStatus) InitializeConditions() { + pCondSet.Manage(ps).InitializeConditions() +} + +// PropagateSubscriptionStatuses sets the ParallelConditionSubscriptionsReady based on +// the status of the incoming subscriptions. +func (ps *ParallelStatus) PropagateSubscriptionStatuses(filterSubscriptions []*messagingv1.Subscription, subscriptions []*messagingv1.Subscription) { + if ps.BranchStatuses == nil { + ps.BranchStatuses = make([]ParallelBranchStatus, len(subscriptions)) + } + allReady := true + // If there are no subscriptions, treat that as a False branch. Could go either way, but this seems right. + if len(subscriptions) == 0 { + allReady = false + } + + for i, s := range subscriptions { + ps.BranchStatuses[i].SubscriptionStatus = ParallelSubscriptionStatus{ + Subscription: corev1.ObjectReference{ + APIVersion: s.APIVersion, + Kind: s.Kind, + Name: s.Name, + Namespace: s.Namespace, + }, + } + + readyCondition := s.Status.GetTopLevelCondition() + if readyCondition != nil { + ps.BranchStatuses[i].SubscriptionStatus.ReadyCondition = *readyCondition + if readyCondition.Status != corev1.ConditionTrue { + allReady = false + } + } else { + allReady = false + } + + fs := filterSubscriptions[i] + ps.BranchStatuses[i].FilterSubscriptionStatus = ParallelSubscriptionStatus{ + Subscription: corev1.ObjectReference{ + APIVersion: fs.APIVersion, + Kind: fs.Kind, + Name: fs.Name, + Namespace: fs.Namespace, + }, + } + readyCondition = fs.Status.GetCondition(messagingv1.SubscriptionConditionReady) + if readyCondition != nil { + ps.BranchStatuses[i].FilterSubscriptionStatus.ReadyCondition = *readyCondition + if readyCondition.Status != corev1.ConditionTrue { + allReady = false + } + } else { + allReady = false + } + + } + if allReady { + pCondSet.Manage(ps).MarkTrue(ParallelConditionSubscriptionsReady) + } else { + ps.MarkSubscriptionsNotReady("SubscriptionsNotReady", "Subscriptions are not ready yet, or there are none") + } +} + +// PropagateChannelStatuses sets the ChannelStatuses and ParallelConditionChannelsReady based on the +// status of the incoming channels. +func (ps *ParallelStatus) PropagateChannelStatuses(ingressChannel *duckv1.Channelable, channels []*duckv1.Channelable) { + if ps.BranchStatuses == nil { + ps.BranchStatuses = make([]ParallelBranchStatus, len(channels)) + } + allReady := true + + ps.IngressChannelStatus.Channel = corev1.ObjectReference{ + APIVersion: ingressChannel.APIVersion, + Kind: ingressChannel.Kind, + Name: ingressChannel.Name, + Namespace: ingressChannel.Namespace, + } + + address := ingressChannel.Status.AddressStatus.Address + if address != nil { + ps.IngressChannelStatus.ReadyCondition = apis.Condition{Type: apis.ConditionReady, Status: corev1.ConditionTrue} + } else { + ps.IngressChannelStatus.ReadyCondition = apis.Condition{Type: apis.ConditionReady, Status: corev1.ConditionFalse, Reason: "NotAddressable", Message: "Channel is not addressable"} + allReady = false + } + ps.setAddress(address) + + for i, c := range channels { + ps.BranchStatuses[i].FilterChannelStatus = ParallelChannelStatus{ + Channel: corev1.ObjectReference{ + APIVersion: c.APIVersion, + Kind: c.Kind, + Name: c.Name, + Namespace: c.Namespace, + }, + } + // TODO: Once the addressable has a real status to dig through, use that here instead of + // addressable, because it might be addressable but not ready. + address := c.Status.AddressStatus.Address + if address != nil { + ps.BranchStatuses[i].FilterChannelStatus.ReadyCondition = apis.Condition{Type: apis.ConditionReady, Status: corev1.ConditionTrue} + } else { + ps.BranchStatuses[i].FilterChannelStatus.ReadyCondition = apis.Condition{Type: apis.ConditionReady, Status: corev1.ConditionFalse, Reason: "NotAddressable", Message: "Channel is not addressable"} + allReady = false + } + } + if allReady { + pCondSet.Manage(ps).MarkTrue(ParallelConditionChannelsReady) + } else { + ps.MarkChannelsNotReady("ChannelsNotReady", "Channels are not ready yet, or there are none") + } +} + +func (ps *ParallelStatus) MarkChannelsNotReady(reason, messageFormat string, messageA ...interface{}) { + pCondSet.Manage(ps).MarkFalse(ParallelConditionChannelsReady, reason, messageFormat, messageA...) +} + +func (ps *ParallelStatus) MarkSubscriptionsNotReady(reason, messageFormat string, messageA ...interface{}) { + pCondSet.Manage(ps).MarkFalse(ParallelConditionSubscriptionsReady, reason, messageFormat, messageA...) +} + +func (ps *ParallelStatus) MarkAddressableNotReady(reason, messageFormat string, messageA ...interface{}) { + pCondSet.Manage(ps).MarkFalse(ParallelConditionAddressable, reason, messageFormat, messageA...) +} + +func (ps *ParallelStatus) setAddress(address *pkgduckv1.Addressable) { + ps.Address = address + if address == nil { + pCondSet.Manage(ps).MarkFalse(ParallelConditionAddressable, "emptyAddress", "addressable is nil") + } else { + pCondSet.Manage(ps).MarkTrue(ParallelConditionAddressable) + } +} diff --git a/pkg/apis/flows/v1/parallel_lifecycle_test.go b/pkg/apis/flows/v1/parallel_lifecycle_test.go new file mode 100644 index 00000000000..d5fd532ec48 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_lifecycle_test.go @@ -0,0 +1,433 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "testing" + + "knative.dev/pkg/apis" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var parallelConditionReady = apis.Condition{ + Type: ParallelConditionReady, + Status: corev1.ConditionTrue, +} + +func TestParallelGetConditionSet(t *testing.T) { + r := &Parallel{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestParallelGetCondition(t *testing.T) { + tests := []struct { + name string + ss *ParallelStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ss: &ParallelStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + parallelConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: ¶llelConditionReady, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ss.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestParallelInitializeConditions(t *testing.T) { + tests := []struct { + name string + ts *ParallelStatus + want *ParallelStatus + }{{ + name: "empty", + ts: &ParallelStatus{}, + want: &ParallelStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ParallelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionChannelsReady, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionSubscriptionsReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one false", + ts: &ParallelStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ParallelConditionChannelsReady, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &ParallelStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ParallelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionChannelsReady, + Status: corev1.ConditionFalse, + }, { + Type: ParallelConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionSubscriptionsReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + ts: &ParallelStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ParallelConditionSubscriptionsReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &ParallelStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ParallelConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionChannelsReady, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: ParallelConditionSubscriptionsReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ts.InitializeConditions() + if diff := cmp.Diff(test.want, test.ts, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestParallelPropagateSubscriptionStatuses(t *testing.T) { + tests := []struct { + name string + fsubs []*messagingv1.Subscription + subs []*messagingv1.Subscription + want corev1.ConditionStatus + }{{ + name: "empty", + fsubs: []*messagingv1.Subscription{}, + subs: []*messagingv1.Subscription{}, + want: corev1.ConditionFalse, + }, { + name: "empty status", + fsubs: []*messagingv1.Subscription{{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "messaging.knative.dev/v1", + Kind: "Subscription", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "sub", + Namespace: "testns", + }, + Status: messagingv1.SubscriptionStatus{}, + }}, subs: []*messagingv1.Subscription{{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "messaging.knative.dev/v1", + Kind: "Subscription", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "sub", + Namespace: "testns", + }, + Status: messagingv1.SubscriptionStatus{}, + }}, + want: corev1.ConditionFalse, + }, { + name: "one filter and subscriber subscription not ready", + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", false)}, + want: corev1.ConditionFalse, + }, { + name: "one filter and one subscription ready", + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: corev1.ConditionTrue, + }, { + name: "one filter subscription not ready and one subscription ready", + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: corev1.ConditionFalse, + }, { + name: "one subscription ready, one not", + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true), getSubscription("fsub1", false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", false)}, + want: corev1.ConditionFalse, + }, { + name: "two subscriptions ready", + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true), getSubscription("fsub1", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: corev1.ConditionTrue, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := ParallelStatus{} + ps.PropagateSubscriptionStatuses(test.fsubs, test.subs) + got := ps.GetCondition(ParallelConditionSubscriptionsReady).Status + want := test.want + if want != got { + t.Errorf("unexpected conditions (-want, +got) = %v %v", want, got) + } + }) + } +} + +func TestParallelPropagateChannelStatuses(t *testing.T) { + tests := []struct { + name string + ichannel *eventingduckv1.Channelable + channels []*eventingduckv1.Channelable + want corev1.ConditionStatus + }{{ + name: "ingress false, empty", + ichannel: getChannelable(false), + channels: []*eventingduckv1.Channelable{}, + want: corev1.ConditionFalse, + }, { + name: "ingress false, one channelable not ready", + ichannel: getChannelable(false), + channels: []*eventingduckv1.Channelable{getChannelable(false)}, + want: corev1.ConditionFalse, + }, { + name: "ingress true, one channelable not ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(false)}, + want: corev1.ConditionFalse, + }, { + name: "ingress false, one channelable ready", + ichannel: getChannelable(false), + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + want: corev1.ConditionFalse, + }, { + name: "ingress true, one channelable ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + want: corev1.ConditionTrue, + }, { + name: "ingress true, one channelable ready, one not", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(false)}, + want: corev1.ConditionFalse, + }, { + name: "ingress true, two channelables ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + want: corev1.ConditionTrue, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := ParallelStatus{} + ps.PropagateChannelStatuses(test.ichannel, test.channels) + got := ps.GetCondition(ParallelConditionChannelsReady).Status + want := test.want + if want != got { + t.Errorf("unexpected conditions (-want, +got) = %v %v", want, got) + } + }) + } +} + +func TestParallelReady(t *testing.T) { + tests := []struct { + name string + fsubs []*messagingv1.Subscription + subs []*messagingv1.Subscription + ichannel *eventingduckv1.Channelable + channels []*eventingduckv1.Channelable + want bool + }{{ + name: "ingress false, empty", + fsubs: []*messagingv1.Subscription{}, + subs: []*messagingv1.Subscription{}, + ichannel: getChannelable(false), + channels: []*eventingduckv1.Channelable{}, + want: false, + }, { + name: "ingress true, empty", + fsubs: []*messagingv1.Subscription{}, + subs: []*messagingv1.Subscription{}, + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{}, + want: false, + }, { + name: "ingress true, one channelable not ready, one subscription ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(false)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: false, + }, { + name: "ingress true, one channelable ready, one subscription not ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", false)}, + want: false, + }, { + name: "ingress false, one channelable ready, one subscription ready", + ichannel: getChannelable(false), + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: false, + }, { + name: "ingress true, one channelable ready, one subscription ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: true, + }, { + name: "ingress true, one channelable ready, one not, two subsriptions ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(false)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true), getSubscription("fsub1", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: false, + }, { + name: "ingress true, two channelables ready, one subscription ready, one not", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true), getSubscription("fsub1", false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", false)}, + want: false, + }, { + name: "ingress false, two channelables ready, two subscriptions ready", + ichannel: getChannelable(false), + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true), getSubscription("fsub1", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: false, + }, { + name: "ingress true, two channelables ready, two subscriptions ready", + ichannel: getChannelable(true), + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + fsubs: []*messagingv1.Subscription{getSubscription("fsub0", true), getSubscription("fsub1", true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: true, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := ParallelStatus{} + ps.PropagateChannelStatuses(test.ichannel, test.channels) + ps.PropagateSubscriptionStatuses(test.fsubs, test.subs) + got := ps.IsReady() + want := test.want + if want != got { + t.Errorf("unexpected conditions (-want, +got) = %v %v", want, got) + } + }) + } +} + +func TestParallelPropagateSetAddress(t *testing.T) { + URL, _ := apis.ParseURL("http://example.com") + tests := []struct { + name string + address *duckv1.Addressable + want *duckv1.Addressable + wantStatus corev1.ConditionStatus + }{{ + name: "nil", + address: nil, + want: nil, + wantStatus: corev1.ConditionFalse, + }, { + name: "empty", + address: &duckv1.Addressable{}, + want: &duckv1.Addressable{}, + wantStatus: corev1.ConditionTrue, + }, { + name: "URL", + address: &duckv1.Addressable{URL: URL}, + want: &duckv1.Addressable{URL: URL}, + wantStatus: corev1.ConditionTrue, + }, { + name: "nil", + address: &duckv1.Addressable{URL: nil}, + want: &duckv1.Addressable{}, + wantStatus: corev1.ConditionTrue, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := ParallelStatus{} + ps.setAddress(test.address) + got := ps.Address + if diff := cmp.Diff(test.want, got, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected address (-want, +got) = %v", diff) + } + gotStatus := ps.GetCondition(ParallelConditionAddressable).Status + if test.wantStatus != gotStatus { + t.Errorf("unexpected conditions (-want, +got) = %v %v", test.wantStatus, gotStatus) + } + }) + } +} diff --git a/pkg/apis/flows/v1/parallel_types.go b/pkg/apis/flows/v1/parallel_types.go new file mode 100644 index 00000000000..40998d780d1 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_types.go @@ -0,0 +1,165 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// Parallel defines conditional branches that will be wired in +// series through Channels and Subscriptions. +type Parallel struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Parallel. + Spec ParallelSpec `json:"spec,omitempty"` + + // Status represents the current state of the Parallel. This data may be out of + // date. + // +optional + Status ParallelStatus `json:"status,omitempty"` +} + +var ( + // Check that Parallel can be validated and defaulted. + _ apis.Validatable = (*Parallel)(nil) + _ apis.Defaultable = (*Parallel)(nil) + + // Check that Parallel can return its spec untyped. + _ apis.HasSpec = (*Parallel)(nil) + + // TODO: make appropriate fields immutable. + //_ apis.Immutable = (*Parallel)(nil) + + _ runtime.Object = (*Parallel)(nil) + + // Check that we can create OwnerReferences to a Parallel. + _ kmeta.OwnerRefable = (*Parallel)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Parallel)(nil) +) + +type ParallelSpec struct { + // Branches is the list of Filter/Subscribers pairs. + Branches []ParallelBranch `json:"branches"` + + // ChannelTemplate specifies which Channel CRD to use. If left unspecified, it is set to the default Channel CRD + // for the namespace (or cluster, in case there are no defaults for the namespace). + // +optional + ChannelTemplate *messagingv1.ChannelTemplateSpec `json:"channelTemplate"` + + // Reply is a Reference to where the result of a case Subscriber gets sent to + // when the case does not have a Reply + // +optional + Reply *duckv1.Destination `json:"reply,omitempty"` +} + +type ParallelBranch struct { + // Filter is the expression guarding the branch + // +optional + Filter *duckv1.Destination `json:"filter,omitempty"` + + // Subscriber receiving the event when the filter passes + Subscriber duckv1.Destination `json:"subscriber"` + + // Reply is a Reference to where the result of Subscriber of this case gets sent to. + // If not specified, sent the result to the Parallel Reply + // +optional + Reply *duckv1.Destination `json:"reply,omitempty"` + + // Delivery is the delivery specification for events to the subscriber + // This includes things like retries, DLQ, etc. + // +optional + Delivery *eventingduckv1.DeliverySpec `json:"delivery,omitempty"` +} + +// ParallelStatus represents the current state of a Parallel. +type ParallelStatus 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"` + + // IngressChannelStatus corresponds to the ingress channel status. + IngressChannelStatus ParallelChannelStatus `json:"ingressChannelStatus"` + + // BranchStatuses is an array of corresponding to branch statuses. + // Matches the Spec.Branches array in the order. + BranchStatuses []ParallelBranchStatus `json:"branchStatuses"` + + // AddressStatus is the starting point to this Parallel. Sending to this + // will target the first subscriber. + // It generally has the form {channel}.{namespace}.svc.{cluster domain name} + duckv1.AddressStatus `json:",inline"` +} + +// ParallelBranchStatus represents the current state of a Parallel branch +type ParallelBranchStatus struct { + // FilterSubscriptionStatus corresponds to the filter subscription status. + FilterSubscriptionStatus ParallelSubscriptionStatus `json:"filterSubscriptionStatus"` + + // FilterChannelStatus corresponds to the filter channel status. + FilterChannelStatus ParallelChannelStatus `json:"filterChannelStatus"` + + // SubscriptionStatus corresponds to the subscriber subscription status. + SubscriptionStatus ParallelSubscriptionStatus `json:"subscriberSubscriptionStatus"` +} + +type ParallelChannelStatus struct { + // Channel is the reference to the underlying channel. + Channel corev1.ObjectReference `json:"channel"` + + // ReadyCondition indicates whether the Channel is ready or not. + ReadyCondition apis.Condition `json:"ready"` +} + +type ParallelSubscriptionStatus struct { + // Subscription is the reference to the underlying Subscription. + Subscription corev1.ObjectReference `json:"subscription"` + + // ReadyCondition indicates whether the Subscription is ready or not. + ReadyCondition apis.Condition `json:"ready"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ParallelList is a collection of Parallels. +type ParallelList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Parallel `json:"items"` +} + +// GetStatus retrieves the status of the Parallel. Implements the KRShaped interface. +func (p *Parallel) GetStatus() *duckv1.Status { + return &p.Status.Status +} diff --git a/pkg/apis/flows/v1/parallel_types_test.go b/pkg/apis/flows/v1/parallel_types_test.go new file mode 100644 index 00000000000..927833db5f2 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_types_test.go @@ -0,0 +1,35 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import "testing" + +func TestParallelGetStatus(t *testing.T) { + r := &Parallel{ + Status: ParallelStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestParallelKind(t *testing.T) { + parallel := Parallel{} + if parallel.GetGroupVersionKind().String() != "flows.knative.dev/v1, Kind=Parallel" { + t.Errorf("unexpected gvk: %v", parallel.GetGroupVersionKind()) + } +} diff --git a/pkg/apis/flows/v1/parallel_validation.go b/pkg/apis/flows/v1/parallel_validation.go new file mode 100644 index 00000000000..7aa30c0d3e3 --- /dev/null +++ b/pkg/apis/flows/v1/parallel_validation.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 v1 + +import ( + "context" + + "knative.dev/pkg/apis" +) + +func (p *Parallel) Validate(ctx context.Context) *apis.FieldError { + return p.Spec.Validate(ctx).ViaField("spec") +} + +func (ps *ParallelSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + if len(ps.Branches) == 0 { + errs = errs.Also(apis.ErrMissingField("branches")) + } + + for i, s := range ps.Branches { + if err := s.Filter.Validate(ctx); err != nil { + errs = errs.Also(apis.ErrInvalidArrayValue(s, "branches.filter", i)) + } + + if e := s.Subscriber.Validate(ctx); e != nil { + errs = errs.Also(apis.ErrInvalidArrayValue(s, "branches.subscriber", i)) + } + + if e := s.Reply.Validate(ctx); e != nil { + errs = errs.Also(apis.ErrInvalidArrayValue(s, "branches.reply", i)) + } + } + + if ps.ChannelTemplate == nil { + errs = errs.Also(apis.ErrMissingField("channelTemplate")) + return errs + } + + if len(ps.ChannelTemplate.APIVersion) == 0 { + errs = errs.Also(apis.ErrMissingField("channelTemplate.apiVersion")) + } + + if len(ps.ChannelTemplate.Kind) == 0 { + errs = errs.Also(apis.ErrMissingField("channelTemplate.kind")) + } + + if err := ps.Reply.Validate(ctx); err != nil { + errs = errs.Also(err.ViaField("reply")) + } + + return errs +} diff --git a/pkg/apis/flows/v1/register.go b/pkg/apis/flows/v1/register.go new file mode 100644 index 00000000000..821e7468a29 --- /dev/null +++ b/pkg/apis/flows/v1/register.go @@ -0,0 +1,55 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "knative.dev/eventing/pkg/apis/flows" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: flows.GroupName, Version: "v1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Sequence{}, + &SequenceList{}, + &Parallel{}, + &ParallelList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/flows/v1/sequence_conversion.go b/pkg/apis/flows/v1/sequence_conversion.go new file mode 100644 index 00000000000..34e26a3abb0 --- /dev/null +++ b/pkg/apis/flows/v1/sequence_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Sequence) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Sequence) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/flows/v1/sequence_conversion_test.go b/pkg/apis/flows/v1/sequence_conversion_test.go new file mode 100644 index 00000000000..94b87c5c7ea --- /dev/null +++ b/pkg/apis/flows/v1/sequence_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" +) + +func TestSequenceConversionBadType(t *testing.T) { + good, bad := &Sequence{}, &Sequence{} + + 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/flows/v1/sequence_defaults.go b/pkg/apis/flows/v1/sequence_defaults.go new file mode 100644 index 00000000000..64d681f6075 --- /dev/null +++ b/pkg/apis/flows/v1/sequence_defaults.go @@ -0,0 +1,58 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + + "knative.dev/eventing/pkg/apis/messaging/config" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + "knative.dev/pkg/apis" +) + +func (s *Sequence) SetDefaults(ctx context.Context) { + withNS := apis.WithinParent(ctx, s.ObjectMeta) + if s != nil && s.Spec.ChannelTemplate == nil { + cfg := config.FromContextOrDefaults(ctx) + c, err := cfg.ChannelDefaults.GetChannelConfig(apis.ParentMeta(ctx).Namespace) + + if err == nil { + s.Spec.ChannelTemplate = &messagingv1.ChannelTemplateSpec{ + TypeMeta: c.TypeMeta, + Spec: c.Spec, + } + } + } + s.Spec.SetDefaults(withNS) +} + +func (ss *SequenceSpec) SetDefaults(ctx context.Context) { + // Default the namespace for all the steps. + for _, s := range ss.Steps { + s.SetDefaults(ctx) + } + // Default the reply + if ss.Reply != nil { + ss.Reply.SetDefaults(ctx) + } +} + +func (ss *SequenceStep) SetDefaults(ctx context.Context) { + ss.Destination.SetDefaults(ctx) + + // No delivery defaults. +} diff --git a/pkg/apis/flows/v1/sequence_defaults_test.go b/pkg/apis/flows/v1/sequence_defaults_test.go new file mode 100644 index 00000000000..501e7d3bbb5 --- /dev/null +++ b/pkg/apis/flows/v1/sequence_defaults_test.go @@ -0,0 +1,139 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/google/go-cmp/cmp" + "knative.dev/eventing/pkg/apis/messaging/config" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +const ( + testNS = "testnamespace" +) + +var ( + configDefaultChannelTemplate = &config.ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "InMemoryChannel", + }, + } +) + +func TestSequenceSetDefaults(t *testing.T) { + testCases := map[string]struct { + nilChannelDefaulter bool + channelTemplate *config.ChannelTemplateSpec + initial Sequence + expected Sequence + }{ + "nil ChannelDefaulter": { + nilChannelDefaulter: true, + expected: Sequence{}, + }, + "unset ChannelDefaulter": { + expected: Sequence{}, + }, + "set ChannelDefaulter": { + channelTemplate: configDefaultChannelTemplate, + expected: Sequence{ + Spec: SequenceSpec{ + ChannelTemplate: defaultChannelTemplate, + }, + }, + }, + "steps and reply namespace defaulted": { + channelTemplate: configDefaultChannelTemplate, + initial: Sequence{ + ObjectMeta: metav1.ObjectMeta{Namespace: testNS}, + Spec: SequenceSpec{ + Steps: []SequenceStep{ + {Destination: duckv1.Destination{ + Ref: &duckv1.KReference{Name: "first"}}}, + {Destination: duckv1.Destination{ + Ref: &duckv1.KReference{Name: "second"}}}, + }, + Reply: &duckv1.Destination{ + Ref: &duckv1.KReference{Name: "reply"}, + }, + }, + }, + expected: Sequence{ + ObjectMeta: metav1.ObjectMeta{Namespace: testNS}, + Spec: SequenceSpec{ + ChannelTemplate: defaultChannelTemplate, + Steps: []SequenceStep{ + {Destination: duckv1.Destination{ + Ref: &duckv1.KReference{Namespace: testNS, Name: "first"}}}, + {Destination: duckv1.Destination{ + Ref: &duckv1.KReference{Namespace: testNS, Name: "second"}}}, + }, + Reply: &duckv1.Destination{ + Ref: &duckv1.KReference{Namespace: testNS, Name: "reply"}, + }, + }, + }, + }, + "template already specified": { + channelTemplate: configDefaultChannelTemplate, + initial: Sequence{ + Spec: SequenceSpec{ + ChannelTemplate: &messagingv1.ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + expected: Sequence{ + Spec: SequenceSpec{ + ChannelTemplate: &messagingv1.ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + ctx := context.Background() + if !tc.nilChannelDefaulter { + ctx = config.ToContext(ctx, &config.Config{ + ChannelDefaults: &config.ChannelDefaults{ + ClusterDefault: tc.channelTemplate, + }, + }) + } + tc.initial.SetDefaults(ctx) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/flows/v1/sequence_lifecycle.go b/pkg/apis/flows/v1/sequence_lifecycle.go new file mode 100644 index 00000000000..175b40d400d --- /dev/null +++ b/pkg/apis/flows/v1/sequence_lifecycle.go @@ -0,0 +1,174 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var sCondSet = apis.NewLivingConditionSet(SequenceConditionReady, SequenceConditionChannelsReady, SequenceConditionSubscriptionsReady, SequenceConditionAddressable) + +const ( + // SequenceConditionReady has status True when all subconditions below have been set to True. + SequenceConditionReady = apis.ConditionReady + + // SequenceConditionChannelsReady has status True when all the channels created as part of + // this sequence are ready. + SequenceConditionChannelsReady apis.ConditionType = "ChannelsReady" + + // SequenceConditionSubscriptionsReady has status True when all the subscriptions created as part of + // this sequence are ready. + SequenceConditionSubscriptionsReady apis.ConditionType = "SubscriptionsReady" + + // SequenceConditionAddressable has status true when this Sequence meets + // the Addressable contract and has a non-empty hostname. + SequenceConditionAddressable apis.ConditionType = "Addressable" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Sequence) GetConditionSet() apis.ConditionSet { + return sCondSet +} + +// GetGroupVersionKind returns GroupVersionKind for InMemoryChannels +func (*Sequence) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Sequence") +} + +// GetUntypedSpec returns the spec of the Sequence. +func (s *Sequence) GetUntypedSpec() interface{} { + return s.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ss *SequenceStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return sCondSet.Manage(ss).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (ss *SequenceStatus) IsReady() bool { + return sCondSet.Manage(ss).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ss *SequenceStatus) InitializeConditions() { + sCondSet.Manage(ss).InitializeConditions() +} + +// PropagateSubscriptionStatuses sets the SubscriptionStatuses and SequenceConditionSubscriptionsReady based on +// the status of the incoming subscriptions. +func (ss *SequenceStatus) PropagateSubscriptionStatuses(subscriptions []*messagingv1.Subscription) { + ss.SubscriptionStatuses = make([]SequenceSubscriptionStatus, len(subscriptions)) + allReady := true + // If there are no subscriptions, treat that as a False case. Could go either way, but this seems right. + if len(subscriptions) == 0 { + allReady = false + + } + for i, s := range subscriptions { + ss.SubscriptionStatuses[i] = SequenceSubscriptionStatus{ + Subscription: corev1.ObjectReference{ + APIVersion: s.APIVersion, + Kind: s.Kind, + Name: s.Name, + Namespace: s.Namespace, + }, + } + readyCondition := s.Status.GetCondition(messagingv1.SubscriptionConditionReady) + if readyCondition != nil { + ss.SubscriptionStatuses[i].ReadyCondition = *readyCondition + if readyCondition.Status != corev1.ConditionTrue { + allReady = false + } + } else { + allReady = false + } + + } + if allReady { + sCondSet.Manage(ss).MarkTrue(SequenceConditionSubscriptionsReady) + } else { + ss.MarkSubscriptionsNotReady("SubscriptionsNotReady", "Subscriptions are not ready yet, or there are none") + } +} + +// PropagateChannelStatuses sets the ChannelStatuses and SequenceConditionChannelsReady based on the +// status of the incoming channels. +func (ss *SequenceStatus) PropagateChannelStatuses(channels []*eventingduckv1.Channelable) { + ss.ChannelStatuses = make([]SequenceChannelStatus, len(channels)) + allReady := true + // If there are no channels, treat that as a False case. Could go either way, but this seems right. + if len(channels) == 0 { + allReady = false + + } + for i, c := range channels { + ss.ChannelStatuses[i] = SequenceChannelStatus{ + Channel: corev1.ObjectReference{ + APIVersion: c.APIVersion, + Kind: c.Kind, + Name: c.Name, + Namespace: c.Namespace, + }, + } + // TODO: Once the addressable has a real status to dig through, use that here instead of + // addressable, because it might be addressable but not ready. + address := c.Status.AddressStatus.Address + if address != nil { + ss.ChannelStatuses[i].ReadyCondition = apis.Condition{Type: apis.ConditionReady, Status: corev1.ConditionTrue} + } else { + ss.ChannelStatuses[i].ReadyCondition = apis.Condition{Type: apis.ConditionReady, Status: corev1.ConditionFalse, Reason: "NotAddressable", Message: "Channel is not addressable"} + allReady = false + } + + // Mark the Sequence address as the Address of the first channel. + if i == 0 { + ss.setAddress(address) + } + } + if allReady { + sCondSet.Manage(ss).MarkTrue(SequenceConditionChannelsReady) + } else { + ss.MarkChannelsNotReady("ChannelsNotReady", "Channels are not ready yet, or there are none") + } +} + +func (ss *SequenceStatus) MarkChannelsNotReady(reason, messageFormat string, messageA ...interface{}) { + sCondSet.Manage(ss).MarkFalse(SequenceConditionChannelsReady, reason, messageFormat, messageA...) +} + +func (ss *SequenceStatus) MarkSubscriptionsNotReady(reason, messageFormat string, messageA ...interface{}) { + sCondSet.Manage(ss).MarkFalse(SequenceConditionSubscriptionsReady, reason, messageFormat, messageA...) +} + +func (ss *SequenceStatus) MarkAddressableNotReady(reason, messageFormat string, messageA ...interface{}) { + sCondSet.Manage(ss).MarkFalse(SequenceConditionAddressable, reason, messageFormat, messageA...) +} + +func (ss *SequenceStatus) setAddress(address *duckv1.Addressable) { + if address == nil || address.URL == nil { + sCondSet.Manage(ss).MarkFalse(SequenceConditionAddressable, "emptyAddress", "addressable is nil") + } else { + ss.AddressStatus.Address = &duckv1.Addressable{URL: address.URL} + sCondSet.Manage(ss).MarkTrue(SequenceConditionAddressable) + } +} diff --git a/pkg/apis/flows/v1/sequence_lifecycle_test.go b/pkg/apis/flows/v1/sequence_lifecycle_test.go new file mode 100644 index 00000000000..76e83ab93b7 --- /dev/null +++ b/pkg/apis/flows/v1/sequence_lifecycle_test.go @@ -0,0 +1,402 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" +) + +var sequenceConditionReady = apis.Condition{ + Type: SequenceConditionReady, + Status: corev1.ConditionTrue, +} + +func TestSequenceGetConditionSet(t *testing.T) { + r := &Sequence{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func getSubscription(name string, ready bool) *messagingv1.Subscription { + s := messagingv1.Subscription{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Subscription", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "testns", + }, + Status: messagingv1.SubscriptionStatus{}, + } + if ready { + s.Status.MarkChannelReady() + s.Status.MarkReferencesResolved() + s.Status.MarkAddedToChannel() + } else { + s.Status.MarkChannelFailed("testInducedFailure", "Test Induced failure") + s.Status.MarkReferencesNotResolved("testInducedFailure", "Test Induced failure") + s.Status.MarkNotAddedToChannel("testInducedfailure", "Test Induced failure") + } + return &s +} + +func getChannelable(ready bool) *eventingduckv1.Channelable { + URL, _ := apis.ParseURL("http://example.com") + c := eventingduckv1.Channelable{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "messaging.knative.dev/v1", + Kind: "InMemoryChannel", + }, + ObjectMeta: metav1.ObjectMeta{}, + Status: eventingduckv1.ChannelableStatus{}, + } + + if ready { + c.Status.Address = &duckv1.Addressable{URL: URL} + } + + return &c +} + +func TestSequenceGetCondition(t *testing.T) { + tests := []struct { + name string + ss *SequenceStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ss: &SequenceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + sequenceConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &sequenceConditionReady, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ss.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestSequenceInitializeConditions(t *testing.T) { + tests := []struct { + name string + ts *SequenceStatus + want *SequenceStatus + }{{ + name: "empty", + ts: &SequenceStatus{}, + want: &SequenceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SequenceConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionChannelsReady, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionSubscriptionsReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one false", + ts: &SequenceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SequenceConditionChannelsReady, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &SequenceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SequenceConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionChannelsReady, + Status: corev1.ConditionFalse, + }, { + Type: SequenceConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionSubscriptionsReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + ts: &SequenceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SequenceConditionSubscriptionsReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &SequenceStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: SequenceConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionChannelsReady, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: SequenceConditionSubscriptionsReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ts.InitializeConditions() + if diff := cmp.Diff(test.want, test.ts, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestSequencePropagateSubscriptionStatuses(t *testing.T) { + tests := []struct { + name string + subs []*messagingv1.Subscription + want corev1.ConditionStatus + }{{ + name: "empty", + subs: []*messagingv1.Subscription{}, + want: corev1.ConditionFalse, + }, { + name: "empty status", + subs: []*messagingv1.Subscription{{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "eventing.knative.dev/v1alpha1", + Kind: "Subscription", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "sub", + Namespace: "testns", + }, + Status: messagingv1.SubscriptionStatus{}, + }, + }, + want: corev1.ConditionFalse, + }, { + name: "one subscription not ready", + subs: []*messagingv1.Subscription{getSubscription("sub0", false)}, + want: corev1.ConditionFalse, + }, { + name: "one subscription ready", + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: corev1.ConditionTrue, + }, { + name: "one subscription ready, one not", + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", false)}, + want: corev1.ConditionFalse, + }, { + name: "two subscriptions ready", + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: corev1.ConditionTrue, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := SequenceStatus{} + ps.PropagateSubscriptionStatuses(test.subs) + got := ps.GetCondition(SequenceConditionSubscriptionsReady).Status + want := test.want + if want != got { + t.Errorf("unexpected conditions (-want, +got) = %v %v", want, got) + } + }) + } +} + +func TestSequencePropagateChannelStatuses(t *testing.T) { + tests := []struct { + name string + channels []*eventingduckv1.Channelable + want corev1.ConditionStatus + }{{ + name: "empty", + channels: []*eventingduckv1.Channelable{}, + want: corev1.ConditionFalse, + }, { + name: "one channelable not ready", + channels: []*eventingduckv1.Channelable{getChannelable(false)}, + want: corev1.ConditionFalse, + }, { + name: "one channelable ready", + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + want: corev1.ConditionTrue, + }, { + name: "one channelable ready, one not", + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(false)}, + want: corev1.ConditionFalse, + }, { + name: "two channelables ready", + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + want: corev1.ConditionTrue, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := SequenceStatus{} + ps.PropagateChannelStatuses(test.channels) + got := ps.GetCondition(SequenceConditionChannelsReady).Status + want := test.want + if want != got { + t.Errorf("unexpected conditions (-want, +got) = %v %v", want, got) + } + }) + } +} + +func TestSequenceReady(t *testing.T) { + tests := []struct { + name string + subs []*messagingv1.Subscription + channels []*eventingduckv1.Channelable + want bool + }{{ + name: "empty", + subs: []*messagingv1.Subscription{}, + channels: []*eventingduckv1.Channelable{}, + want: false, + }, { + name: "one channelable not ready, one subscription ready", + channels: []*eventingduckv1.Channelable{getChannelable(false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: false, + }, { + name: "one channelable ready, one subscription not ready", + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", false)}, + want: false, + }, { + name: "one channelable ready, one subscription ready", + channels: []*eventingduckv1.Channelable{getChannelable(true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true)}, + want: true, + }, { + name: "one channelable ready, one not, two subsriptions ready", + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(false)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: false, + }, { + name: "two channelables ready, one subscription ready, one not", + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", false)}, + want: false, + }, { + name: "two channelables ready, two subscriptions ready", + channels: []*eventingduckv1.Channelable{getChannelable(true), getChannelable(true)}, + subs: []*messagingv1.Subscription{getSubscription("sub0", true), getSubscription("sub1", true)}, + want: true, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := SequenceStatus{} + ps.PropagateChannelStatuses(test.channels) + ps.PropagateSubscriptionStatuses(test.subs) + got := ps.IsReady() + want := test.want + if want != got { + t.Errorf("unexpected conditions (-want, +got) = %v %v", want, got) + } + }) + } +} + +func TestSequencePropagateSetAddress(t *testing.T) { + URL, _ := apis.ParseURL("http://example.com") + tests := []struct { + name string + address *duckv1.Addressable + want *duckv1.Addressable + wantStatus corev1.ConditionStatus + }{{ + name: "nil", + address: nil, + want: nil, + wantStatus: corev1.ConditionFalse, + }, { + name: "empty", + address: &duckv1.Addressable{}, + want: nil, + wantStatus: corev1.ConditionFalse, + }, { + name: "URL", + address: &duckv1.Addressable{URL: URL}, + want: &duckv1.Addressable{URL: URL}, + wantStatus: corev1.ConditionTrue, + }, { + name: "nil", + address: &duckv1.Addressable{URL: nil}, + want: nil, + wantStatus: corev1.ConditionFalse, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ps := SequenceStatus{} + ps.setAddress(test.address) + got := ps.Address + if diff := cmp.Diff(test.want, got, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected address (-want, +got) = %v", diff) + } + gotStatus := ps.GetCondition(SequenceConditionAddressable).Status + if test.wantStatus != gotStatus { + t.Errorf("unexpected conditions (-want, +got) = %v %v", test.wantStatus, gotStatus) + } + }) + } +} diff --git a/pkg/apis/flows/v1/sequence_types.go b/pkg/apis/flows/v1/sequence_types.go new file mode 100644 index 00000000000..e287f61fffa --- /dev/null +++ b/pkg/apis/flows/v1/sequence_types.go @@ -0,0 +1,146 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// Sequence defines a sequence of Subscribers that will be wired in +// series through Channels and Subscriptions. +type Sequence struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Sequence. + Spec SequenceSpec `json:"spec,omitempty"` + + // Status represents the current state of the Sequence. This data may be out of + // date. + // +optional + Status SequenceStatus `json:"status,omitempty"` +} + +var ( + // Check that Sequence can be validated and defaulted. + _ apis.Validatable = (*Sequence)(nil) + _ apis.Defaultable = (*Sequence)(nil) + + // Check that Sequence can return its spec untyped. + _ apis.HasSpec = (*Sequence)(nil) + + // TODO: make appropriate fields immutable. + //_ apis.Immutable = (*Sequence)(nil) + + _ runtime.Object = (*Sequence)(nil) + + // Check that we can create OwnerReferences to a Sequence. + _ kmeta.OwnerRefable = (*Sequence)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Sequence)(nil) +) + +type SequenceSpec struct { + // Steps is the list of Destinations (processors / functions) that will be called in the order + // provided. Each step has its own delivery options + Steps []SequenceStep `json:"steps"` + + // ChannelTemplate specifies which Channel CRD to use. If left unspecified, it is set to the default Channel CRD + // for the namespace (or cluster, in case there are no defaults for the namespace). + // +optional + ChannelTemplate *messagingv1.ChannelTemplateSpec `json:"channelTemplate,omitempty"` + + // Reply is a Reference to where the result of the last Subscriber gets sent to. + // +optional + Reply *duckv1.Destination `json:"reply,omitempty"` +} + +type SequenceStep struct { + // Subscriber receiving the step event + duckv1.Destination `json:",inline"` + + // Delivery is the delivery specification for events to the subscriber + // This includes things like retries, DLQ, etc. + // +optional + Delivery *eventingduckv1.DeliverySpec `json:"delivery,omitempty"` +} + +type SequenceChannelStatus struct { + // Channel is the reference to the underlying channel. + Channel corev1.ObjectReference `json:"channel"` + + // ReadyCondition indicates whether the Channel is ready or not. + ReadyCondition apis.Condition `json:"ready"` +} + +type SequenceSubscriptionStatus struct { + // Subscription is the reference to the underlying Subscription. + Subscription corev1.ObjectReference `json:"subscription"` + + // ReadyCondition indicates whether the Subscription is ready or not. + ReadyCondition apis.Condition `json:"ready"` +} + +// SequenceStatus represents the current state of a Sequence. +type SequenceStatus 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"` + + // SubscriptionStatuses is an array of corresponding Subscription statuses. + // Matches the Spec.Steps array in the order. + SubscriptionStatuses []SequenceSubscriptionStatus `json:"subscriptionStatuses"` + + // ChannelStatuses is an array of corresponding Channel statuses. + // Matches the Spec.Steps array in the order. + ChannelStatuses []SequenceChannelStatus `json:"channelStatuses"` + + // AddressStatus is the starting point to this Sequence. Sending to this + // will target the first subscriber. + // It generally has the form {channel}.{namespace}.svc.{cluster domain name} + duckv1.AddressStatus `json:",inline"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SequenceList is a collection of Sequences. +type SequenceList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Sequence `json:"items"` +} + +// GetStatus retrieves the status of the Sequence. Implements the KRShaped interface. +func (p *Sequence) GetStatus() *duckv1.Status { + return &p.Status.Status +} diff --git a/pkg/apis/flows/v1/sequence_types_test.go b/pkg/apis/flows/v1/sequence_types_test.go new file mode 100644 index 00000000000..793725023e2 --- /dev/null +++ b/pkg/apis/flows/v1/sequence_types_test.go @@ -0,0 +1,43 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import "testing" + +func TestSequenceGetStatus(t *testing.T) { + r := &Sequence{ + Status: SequenceStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestSequenceKind(t *testing.T) { + sequence := Sequence{} + if sequence.GetGroupVersionKind().String() != "flows.knative.dev/v1, Kind=Sequence" { + t.Errorf("unexpected gvk: %v", sequence.GetGroupVersionKind()) + } +} + +func TestSequence_GetGroupVersionKind(t *testing.T) { + s := Sequence{} + gvk := s.GetGroupVersionKind() + if gvk.Kind != "Sequence" { + t.Errorf("Should be Sequence.") + } +} diff --git a/pkg/apis/flows/v1/sequence_validation.go b/pkg/apis/flows/v1/sequence_validation.go new file mode 100644 index 00000000000..a352bb18fad --- /dev/null +++ b/pkg/apis/flows/v1/sequence_validation.go @@ -0,0 +1,72 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + + "knative.dev/pkg/apis" +) + +func (p *Sequence) Validate(ctx context.Context) *apis.FieldError { + return p.Spec.Validate(ctx).ViaField("spec") +} + +func (ps *SequenceSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + if len(ps.Steps) == 0 { + errs = errs.Also(apis.ErrMissingField("steps")) + } + + for i, s := range ps.Steps { + if e := s.Validate(ctx); e != nil { + errs = errs.Also(apis.ErrInvalidArrayValue(s, "steps", i)) + } + } + + if ps.ChannelTemplate == nil { + errs = errs.Also(apis.ErrMissingField("channelTemplate")) + return errs + } + + if len(ps.ChannelTemplate.APIVersion) == 0 { + errs = errs.Also(apis.ErrMissingField("channelTemplate.apiVersion")) + } + + if len(ps.ChannelTemplate.Kind) == 0 { + errs = errs.Also(apis.ErrMissingField("channelTemplate.kind")) + } + + if err := ps.Reply.Validate(ctx); err != nil { + errs = errs.Also(err.ViaField("reply")) + } + + return errs +} + +func (ss *SequenceStep) Validate(ctx context.Context) *apis.FieldError { + errs := ss.Destination.Validate(ctx) + + if ss.Delivery != nil { + if de := ss.Delivery.Validate(ctx); de != nil { + errs = errs.Also(de.ViaField("delivery")) + } + } + + return errs +} diff --git a/pkg/apis/flows/v1/test_helpers.go b/pkg/apis/flows/v1/test_helpers.go new file mode 100644 index 00000000000..308dcba8771 --- /dev/null +++ b/pkg/apis/flows/v1/test_helpers.go @@ -0,0 +1,37 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "github.com/google/go-cmp/cmp/cmpopts" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + "knative.dev/pkg/apis" +) + +var ( + defaultChannelTemplate = &messagingv1.ChannelTemplateSpec{ + TypeMeta: v1.TypeMeta{ + APIVersion: SchemeGroupVersion.String(), + Kind: "InMemoryChannel", + }, + } + ignoreAllButTypeAndStatus = cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") +) diff --git a/pkg/apis/flows/v1/zz_generated.deepcopy.go b/pkg/apis/flows/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..e199236dc58 --- /dev/null +++ b/pkg/apis/flows/v1/zz_generated.deepcopy.go @@ -0,0 +1,419 @@ +// +build !ignore_autogenerated + +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + apisduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Parallel) DeepCopyInto(out *Parallel) { + *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 Parallel. +func (in *Parallel) DeepCopy() *Parallel { + if in == nil { + return nil + } + out := new(Parallel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Parallel) 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 *ParallelBranch) DeepCopyInto(out *ParallelBranch) { + *out = *in + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + in.Subscriber.DeepCopyInto(&out.Subscriber) + if in.Reply != nil { + in, out := &in.Reply, &out.Reply + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(apisduckv1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelBranch. +func (in *ParallelBranch) DeepCopy() *ParallelBranch { + if in == nil { + return nil + } + out := new(ParallelBranch) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelBranchStatus) DeepCopyInto(out *ParallelBranchStatus) { + *out = *in + in.FilterSubscriptionStatus.DeepCopyInto(&out.FilterSubscriptionStatus) + in.FilterChannelStatus.DeepCopyInto(&out.FilterChannelStatus) + in.SubscriptionStatus.DeepCopyInto(&out.SubscriptionStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelBranchStatus. +func (in *ParallelBranchStatus) DeepCopy() *ParallelBranchStatus { + if in == nil { + return nil + } + out := new(ParallelBranchStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelChannelStatus) DeepCopyInto(out *ParallelChannelStatus) { + *out = *in + out.Channel = in.Channel + in.ReadyCondition.DeepCopyInto(&out.ReadyCondition) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelChannelStatus. +func (in *ParallelChannelStatus) DeepCopy() *ParallelChannelStatus { + if in == nil { + return nil + } + out := new(ParallelChannelStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelList) DeepCopyInto(out *ParallelList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Parallel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelList. +func (in *ParallelList) DeepCopy() *ParallelList { + if in == nil { + return nil + } + out := new(ParallelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ParallelList) 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 *ParallelSpec) DeepCopyInto(out *ParallelSpec) { + *out = *in + if in.Branches != nil { + in, out := &in.Branches, &out.Branches + *out = make([]ParallelBranch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ChannelTemplate != nil { + in, out := &in.ChannelTemplate, &out.ChannelTemplate + *out = new(messagingv1.ChannelTemplateSpec) + (*in).DeepCopyInto(*out) + } + if in.Reply != nil { + in, out := &in.Reply, &out.Reply + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelSpec. +func (in *ParallelSpec) DeepCopy() *ParallelSpec { + if in == nil { + return nil + } + out := new(ParallelSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelStatus) DeepCopyInto(out *ParallelStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.IngressChannelStatus.DeepCopyInto(&out.IngressChannelStatus) + if in.BranchStatuses != nil { + in, out := &in.BranchStatuses, &out.BranchStatuses + *out = make([]ParallelBranchStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.AddressStatus.DeepCopyInto(&out.AddressStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelStatus. +func (in *ParallelStatus) DeepCopy() *ParallelStatus { + if in == nil { + return nil + } + out := new(ParallelStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParallelSubscriptionStatus) DeepCopyInto(out *ParallelSubscriptionStatus) { + *out = *in + out.Subscription = in.Subscription + in.ReadyCondition.DeepCopyInto(&out.ReadyCondition) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParallelSubscriptionStatus. +func (in *ParallelSubscriptionStatus) DeepCopy() *ParallelSubscriptionStatus { + if in == nil { + return nil + } + out := new(ParallelSubscriptionStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Sequence) DeepCopyInto(out *Sequence) { + *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 Sequence. +func (in *Sequence) DeepCopy() *Sequence { + if in == nil { + return nil + } + out := new(Sequence) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Sequence) 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 *SequenceChannelStatus) DeepCopyInto(out *SequenceChannelStatus) { + *out = *in + out.Channel = in.Channel + in.ReadyCondition.DeepCopyInto(&out.ReadyCondition) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SequenceChannelStatus. +func (in *SequenceChannelStatus) DeepCopy() *SequenceChannelStatus { + if in == nil { + return nil + } + out := new(SequenceChannelStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SequenceList) DeepCopyInto(out *SequenceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Sequence, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SequenceList. +func (in *SequenceList) DeepCopy() *SequenceList { + if in == nil { + return nil + } + out := new(SequenceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SequenceList) 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 *SequenceSpec) DeepCopyInto(out *SequenceSpec) { + *out = *in + if in.Steps != nil { + in, out := &in.Steps, &out.Steps + *out = make([]SequenceStep, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ChannelTemplate != nil { + in, out := &in.ChannelTemplate, &out.ChannelTemplate + *out = new(messagingv1.ChannelTemplateSpec) + (*in).DeepCopyInto(*out) + } + if in.Reply != nil { + in, out := &in.Reply, &out.Reply + *out = new(duckv1.Destination) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SequenceSpec. +func (in *SequenceSpec) DeepCopy() *SequenceSpec { + if in == nil { + return nil + } + out := new(SequenceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SequenceStatus) DeepCopyInto(out *SequenceStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + if in.SubscriptionStatuses != nil { + in, out := &in.SubscriptionStatuses, &out.SubscriptionStatuses + *out = make([]SequenceSubscriptionStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ChannelStatuses != nil { + in, out := &in.ChannelStatuses, &out.ChannelStatuses + *out = make([]SequenceChannelStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.AddressStatus.DeepCopyInto(&out.AddressStatus) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SequenceStatus. +func (in *SequenceStatus) DeepCopy() *SequenceStatus { + if in == nil { + return nil + } + out := new(SequenceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SequenceStep) DeepCopyInto(out *SequenceStep) { + *out = *in + in.Destination.DeepCopyInto(&out.Destination) + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(apisduckv1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SequenceStep. +func (in *SequenceStep) DeepCopy() *SequenceStep { + if in == nil { + return nil + } + out := new(SequenceStep) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SequenceSubscriptionStatus) DeepCopyInto(out *SequenceSubscriptionStatus) { + *out = *in + out.Subscription = in.Subscription + in.ReadyCondition.DeepCopyInto(&out.ReadyCondition) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SequenceSubscriptionStatus. +func (in *SequenceSubscriptionStatus) DeepCopy() *SequenceSubscriptionStatus { + if in == nil { + return nil + } + out := new(SequenceSubscriptionStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 79e6b37f423..b69841c4ab2 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -27,6 +27,7 @@ import ( configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" + flowsv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" messagingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1" messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" @@ -40,6 +41,7 @@ type Interface interface { EventingV1beta1() eventingv1beta1.EventingV1beta1Interface EventingV1() eventingv1.EventingV1Interface FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface + FlowsV1() flowsv1.FlowsV1Interface MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface MessagingV1() messagingv1.MessagingV1Interface SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface @@ -54,6 +56,7 @@ type Clientset struct { eventingV1beta1 *eventingv1beta1.EventingV1beta1Client eventingV1 *eventingv1.EventingV1Client flowsV1beta1 *flowsv1beta1.FlowsV1beta1Client + flowsV1 *flowsv1.FlowsV1Client messagingV1beta1 *messagingv1beta1.MessagingV1beta1Client messagingV1 *messagingv1.MessagingV1Client sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client @@ -80,6 +83,11 @@ func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return c.flowsV1beta1 } +// FlowsV1 retrieves the FlowsV1Client +func (c *Clientset) FlowsV1() flowsv1.FlowsV1Interface { + return c.flowsV1 +} + // MessagingV1beta1 retrieves the MessagingV1beta1Client func (c *Clientset) MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface { return c.messagingV1beta1 @@ -137,6 +145,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.flowsV1, err = flowsv1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.messagingV1beta1, err = messagingv1beta1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -169,6 +181,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { cs.eventingV1beta1 = eventingv1beta1.NewForConfigOrDie(c) cs.eventingV1 = eventingv1.NewForConfigOrDie(c) cs.flowsV1beta1 = flowsv1beta1.NewForConfigOrDie(c) + cs.flowsV1 = flowsv1.NewForConfigOrDie(c) cs.messagingV1beta1 = messagingv1beta1.NewForConfigOrDie(c) cs.messagingV1 = messagingv1.NewForConfigOrDie(c) cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) @@ -185,6 +198,7 @@ func New(c rest.Interface) *Clientset { cs.eventingV1beta1 = eventingv1beta1.New(c) cs.eventingV1 = eventingv1.New(c) cs.flowsV1beta1 = flowsv1beta1.New(c) + cs.flowsV1 = flowsv1.New(c) cs.messagingV1beta1 = messagingv1beta1.New(c) cs.messagingV1 = messagingv1.New(c) cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index ce1f004c08d..dd0fed242f3 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -31,6 +31,8 @@ import ( fakeeventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" fakeeventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake" + flowsv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1" + fakeflowsv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1/fake" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" fakeflowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1/fake" messagingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1" @@ -110,6 +112,11 @@ func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return &fakeflowsv1beta1.FakeFlowsV1beta1{Fake: &c.Fake} } +// FlowsV1 retrieves the FlowsV1Client +func (c *Clientset) FlowsV1() flowsv1.FlowsV1Interface { + return &fakeflowsv1.FakeFlowsV1{Fake: &c.Fake} +} + // MessagingV1beta1 retrieves the MessagingV1beta1Client func (c *Clientset) MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface { return &fakemessagingv1beta1.FakeMessagingV1beta1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 45c06ec14ba..f2579b5b7e6 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -27,6 +27,7 @@ import ( configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -42,6 +43,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ eventingv1beta1.AddToScheme, eventingv1.AddToScheme, flowsv1beta1.AddToScheme, + flowsv1.AddToScheme, messagingv1beta1.AddToScheme, messagingv1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index a4858f13a52..e055463a7d0 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -27,6 +27,7 @@ import ( configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -42,6 +43,7 @@ var localSchemeBuilder = runtime.SchemeBuilder{ eventingv1beta1.AddToScheme, eventingv1.AddToScheme, flowsv1beta1.AddToScheme, + flowsv1.AddToScheme, messagingv1beta1.AddToScheme, messagingv1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/flows/v1/doc.go b/pkg/client/clientset/versioned/typed/flows/v1/doc.go new file mode 100644 index 00000000000..5b83bd1f41a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/pkg/client/clientset/versioned/typed/flows/v1/fake/doc.go b/pkg/client/clientset/versioned/typed/flows/v1/fake/doc.go new file mode 100644 index 00000000000..c7f6e65cab8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_flows_client.go b/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_flows_client.go new file mode 100644 index 00000000000..35091f29ab1 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_flows_client.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1" +) + +type FakeFlowsV1 struct { + *testing.Fake +} + +func (c *FakeFlowsV1) Parallels(namespace string) v1.ParallelInterface { + return &FakeParallels{c, namespace} +} + +func (c *FakeFlowsV1) Sequences(namespace string) v1.SequenceInterface { + return &FakeSequences{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeFlowsV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_parallel.go b/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_parallel.go new file mode 100644 index 00000000000..3483ead0be9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_parallel.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" +) + +// FakeParallels implements ParallelInterface +type FakeParallels struct { + Fake *FakeFlowsV1 + ns string +} + +var parallelsResource = schema.GroupVersionResource{Group: "flows.knative.dev", Version: "v1", Resource: "parallels"} + +var parallelsKind = schema.GroupVersionKind{Group: "flows.knative.dev", Version: "v1", Kind: "Parallel"} + +// Get takes name of the parallel, and returns the corresponding parallel object, and an error if there is any. +func (c *FakeParallels) Get(name string, options v1.GetOptions) (result *flowsv1.Parallel, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(parallelsResource, c.ns, name), &flowsv1.Parallel{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Parallel), err +} + +// List takes label and field selectors, and returns the list of Parallels that match those selectors. +func (c *FakeParallels) List(opts v1.ListOptions) (result *flowsv1.ParallelList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(parallelsResource, parallelsKind, c.ns, opts), &flowsv1.ParallelList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &flowsv1.ParallelList{ListMeta: obj.(*flowsv1.ParallelList).ListMeta} + for _, item := range obj.(*flowsv1.ParallelList).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 parallels. +func (c *FakeParallels) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(parallelsResource, c.ns, opts)) + +} + +// Create takes the representation of a parallel and creates it. Returns the server's representation of the parallel, and an error, if there is any. +func (c *FakeParallels) Create(parallel *flowsv1.Parallel) (result *flowsv1.Parallel, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(parallelsResource, c.ns, parallel), &flowsv1.Parallel{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Parallel), err +} + +// Update takes the representation of a parallel and updates it. Returns the server's representation of the parallel, and an error, if there is any. +func (c *FakeParallels) Update(parallel *flowsv1.Parallel) (result *flowsv1.Parallel, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(parallelsResource, c.ns, parallel), &flowsv1.Parallel{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Parallel), 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 *FakeParallels) UpdateStatus(parallel *flowsv1.Parallel) (*flowsv1.Parallel, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(parallelsResource, "status", c.ns, parallel), &flowsv1.Parallel{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Parallel), err +} + +// Delete takes name of the parallel and deletes it. Returns an error if one occurs. +func (c *FakeParallels) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(parallelsResource, c.ns, name), &flowsv1.Parallel{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeParallels) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(parallelsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &flowsv1.ParallelList{}) + return err +} + +// Patch applies the patch and returns the patched parallel. +func (c *FakeParallels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *flowsv1.Parallel, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(parallelsResource, c.ns, name, pt, data, subresources...), &flowsv1.Parallel{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Parallel), err +} diff --git a/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_sequence.go b/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_sequence.go new file mode 100644 index 00000000000..bd35aa39173 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/fake/fake_sequence.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" +) + +// FakeSequences implements SequenceInterface +type FakeSequences struct { + Fake *FakeFlowsV1 + ns string +} + +var sequencesResource = schema.GroupVersionResource{Group: "flows.knative.dev", Version: "v1", Resource: "sequences"} + +var sequencesKind = schema.GroupVersionKind{Group: "flows.knative.dev", Version: "v1", Kind: "Sequence"} + +// Get takes name of the sequence, and returns the corresponding sequence object, and an error if there is any. +func (c *FakeSequences) Get(name string, options v1.GetOptions) (result *flowsv1.Sequence, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(sequencesResource, c.ns, name), &flowsv1.Sequence{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Sequence), err +} + +// List takes label and field selectors, and returns the list of Sequences that match those selectors. +func (c *FakeSequences) List(opts v1.ListOptions) (result *flowsv1.SequenceList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(sequencesResource, sequencesKind, c.ns, opts), &flowsv1.SequenceList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &flowsv1.SequenceList{ListMeta: obj.(*flowsv1.SequenceList).ListMeta} + for _, item := range obj.(*flowsv1.SequenceList).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 sequences. +func (c *FakeSequences) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(sequencesResource, c.ns, opts)) + +} + +// Create takes the representation of a sequence and creates it. Returns the server's representation of the sequence, and an error, if there is any. +func (c *FakeSequences) Create(sequence *flowsv1.Sequence) (result *flowsv1.Sequence, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(sequencesResource, c.ns, sequence), &flowsv1.Sequence{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Sequence), err +} + +// Update takes the representation of a sequence and updates it. Returns the server's representation of the sequence, and an error, if there is any. +func (c *FakeSequences) Update(sequence *flowsv1.Sequence) (result *flowsv1.Sequence, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(sequencesResource, c.ns, sequence), &flowsv1.Sequence{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Sequence), 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 *FakeSequences) UpdateStatus(sequence *flowsv1.Sequence) (*flowsv1.Sequence, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(sequencesResource, "status", c.ns, sequence), &flowsv1.Sequence{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Sequence), err +} + +// Delete takes name of the sequence and deletes it. Returns an error if one occurs. +func (c *FakeSequences) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(sequencesResource, c.ns, name), &flowsv1.Sequence{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeSequences) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(sequencesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &flowsv1.SequenceList{}) + return err +} + +// Patch applies the patch and returns the patched sequence. +func (c *FakeSequences) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *flowsv1.Sequence, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(sequencesResource, c.ns, name, pt, data, subresources...), &flowsv1.Sequence{}) + + if obj == nil { + return nil, err + } + return obj.(*flowsv1.Sequence), err +} diff --git a/pkg/client/clientset/versioned/typed/flows/v1/flows_client.go b/pkg/client/clientset/versioned/typed/flows/v1/flows_client.go new file mode 100644 index 00000000000..cd2e6fb94e4 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/flows_client.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/flows/v1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type FlowsV1Interface interface { + RESTClient() rest.Interface + ParallelsGetter + SequencesGetter +} + +// FlowsV1Client is used to interact with features provided by the flows.knative.dev group. +type FlowsV1Client struct { + restClient rest.Interface +} + +func (c *FlowsV1Client) Parallels(namespace string) ParallelInterface { + return newParallels(c, namespace) +} + +func (c *FlowsV1Client) Sequences(namespace string) SequenceInterface { + return newSequences(c, namespace) +} + +// NewForConfig creates a new FlowsV1Client for the given config. +func NewForConfig(c *rest.Config) (*FlowsV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &FlowsV1Client{client}, nil +} + +// NewForConfigOrDie creates a new FlowsV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *FlowsV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new FlowsV1Client for the given RESTClient. +func New(c rest.Interface) *FlowsV1Client { + return &FlowsV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FlowsV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/flows/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/flows/v1/generated_expansion.go new file mode 100644 index 00000000000..9612fb9083d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ParallelExpansion interface{} + +type SequenceExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/flows/v1/parallel.go b/pkg/client/clientset/versioned/typed/flows/v1/parallel.go new file mode 100644 index 00000000000..32b162bbac7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/parallel.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/flows/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// ParallelsGetter has a method to return a ParallelInterface. +// A group's client should implement this interface. +type ParallelsGetter interface { + Parallels(namespace string) ParallelInterface +} + +// ParallelInterface has methods to work with Parallel resources. +type ParallelInterface interface { + Create(*v1.Parallel) (*v1.Parallel, error) + Update(*v1.Parallel) (*v1.Parallel, error) + UpdateStatus(*v1.Parallel) (*v1.Parallel, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Parallel, error) + List(opts metav1.ListOptions) (*v1.ParallelList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Parallel, err error) + ParallelExpansion +} + +// parallels implements ParallelInterface +type parallels struct { + client rest.Interface + ns string +} + +// newParallels returns a Parallels +func newParallels(c *FlowsV1Client, namespace string) *parallels { + return ¶llels{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the parallel, and returns the corresponding parallel object, and an error if there is any. +func (c *parallels) Get(name string, options metav1.GetOptions) (result *v1.Parallel, err error) { + result = &v1.Parallel{} + err = c.client.Get(). + Namespace(c.ns). + Resource("parallels"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Parallels that match those selectors. +func (c *parallels) List(opts metav1.ListOptions) (result *v1.ParallelList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.ParallelList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("parallels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested parallels. +func (c *parallels) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("parallels"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a parallel and creates it. Returns the server's representation of the parallel, and an error, if there is any. +func (c *parallels) Create(parallel *v1.Parallel) (result *v1.Parallel, err error) { + result = &v1.Parallel{} + err = c.client.Post(). + Namespace(c.ns). + Resource("parallels"). + Body(parallel). + Do(). + Into(result) + return +} + +// Update takes the representation of a parallel and updates it. Returns the server's representation of the parallel, and an error, if there is any. +func (c *parallels) Update(parallel *v1.Parallel) (result *v1.Parallel, err error) { + result = &v1.Parallel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("parallels"). + Name(parallel.Name). + Body(parallel). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *parallels) UpdateStatus(parallel *v1.Parallel) (result *v1.Parallel, err error) { + result = &v1.Parallel{} + err = c.client.Put(). + Namespace(c.ns). + Resource("parallels"). + Name(parallel.Name). + SubResource("status"). + Body(parallel). + Do(). + Into(result) + return +} + +// Delete takes name of the parallel and deletes it. Returns an error if one occurs. +func (c *parallels) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("parallels"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *parallels) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("parallels"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched parallel. +func (c *parallels) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Parallel, err error) { + result = &v1.Parallel{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("parallels"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/flows/v1/sequence.go b/pkg/client/clientset/versioned/typed/flows/v1/sequence.go new file mode 100644 index 00000000000..414c70b41e7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/flows/v1/sequence.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/flows/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// SequencesGetter has a method to return a SequenceInterface. +// A group's client should implement this interface. +type SequencesGetter interface { + Sequences(namespace string) SequenceInterface +} + +// SequenceInterface has methods to work with Sequence resources. +type SequenceInterface interface { + Create(*v1.Sequence) (*v1.Sequence, error) + Update(*v1.Sequence) (*v1.Sequence, error) + UpdateStatus(*v1.Sequence) (*v1.Sequence, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Sequence, error) + List(opts metav1.ListOptions) (*v1.SequenceList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Sequence, err error) + SequenceExpansion +} + +// sequences implements SequenceInterface +type sequences struct { + client rest.Interface + ns string +} + +// newSequences returns a Sequences +func newSequences(c *FlowsV1Client, namespace string) *sequences { + return &sequences{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the sequence, and returns the corresponding sequence object, and an error if there is any. +func (c *sequences) Get(name string, options metav1.GetOptions) (result *v1.Sequence, err error) { + result = &v1.Sequence{} + err = c.client.Get(). + Namespace(c.ns). + Resource("sequences"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Sequences that match those selectors. +func (c *sequences) List(opts metav1.ListOptions) (result *v1.SequenceList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.SequenceList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("sequences"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested sequences. +func (c *sequences) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("sequences"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a sequence and creates it. Returns the server's representation of the sequence, and an error, if there is any. +func (c *sequences) Create(sequence *v1.Sequence) (result *v1.Sequence, err error) { + result = &v1.Sequence{} + err = c.client.Post(). + Namespace(c.ns). + Resource("sequences"). + Body(sequence). + Do(). + Into(result) + return +} + +// Update takes the representation of a sequence and updates it. Returns the server's representation of the sequence, and an error, if there is any. +func (c *sequences) Update(sequence *v1.Sequence) (result *v1.Sequence, err error) { + result = &v1.Sequence{} + err = c.client.Put(). + Namespace(c.ns). + Resource("sequences"). + Name(sequence.Name). + Body(sequence). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *sequences) UpdateStatus(sequence *v1.Sequence) (result *v1.Sequence, err error) { + result = &v1.Sequence{} + err = c.client.Put(). + Namespace(c.ns). + Resource("sequences"). + Name(sequence.Name). + SubResource("status"). + Body(sequence). + Do(). + Into(result) + return +} + +// Delete takes name of the sequence and deletes it. Returns an error if one occurs. +func (c *sequences) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("sequences"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *sequences) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("sequences"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched sequence. +func (c *sequences) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Sequence, err error) { + result = &v1.Sequence{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("sequences"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/flows/interface.go b/pkg/client/informers/externalversions/flows/interface.go index fb7f1417715..96d048edd66 100644 --- a/pkg/client/informers/externalversions/flows/interface.go +++ b/pkg/client/informers/externalversions/flows/interface.go @@ -19,6 +19,7 @@ limitations under the License. package flows import ( + v1 "knative.dev/eventing/pkg/client/informers/externalversions/flows/v1" v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/flows/v1beta1" internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" ) @@ -27,6 +28,8 @@ import ( type Interface interface { // V1beta1 provides access to shared informers for resources in V1beta1. V1beta1() v1beta1.Interface + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1beta1() v1beta1.Interface { return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/flows/v1/interface.go b/pkg/client/informers/externalversions/flows/v1/interface.go new file mode 100644 index 00000000000..96c6ac42e91 --- /dev/null +++ b/pkg/client/informers/externalversions/flows/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Parallels returns a ParallelInformer. + Parallels() ParallelInformer + // Sequences returns a SequenceInformer. + Sequences() SequenceInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Parallels returns a ParallelInformer. +func (v *version) Parallels() ParallelInformer { + return ¶llelInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Sequences returns a SequenceInformer. +func (v *version) Sequences() SequenceInformer { + return &sequenceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/flows/v1/parallel.go b/pkg/client/informers/externalversions/flows/v1/parallel.go new file mode 100644 index 00000000000..d647ea206b1 --- /dev/null +++ b/pkg/client/informers/externalversions/flows/v1/parallel.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/flows/v1" +) + +// ParallelInformer provides access to a shared informer and lister for +// Parallels. +type ParallelInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.ParallelLister +} + +type parallelInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewParallelInformer constructs a new informer for Parallel 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 NewParallelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredParallelInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredParallelInformer constructs a new informer for Parallel 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 NewFilteredParallelInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.FlowsV1().Parallels(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.FlowsV1().Parallels(namespace).Watch(options) + }, + }, + &flowsv1.Parallel{}, + resyncPeriod, + indexers, + ) +} + +func (f *parallelInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredParallelInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *parallelInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&flowsv1.Parallel{}, f.defaultInformer) +} + +func (f *parallelInformer) Lister() v1.ParallelLister { + return v1.NewParallelLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/flows/v1/sequence.go b/pkg/client/informers/externalversions/flows/v1/sequence.go new file mode 100644 index 00000000000..6a03d2a238f --- /dev/null +++ b/pkg/client/informers/externalversions/flows/v1/sequence.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/flows/v1" +) + +// SequenceInformer provides access to a shared informer and lister for +// Sequences. +type SequenceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.SequenceLister +} + +type sequenceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewSequenceInformer constructs a new informer for Sequence 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 NewSequenceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredSequenceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredSequenceInformer constructs a new informer for Sequence 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 NewFilteredSequenceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.FlowsV1().Sequences(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.FlowsV1().Sequences(namespace).Watch(options) + }, + }, + &flowsv1.Sequence{}, + resyncPeriod, + indexers, + ) +} + +func (f *sequenceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredSequenceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *sequenceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&flowsv1.Sequence{}, f.defaultInformer) +} + +func (f *sequenceInformer) Lister() v1.SequenceLister { + return v1.NewSequenceLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 6c7a760bf1e..029ac619b48 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -26,6 +26,7 @@ import ( v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" v1 "knative.dev/eventing/pkg/apis/eventing/v1" v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1 "knative.dev/eventing/pkg/apis/messaging/v1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -77,6 +78,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1beta1.SchemeGroupVersion.WithResource("triggers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1beta1().Triggers().Informer()}, nil + // Group=flows.knative.dev, Version=v1 + case flowsv1.SchemeGroupVersion.WithResource("parallels"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Flows().V1().Parallels().Informer()}, nil + case flowsv1.SchemeGroupVersion.WithResource("sequences"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Flows().V1().Sequences().Informer()}, nil + // Group=flows.knative.dev, Version=v1beta1 case flowsv1beta1.SchemeGroupVersion.WithResource("parallels"): return &genericInformer{resource: resource.GroupResource(), informer: f.Flows().V1beta1().Parallels().Informer()}, nil diff --git a/pkg/client/injection/informers/flows/v1/parallel/fake/fake.go b/pkg/client/injection/informers/flows/v1/parallel/fake/fake.go new file mode 100644 index 00000000000..a48d45380f9 --- /dev/null +++ b/pkg/client/injection/informers/flows/v1/parallel/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + parallel "knative.dev/eventing/pkg/client/injection/informers/flows/v1/parallel" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = parallel.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Flows().V1().Parallels() + return context.WithValue(ctx, parallel.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/flows/v1/parallel/parallel.go b/pkg/client/injection/informers/flows/v1/parallel/parallel.go new file mode 100644 index 00000000000..ad7ab1ee82b --- /dev/null +++ b/pkg/client/injection/informers/flows/v1/parallel/parallel.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package parallel + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/flows/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Flows().V1().Parallels() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.ParallelInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/flows/v1.ParallelInformer from context.") + } + return untyped.(v1.ParallelInformer) +} diff --git a/pkg/client/injection/informers/flows/v1/sequence/fake/fake.go b/pkg/client/injection/informers/flows/v1/sequence/fake/fake.go new file mode 100644 index 00000000000..974372d61c4 --- /dev/null +++ b/pkg/client/injection/informers/flows/v1/sequence/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + sequence "knative.dev/eventing/pkg/client/injection/informers/flows/v1/sequence" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = sequence.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Flows().V1().Sequences() + return context.WithValue(ctx, sequence.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/flows/v1/sequence/sequence.go b/pkg/client/injection/informers/flows/v1/sequence/sequence.go new file mode 100644 index 00000000000..feb0cd29f06 --- /dev/null +++ b/pkg/client/injection/informers/flows/v1/sequence/sequence.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package sequence + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/flows/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Flows().V1().Sequences() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.SequenceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/flows/v1.SequenceInformer from context.") + } + return untyped.(v1.SequenceInformer) +} diff --git a/pkg/client/injection/reconciler/flows/v1/parallel/controller.go b/pkg/client/injection/reconciler/flows/v1/parallel/controller.go new file mode 100644 index 00000000000..20b5f3aab72 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/parallel/controller.go @@ -0,0 +1,139 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package parallel + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + 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" + parallel "knative.dev/eventing/pkg/client/injection/informers/flows/v1/parallel" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +const ( + defaultControllerAgentName = "parallel-controller" + defaultFinalizerName = "parallels.flows.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + parallelInformer := parallel.Get(ctx) + + lister := parallelInformer.Lister() + + 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.Get(ctx), + Lister: lister, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/flows/v1/parallel/reconciler.go b/pkg/client/injection/reconciler/flows/v1/parallel/reconciler.go new file mode 100644 index 00000000000..4a60a9e5178 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/parallel/reconciler.go @@ -0,0 +1,434 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package parallel + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/flows/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + flowsv1 "knative.dev/eventing/pkg/client/listers/flows/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Parallel. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.Parallel. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.Parallel) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Parallel. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.Parallel. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.Parallel) reconciler.Event +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Parallel if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1.Parallel. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1.Parallel) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Parallel if they want to process tombstoned resources +// even when they are not the leader. Due to the nature of how finalizers are handled +// there are no guarantees that this will be called. +type ReadOnlyFinalizer interface { + // ObserveFinalizeKind implements custom logic to observe the final state of v1.Parallel. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1.Parallel) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.Parallel 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 flowsv1.ParallelLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +// 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 flowsv1.ParallelLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + // 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) + } + // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. + + 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 + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + // Establish whether we are the leader for use below. + isLeader := r.IsLeaderFor(types.NamespacedName{ + Namespace: namespace, + Name: name, + }) + roi, isROI := r.reconciler.(ReadOnlyInterface) + rof, isROF := r.reconciler.(ReadOnlyFinalizer) + if !isLeader && !isROI && !isROF { + // If we are not the leader, and we don't implement either ReadOnly + // interface, then take a fast-path out. + return nil + } + + // 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.Parallels(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + if isLeader { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + reconciler.PreProcessReconcile(ctx, resource) + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + reconciler.PostProcessReconcile(ctx, resource, original) + + } else if isROI { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveKind")) + + // Observe any changes to this resource, since we are not the leader. + reconcileEvent = roi.ObserveKind(ctx, resource) + } + } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + } else if !isLeader && isROF { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) + + // For finalizing reconcilers, just observe when we aren't the leader. + reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if !isLeader { + logger.Warn("Saw status changes when we aren't the leader!") + // TODO: Consider logging the diff at Debug? + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.Parallel, desired *v1.Parallel) 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.FlowsV1().Parallels(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.FlowsV1().Parallels(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Parallel) (*v1.Parallel, error) { + + getter := r.Lister.Parallels(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.FlowsV1().Parallels(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Parallel) (*v1.Parallel, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Parallel, reconcileEvent reconciler.Event) (*v1.Parallel, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/flows/v1/parallel/stub/controller.go b/pkg/client/injection/reconciler/flows/v1/parallel/stub/controller.go new file mode 100644 index 00000000000..562b13dc5ca --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/parallel/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package parallel + +import ( + context "context" + + parallel "knative.dev/eventing/pkg/client/injection/informers/flows/v1/parallel" + v1parallel "knative.dev/eventing/pkg/client/injection/reconciler/flows/v1/parallel" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Parallel and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + parallelInformer := parallel.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1parallel.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + parallelInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/flows/v1/parallel/stub/reconciler.go b/pkg/client/injection/reconciler/flows/v1/parallel/stub/reconciler.go new file mode 100644 index 00000000000..bd2155588f5 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/parallel/stub/reconciler.go @@ -0,0 +1,87 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package parallel + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" + parallel "knative.dev/eventing/pkg/client/injection/reconciler/flows/v1/parallel" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason ParallelReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "ParallelReconciled", "Parallel reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Parallel resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ parallel.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ parallel.Finalizer = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ parallel.ReadOnlyInterface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyFinalizer +// Implement this to observe tombstoned resources even when we are not +// the leader (best effort). +//var _ parallel.ReadOnlyFinalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *flowsv1.Parallel) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *flowsv1.Parallel) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} + +// Optionally, use ObserveKind to observe the resource when we are not the leader. +// func (r *Reconciler) ObserveKind(ctx context.Context, o *flowsv1.Parallel) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +// } + +// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. +//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *flowsv1.Parallel) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +//} diff --git a/pkg/client/injection/reconciler/flows/v1/sequence/controller.go b/pkg/client/injection/reconciler/flows/v1/sequence/controller.go new file mode 100644 index 00000000000..252e9d964b1 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/sequence/controller.go @@ -0,0 +1,139 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package sequence + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + 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" + sequence "knative.dev/eventing/pkg/client/injection/informers/flows/v1/sequence" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +const ( + defaultControllerAgentName = "sequence-controller" + defaultFinalizerName = "sequences.flows.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + sequenceInformer := sequence.Get(ctx) + + lister := sequenceInformer.Lister() + + 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.Get(ctx), + Lister: lister, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/flows/v1/sequence/reconciler.go b/pkg/client/injection/reconciler/flows/v1/sequence/reconciler.go new file mode 100644 index 00000000000..cb9c07453a1 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/sequence/reconciler.go @@ -0,0 +1,434 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package sequence + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/flows/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + flowsv1 "knative.dev/eventing/pkg/client/listers/flows/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Sequence. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.Sequence. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.Sequence) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Sequence. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.Sequence. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.Sequence) reconciler.Event +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Sequence if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1.Sequence. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1.Sequence) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Sequence if they want to process tombstoned resources +// even when they are not the leader. Due to the nature of how finalizers are handled +// there are no guarantees that this will be called. +type ReadOnlyFinalizer interface { + // ObserveFinalizeKind implements custom logic to observe the final state of v1.Sequence. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1.Sequence) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.Sequence 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 flowsv1.SequenceLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +// 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 flowsv1.SequenceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + // 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) + } + // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. + + 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 + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // Convert the namespace/name string into a distinct namespace and name + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + // Establish whether we are the leader for use below. + isLeader := r.IsLeaderFor(types.NamespacedName{ + Namespace: namespace, + Name: name, + }) + roi, isROI := r.reconciler.(ReadOnlyInterface) + rof, isROF := r.reconciler.(ReadOnlyFinalizer) + if !isLeader && !isROI && !isROF { + // If we are not the leader, and we don't implement either ReadOnly + // interface, then take a fast-path out. + return nil + } + + // 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.Sequences(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + if isLeader { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + return fmt.Errorf("failed to set finalizers: %w", err) + } + + reconciler.PreProcessReconcile(ctx, resource) + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + reconciler.PostProcessReconcile(ctx, resource, original) + + } else if isROI { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveKind")) + + // Observe any changes to this resource, since we are not the leader. + reconcileEvent = roi.ObserveKind(ctx, resource) + } + } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + return fmt.Errorf("failed to clear finalizers: %w", err) + } + } else if !isLeader && isROF { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) + + // For finalizing reconcilers, just observe when we aren't the leader. + reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if !isLeader { + logger.Warn("Saw status changes when we aren't the leader!") + // TODO: Consider logging the diff at Debug? + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.Sequence, desired *v1.Sequence) 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.FlowsV1().Sequences(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.FlowsV1().Sequences(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Sequence) (*v1.Sequence, error) { + + getter := r.Lister.Sequences(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.FlowsV1().Sequences(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Sequence) (*v1.Sequence, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Sequence, reconcileEvent reconciler.Event) (*v1.Sequence, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/flows/v1/sequence/stub/controller.go b/pkg/client/injection/reconciler/flows/v1/sequence/stub/controller.go new file mode 100644 index 00000000000..516bf046b04 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/sequence/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package sequence + +import ( + context "context" + + sequence "knative.dev/eventing/pkg/client/injection/informers/flows/v1/sequence" + v1sequence "knative.dev/eventing/pkg/client/injection/reconciler/flows/v1/sequence" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Sequence and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + sequenceInformer := sequence.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1sequence.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + sequenceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/flows/v1/sequence/stub/reconciler.go b/pkg/client/injection/reconciler/flows/v1/sequence/stub/reconciler.go new file mode 100644 index 00000000000..c1b0532a7b6 --- /dev/null +++ b/pkg/client/injection/reconciler/flows/v1/sequence/stub/reconciler.go @@ -0,0 +1,87 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package sequence + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + flowsv1 "knative.dev/eventing/pkg/apis/flows/v1" + sequence "knative.dev/eventing/pkg/client/injection/reconciler/flows/v1/sequence" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason SequenceReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "SequenceReconciled", "Sequence reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Sequence resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ sequence.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ sequence.Finalizer = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ sequence.ReadOnlyInterface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyFinalizer +// Implement this to observe tombstoned resources even when we are not +// the leader (best effort). +//var _ sequence.ReadOnlyFinalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *flowsv1.Sequence) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *flowsv1.Sequence) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} + +// Optionally, use ObserveKind to observe the resource when we are not the leader. +// func (r *Reconciler) ObserveKind(ctx context.Context, o *flowsv1.Sequence) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +// } + +// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. +//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *flowsv1.Sequence) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +//} diff --git a/pkg/client/listers/flows/v1/expansion_generated.go b/pkg/client/listers/flows/v1/expansion_generated.go new file mode 100644 index 00000000000..791c076686c --- /dev/null +++ b/pkg/client/listers/flows/v1/expansion_generated.go @@ -0,0 +1,35 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ParallelListerExpansion allows custom methods to be added to +// ParallelLister. +type ParallelListerExpansion interface{} + +// ParallelNamespaceListerExpansion allows custom methods to be added to +// ParallelNamespaceLister. +type ParallelNamespaceListerExpansion interface{} + +// SequenceListerExpansion allows custom methods to be added to +// SequenceLister. +type SequenceListerExpansion interface{} + +// SequenceNamespaceListerExpansion allows custom methods to be added to +// SequenceNamespaceLister. +type SequenceNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/flows/v1/parallel.go b/pkg/client/listers/flows/v1/parallel.go new file mode 100644 index 00000000000..bcf84cec7d8 --- /dev/null +++ b/pkg/client/listers/flows/v1/parallel.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/flows/v1" +) + +// ParallelLister helps list Parallels. +type ParallelLister interface { + // List lists all Parallels in the indexer. + List(selector labels.Selector) (ret []*v1.Parallel, err error) + // Parallels returns an object that can list and get Parallels. + Parallels(namespace string) ParallelNamespaceLister + ParallelListerExpansion +} + +// parallelLister implements the ParallelLister interface. +type parallelLister struct { + indexer cache.Indexer +} + +// NewParallelLister returns a new ParallelLister. +func NewParallelLister(indexer cache.Indexer) ParallelLister { + return ¶llelLister{indexer: indexer} +} + +// List lists all Parallels in the indexer. +func (s *parallelLister) List(selector labels.Selector) (ret []*v1.Parallel, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Parallel)) + }) + return ret, err +} + +// Parallels returns an object that can list and get Parallels. +func (s *parallelLister) Parallels(namespace string) ParallelNamespaceLister { + return parallelNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ParallelNamespaceLister helps list and get Parallels. +type ParallelNamespaceLister interface { + // List lists all Parallels in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Parallel, err error) + // Get retrieves the Parallel from the indexer for a given namespace and name. + Get(name string) (*v1.Parallel, error) + ParallelNamespaceListerExpansion +} + +// parallelNamespaceLister implements the ParallelNamespaceLister +// interface. +type parallelNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Parallels in the indexer for a given namespace. +func (s parallelNamespaceLister) List(selector labels.Selector) (ret []*v1.Parallel, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Parallel)) + }) + return ret, err +} + +// Get retrieves the Parallel from the indexer for a given namespace and name. +func (s parallelNamespaceLister) Get(name string) (*v1.Parallel, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("parallel"), name) + } + return obj.(*v1.Parallel), nil +} diff --git a/pkg/client/listers/flows/v1/sequence.go b/pkg/client/listers/flows/v1/sequence.go new file mode 100644 index 00000000000..e6f126333cc --- /dev/null +++ b/pkg/client/listers/flows/v1/sequence.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/flows/v1" +) + +// SequenceLister helps list Sequences. +type SequenceLister interface { + // List lists all Sequences in the indexer. + List(selector labels.Selector) (ret []*v1.Sequence, err error) + // Sequences returns an object that can list and get Sequences. + Sequences(namespace string) SequenceNamespaceLister + SequenceListerExpansion +} + +// sequenceLister implements the SequenceLister interface. +type sequenceLister struct { + indexer cache.Indexer +} + +// NewSequenceLister returns a new SequenceLister. +func NewSequenceLister(indexer cache.Indexer) SequenceLister { + return &sequenceLister{indexer: indexer} +} + +// List lists all Sequences in the indexer. +func (s *sequenceLister) List(selector labels.Selector) (ret []*v1.Sequence, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Sequence)) + }) + return ret, err +} + +// Sequences returns an object that can list and get Sequences. +func (s *sequenceLister) Sequences(namespace string) SequenceNamespaceLister { + return sequenceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// SequenceNamespaceLister helps list and get Sequences. +type SequenceNamespaceLister interface { + // List lists all Sequences in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Sequence, err error) + // Get retrieves the Sequence from the indexer for a given namespace and name. + Get(name string) (*v1.Sequence, error) + SequenceNamespaceListerExpansion +} + +// sequenceNamespaceLister implements the SequenceNamespaceLister +// interface. +type sequenceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Sequences in the indexer for a given namespace. +func (s sequenceNamespaceLister) List(selector labels.Selector) (ret []*v1.Sequence, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Sequence)) + }) + return ret, err +} + +// Get retrieves the Sequence from the indexer for a given namespace and name. +func (s sequenceNamespaceLister) Get(name string) (*v1.Sequence, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("sequence"), name) + } + return obj.(*v1.Sequence), nil +} From be22d0aa59c3b37faa826d7732b80b5d0f9244ac Mon Sep 17 00:00:00 2001 From: Lionel Villard Date: Thu, 25 Jun 2020 16:34:23 -0400 Subject: [PATCH 2/2] remove krshapedlogic=true --- pkg/apis/flows/v1/parallel_types.go | 1 - pkg/apis/flows/v1/sequence_types.go | 1 - 2 files changed, 2 deletions(-) diff --git a/pkg/apis/flows/v1/parallel_types.go b/pkg/apis/flows/v1/parallel_types.go index 40998d780d1..2dc32963616 100644 --- a/pkg/apis/flows/v1/parallel_types.go +++ b/pkg/apis/flows/v1/parallel_types.go @@ -29,7 +29,6 @@ import ( ) // +genclient -// +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Parallel defines conditional branches that will be wired in // series through Channels and Subscriptions. diff --git a/pkg/apis/flows/v1/sequence_types.go b/pkg/apis/flows/v1/sequence_types.go index e287f61fffa..df7b71c9e8f 100644 --- a/pkg/apis/flows/v1/sequence_types.go +++ b/pkg/apis/flows/v1/sequence_types.go @@ -30,7 +30,6 @@ import ( ) // +genclient -// +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Sequence defines a sequence of Subscribers that will be wired in // series through Channels and Subscriptions.