From 0c2a84d52068014ad1a6b3fcc707844f2742e514 Mon Sep 17 00:00:00 2001 From: Ville Aikas Date: Thu, 18 Jun 2020 11:52:00 -0700 Subject: [PATCH 1/6] new types, codegen --- hack/update-codegen.sh | 4 +- pkg/apis/eventing/v1/broker_conversion.go | 34 ++ .../eventing/v1/broker_conversion_test.go | 34 ++ pkg/apis/eventing/v1/broker_defaults.go | 47 ++ pkg/apis/eventing/v1/broker_defaults_test.go | 249 ++++++++++ pkg/apis/eventing/v1/broker_lifecycle.go | 114 +++++ pkg/apis/eventing/v1/broker_lifecycle_test.go | 341 +++++++++++++ pkg/apis/eventing/v1/broker_types.go | 119 +++++ pkg/apis/eventing/v1/broker_types_test.go | 36 ++ pkg/apis/eventing/v1/broker_validation.go | 76 +++ .../eventing/v1/broker_validation_test.go | 205 ++++++++ pkg/apis/eventing/v1/doc.go | 20 + pkg/apis/eventing/v1/eventtype_conversion.go | 34 ++ .../eventing/v1/eventtype_conversion_test.go | 34 ++ pkg/apis/eventing/v1/eventtype_defaults.go | 29 ++ .../eventing/v1/eventtype_defaults_test.go | 87 ++++ pkg/apis/eventing/v1/eventtype_lifecycle.go | 103 ++++ .../eventing/v1/eventtype_lifecycle_test.go | 257 ++++++++++ pkg/apis/eventing/v1/eventtype_types.go | 119 +++++ pkg/apis/eventing/v1/eventtype_types_test.go | 39 ++ pkg/apis/eventing/v1/eventtype_validation.go | 62 +++ .../eventing/v1/eventtype_validation_test.go | 258 ++++++++++ pkg/apis/eventing/v1/register.go | 57 +++ pkg/apis/eventing/v1/test_helper.go | 122 +++++ pkg/apis/eventing/v1/trigger_conversion.go | 34 ++ .../eventing/v1/trigger_conversion_test.go | 34 ++ pkg/apis/eventing/v1/trigger_defaults.go | 52 ++ pkg/apis/eventing/v1/trigger_defaults_test.go | 122 +++++ pkg/apis/eventing/v1/trigger_lifecycle.go | 187 ++++++++ .../eventing/v1/trigger_lifecycle_test.go | 360 ++++++++++++++ pkg/apis/eventing/v1/trigger_types.go | 129 +++++ pkg/apis/eventing/v1/trigger_types_test.go | 37 ++ pkg/apis/eventing/v1/trigger_validation.go | 155 ++++++ .../eventing/v1/trigger_validation_test.go | 450 ++++++++++++++++++ pkg/apis/eventing/v1/zz_generated.deepcopy.go | 387 +++++++++++++++ pkg/client/clientset/versioned/clientset.go | 14 + .../versioned/fake/clientset_generated.go | 7 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/register.go | 2 + .../versioned/typed/eventing/v1/broker.go | 191 ++++++++ .../versioned/typed/eventing/v1/doc.go | 20 + .../typed/eventing/v1/eventing_client.go | 99 ++++ .../versioned/typed/eventing/v1/eventtype.go | 191 ++++++++ .../versioned/typed/eventing/v1/fake/doc.go | 20 + .../typed/eventing/v1/fake/fake_broker.go | 140 ++++++ .../eventing/v1/fake/fake_eventing_client.go | 48 ++ .../typed/eventing/v1/fake/fake_eventtype.go | 140 ++++++ .../typed/eventing/v1/fake/fake_trigger.go | 140 ++++++ .../typed/eventing/v1/generated_expansion.go | 25 + .../versioned/typed/eventing/v1/trigger.go | 191 ++++++++ .../externalversions/eventing/interface.go | 8 + .../externalversions/eventing/v1/broker.go | 89 ++++ .../externalversions/eventing/v1/eventtype.go | 89 ++++ .../externalversions/eventing/v1/interface.go | 59 +++ .../externalversions/eventing/v1/trigger.go | 89 ++++ .../informers/externalversions/generic.go | 9 + .../informers/eventing/v1/broker/broker.go | 52 ++ .../informers/eventing/v1/broker/fake/fake.go | 40 ++ .../eventing/v1/eventtype/eventtype.go | 52 ++ .../eventing/v1/eventtype/fake/fake.go | 40 ++ .../eventing/v1/trigger/fake/fake.go | 40 ++ .../informers/eventing/v1/trigger/trigger.go | 52 ++ .../eventing/v1/broker/controller.go | 122 +++++ .../eventing/v1/broker/reconciler.go | 368 ++++++++++++++ .../eventing/v1/broker/stub/controller.go | 63 +++ .../eventing/v1/broker/stub/reconciler.go | 66 +++ .../eventing/v1/eventtype/controller.go | 118 +++++ .../eventing/v1/eventtype/reconciler.go | 357 ++++++++++++++ .../eventing/v1/eventtype/stub/controller.go | 54 +++ .../eventing/v1/eventtype/stub/reconciler.go | 66 +++ pkg/client/listers/eventing/v1/broker.go | 94 ++++ pkg/client/listers/eventing/v1/eventtype.go | 94 ++++ .../eventing/v1/expansion_generated.go | 43 ++ pkg/client/listers/eventing/v1/trigger.go | 94 ++++ 74 files changed, 7813 insertions(+), 2 deletions(-) create mode 100644 pkg/apis/eventing/v1/broker_conversion.go create mode 100644 pkg/apis/eventing/v1/broker_conversion_test.go create mode 100644 pkg/apis/eventing/v1/broker_defaults.go create mode 100644 pkg/apis/eventing/v1/broker_defaults_test.go create mode 100644 pkg/apis/eventing/v1/broker_lifecycle.go create mode 100644 pkg/apis/eventing/v1/broker_lifecycle_test.go create mode 100644 pkg/apis/eventing/v1/broker_types.go create mode 100644 pkg/apis/eventing/v1/broker_types_test.go create mode 100644 pkg/apis/eventing/v1/broker_validation.go create mode 100644 pkg/apis/eventing/v1/broker_validation_test.go create mode 100644 pkg/apis/eventing/v1/doc.go create mode 100644 pkg/apis/eventing/v1/eventtype_conversion.go create mode 100644 pkg/apis/eventing/v1/eventtype_conversion_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_defaults.go create mode 100644 pkg/apis/eventing/v1/eventtype_defaults_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_lifecycle.go create mode 100644 pkg/apis/eventing/v1/eventtype_lifecycle_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_types.go create mode 100644 pkg/apis/eventing/v1/eventtype_types_test.go create mode 100644 pkg/apis/eventing/v1/eventtype_validation.go create mode 100644 pkg/apis/eventing/v1/eventtype_validation_test.go create mode 100644 pkg/apis/eventing/v1/register.go create mode 100644 pkg/apis/eventing/v1/test_helper.go create mode 100644 pkg/apis/eventing/v1/trigger_conversion.go create mode 100644 pkg/apis/eventing/v1/trigger_conversion_test.go create mode 100644 pkg/apis/eventing/v1/trigger_defaults.go create mode 100644 pkg/apis/eventing/v1/trigger_defaults_test.go create mode 100644 pkg/apis/eventing/v1/trigger_lifecycle.go create mode 100644 pkg/apis/eventing/v1/trigger_lifecycle_test.go create mode 100644 pkg/apis/eventing/v1/trigger_types.go create mode 100644 pkg/apis/eventing/v1/trigger_types_test.go create mode 100644 pkg/apis/eventing/v1/trigger_validation.go create mode 100644 pkg/apis/eventing/v1/trigger_validation_test.go create mode 100644 pkg/apis/eventing/v1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/broker.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go create mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/trigger.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/broker.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/eventtype.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/interface.go create mode 100644 pkg/client/informers/externalversions/eventing/v1/trigger.go create mode 100644 pkg/client/injection/informers/eventing/v1/broker/broker.go create mode 100644 pkg/client/injection/informers/eventing/v1/broker/fake/fake.go create mode 100644 pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go create mode 100644 pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go create mode 100644 pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go create mode 100644 pkg/client/injection/informers/eventing/v1/trigger/trigger.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go create mode 100644 pkg/client/listers/eventing/v1/broker.go create mode 100644 pkg/client/listers/eventing/v1/eventtype.go create mode 100644 pkg/client/listers/eventing/v1/expansion_generated.go create mode 100644 pkg/client/listers/eventing/v1/trigger.go diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 50d7b7c174d..2c2567cf168 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -45,7 +45,7 @@ chmod +x ${CODEGEN_PKG}/generate-groups.sh # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Deep copy config @@ -65,7 +65,7 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ chmod +x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1beta1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/eventing/v1/broker_conversion.go b/pkg/apis/eventing/v1/broker_conversion.go new file mode 100644 index 00000000000..0f7d820ed94 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/eventing/v1/broker_conversion_test.go b/pkg/apis/eventing/v1/broker_conversion_test.go new file mode 100644 index 00000000000..311c51fdf9c --- /dev/null +++ b/pkg/apis/eventing/v1/broker_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" +) + +func TestBrokerConversionBadType(t *testing.T) { + good, bad := &Broker{}, &Broker{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/eventing/v1/broker_defaults.go b/pkg/apis/eventing/v1/broker_defaults.go new file mode 100644 index 00000000000..2ae42be8e7e --- /dev/null +++ b/pkg/apis/eventing/v1/broker_defaults.go @@ -0,0 +1,47 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + "knative.dev/eventing/pkg/apis/config" + "knative.dev/eventing/pkg/apis/eventing" + "knative.dev/pkg/apis" +) + +func (b *Broker) SetDefaults(ctx context.Context) { + // Default Spec fields. + withNS := apis.WithinParent(ctx, b.ObjectMeta) + b.Spec.SetDefaults(withNS) + eventing.DefaultBrokerClassIfUnset(withNS, &b.ObjectMeta) +} + +func (bs *BrokerSpec) SetDefaults(ctx context.Context) { + if bs.Config != nil { + // Default the namespace if not given + bs.Config.SetDefaults(ctx) + return + } + + cfg := config.FromContextOrDefaults(ctx) + c, err := cfg.Defaults.GetBrokerConfig(apis.ParentMeta(ctx).Namespace) + if err == nil { + c.SetDefaults(ctx) + bs.Config = c + } +} diff --git a/pkg/apis/eventing/v1/broker_defaults_test.go b/pkg/apis/eventing/v1/broker_defaults_test.go new file mode 100644 index 00000000000..1d87225851e --- /dev/null +++ b/pkg/apis/eventing/v1/broker_defaults_test.go @@ -0,0 +1,249 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "knative.dev/eventing/pkg/apis/config" + "knative.dev/eventing/pkg/apis/eventing" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + defaultConfig = &config.Config{ + Defaults: &config.Defaults{ + // NamespaceDefaultsConfig are the default Broker Configs for each namespace. + // Namespace is the key, the value is the KReference to the config. + NamespaceDefaultsConfig: map[string]*config.ClassAndKRef{ + "mynamespace": { + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "kafka-channel", + }, + }, + "mynamespace2": { + BrokerClass: "mynamespace2class", + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "natss-channel", + }, + }, + "mynamespace3": { + BrokerClass: "mynamespace3class", + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Name: "natss-channel", + }, + }, + }, + ClusterDefault: &config.ClassAndKRef{ + BrokerClass: eventing.MTChannelBrokerClassValue, + KReference: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + } +) + +func TestBrokerSetDefaults(t *testing.T) { + testCases := map[string]struct { + initial Broker + expected Broker + }{ + "default everything from cluster": { + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + }, + "default annotation from cluster": { + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + initial: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: "v1", + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "imc-channel", + }, + }, + }, + }, + "config already specified, adds annotation": { + initial: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + APIVersion: SchemeGroupVersion.String(), + Kind: "OtherChannel", + }, + }, + }, + }, + "no config, uses namespace broker config, cluster class": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Namespace: "mynamespace"}, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "mynamespace", + Annotations: map[string]string{ + eventing.BrokerClassKey: eventing.MTChannelBrokerClassValue, + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "kafka-channel", + APIVersion: "v1", + }, + }, + }, + }, + "no config, uses namespace broker config, defaults namespace, cluster class": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Namespace: "mynamespace3"}, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "mynamespace3", + Annotations: map[string]string{ + eventing.BrokerClassKey: "mynamespace3class", + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "mynamespace3", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + }, + "no config, uses namespace broker config and class": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Namespace: "mynamespace2"}, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "mynamespace2", + Annotations: map[string]string{ + eventing.BrokerClassKey: "mynamespace2class", + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "knative-eventing", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + }, + "config, missing namespace, defaulted": { + initial: Broker{ + ObjectMeta: metav1.ObjectMeta{Name: "rando", Namespace: "randons"}, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + expected: Broker{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rando", + Namespace: "randons", + Annotations: map[string]string{ + eventing.BrokerClassKey: "MTChannelBasedBroker", + }, + }, + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Kind: "ConfigMap", + Namespace: "randons", + Name: "natss-channel", + APIVersion: "v1", + }, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(config.ToContext(context.Background(), defaultConfig)) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/broker_lifecycle.go b/pkg/apis/eventing/v1/broker_lifecycle.go new file mode 100644 index 00000000000..92972d09992 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_lifecycle.go @@ -0,0 +1,114 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + + "knative.dev/eventing/pkg/apis/duck" + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" +) + +var brokerCondSet = apis.NewLivingConditionSet( + BrokerConditionIngress, + BrokerConditionTriggerChannel, + BrokerConditionFilter, + BrokerConditionAddressable, +) + +const ( + BrokerConditionReady = apis.ConditionReady + BrokerConditionIngress apis.ConditionType = "IngressReady" + BrokerConditionTriggerChannel apis.ConditionType = "TriggerChannelReady" + BrokerConditionFilter apis.ConditionType = "FilterReady" + BrokerConditionAddressable apis.ConditionType = "Addressable" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Broker) GetConditionSet() apis.ConditionSet { + return brokerCondSet +} + +// GetTopLevelCondition returns the top level Condition. +func (bs *BrokerStatus) GetTopLevelCondition() *apis.Condition { + return brokerCondSet.Manage(bs).GetTopLevelCondition() +} + +// SetAddress makes this Broker addressable by setting the URI. It also +// sets the BrokerConditionAddressable to true. +func (bs *BrokerStatus) SetAddress(url *apis.URL) { + bs.Address.URL = url + if url != nil { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionAddressable) + } else { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionAddressable, "nil URL", "URL is nil") + } +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (bs *BrokerStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return brokerCondSet.Manage(bs).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (bs *BrokerStatus) IsReady() bool { + return brokerCondSet.Manage(bs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (bs *BrokerStatus) InitializeConditions() { + brokerCondSet.Manage(bs).InitializeConditions() +} + +func (bs *BrokerStatus) MarkIngressFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionIngress, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateIngressAvailability(ep *corev1.Endpoints) { + if duck.EndpointsAreAvailable(ep) { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionIngress) + } else { + bs.MarkIngressFailed("EndpointsUnavailable", "Endpoints %q are unavailable.", ep.Name) + } +} + +func (bs *BrokerStatus) MarkTriggerChannelFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionTriggerChannel, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *duckv1beta1.ChannelableStatus) { + // TODO: Once you can get a Ready status from Channelable in a generic way, use it here... + address := cs.AddressStatus.Address + if address != nil { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionTriggerChannel) + } else { + bs.MarkTriggerChannelFailed("ChannelNotReady", "trigger Channel is not ready: not addressable") + } +} + +func (bs *BrokerStatus) MarkFilterFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionFilter, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateFilterAvailability(ep *corev1.Endpoints) { + if duck.EndpointsAreAvailable(ep) { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionFilter) + } else { + bs.MarkFilterFailed("EndpointsUnavailable", "Endpoints %q are unavailable.", ep.Name) + } +} diff --git a/pkg/apis/eventing/v1/broker_lifecycle_test.go b/pkg/apis/eventing/v1/broker_lifecycle_test.go new file mode 100644 index 00000000000..9265a4f86ce --- /dev/null +++ b/pkg/apis/eventing/v1/broker_lifecycle_test.go @@ -0,0 +1,341 @@ +/* +Copyright 2020 The Knative Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + trueVal = true + falseVal = false +) + +var ( + brokerConditionReady = apis.Condition{ + Type: BrokerConditionReady, + Status: corev1.ConditionTrue, + } + + brokerConditionIngress = apis.Condition{ + Type: BrokerConditionIngress, + Status: corev1.ConditionTrue, + } + + brokerConditionTriggerChannel = apis.Condition{ + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionTrue, + } + + brokerConditionFilter = apis.Condition{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + } + + brokerConditionAddressable = apis.Condition{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionFalse, + } +) + +func TestBrokerGetCondition(t *testing.T) { + tests := []struct { + name string + bs *BrokerStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &brokerConditionReady, + }, { + name: "multiple conditions", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionIngress, + brokerConditionTriggerChannel, + brokerConditionFilter, + }, + }, + }, + condQuery: BrokerConditionFilter, + want: &brokerConditionFilter, + }, { + name: "multiple conditions, condition false", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionTriggerChannel, + brokerConditionFilter, + brokerConditionAddressable, + }, + }, + }, + condQuery: BrokerConditionAddressable, + want: &brokerConditionAddressable, + }, { + name: "unknown condition", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + brokerConditionAddressable, + brokerConditionReady, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.bs.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestBrokerInitializeConditions(t *testing.T) { + tests := []struct { + name string + bs *BrokerStatus + want *BrokerStatus + }{{ + name: "empty", + bs: &BrokerStatus{}, + want: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one false", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionFalse, + }}, + }, + }, + }, { + name: "one true", + bs: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &BrokerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: BrokerConditionAddressable, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionFilter, + Status: corev1.ConditionTrue, + }, { + Type: BrokerConditionIngress, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: BrokerConditionTriggerChannel, + Status: corev1.ConditionUnknown, + }}, + }, + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.bs.InitializeConditions() + if diff := cmp.Diff(test.want, test.bs, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestBrokerIsReady(t *testing.T) { + tests := []struct { + name string + markIngressReady *bool + markTriggerChannelReady *bool + markFilterReady *bool + address *apis.URL + markIngressSubscriptionOwned bool + markIngressSubscriptionReady *bool + wantReady bool + }{{ + name: "all happy", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: true, + }, { + name: "all happy - deprecated", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: true, + }, { + name: "ingress sad", + markIngressReady: &falseVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "trigger channel sad", + markIngressReady: &trueVal, + markTriggerChannelReady: &falseVal, + markFilterReady: &trueVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "filter sad", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &falseVal, + address: &apis.URL{Scheme: "http", Host: "hostname"}, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "addressable sad", + markIngressReady: &trueVal, + markTriggerChannelReady: &trueVal, + markFilterReady: &trueVal, + address: nil, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &trueVal, + wantReady: false, + }, { + name: "all sad", + markIngressReady: &falseVal, + markTriggerChannelReady: &falseVal, + markFilterReady: &falseVal, + address: nil, + markIngressSubscriptionOwned: true, + markIngressSubscriptionReady: &falseVal, + wantReady: false, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + bs := &BrokerStatus{} + if test.markIngressReady != nil { + var ep *corev1.Endpoints + if *test.markIngressReady { + ep = TestHelper.AvailableEndpoints() + } else { + ep = TestHelper.UnavailableEndpoints() + } + bs.PropagateIngressAvailability(ep) + } + if test.markTriggerChannelReady != nil { + var c *duckv1beta1.ChannelableStatus + if *test.markTriggerChannelReady { + c = TestHelper.ReadyChannelStatus() + } else { + c = TestHelper.NotReadyChannelStatus() + } + bs.PropagateTriggerChannelReadiness(c) + } + if test.markFilterReady != nil { + var ep *corev1.Endpoints + if *test.markFilterReady { + ep = TestHelper.AvailableEndpoints() + } else { + ep = TestHelper.UnavailableEndpoints() + } + bs.PropagateFilterAvailability(ep) + } + bs.SetAddress(test.address) + + got := bs.IsReady() + if test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + + }) + } +} diff --git a/pkg/apis/eventing/v1/broker_types.go b/pkg/apis/eventing/v1/broker_types.go new file mode 100644 index 00000000000..d740928e51c --- /dev/null +++ b/pkg/apis/eventing/v1/broker_types.go @@ -0,0 +1,119 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:class=eventing.knative.dev/broker.class,krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Broker collects a pool of events that are consumable using Triggers. Brokers +// provide a well-known endpoint for event delivery that senders can use with +// minimal knowledge of the event routing strategy. Receivers use Triggers to +// request delivery of events from a Broker's pool to a specific URL or +// Addressable endpoint. +type Broker struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Broker. + Spec BrokerSpec `json:"spec,omitempty"` + + // Status represents the current state of the Broker. This data may be out of + // date. + // +optional + Status BrokerStatus `json:"status,omitempty"` +} + +var ( + // Check that Broker can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Broker)(nil) + _ apis.Defaultable = (*Broker)(nil) + + // Check that Broker can return its spec untyped. + _ apis.HasSpec = (*Broker)(nil) + + _ runtime.Object = (*Broker)(nil) + + // Check that we can create OwnerReferences to a Broker. + _ kmeta.OwnerRefable = (*Broker)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Broker)(nil) +) + +type BrokerSpec struct { + // Config is a KReference to the configuration that specifies + // configuration options for this Broker. For example, this could be + // a pointer to a ConfigMap. + // +optional + Config *duckv1.KReference `json:"config,omitempty"` + + // Delivery is the delivery specification for Events within the Broker mesh. + // This includes things like retries, DLQ, etc. + // +optional + Delivery *eventingduckv1beta1.DeliverySpec `json:"delivery,omitempty"` +} + +// BrokerStatus represents the current state of a Broker. +type BrokerStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Broker that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // Broker is Addressable. It exposes the endpoint as an URI to get events + // delivered into the Broker mesh. + Address duckv1.Addressable `json:"address,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// BrokerList is a collection of Brokers. +type BrokerList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []Broker `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for Brokers +func (t *Broker) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Broker") +} + +// GetUntypedSpec returns the spec of the Broker. +func (b *Broker) GetUntypedSpec() interface{} { + return b.Spec +} + +// GetStatus retrieves the status of the Broker. Implements the KRShaped interface. +func (t *Broker) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/eventing/v1/broker_types_test.go b/pkg/apis/eventing/v1/broker_types_test.go new file mode 100644 index 00000000000..ce6334cb02c --- /dev/null +++ b/pkg/apis/eventing/v1/broker_types_test.go @@ -0,0 +1,36 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import "testing" + +func TestBrokerGetStatus(t *testing.T) { + r := &Broker{ + Status: BrokerStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestBroker_GetGroupVersionKind(t *testing.T) { + b := Broker{} + gvk := b.GetGroupVersionKind() + if gvk.Kind != "Broker" { + t.Errorf("Should be Broker.") + } +} diff --git a/pkg/apis/eventing/v1/broker_validation.go b/pkg/apis/eventing/v1/broker_validation.go new file mode 100644 index 00000000000..e7e0e8a3c46 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_validation.go @@ -0,0 +1,76 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +const ( + BrokerClassAnnotationKey = "eventing.knative.dev/broker.class" +) + +func (b *Broker) Validate(ctx context.Context) *apis.FieldError { + withNS := apis.AllowDifferentNamespace(apis.WithinParent(ctx, b.ObjectMeta)) + return b.Spec.Validate(withNS).ViaField("spec") +} + +func (bs *BrokerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + // Validate the Config + if bs.Config != nil { + if ce := bs.Config.Validate(ctx); ce != nil { + errs = errs.Also(ce.ViaField("config")) + } + } + + if bs.Delivery != nil { + if de := bs.Delivery.Validate(ctx); de != nil { + errs = errs.Also(de.ViaField("delivery")) + } + } + return errs +} + +func (b *Broker) CheckImmutableFields(ctx context.Context, original *Broker) *apis.FieldError { + if original == nil { + return nil + } + + // Make sure you can't change the class annotation. + diff, err := kmp.ShortDiff(original.GetAnnotations()[BrokerClassAnnotationKey], b.GetAnnotations()[BrokerClassAnnotationKey]) + + if err != nil { + return &apis.FieldError{ + Message: "couldn't diff the Broker objects", + Details: err.Error(), + } + } + + if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"annotations"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1/broker_validation_test.go b/pkg/apis/eventing/v1/broker_validation_test.go new file mode 100644 index 00000000000..75535127f33 --- /dev/null +++ b/pkg/apis/eventing/v1/broker_validation_test.go @@ -0,0 +1,205 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +func TestBrokerImmutableFields(t *testing.T) { + original := &Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"eventing.knative.dev/broker.class": "original"}, + }, + } + current := &Broker{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"eventing.knative.dev/broker.class": "current"}, + }, + } + + tests := map[string]struct { + og *Broker + wantErr *apis.FieldError + }{ + "nil original": { + wantErr: nil, + }, + "no ChannelTemplateSpec mutation": { + og: current, + wantErr: nil, + }, + "ChannelTemplateSpec mutated": { + og: original, + wantErr: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"annotations"}, + Details: `{string}: + -: "original" + +: "current" +`, + }, + }, + } + + for n, test := range tests { + t.Run(n, func(t *testing.T) { + gotErr := current.CheckImmutableFields(context.Background(), test.og) + if diff := cmp.Diff(test.wantErr.Error(), gotErr.Error()); diff != "" { + t.Errorf("Broker.CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} + +func TestValidate(t *testing.T) { + invalidString := "invalid time" + tests := []struct { + name string + b Broker + want *apis.FieldError + }{{ + name: "valid empty", + b: Broker{}, + }, { + name: "valid config", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, + }, { + name: "valid config, no namespace", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, + }, { + name: "invalid config, missing name", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, + want: apis.ErrMissingField("spec.config.name"), + }, { + name: "invalid config, missing apiVersion", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + }, + }, + }, + want: apis.ErrMissingField("spec.config.apiVersion"), + }, { + name: "invalid config, missing kind", + b: Broker{ + Spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + APIVersion: "apiversion", + }, + }, + }, + want: apis.ErrMissingField("spec.config.kind"), + }, { + name: "invalid delivery, invalid delay string", + b: Broker{ + Spec: BrokerSpec{ + Delivery: &eventingduckv1beta1.DeliverySpec{ + BackoffDelay: &invalidString, + }, + }, + }, + want: apis.ErrInvalidValue(invalidString, "spec.delivery.backoffDelay"), + }, {}} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.b.Validate(context.Background()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("BrokerSpec.Validate (-want, +got) = %v", diff) + } + }) + } +} + +func TestValidSpec(t *testing.T) { + bop := eventingduckv1beta1.BackoffPolicyExponential + tests := []struct { + name string + spec BrokerSpec + want *apis.FieldError + }{{ + name: "valid empty", + spec: BrokerSpec{}, + }, { + name: "valid config", + spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + }, + }, { + name: "valid delivery", + spec: BrokerSpec{ + Config: &duckv1.KReference{ + Namespace: "namespace", + Name: "name", + Kind: "kind", + APIVersion: "apiversion", + }, + Delivery: &eventingduckv1beta1.DeliverySpec{BackoffPolicy: &bop}, + }, + }, {}} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.spec.Validate(context.Background()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("BrokerSpec.Validate (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/doc.go b/pkg/apis/eventing/v1/doc.go new file mode 100644 index 00000000000..6de34688b38 --- /dev/null +++ b/pkg/apis/eventing/v1/doc.go @@ -0,0 +1,20 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1beta1 is the v1beta1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=eventing.knative.dev +package v1 diff --git a/pkg/apis/eventing/v1/eventtype_conversion.go b/pkg/apis/eventing/v1/eventtype_conversion.go new file mode 100644 index 00000000000..3b36fca9774 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/eventing/v1/eventtype_conversion_test.go b/pkg/apis/eventing/v1/eventtype_conversion_test.go new file mode 100644 index 00000000000..39145489459 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" +) + +func TestEventTypeConversionBadType(t *testing.T) { + good, bad := &EventType{}, &EventType{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_defaults.go b/pkg/apis/eventing/v1/eventtype_defaults.go new file mode 100644 index 00000000000..fa02a0d929c --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_defaults.go @@ -0,0 +1,29 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import "context" + +func (et *EventType) SetDefaults(ctx context.Context) { + et.Spec.SetDefaults(ctx) +} + +func (ets *EventTypeSpec) SetDefaults(ctx context.Context) { + if ets.Broker == "" { + ets.Broker = "default" + } +} diff --git a/pkg/apis/eventing/v1/eventtype_defaults_test.go b/pkg/apis/eventing/v1/eventtype_defaults_test.go new file mode 100644 index 00000000000..3f73f59bf11 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_defaults_test.go @@ -0,0 +1,87 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + "knative.dev/pkg/apis" +) + +func TestEventTypeDefaults(t *testing.T) { + testSource := apis.HTTP("test-source") + testSchema := apis.HTTP("test-schema") + testCases := map[string]struct { + initial EventType + expected EventType + }{ + "nil spec": { + initial: EventType{}, + expected: EventType{ + Spec: EventTypeSpec{ + Broker: "default", + }, + }, + }, + "broker empty": { + initial: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "", + Schema: testSchema, + }, + }, + expected: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "default", + Schema: testSchema, + }, + }, + }, + "broker not set": { + initial: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Schema: testSchema, + }, + }, + expected: EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "default", + Schema: testSchema, + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.TODO()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_lifecycle.go b/pkg/apis/eventing/v1/eventtype_lifecycle.go new file mode 100644 index 00000000000..50f9758563b --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_lifecycle.go @@ -0,0 +1,103 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + + "knative.dev/pkg/apis" +) + +var eventTypeCondSet = apis.NewLivingConditionSet(EventTypeConditionBrokerExists, EventTypeConditionBrokerReady) + +const ( + EventTypeConditionReady = apis.ConditionReady + EventTypeConditionBrokerExists apis.ConditionType = "BrokerExists" + EventTypeConditionBrokerReady apis.ConditionType = "BrokerReady" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*EventType) GetConditionSet() apis.ConditionSet { + return eventTypeCondSet +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (et *EventTypeStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return eventTypeCondSet.Manage(et).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (et *EventTypeStatus) IsReady() bool { + return eventTypeCondSet.Manage(et).IsHappy() +} + +// GetTopLevelCondition returns the top level Condition. +func (et *EventTypeStatus) GetTopLevelCondition() *apis.Condition { + return eventTypeCondSet.Manage(et).GetTopLevelCondition() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (et *EventTypeStatus) InitializeConditions() { + eventTypeCondSet.Manage(et).InitializeConditions() +} + +func (et *EventTypeStatus) MarkBrokerExists() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerExists) +} + +func (et *EventTypeStatus) MarkBrokerDoesNotExist() { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerExists, "BrokerDoesNotExist", "Broker does not exist") +} + +func (et *EventTypeStatus) MarkBrokerExistsUnknown(reason, messageFormat string, messageA ...interface{}) { + eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerExists, reason, messageFormat, messageA...) +} + +func (et *EventTypeStatus) MarkBrokerReady() { + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) +} + +func (et *EventTypeStatus) MarkBrokerFailed(reason, messageFormat string, messageA ...interface{}) { + eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, reason, messageFormat, messageA...) +} + +func (et *EventTypeStatus) MarkBrokerUnknown(reason, messageFormat string, messageA ...interface{}) { + eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerReady, reason, messageFormat, messageA...) +} + +func (et *EventTypeStatus) MarkBrokerNotConfigured() { + eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerReady, + "BrokerNotConfigured", "Broker has not yet been reconciled.") +} + +func (et *EventTypeStatus) PropagateBrokerStatus(bs *BrokerStatus) { + bc := brokerCondSet.Manage(bs).GetTopLevelCondition() + if bc == nil { + et.MarkBrokerNotConfigured() + return + } + switch { + case bc.Status == corev1.ConditionUnknown: + et.MarkBrokerUnknown(bc.Reason, bc.Message) + case bc.Status == corev1.ConditionTrue: + eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) + case bc.Status == corev1.ConditionFalse: + et.MarkBrokerFailed(bc.Reason, bc.Message) + default: + et.MarkBrokerUnknown("BrokerUnknown", "The status of Broker is invalid: %v", bc.Status) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_lifecycle_test.go b/pkg/apis/eventing/v1/eventtype_lifecycle_test.go new file mode 100644 index 00000000000..426c08d1aec --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_lifecycle_test.go @@ -0,0 +1,257 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + trueValue = true + falseValue = false +) + +var ( + eventTypeConditionReady = apis.Condition{ + Type: EventTypeConditionReady, + Status: corev1.ConditionTrue, + } + + eventTypeConditionBrokerExists = apis.Condition{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionTrue, + } + + eventTypeConditionBrokerReady = apis.Condition{ + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + } +) + +func TestEventTypeGetConditionSet(t *testing.T) { + r := &EventType{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestEventTypeGetCondition(t *testing.T) { + tests := []struct { + name string + ets *EventTypeStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &eventTypeConditionReady, + }, { + name: "broker exists condition", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionBrokerExists, + }, + }, + }, + condQuery: EventTypeConditionBrokerExists, + want: &eventTypeConditionBrokerExists, + }, { + name: "multiple conditions, condition true", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionBrokerExists, + eventTypeConditionBrokerReady, + }, + }, + }, + condQuery: EventTypeConditionBrokerReady, + want: &eventTypeConditionBrokerReady, + }, { + name: "unknown condition", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + eventTypeConditionBrokerReady, + eventTypeConditionReady, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ets.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestEventTypeInitializeConditions(t *testing.T) { + tests := []struct { + name string + ets *EventTypeStatus + want *EventTypeStatus + }{{ + name: "empty", + ets: &EventTypeStatus{}, + want: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one false", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionFalse, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + ets: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &EventTypeStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: EventTypeConditionBrokerExists, + Status: corev1.ConditionUnknown, + }, { + Type: EventTypeConditionBrokerReady, + Status: corev1.ConditionTrue, + }, { + Type: EventTypeConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ets.InitializeConditions() + if diff := cmp.Diff(test.want, test.ets, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestEventTypeConditionStatus(t *testing.T) { + tests := []struct { + name string + markBrokerExists *bool + brokerStatus *BrokerStatus + wantConditionStatus corev1.ConditionStatus + }{{ + name: "all happy", + markBrokerExists: &trueValue, + brokerStatus: TestHelper.ReadyBrokerStatus(), + wantConditionStatus: corev1.ConditionTrue, + }, { + name: "broker exist sad", + markBrokerExists: &falseValue, + brokerStatus: nil, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "broker ready sad", + markBrokerExists: &trueValue, + brokerStatus: TestHelper.FalseBrokerStatus(), + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "broker ready unknown", + markBrokerExists: &trueValue, + brokerStatus: TestHelper.UnknownBrokerStatus(), + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "all sad", + markBrokerExists: &falseValue, + brokerStatus: nil, + wantConditionStatus: corev1.ConditionFalse, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ets := &EventTypeStatus{} + if test.markBrokerExists != nil { + if *test.markBrokerExists { + ets.MarkBrokerExists() + } else { + ets.MarkBrokerDoesNotExist() + } + } + if test.brokerStatus != nil { + ets.PropagateBrokerStatus(test.brokerStatus) + } + + got := ets.GetTopLevelCondition().Status + if test.wantConditionStatus != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantConditionStatus, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/eventtype_types.go b/pkg/apis/eventing/v1/eventtype_types.go new file mode 100644 index 00000000000..8686872fb01 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_types.go @@ -0,0 +1,119 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type EventType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the EventType. + Spec EventTypeSpec `json:"spec,omitempty"` + + // Status represents the current state of the EventType. + // This data may be out of date. + // +optional + // TODO might be removed https://github.com/knative/eventing/issues/2750 + Status EventTypeStatus `json:"status,omitempty"` +} + +var ( + // Check that EventType can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*EventType)(nil) + _ apis.Defaultable = (*EventType)(nil) + + // Check that EventType can return its spec untyped. + _ apis.HasSpec = (*EventType)(nil) + + _ runtime.Object = (*EventType)(nil) + + // Check that we can create OwnerReferences to an EventType. + _ kmeta.OwnerRefable = (*EventType)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*EventType)(nil) +) + +type EventTypeSpec struct { + // Type represents the CloudEvents type. It is authoritative. + Type string `json:"type"` + // Source is a URI, it represents the CloudEvents source. + // +optional + Source *apis.URL `json:"source,omitempty"` + // Schema is a URI, it represents the CloudEvents schemaurl extension attribute. + // It may be a JSON schema, a protobuf schema, etc. It is optional. + // +optional + Schema *apis.URL `json:"schema,omitempty"` + // SchemaData allows the CloudEvents schema to be stored directly in the + // EventType. Content is dependent on the encoding. Optional attribute. + // The contents are not validated or manipulated by the system. + // +optional + SchemaData string `json:"schemaData,omitempty"` + // TODO remove https://github.com/knative/eventing/issues/2750 + // Broker refers to the Broker that can provide the EventType. + // +optional + Broker string `json:"broker,omitempty"` + // Description is an optional field used to describe the EventType, in any meaningful way. + // +optional + Description string `json:"description,omitempty"` +} + +// EventTypeStatus represents the current state of a EventType. +type EventTypeStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// EventTypeList is a collection of EventTypes. +type EventTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []EventType `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for EventType +func (p *EventType) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("EventType") +} + +// GetUntypedSpec returns the spec of the EventType. +func (e *EventType) GetUntypedSpec() interface{} { + return e.Spec +} + +// GetStatus retrieves the status of the EventType. Implements the KRShaped interface. +func (t *EventType) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/eventing/v1/eventtype_types_test.go b/pkg/apis/eventing/v1/eventtype_types_test.go new file mode 100644 index 00000000000..09d5ac826a5 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_types_test.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "testing" +) + +func TestEventTypeGetStatus(t *testing.T) { + r := &EventType{ + Status: EventTypeStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestEventType_GetGroupVersionKind(t *testing.T) { + src := EventType{} + gvk := src.GetGroupVersionKind() + + if gvk.Kind != "EventType" { + t.Errorf("Should be EventType.") + } +} diff --git a/pkg/apis/eventing/v1/eventtype_validation.go b/pkg/apis/eventing/v1/eventtype_validation.go new file mode 100644 index 00000000000..46939f77e02 --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_validation.go @@ -0,0 +1,62 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +func (et *EventType) Validate(ctx context.Context) *apis.FieldError { + return et.Spec.Validate(ctx).ViaField("spec") +} + +func (ets *EventTypeSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if ets.Type == "" { + fe := apis.ErrMissingField("type") + errs = errs.Also(fe) + } + // TODO validate Source is a valid URI. + // TODO validate Schema is a valid URI. + // There is no validation of the SchemaData, it is application specific data. + return errs +} + +func (et *EventType) CheckImmutableFields(ctx context.Context, original *EventType) *apis.FieldError { + if original == nil { + return nil + } + + // All fields are immutable. + if diff, err := kmp.ShortDiff(original.Spec, et.Spec); err != nil { + return &apis.FieldError{ + Message: "Failed to diff EventType", + Paths: []string{"spec"}, + Details: err.Error(), + } + } else if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1/eventtype_validation_test.go b/pkg/apis/eventing/v1/eventtype_validation_test.go new file mode 100644 index 00000000000..e522581604f --- /dev/null +++ b/pkg/apis/eventing/v1/eventtype_validation_test.go @@ -0,0 +1,258 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "knative.dev/pkg/apis" +) + +func TestEventTypeValidation(t *testing.T) { + name := "invalid type" + et := &EventType{Spec: EventTypeSpec{}} + + want := &apis.FieldError{ + Paths: []string{"spec.type"}, + Message: "missing field(s)", + } + + t.Run(name, func(t *testing.T) { + got := et.Validate(context.TODO()) + if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { + t.Errorf("EventType.Validate (-want, +got) = %v", diff) + } + }) +} + +func TestEventTypeSpecValidation(t *testing.T) { + testSource := apis.HTTP("test-source") + tests := []struct { + name string + ets *EventTypeSpec + want *apis.FieldError + }{{ + name: "invalid eventtype type", + ets: &EventTypeSpec{}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("type") + return fe + }(), + }, { + name: "valid eventtype", + ets: &EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ets.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate EventTypeSpec (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestEventTypeImmutableFields(t *testing.T) { + differentSource := apis.HTTP("original-source") + testSource := apis.HTTP("test-source") + testSchema := apis.HTTP("test-schema") + testSchemaData := `{"data": "awesome"}` + differentSchema := apis.HTTP("original-schema") + tests := []struct { + name string + current *EventType + original *EventType + want *apis.FieldError + }{{ + name: "good (no change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + SchemaData: testSchemaData, + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + SchemaData: testSchemaData, + }, + }, + want: nil, + }, { + name: "new nil is ok", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + }, + }, + original: nil, + want: nil, + }, { + name: "bad (broker change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "original-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.EventTypeSpec}.Broker: + -: "original-broker" + +: "test-broker" +`, + }, + }, { + name: "bad (type change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "original-type", + Source: testSource, + Broker: "test-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.EventTypeSpec}.Type: + -: "original-type" + +: "test-type" +`, + }, + }, { + name: "bad (source change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: differentSource, + Broker: "test-broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.EventTypeSpec}.Source.Host: + -: "original-source" + +: "test-source" +`, + }, + }, { + name: "bad (schema change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: differentSchema, + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.EventTypeSpec}.Schema.Host: + -: "original-schema" + +: "test-schema" +`, + }, + }, { + name: "bad (description change)", + current: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + Description: "test-description", + }, + }, + original: &EventType{ + Spec: EventTypeSpec{ + Type: "test-type", + Source: testSource, + Broker: "test-broker", + Schema: testSchema, + Description: "original-description", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1beta1.EventTypeSpec}.Description: + -: "original-description" + +: "test-description" +`, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.current.CheckImmutableFields(context.TODO(), test.original) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/register.go b/pkg/apis/eventing/v1/register.go new file mode 100644 index 00000000000..2d243ad9316 --- /dev/null +++ b/pkg/apis/eventing/v1/register.go @@ -0,0 +1,57 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "knative.dev/eventing/pkg/apis/eventing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: eventing.GroupName, Version: "v1beta1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Broker{}, + &BrokerList{}, + &EventType{}, + &EventTypeList{}, + &Trigger{}, + &TriggerList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/eventing/v1/test_helper.go b/pkg/apis/eventing/v1/test_helper.go new file mode 100644 index 00000000000..49073aec4d9 --- /dev/null +++ b/pkg/apis/eventing/v1/test_helper.go @@ -0,0 +1,122 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +type testHelper struct{} + +// TestHelper contains helpers for unit tests. +var TestHelper = testHelper{} + +func (testHelper) ReadySubscriptionCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + Severity: apis.ConditionSeverityError, + } +} + +func (testHelper) FalseSubscriptionCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionFalse, + Severity: apis.ConditionSeverityError, + Message: "test induced failure condition", + } +} + +func (testHelper) ReadySubscriptionStatus() *messagingv1beta1.SubscriptionStatus { + ss := &messagingv1beta1.SubscriptionStatus{} + ss.MarkChannelReady() + ss.MarkReferencesResolved() + ss.MarkAddedToChannel() + return ss +} + +func (t testHelper) ReadyBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + bs.PropagateIngressAvailability(t.AvailableEndpoints()) + bs.PropagateTriggerChannelReadiness(t.ReadyChannelStatus()) + bs.PropagateFilterAvailability(t.AvailableEndpoints()) + bs.SetAddress(apis.HTTP("example.com")) + return bs +} + +func (testHelper) ReadyBrokerCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + Severity: apis.ConditionSeverityError, + } +} + +func (testHelper) UnknownBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + return bs +} + +func (testHelper) FalseBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + bs.SetAddress(nil) + return bs +} + +func (testHelper) UnavailableEndpoints() *corev1.Endpoints { + ep := &corev1.Endpoints{} + ep.Name = "unavailable" + ep.Subsets = []corev1.EndpointSubset{{ + NotReadyAddresses: []corev1.EndpointAddress{{ + IP: "127.0.0.1", + }}, + }} + return ep +} + +func (testHelper) AvailableEndpoints() *corev1.Endpoints { + ep := &corev1.Endpoints{} + ep.Name = "available" + ep.Subsets = []corev1.EndpointSubset{{ + Addresses: []corev1.EndpointAddress{{ + IP: "127.0.0.1", + }}, + }} + return ep +} + +func (testHelper) ReadyChannelStatus() *duckv1beta1.ChannelableStatus { + cs := &duckv1beta1.ChannelableStatus{ + Status: duckv1.Status{}, + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{Scheme: "http", Host: "foo"}, + }, + }, + SubscribableStatus: duckv1beta1.SubscribableStatus{}} + return cs +} + +func (t testHelper) NotReadyChannelStatus() *duckv1beta1.ChannelableStatus { + return &duckv1beta1.ChannelableStatus{} +} diff --git a/pkg/apis/eventing/v1/trigger_conversion.go b/pkg/apis/eventing/v1/trigger_conversion.go new file mode 100644 index 00000000000..e856396e321 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +} diff --git a/pkg/apis/eventing/v1/trigger_conversion_test.go b/pkg/apis/eventing/v1/trigger_conversion_test.go new file mode 100644 index 00000000000..27ff6e46e16 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "testing" +) + +func TestTriggerConversionBadType(t *testing.T) { + good, bad := &Trigger{}, &Trigger{} + + if err := good.ConvertTo(context.Background(), bad); err == nil { + t.Errorf("ConvertTo() = %#v, wanted error", bad) + } + + if err := good.ConvertFrom(context.Background(), bad); err == nil { + t.Errorf("ConvertFrom() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/eventing/v1/trigger_defaults.go b/pkg/apis/eventing/v1/trigger_defaults.go new file mode 100644 index 00000000000..6a2682d70f3 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_defaults.go @@ -0,0 +1,52 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + + "knative.dev/pkg/apis" +) + +const ( + brokerLabel = "eventing.knative.dev/broker" +) + +func (t *Trigger) SetDefaults(ctx context.Context) { + withNS := apis.WithinParent(ctx, t.ObjectMeta) + t.Spec.SetDefaults(withNS) + setLabels(t) +} + +func (ts *TriggerSpec) SetDefaults(ctx context.Context) { + if ts.Broker == "" { + ts.Broker = "default" + } + // Make a default filter that allows anything. + if ts.Filter == nil { + ts.Filter = &TriggerFilter{} + } + // Default the Subscriber namespace + ts.Subscriber.SetDefaults(ctx) +} + +func setLabels(t *Trigger) { + if len(t.Labels) == 0 { + t.Labels = map[string]string{} + } + t.Labels[brokerLabel] = t.Spec.Broker +} diff --git a/pkg/apis/eventing/v1/trigger_defaults_test.go b/pkg/apis/eventing/v1/trigger_defaults_test.go new file mode 100644 index 00000000000..3d844407692 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_defaults_test.go @@ -0,0 +1,122 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" + + "github.com/google/go-cmp/cmp" +) + +var ( + defaultBroker = "default" + otherBroker = "other_broker" + namespace = "testnamespace" + emptyTriggerFilter = &TriggerFilter{} + defaultTrigger = Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{brokerLabel: defaultBroker}, + }, + Spec: TriggerSpec{ + Broker: defaultBroker, + Filter: emptyTriggerFilter, + }, + } +) + +func TestTriggerDefaults(t *testing.T) { + testCases := map[string]struct { + initial Trigger + expected Trigger + }{ + "nil broker": { + initial: Trigger{Spec: TriggerSpec{Filter: emptyTriggerFilter}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{brokerLabel: defaultBroker}, + }, + Spec: TriggerSpec{Broker: defaultBroker, Filter: emptyTriggerFilter}}, + }, + "nil filter": { + initial: Trigger{Spec: TriggerSpec{Broker: otherBroker}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{brokerLabel: otherBroker}, + }, + Spec: TriggerSpec{Broker: otherBroker, Filter: emptyTriggerFilter}}, + }, + "subscriber, ns defaulted": { + initial: Trigger{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + }, + Spec: TriggerSpec{ + Broker: otherBroker, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: "foo", + }, + }}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: namespace, + Labels: map[string]string{brokerLabel: otherBroker}, + }, + Spec: TriggerSpec{ + Broker: otherBroker, + Filter: emptyTriggerFilter, + Subscriber: duckv1.Destination{ + Ref: &duckv1.KReference{ + Name: "foo", + Namespace: namespace, + }, + }, + }}, + }, + "nil broker and nil filter": { + initial: Trigger{}, + expected: defaultTrigger, + }, + "with broker and label": { + initial: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{"otherLabel": "my-other-label"}, + }, + Spec: TriggerSpec{Broker: defaultBroker}}, + expected: Trigger{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{ + "otherLabel": "my-other-label", + brokerLabel: defaultBroker}, + }, + Spec: TriggerSpec{Broker: defaultBroker, Filter: emptyTriggerFilter}}, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.TODO()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Fatalf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/trigger_lifecycle.go b/pkg/apis/eventing/v1/trigger_lifecycle.go new file mode 100644 index 00000000000..2ad85b219fa --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_lifecycle.go @@ -0,0 +1,187 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed, TriggerConditionDependency, TriggerConditionSubscriberResolved) + +const ( + // TriggerConditionReady has status True when all subconditions below have been set to True. + TriggerConditionReady = apis.ConditionReady + + TriggerConditionBroker apis.ConditionType = "BrokerReady" + + TriggerConditionSubscribed apis.ConditionType = "SubscriptionReady" + + TriggerConditionDependency apis.ConditionType = "DependencyReady" + + TriggerConditionSubscriberResolved apis.ConditionType = "SubscriberResolved" + + // TriggerAnyFilter Constant to represent that we should allow anything. + TriggerAnyFilter = "" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Trigger) GetConditionSet() apis.ConditionSet { + return triggerCondSet +} + +// GetGroupVersionKind returns GroupVersionKind for Triggers +func (t *Trigger) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Trigger") +} + +// GetUntypedSpec returns the spec of the Trigger. +func (t *Trigger) GetUntypedSpec() interface{} { + return t.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ts *TriggerStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return triggerCondSet.Manage(ts).GetCondition(t) +} + +// GetTopLevelCondition returns the top level Condition. +func (ts *TriggerStatus) GetTopLevelCondition() *apis.Condition { + return triggerCondSet.Manage(ts).GetTopLevelCondition() +} + +// IsReady returns true if the resource is ready overall. +func (ts *TriggerStatus) IsReady() bool { + return triggerCondSet.Manage(ts).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ts *TriggerStatus) InitializeConditions() { + triggerCondSet.Manage(ts).InitializeConditions() +} + +func (ts *TriggerStatus) PropagateBrokerCondition(bc *apis.Condition) { + if bc == nil { + ts.MarkBrokerNotConfigured() + return + } + + switch { + case bc.Status == corev1.ConditionUnknown: + ts.MarkBrokerUnknown(bc.Reason, bc.Message) + case bc.Status == corev1.ConditionTrue: + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionBroker) + case bc.Status == corev1.ConditionFalse: + ts.MarkBrokerFailed(bc.Reason, bc.Message) + default: + ts.MarkBrokerUnknown("BrokerUnknown", "The status of Broker is invalid: %v", bc.Status) + } +} + +func (ts *TriggerStatus) MarkBrokerFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBroker, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkBrokerUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionBroker, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkBrokerNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionBroker, + "BrokerNotConfigured", "Broker has not yet been reconciled.") +} + +func (ts *TriggerStatus) PropagateSubscriptionCondition(sc *apis.Condition) { + if sc == nil { + ts.MarkSubscriptionNotConfigured() + return + } + + switch { + case sc.Status == corev1.ConditionUnknown: + ts.MarkSubscribedUnknown(sc.Reason, sc.Message) + case sc.Status == corev1.ConditionTrue: + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscribed) + case sc.Status == corev1.ConditionFalse: + ts.MarkNotSubscribed(sc.Reason, sc.Message) + default: + ts.MarkSubscribedUnknown("SubscriptionUnknown", "The status of Subscription is invalid: %v", sc.Status) + } +} + +func (ts *TriggerStatus) MarkNotSubscribed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscribed, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscribedUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscribed, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscriptionNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscribed, + "SubscriptionNotConfigured", "Subscription has not yet been reconciled.") +} + +func (ts *TriggerStatus) MarkSubscriberResolvedSucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscriberResolved) +} + +func (ts *TriggerStatus) MarkSubscriberResolvedFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscriberResolved, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscriberResolvedUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscriberResolved, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencySucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionDependency) +} + +func (ts *TriggerStatus) MarkDependencyFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, + "DependencyNotConfigured", "Dependency has not yet been reconciled.") +} + +func (ts *TriggerStatus) PropagateDependencyStatus(ks *duckv1.KResource) { + kc := ks.Status.GetCondition(apis.ConditionReady) + if kc == nil { + ts.MarkDependencyNotConfigured() + return + } + + switch { + case kc.Status == corev1.ConditionUnknown: + ts.MarkDependencyUnknown(kc.Reason, kc.Message) + case kc.Status == corev1.ConditionTrue: + ts.MarkDependencySucceeded() + case kc.Status == corev1.ConditionFalse: + ts.MarkDependencyFailed(kc.Reason, kc.Message) + default: + ts.MarkDependencyUnknown("DependencyUnknown", "The status of Dependency is invalid: %v", kc.Status) + } +} diff --git a/pkg/apis/eventing/v1/trigger_lifecycle_test.go b/pkg/apis/eventing/v1/trigger_lifecycle_test.go new file mode 100644 index 00000000000..8a6bee1e531 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_lifecycle_test.go @@ -0,0 +1,360 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "testing" + + "knative.dev/pkg/apis" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + corev1 "k8s.io/api/core/v1" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + ignoreAllButTypeAndStatus = cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") + + triggerConditionReady = apis.Condition{ + Type: TriggerConditionReady, + Status: corev1.ConditionTrue, + } + + triggerConditionBroker = apis.Condition{ + Type: TriggerConditionBroker, + Status: corev1.ConditionTrue, + } + + triggerConditionDependency = apis.Condition{ + Type: TriggerConditionDependency, + Status: corev1.ConditionTrue, + } + + triggerConditionSubscriberResolved = apis.Condition{ + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionTrue, + } + + triggerConditionSubscribed = apis.Condition{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionFalse, + } +) + +func TestTriggerGetConditionSet(t *testing.T) { + r := &Trigger{} + + if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestTriggerGetCondition(t *testing.T) { + tests := []struct { + name string + ts *TriggerStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &triggerConditionReady, + }, { + name: "multiple conditions", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionBroker, + triggerConditionSubscribed, + triggerConditionDependency, + triggerConditionSubscriberResolved, + }, + }, + }, + condQuery: TriggerConditionSubscribed, + want: &triggerConditionSubscribed, + }, { + name: "multiple conditions, condition false", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionBroker, + triggerConditionSubscribed, + triggerConditionDependency, + triggerConditionSubscriberResolved, + }, + }, + }, + condQuery: TriggerConditionSubscribed, + want: &triggerConditionSubscribed, + }, { + name: "unknown condition", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + triggerConditionSubscribed, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ts.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerInitializeConditions(t *testing.T) { + tests := []struct { + name string + ts *TriggerStatus + want *TriggerStatus + }{{ + name: "empty", + ts: &TriggerStatus{}, + want: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one false", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionFalse, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, + }, + { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionUnknown, + }, + }, + }, + }, + }, { + name: "one true", + ts: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionSubscribed, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &TriggerStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: TriggerConditionBroker, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionDependency, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionReady, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscriberResolved, + Status: corev1.ConditionUnknown, + }, { + Type: TriggerConditionSubscribed, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.ts.InitializeConditions() + if diff := cmp.Diff(test.want, test.ts, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerConditionStatus(t *testing.T) { + tests := []struct { + name string + brokerStatus *BrokerStatus + markKubernetesServiceExists bool + markVirtualServiceExists bool + subscriptionCondition *apis.Condition + subscriberResolvedStatus bool + dependencyAnnotationExists bool + dependencyStatus corev1.ConditionStatus + wantConditionStatus corev1.ConditionStatus + }{{ + name: "all happy", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionTrue, + }, { + name: "broker status unknown", + brokerStatus: TestHelper.UnknownBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "broker status false", + brokerStatus: TestHelper.FalseBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "subscribed sad", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.FalseSubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: false, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "failed to resolve subscriber", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: false, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionTrue, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "dependency unknown", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionUnknown, + wantConditionStatus: corev1.ConditionUnknown, + }, { + name: "dependency false", + brokerStatus: TestHelper.ReadyBrokerStatus(), + markKubernetesServiceExists: true, + markVirtualServiceExists: true, + subscriptionCondition: TestHelper.ReadySubscriptionCondition(), + subscriberResolvedStatus: true, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionFalse, + wantConditionStatus: corev1.ConditionFalse, + }, { + name: "all sad", + brokerStatus: TestHelper.FalseBrokerStatus(), + markKubernetesServiceExists: false, + markVirtualServiceExists: false, + subscriptionCondition: TestHelper.FalseSubscriptionCondition(), + subscriberResolvedStatus: false, + dependencyAnnotationExists: true, + dependencyStatus: corev1.ConditionFalse, + wantConditionStatus: corev1.ConditionFalse, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ts := &TriggerStatus{} + if test.brokerStatus != nil { + ts.PropagateBrokerCondition(test.brokerStatus.GetTopLevelCondition()) + } + if test.subscriptionCondition != nil { + ts.PropagateSubscriptionCondition(test.subscriptionCondition) + } + if test.subscriberResolvedStatus { + ts.MarkSubscriberResolvedSucceeded() + } else { + ts.MarkSubscriberResolvedFailed("Unable to get the Subscriber's URI", "subscriber not found") + } + if !test.dependencyAnnotationExists { + ts.MarkDependencySucceeded() + } else { + if test.dependencyStatus == corev1.ConditionTrue { + ts.MarkDependencySucceeded() + } else if test.dependencyStatus == corev1.ConditionUnknown { + ts.MarkDependencyUnknown("The status of dependency is unknown", "The status of dependency is unknown: nil") + } else { + ts.MarkDependencyFailed("The status of dependency is false", "The status of dependency is unknown: nil") + } + } + got := ts.GetTopLevelCondition().Status + if test.wantConditionStatus != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantConditionStatus, got) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/trigger_types.go b/pkg/apis/eventing/v1/trigger_types.go new file mode 100644 index 00000000000..67eb11453bd --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_types.go @@ -0,0 +1,129 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +const ( + // DependencyAnnotation is the annotation key used to mark the sources that the Trigger depends on. + // This will be used when the kn client creates a source and trigger pair for the user such that the trigger only receives events produced by the paired source. + DependencyAnnotation = "knative.dev/dependency" + // InjectionAnnotation is the annotation key used to enable knative eventing injection for a namespace and automatically create a default broker. + // This will be used when the client creates a trigger paired with default broker and the default broker doesn't exist in the namespace + InjectionAnnotation = "knative-eventing-injection" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Trigger represents a request to have events delivered to a consumer from a +// Broker's event pool. +type Trigger struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Trigger. + Spec TriggerSpec `json:"spec,omitempty"` + + // Status represents the current state of the Trigger. This data may be out of + // date. + // +optional + Status TriggerStatus `json:"status,omitempty"` +} + +var ( + // Check that Trigger can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Trigger)(nil) + _ apis.Defaultable = (*Trigger)(nil) + + // Check that Trigger can return its spec untyped. + _ apis.HasSpec = (*Trigger)(nil) + + _ runtime.Object = (*Trigger)(nil) + + // Check that we can create OwnerReferences to a Trigger. + _ kmeta.OwnerRefable = (*Trigger)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Trigger)(nil) +) + +type TriggerSpec struct { + // Broker is the broker that this trigger receives events from. If not specified, will default + // to 'default'. + Broker string `json:"broker,omitempty"` + + // Filter is the filter to apply against all events from the Broker. Only events that pass this + // filter will be sent to the Subscriber. If not specified, will default to allowing all events. + // + // +optional + Filter *TriggerFilter `json:"filter,omitempty"` + + // Subscriber is the addressable that receives events from the Broker that pass the Filter. It + // is required. + Subscriber duckv1.Destination `json:"subscriber"` +} + +type TriggerFilter struct { + // Attributes filters events by exact match on event context attributes. + // Each key in the map is compared with the equivalent key in the event + // context. An event passes the filter if all values are equal to the + // specified values. + // + // Nested context attributes are not supported as keys. Only string values are supported. + // + // +optional + Attributes TriggerFilterAttributes `json:"attributes,omitempty"` +} + +// TriggerFilterAttributes is a map of context attribute names to values for +// filtering by equality. Only exact matches will pass the filter. You can use the value '' +// to indicate all strings match. +type TriggerFilterAttributes map[string]string + +// TriggerStatus represents the current state of a Trigger. +type TriggerStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Trigger that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // SubscriberURI is the resolved URI of the receiver for this Trigger. + SubscriberURI *apis.URL `json:"subscriberUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TriggerList is a collection of Triggers. +type TriggerList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Trigger `json:"items"` +} + +// GetStatus retrieves the status of the Trigger. Implements the KRShaped interface. +func (t *Trigger) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/eventing/v1/trigger_types_test.go b/pkg/apis/eventing/v1/trigger_types_test.go new file mode 100644 index 00000000000..12e2cfbae41 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_types_test.go @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import "testing" + +func TestTriggerGetStatus(t *testing.T) { + r := &Trigger{ + Status: TriggerStatus{}, + } + if got, want := r.GetStatus(), &r.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} + +func TestTrigger_GetGroupVersionKind(t *testing.T) { + + tr := Trigger{} + gvk := tr.GetGroupVersionKind() + if gvk.Kind != "Trigger" { + t.Errorf("Should be Trigger.") + } +} diff --git a/pkg/apis/eventing/v1/trigger_validation.go b/pkg/apis/eventing/v1/trigger_validation.go new file mode 100644 index 00000000000..8a18a89e182 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_validation.go @@ -0,0 +1,155 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + "encoding/json" + "fmt" + "regexp" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" + + corev1 "k8s.io/api/core/v1" +) + +var ( + // Only allow lowercase alphanumeric, starting with letters. + validAttributeName = regexp.MustCompile(`^[a-z][a-z0-9]*$`) +) + +// Validate the Trigger. +func (t *Trigger) Validate(ctx context.Context) *apis.FieldError { + errs := t.Spec.Validate(ctx).ViaField("spec") + errs = t.validateAnnotation(errs, DependencyAnnotation, t.validateDependencyAnnotation) + errs = t.validateAnnotation(errs, InjectionAnnotation, t.validateInjectionAnnotation) + return errs +} + +// Validate the TriggerSpec. +func (ts *TriggerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if ts.Broker == "" { + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + } + + if ts.Filter != nil { + for attr := range map[string]string(ts.Filter.Attributes) { + if !validAttributeName.MatchString(attr) { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Invalid attribute name: %q", attr), + Paths: []string{"filter.attributes"}, + } + errs = errs.Also(fe) + } + } + } + + if fe := ts.Subscriber.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("subscriber")) + } + + return errs +} + +// CheckImmutableFields checks that any immutable fields were not changed. +func (t *Trigger) CheckImmutableFields(ctx context.Context, original *Trigger) *apis.FieldError { + if original == nil { + return nil + } + + if diff, err := kmp.ShortDiff(original.Spec.Broker, t.Spec.Broker); err != nil { + return &apis.FieldError{ + Message: "Failed to diff Trigger", + Paths: []string{"spec"}, + Details: err.Error(), + } + } else if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "broker"}, + Details: diff, + } + } + return nil +} + +func GetObjRefFromDependencyAnnotation(dependencyAnnotation string) (corev1.ObjectReference, error) { + var objectRef corev1.ObjectReference + if err := json.Unmarshal([]byte(dependencyAnnotation), &objectRef); err != nil { + return objectRef, err + } + return objectRef, nil +} + +func (t *Trigger) validateAnnotation(errs *apis.FieldError, annotation string, function func(string) *apis.FieldError) *apis.FieldError { + if annotationValue, ok := t.GetAnnotations()[annotation]; ok { + annotationPrefix := fmt.Sprintf("metadata.annotations[%s]", annotation) + errs = errs.Also(function(annotationValue).ViaField(annotationPrefix)) + } + return errs +} + +func (t *Trigger) validateDependencyAnnotation(dependencyAnnotation string) *apis.FieldError { + depObjRef, err := GetObjRefFromDependencyAnnotation(dependencyAnnotation) + if err != nil { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided annotation was not a corev1.ObjectReference: %q", dependencyAnnotation), + Details: err.Error(), + Paths: []string{""}, + } + } + var errs *apis.FieldError + if depObjRef.Namespace != "" && depObjRef.Namespace != t.GetNamespace() { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Namespace must be empty or equal to the trigger namespace %q", t.GetNamespace()), + Paths: []string{"namespace"}, + } + errs = errs.Also(fe) + } + if depObjRef.Kind == "" { + fe := apis.ErrMissingField("kind") + errs = errs.Also(fe) + } + if depObjRef.Name == "" { + fe := apis.ErrMissingField("name") + errs = errs.Also(fe) + } + if depObjRef.APIVersion == "" { + fe := apis.ErrMissingField("apiVersion") + errs = errs.Also(fe) + } + return errs +} + +func (t *Trigger) validateInjectionAnnotation(injectionAnnotation string) *apis.FieldError { + if injectionAnnotation != "enabled" { + return &apis.FieldError{ + Message: fmt.Sprintf(`The provided injection annotation value can only be "enabled", not %q`, injectionAnnotation), + Paths: []string{""}, + } + } + if t.Spec.Broker != "default" { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided injection annotation is only used for default broker, but non-default broker specified here: %q", t.Spec.Broker), + Paths: []string{""}, + } + } + return nil +} diff --git a/pkg/apis/eventing/v1/trigger_validation_test.go b/pkg/apis/eventing/v1/trigger_validation_test.go new file mode 100644 index 00000000000..59e4b266bc6 --- /dev/null +++ b/pkg/apis/eventing/v1/trigger_validation_test.go @@ -0,0 +1,450 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var ( + validEmptyFilter = &TriggerFilter{} + validAttributesFilter = &TriggerFilter{ + Attributes: TriggerFilterAttributes{ + "type": "other_type", + "source": "other_source", + }, + } + validSubscriber = duckv1.Destination{ + Ref: &duckv1.KReference{ + Namespace: "namespace", + Name: "subscriber_test", + Kind: "Service", + APIVersion: "serving.knative.dev/v1alpha1", + }, + } + invalidSubscriber = duckv1.Destination{ + Ref: &duckv1.KReference{ + Namespace: "namespace", + Kind: "Service", + APIVersion: "serving.knative.dev/v1alpha1", + }, + } + // Dependency annotation + invalidDependencyAnnotation = "invalid dependency annotation" + dependencyAnnotationPath = fmt.Sprintf("metadata.annotations[%s]", DependencyAnnotation) + // Create default broker annotation + validInjectionAnnotation = "enabled" + invalidInjectionAnnotation = "disabled" + injectionAnnotationPath = fmt.Sprintf("metadata.annotations[%s]", InjectionAnnotation) +) + +func TestTriggerValidation(t *testing.T) { + tests := []struct { + name string + t *Trigger + want *apis.FieldError + }{{ + name: "invalid trigger spec", + t: &Trigger{Spec: TriggerSpec{}}, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("spec.broker") + errs = errs.Also(fe) + fe = apis.ErrGeneric("expected at least one, got none", "spec.subscriber.ref", "spec.subscriber.uri") + errs = errs.Also(fe) + return errs + }(), + }, { + name: "invalid dependency annotation, not a corev1.ObjectReference", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Annotations: map[string]string{ + DependencyAnnotation: invalidDependencyAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath}, + Message: "The provided annotation was not a corev1.ObjectReference: \"invalid dependency annotation\"", + Details: "invalid character 'i' looking for beginning of value", + }, + }, { + name: "invalid dependency annotation, trigger namespace is not equal to dependency namespace)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns-1", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"PingSource\",\"namespace\":\"test-ns-2\", \"name\":\"test-ping-source\",\"apiVersion\":\"sources.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "namespace"}, + Message: "Namespace must be empty or equal to the trigger namespace \"test-ns-1\"", + }, + }, + { + name: "invalid dependency annotation, missing kind)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"name\":\"test-ping-source\",\"apiVersion\":\"sources.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "kind"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing name", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"PingSource\",\"apiVersion\":\"sources.knative.dev/v1alpha1\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "name"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing apiVersion", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{\"kind\":\"CronJobSource\",\"name\":\"test-cronjob-source\"}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, { + name: "invalid dependency annotation, missing kind, name, apiVersion", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{}", + }}, + Spec: TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{ + dependencyAnnotationPath + "." + "kind", + dependencyAnnotationPath + "." + "name", + dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, + { + name: "invalid trigger spec, invalid dependency annotation(missing kind, name, apiVersion)", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + DependencyAnnotation: "{}", + }}, + Spec: TriggerSpec{Subscriber: validSubscriber}}, + want: &apis.FieldError{ + Paths: []string{ + "spec.broker", + dependencyAnnotationPath + "." + "kind", + dependencyAnnotationPath + "." + "name", + dependencyAnnotationPath + "." + "apiVersion"}, + Message: "missing field(s)", + }, + }, + { + name: "invalid injection annotation value", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + InjectionAnnotation: invalidInjectionAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "default", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{injectionAnnotationPath}, + Message: "The provided injection annotation value can only be \"enabled\", not \"disabled\"", + }, + }, + { + name: "valid injection annotation value, non-default broker specified", + t: &Trigger{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "test-ns", + Annotations: map[string]string{ + InjectionAnnotation: validInjectionAnnotation, + }}, + Spec: TriggerSpec{ + Broker: "test-broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }}, + want: &apis.FieldError{ + Paths: []string{injectionAnnotationPath}, + Message: "The provided injection annotation is only used for default broker, but non-default broker specified here: \"test-broker\"", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.t.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("Trigger.Validate (-want, +got) = %v", diff) + } + }) + } +} + +func TestTriggerSpecValidation(t *testing.T) { + tests := []struct { + name string + ts *TriggerSpec + want *apis.FieldError + }{{ + name: "invalid trigger spec", + ts: &TriggerSpec{}, + want: func() *apis.FieldError { + var errs *apis.FieldError + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + fe = apis.ErrGeneric("expected at least one, got none", "subscriber.ref", "subscriber.uri") + errs = errs.Also(fe) + return errs + + }(), + }, { + name: "missing broker", + ts: &TriggerSpec{ + Broker: "", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("broker") + return fe + }(), + }, { + name: "missing attributes keys, match all", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{ + Attributes: TriggerFilterAttributes{}, + }, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }, { + name: "invalid attribute name, start with number", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{ + Attributes: TriggerFilterAttributes{ + "0invalid": "my-value", + }, + }, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{ + Message: "Invalid attribute name: \"0invalid\"", + Paths: []string{"filter.attributes"}, + }, + }, { + name: "invalid attribute name, capital letters", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: &TriggerFilter{ + Attributes: TriggerFilterAttributes{ + "invALID": "my-value", + }, + }, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{ + Message: "Invalid attribute name: \"invALID\"", + Paths: []string{"filter.attributes"}, + }, + }, { + name: "missing subscriber", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + }, + want: apis.ErrGeneric("expected at least one, got none", "subscriber.ref", "subscriber.uri"), + }, { + name: "missing subscriber.ref.name", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + Subscriber: invalidSubscriber, + }, + want: apis.ErrMissingField("subscriber.ref.name"), + }, { + name: "missing broker", + ts: &TriggerSpec{ + Broker: "", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: apis.ErrMissingField("broker"), + }, { + name: "valid empty filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validEmptyFilter, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }, { + name: "valid SourceAndType filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }, { + name: "valid Attributes filter", + ts: &TriggerSpec{ + Broker: "test_broker", + Filter: validAttributesFilter, + Subscriber: validSubscriber, + }, + want: &apis.FieldError{}, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.ts.Validate(context.TODO()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate TriggerSpec (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestTriggerImmutableFields(t *testing.T) { + tests := []struct { + name string + current *Trigger + original *Trigger + want *apis.FieldError + }{{ + name: "good (no change)", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + want: nil, + }, { + name: "new nil is ok", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: nil, + want: nil, + }, { + name: "good (filter change)", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + Filter: validAttributesFilter, + }, + }, + want: nil, + }, { + name: "bad (broker change)", + current: &Trigger{ + Spec: TriggerSpec{ + Broker: "broker", + }, + }, + original: &Trigger{ + Spec: TriggerSpec{ + Broker: "original_broker", + }, + }, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "broker"}, + Details: `{string}: + -: "original_broker" + +: "broker" +`, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.current.CheckImmutableFields(context.TODO(), test.original) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/eventing/v1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..dcda76b4000 --- /dev/null +++ b/pkg/apis/eventing/v1/zz_generated.deepcopy.go @@ -0,0 +1,387 @@ +// +build !ignore_autogenerated + +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + v1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + apis "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Broker) DeepCopyInto(out *Broker) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Broker. +func (in *Broker) DeepCopy() *Broker { + if in == nil { + return nil + } + out := new(Broker) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Broker) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerList) DeepCopyInto(out *BrokerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Broker, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerList. +func (in *BrokerList) DeepCopy() *BrokerList { + if in == nil { + return nil + } + out := new(BrokerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BrokerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { + *out = *in + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(duckv1.KReference) + **out = **in + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(v1beta1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerSpec. +func (in *BrokerSpec) DeepCopy() *BrokerSpec { + if in == nil { + return nil + } + out := new(BrokerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerStatus) DeepCopyInto(out *BrokerStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.Address.DeepCopyInto(&out.Address) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerStatus. +func (in *BrokerStatus) DeepCopy() *BrokerStatus { + if in == nil { + return nil + } + out := new(BrokerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventType) DeepCopyInto(out *EventType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventType. +func (in *EventType) DeepCopy() *EventType { + if in == nil { + return nil + } + out := new(EventType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EventType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventTypeList) DeepCopyInto(out *EventTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]EventType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeList. +func (in *EventTypeList) DeepCopy() *EventTypeList { + if in == nil { + return nil + } + out := new(EventTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EventTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventTypeSpec) DeepCopyInto(out *EventTypeSpec) { + *out = *in + if in.Source != nil { + in, out := &in.Source, &out.Source + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + if in.Schema != nil { + in, out := &in.Schema, &out.Schema + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeSpec. +func (in *EventTypeSpec) DeepCopy() *EventTypeSpec { + if in == nil { + return nil + } + out := new(EventTypeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EventTypeStatus) DeepCopyInto(out *EventTypeStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeStatus. +func (in *EventTypeStatus) DeepCopy() *EventTypeStatus { + if in == nil { + return nil + } + out := new(EventTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Trigger) DeepCopyInto(out *Trigger) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trigger. +func (in *Trigger) DeepCopy() *Trigger { + if in == nil { + return nil + } + out := new(Trigger) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Trigger) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerFilter) DeepCopyInto(out *TriggerFilter) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(TriggerFilterAttributes, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilter. +func (in *TriggerFilter) DeepCopy() *TriggerFilter { + if in == nil { + return nil + } + out := new(TriggerFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in TriggerFilterAttributes) DeepCopyInto(out *TriggerFilterAttributes) { + { + in := &in + *out = make(TriggerFilterAttributes, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilterAttributes. +func (in TriggerFilterAttributes) DeepCopy() TriggerFilterAttributes { + if in == nil { + return nil + } + out := new(TriggerFilterAttributes) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerList) DeepCopyInto(out *TriggerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Trigger, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerList. +func (in *TriggerList) DeepCopy() *TriggerList { + if in == nil { + return nil + } + out := new(TriggerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TriggerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerSpec) DeepCopyInto(out *TriggerSpec) { + *out = *in + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(TriggerFilter) + (*in).DeepCopyInto(*out) + } + in.Subscriber.DeepCopyInto(&out.Subscriber) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerSpec. +func (in *TriggerSpec) DeepCopy() *TriggerSpec { + if in == nil { + return nil + } + out := new(TriggerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerStatus) DeepCopyInto(out *TriggerStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + if in.SubscriberURI != nil { + in, out := &in.SubscriberURI, &out.SubscriberURI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerStatus. +func (in *TriggerStatus) DeepCopy() *TriggerStatus { + if in == nil { + return nil + } + out := new(TriggerStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 7b5f994fcd5..21897073e17 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -25,6 +25,7 @@ import ( rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" @@ -36,6 +37,7 @@ type Interface interface { Discovery() discovery.DiscoveryInterface ConfigsV1alpha1() configsv1alpha1.ConfigsV1alpha1Interface EventingV1beta1() eventingv1beta1.EventingV1beta1Interface + EventingV1() eventingv1.EventingV1Interface FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface @@ -48,6 +50,7 @@ type Clientset struct { *discovery.DiscoveryClient configsV1alpha1 *configsv1alpha1.ConfigsV1alpha1Client eventingV1beta1 *eventingv1beta1.EventingV1beta1Client + eventingV1 *eventingv1.EventingV1Client flowsV1beta1 *flowsv1beta1.FlowsV1beta1Client messagingV1beta1 *messagingv1beta1.MessagingV1beta1Client sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client @@ -64,6 +67,11 @@ func (c *Clientset) EventingV1beta1() eventingv1beta1.EventingV1beta1Interface { return c.eventingV1beta1 } +// EventingV1 retrieves the EventingV1Client +func (c *Clientset) EventingV1() eventingv1.EventingV1Interface { + return c.eventingV1 +} + // FlowsV1beta1 retrieves the FlowsV1beta1Client func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return c.flowsV1beta1 @@ -113,6 +121,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.eventingV1, err = eventingv1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.flowsV1beta1, err = flowsv1beta1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -143,6 +155,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset cs.configsV1alpha1 = configsv1alpha1.NewForConfigOrDie(c) cs.eventingV1beta1 = eventingv1beta1.NewForConfigOrDie(c) + cs.eventingV1 = eventingv1.NewForConfigOrDie(c) cs.flowsV1beta1 = flowsv1beta1.NewForConfigOrDie(c) cs.messagingV1beta1 = messagingv1beta1.NewForConfigOrDie(c) cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) @@ -157,6 +170,7 @@ func New(c rest.Interface) *Clientset { var cs Clientset cs.configsV1alpha1 = configsv1alpha1.New(c) cs.eventingV1beta1 = eventingv1beta1.New(c) + cs.eventingV1 = eventingv1.New(c) cs.flowsV1beta1 = flowsv1beta1.New(c) cs.messagingV1beta1 = messagingv1beta1.New(c) cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 5f55ecc9095..a3c066cafe7 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -27,6 +27,8 @@ import ( clientset "knative.dev/eventing/pkg/client/clientset/versioned" configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" fakeconfigsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake" + eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" + fakeeventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" fakeeventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" @@ -96,6 +98,11 @@ func (c *Clientset) EventingV1beta1() eventingv1beta1.EventingV1beta1Interface { return &fakeeventingv1beta1.FakeEventingV1beta1{Fake: &c.Fake} } +// EventingV1 retrieves the EventingV1Client +func (c *Clientset) EventingV1() eventingv1.EventingV1Interface { + return &fakeeventingv1.FakeEventingV1{Fake: &c.Fake} +} + // FlowsV1beta1 retrieves the FlowsV1beta1Client func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return &fakeflowsv1beta1.FakeFlowsV1beta1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 6b46a004e41..d767c435481 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -38,6 +39,7 @@ var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ configsv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, + eventingv1.AddToScheme, flowsv1beta1.AddToScheme, messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 76c104bc5bc..a6cb9e4ac2d 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -38,6 +39,7 @@ var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ configsv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, + eventingv1.AddToScheme, flowsv1beta1.AddToScheme, messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/broker.go b/pkg/client/clientset/versioned/typed/eventing/v1/broker.go new file mode 100644 index 00000000000..f7309d95a94 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/broker.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// BrokersGetter has a method to return a BrokerInterface. +// A group's client should implement this interface. +type BrokersGetter interface { + Brokers(namespace string) BrokerInterface +} + +// BrokerInterface has methods to work with Broker resources. +type BrokerInterface interface { + Create(*v1.Broker) (*v1.Broker, error) + Update(*v1.Broker) (*v1.Broker, error) + UpdateStatus(*v1.Broker) (*v1.Broker, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Broker, error) + List(opts metav1.ListOptions) (*v1.BrokerList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Broker, err error) + BrokerExpansion +} + +// brokers implements BrokerInterface +type brokers struct { + client rest.Interface + ns string +} + +// newBrokers returns a Brokers +func newBrokers(c *EventingV1Client, namespace string) *brokers { + return &brokers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the broker, and returns the corresponding broker object, and an error if there is any. +func (c *brokers) Get(name string, options metav1.GetOptions) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Brokers that match those selectors. +func (c *brokers) List(opts metav1.ListOptions) (result *v1.BrokerList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.BrokerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *brokers) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a broker and creates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *brokers) Create(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Post(). + Namespace(c.ns). + Resource("brokers"). + Body(broker). + Do(). + Into(result) + return +} + +// Update takes the representation of a broker and updates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *brokers) Update(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Put(). + Namespace(c.ns). + Resource("brokers"). + Name(broker.Name). + Body(broker). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *brokers) UpdateStatus(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Put(). + Namespace(c.ns). + Resource("brokers"). + Name(broker.Name). + SubResource("status"). + Body(broker). + Do(). + Into(result) + return +} + +// Delete takes name of the broker and deletes it. Returns an error if one occurs. +func (c *brokers) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *brokers) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched broker. +func (c *brokers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("brokers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/doc.go b/pkg/client/clientset/versioned/typed/eventing/v1/doc.go new file mode 100644 index 00000000000..5b83bd1f41a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go new file mode 100644 index 00000000000..33f0a284138 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go @@ -0,0 +1,99 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type EventingV1Interface interface { + RESTClient() rest.Interface + BrokersGetter + EventTypesGetter + TriggersGetter +} + +// EventingV1Client is used to interact with features provided by the eventing.knative.dev group. +type EventingV1Client struct { + restClient rest.Interface +} + +func (c *EventingV1Client) Brokers(namespace string) BrokerInterface { + return newBrokers(c, namespace) +} + +func (c *EventingV1Client) EventTypes(namespace string) EventTypeInterface { + return newEventTypes(c, namespace) +} + +func (c *EventingV1Client) Triggers(namespace string) TriggerInterface { + return newTriggers(c, namespace) +} + +// NewForConfig creates a new EventingV1Client for the given config. +func NewForConfig(c *rest.Config) (*EventingV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &EventingV1Client{client}, nil +} + +// NewForConfigOrDie creates a new EventingV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *EventingV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new EventingV1Client for the given RESTClient. +func New(c rest.Interface) *EventingV1Client { + return &EventingV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *EventingV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go new file mode 100644 index 00000000000..ae2ff540429 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// EventTypesGetter has a method to return a EventTypeInterface. +// A group's client should implement this interface. +type EventTypesGetter interface { + EventTypes(namespace string) EventTypeInterface +} + +// EventTypeInterface has methods to work with EventType resources. +type EventTypeInterface interface { + Create(*v1.EventType) (*v1.EventType, error) + Update(*v1.EventType) (*v1.EventType, error) + UpdateStatus(*v1.EventType) (*v1.EventType, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.EventType, error) + List(opts metav1.ListOptions) (*v1.EventTypeList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.EventType, err error) + EventTypeExpansion +} + +// eventTypes implements EventTypeInterface +type eventTypes struct { + client rest.Interface + ns string +} + +// newEventTypes returns a EventTypes +func newEventTypes(c *EventingV1Client, namespace string) *eventTypes { + return &eventTypes{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any. +func (c *eventTypes) Get(name string, options metav1.GetOptions) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of EventTypes that match those selectors. +func (c *eventTypes) List(opts metav1.ListOptions) (result *v1.EventTypeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.EventTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested eventTypes. +func (c *eventTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *eventTypes) Create(eventType *v1.EventType) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Post(). + Namespace(c.ns). + Resource("eventtypes"). + Body(eventType). + Do(). + Into(result) + return +} + +// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *eventTypes) Update(eventType *v1.EventType) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("eventtypes"). + Name(eventType.Name). + Body(eventType). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *eventTypes) UpdateStatus(eventType *v1.EventType) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Put(). + Namespace(c.ns). + Resource("eventtypes"). + Name(eventType.Name). + SubResource("status"). + Body(eventType). + Do(). + Into(result) + return +} + +// Delete takes name of the eventType and deletes it. Returns an error if one occurs. +func (c *eventTypes) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("eventtypes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *eventTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("eventtypes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched eventType. +func (c *eventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.EventType, err error) { + result = &v1.EventType{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("eventtypes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go new file mode 100644 index 00000000000..c7f6e65cab8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go new file mode 100644 index 00000000000..fff607109c6 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeBrokers implements BrokerInterface +type FakeBrokers struct { + Fake *FakeEventingV1 + ns string +} + +var brokersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "brokers"} + +var brokersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "Broker"} + +// Get takes name of the broker, and returns the corresponding broker object, and an error if there is any. +func (c *FakeBrokers) Get(name string, options v1.GetOptions) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(brokersResource, c.ns, name), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// List takes label and field selectors, and returns the list of Brokers that match those selectors. +func (c *FakeBrokers) List(opts v1.ListOptions) (result *eventingv1.BrokerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(brokersResource, brokersKind, c.ns, opts), &eventingv1.BrokerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.BrokerList{ListMeta: obj.(*eventingv1.BrokerList).ListMeta} + for _, item := range obj.(*eventingv1.BrokerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *FakeBrokers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(brokersResource, c.ns, opts)) + +} + +// Create takes the representation of a broker and creates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *FakeBrokers) Create(broker *eventingv1.Broker) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(brokersResource, c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// Update takes the representation of a broker and updates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *FakeBrokers) Update(broker *eventingv1.Broker) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(brokersResource, c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeBrokers) UpdateStatus(broker *eventingv1.Broker) (*eventingv1.Broker, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(brokersResource, "status", c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// Delete takes name of the broker and deletes it. Returns an error if one occurs. +func (c *FakeBrokers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(brokersResource, c.ns, name), &eventingv1.Broker{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBrokers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(brokersResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.BrokerList{}) + return err +} + +// Patch applies the patch and returns the patched broker. +func (c *FakeBrokers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(brokersResource, c.ns, name, pt, data, subresources...), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go new file mode 100644 index 00000000000..ce798a54a83 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go @@ -0,0 +1,48 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" +) + +type FakeEventingV1 struct { + *testing.Fake +} + +func (c *FakeEventingV1) Brokers(namespace string) v1.BrokerInterface { + return &FakeBrokers{c, namespace} +} + +func (c *FakeEventingV1) EventTypes(namespace string) v1.EventTypeInterface { + return &FakeEventTypes{c, namespace} +} + +func (c *FakeEventingV1) Triggers(namespace string) v1.TriggerInterface { + return &FakeTriggers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeEventingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go new file mode 100644 index 00000000000..05936641b19 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeEventTypes implements EventTypeInterface +type FakeEventTypes struct { + Fake *FakeEventingV1 + ns string +} + +var eventtypesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "eventtypes"} + +var eventtypesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "EventType"} + +// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any. +func (c *FakeEventTypes) Get(name string, options v1.GetOptions) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// List takes label and field selectors, and returns the list of EventTypes that match those selectors. +func (c *FakeEventTypes) List(opts v1.ListOptions) (result *eventingv1.EventTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &eventingv1.EventTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.EventTypeList{ListMeta: obj.(*eventingv1.EventTypeList).ListMeta} + for _, item := range obj.(*eventingv1.EventTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested eventTypes. +func (c *FakeEventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(eventtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *FakeEventTypes) Create(eventType *eventingv1.EventType) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any. +func (c *FakeEventTypes) Update(eventType *eventingv1.EventType) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeEventTypes) UpdateStatus(eventType *eventingv1.EventType) (*eventingv1.EventType, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} + +// Delete takes name of the eventType and deletes it. Returns an error if one occurs. +func (c *FakeEventTypes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(eventtypesResource, c.ns, name), &eventingv1.EventType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(eventtypesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.EventTypeList{}) + return err +} + +// Patch applies the patch and returns the patched eventType. +func (c *FakeEventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.EventType, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, pt, data, subresources...), &eventingv1.EventType{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.EventType), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go new file mode 100644 index 00000000000..6b3795b6fbb --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeTriggers implements TriggerInterface +type FakeTriggers struct { + Fake *FakeEventingV1 + ns string +} + +var triggersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "triggers"} + +var triggersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "Trigger"} + +// Get takes name of the trigger, and returns the corresponding trigger object, and an error if there is any. +func (c *FakeTriggers) Get(name string, options v1.GetOptions) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(triggersResource, c.ns, name), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// List takes label and field selectors, and returns the list of Triggers that match those selectors. +func (c *FakeTriggers) List(opts v1.ListOptions) (result *eventingv1.TriggerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(triggersResource, triggersKind, c.ns, opts), &eventingv1.TriggerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.TriggerList{ListMeta: obj.(*eventingv1.TriggerList).ListMeta} + for _, item := range obj.(*eventingv1.TriggerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *FakeTriggers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(triggersResource, c.ns, opts)) + +} + +// Create takes the representation of a trigger and creates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *FakeTriggers) Create(trigger *eventingv1.Trigger) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(triggersResource, c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// Update takes the representation of a trigger and updates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *FakeTriggers) Update(trigger *eventingv1.Trigger) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(triggersResource, c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTriggers) UpdateStatus(trigger *eventingv1.Trigger) (*eventingv1.Trigger, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(triggersResource, "status", c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// Delete takes name of the trigger and deletes it. Returns an error if one occurs. +func (c *FakeTriggers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(triggersResource, c.ns, name), &eventingv1.Trigger{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTriggers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(triggersResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.TriggerList{}) + return err +} + +// Patch applies the patch and returns the patched trigger. +func (c *FakeTriggers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(triggersResource, c.ns, name, pt, data, subresources...), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go new file mode 100644 index 00000000000..9dbe76ef962 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go @@ -0,0 +1,25 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type BrokerExpansion interface{} + +type EventTypeExpansion interface{} + +type TriggerExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go b/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go new file mode 100644 index 00000000000..9726e4e3c8f --- /dev/null +++ b/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// TriggersGetter has a method to return a TriggerInterface. +// A group's client should implement this interface. +type TriggersGetter interface { + Triggers(namespace string) TriggerInterface +} + +// TriggerInterface has methods to work with Trigger resources. +type TriggerInterface interface { + Create(*v1.Trigger) (*v1.Trigger, error) + Update(*v1.Trigger) (*v1.Trigger, error) + UpdateStatus(*v1.Trigger) (*v1.Trigger, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Trigger, error) + List(opts metav1.ListOptions) (*v1.TriggerList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Trigger, err error) + TriggerExpansion +} + +// triggers implements TriggerInterface +type triggers struct { + client rest.Interface + ns string +} + +// newTriggers returns a Triggers +func newTriggers(c *EventingV1Client, namespace string) *triggers { + return &triggers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the trigger, and returns the corresponding trigger object, and an error if there is any. +func (c *triggers) Get(name string, options metav1.GetOptions) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Triggers that match those selectors. +func (c *triggers) List(opts metav1.ListOptions) (result *v1.TriggerList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TriggerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *triggers) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a trigger and creates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *triggers) Create(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Post(). + Namespace(c.ns). + Resource("triggers"). + Body(trigger). + Do(). + Into(result) + return +} + +// Update takes the representation of a trigger and updates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *triggers) Update(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Put(). + Namespace(c.ns). + Resource("triggers"). + Name(trigger.Name). + Body(trigger). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *triggers) UpdateStatus(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Put(). + Namespace(c.ns). + Resource("triggers"). + Name(trigger.Name). + SubResource("status"). + Body(trigger). + Do(). + Into(result) + return +} + +// Delete takes name of the trigger and deletes it. Returns an error if one occurs. +func (c *triggers) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *triggers) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched trigger. +func (c *triggers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("triggers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/eventing/interface.go b/pkg/client/informers/externalversions/eventing/interface.go index c4e662bafbf..531a3c77218 100644 --- a/pkg/client/informers/externalversions/eventing/interface.go +++ b/pkg/client/informers/externalversions/eventing/interface.go @@ -19,6 +19,7 @@ limitations under the License. package eventing import ( + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1beta1" internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" ) @@ -27,6 +28,8 @@ import ( type Interface interface { // V1beta1 provides access to shared informers for resources in V1beta1. V1beta1() v1beta1.Interface + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1beta1() v1beta1.Interface { return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/eventing/v1/broker.go b/pkg/client/informers/externalversions/eventing/v1/broker.go new file mode 100644 index 00000000000..b35aa4ee2fa --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/broker.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// BrokerInformer provides access to a shared informer and lister for +// Brokers. +type BrokerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.BrokerLister +} + +type brokerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewBrokerInformer constructs a new informer for Broker type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBrokerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBrokerInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredBrokerInformer constructs a new informer for Broker type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBrokerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Brokers(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Brokers(namespace).Watch(options) + }, + }, + &eventingv1.Broker{}, + resyncPeriod, + indexers, + ) +} + +func (f *brokerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBrokerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *brokerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.Broker{}, f.defaultInformer) +} + +func (f *brokerInformer) Lister() v1.BrokerLister { + return v1.NewBrokerLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/eventing/v1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1/eventtype.go new file mode 100644 index 00000000000..7c9034c5a5d --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/eventtype.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// EventTypeInformer provides access to a shared informer and lister for +// EventTypes. +type EventTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.EventTypeLister +} + +type eventTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewEventTypeInformer constructs a new informer for EventType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredEventTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredEventTypeInformer constructs a new informer for EventType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().EventTypes(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().EventTypes(namespace).Watch(options) + }, + }, + &eventingv1.EventType{}, + resyncPeriod, + indexers, + ) +} + +func (f *eventTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredEventTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *eventTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.EventType{}, f.defaultInformer) +} + +func (f *eventTypeInformer) Lister() v1.EventTypeLister { + return v1.NewEventTypeLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/eventing/v1/interface.go b/pkg/client/informers/externalversions/eventing/v1/interface.go new file mode 100644 index 00000000000..b152e717d0f --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/interface.go @@ -0,0 +1,59 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Brokers returns a BrokerInformer. + Brokers() BrokerInformer + // EventTypes returns a EventTypeInformer. + EventTypes() EventTypeInformer + // Triggers returns a TriggerInformer. + Triggers() TriggerInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Brokers returns a BrokerInformer. +func (v *version) Brokers() BrokerInformer { + return &brokerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// EventTypes returns a EventTypeInformer. +func (v *version) EventTypes() EventTypeInformer { + return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Triggers returns a TriggerInformer. +func (v *version) Triggers() TriggerInformer { + return &triggerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/eventing/v1/trigger.go b/pkg/client/informers/externalversions/eventing/v1/trigger.go new file mode 100644 index 00000000000..6f99981bf74 --- /dev/null +++ b/pkg/client/informers/externalversions/eventing/v1/trigger.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// TriggerInformer provides access to a shared informer and lister for +// Triggers. +type TriggerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TriggerLister +} + +type triggerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTriggerInformer constructs a new informer for Trigger type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTriggerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTriggerInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTriggerInformer constructs a new informer for Trigger type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTriggerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Triggers(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Triggers(namespace).Watch(options) + }, + }, + &eventingv1.Trigger{}, + resyncPeriod, + indexers, + ) +} + +func (f *triggerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTriggerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *triggerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.Trigger{}, f.defaultInformer) +} + +func (f *triggerInformer) Lister() v1.TriggerLister { + return v1.NewTriggerLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index c91f5c47581..b264f0f489e 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -61,6 +62,14 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("configmappropagations"): return &genericInformer{resource: resource.GroupResource(), informer: f.Configs().V1alpha1().ConfigMapPropagations().Informer()}, nil + // Group=eventing.knative.dev, Version=v1 + case v1.SchemeGroupVersion.WithResource("brokers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Brokers().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("eventtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().EventTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("triggers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Triggers().Informer()}, nil + // Group=eventing.knative.dev, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithResource("brokers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1beta1().Brokers().Informer()}, nil diff --git a/pkg/client/injection/informers/eventing/v1/broker/broker.go b/pkg/client/injection/informers/eventing/v1/broker/broker.go new file mode 100644 index 00000000000..61f646f0941 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/broker/broker.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package broker + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1().Brokers() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.BrokerInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.BrokerInformer from context.") + } + return untyped.(v1.BrokerInformer) +} diff --git a/pkg/client/injection/informers/eventing/v1/broker/fake/fake.go b/pkg/client/injection/informers/eventing/v1/broker/fake/fake.go new file mode 100644 index 00000000000..5dc3b1c768a --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/broker/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + broker "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = broker.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1().Brokers() + return context.WithValue(ctx, broker.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go b/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go new file mode 100644 index 00000000000..838fa4db171 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package eventtype + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1().EventTypes() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.EventTypeInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.EventTypeInformer from context.") + } + return untyped.(v1.EventTypeInformer) +} diff --git a/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go b/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go new file mode 100644 index 00000000000..6cda229bf31 --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = eventtype.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1().EventTypes() + return context.WithValue(ctx, eventtype.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go b/pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go new file mode 100644 index 00000000000..bf33f84f0ee --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/trigger/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + trigger "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = trigger.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Eventing().V1().Triggers() + return context.WithValue(ctx, trigger.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/eventing/v1/trigger/trigger.go b/pkg/client/injection/informers/eventing/v1/trigger/trigger.go new file mode 100644 index 00000000000..3bd2d81ed3d --- /dev/null +++ b/pkg/client/injection/informers/eventing/v1/trigger/trigger.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package trigger + +import ( + context "context" + + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Eventing().V1().Triggers() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1.TriggerInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.TriggerInformer from context.") + } + return untyped.(v1.TriggerInformer) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/controller.go b/pkg/client/injection/reconciler/eventing/v1/broker/controller.go new file mode 100644 index 00000000000..5fc2915d5c4 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/controller.go @@ -0,0 +1,122 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package broker + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + broker "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "broker-controller" + defaultFinalizerName = "brokers.eventing.knative.dev" + + // ClassAnnotationKey points to the annotation for the class of this resource. + ClassAnnotationKey = "eventing.knative.dev/broker.class" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, classValue string, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + brokerInformer := broker.Get(ctx) + + rec := &reconcilerImpl{ + Client: client.Get(ctx), + Lister: brokerInformer.Lister(), + reconciler: r, + finalizerName: defaultFinalizerName, + classValue: classValue, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go new file mode 100644 index 00000000000..0cf1a49a876 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go @@ -0,0 +1,368 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package broker + +import ( + context "context" + json "encoding/json" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Broker. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.Broker. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.Broker) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Broker. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.Broker. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.Broker) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.Broker resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister eventingv1.BrokerLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string + + // classValue is the resource annotation[eventing.knative.dev/broker.class] instance value this reconciler instance filters on. + classValue string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventingv1.BrokerLister, recorder record.EventRecorder, r Interface, classValue string, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + classValue: classValue, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.Brokers(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + if classValue, found := original.GetAnnotations()[ClassAnnotationKey]; !found || classValue != r.classValue { + logger.Debugw("Skip reconciling resource, class annotation value does not match reconciler instance value.", + zap.String("classKey", ClassAnnotationKey), + zap.String("issue", classValue+"!="+r.classValue)) + return nil + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + logger.Warnw("Failed to set finalizers", zap.Error(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) + + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + logger.Warnw("Failed to clear finalizers", zap.Error(err)) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.Broker, desired *v1.Broker) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1().Brokers(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1().Brokers(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Broker) (*v1.Broker, error) { + + getter := r.Lister.Brokers(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1().Brokers(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Broker) (*v1.Broker, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Broker, reconcileEvent reconciler.Event) (*v1.Broker, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go new file mode 100644 index 00000000000..8d6a39a0ba3 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/stub/controller.go @@ -0,0 +1,63 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package broker + +import ( + context "context" + + cache "k8s.io/client-go/tools/cache" + broker "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker" + v1broker "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/broker" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Broker and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + brokerInformer := broker.Get(ctx) + + classValue := "default" // TODO: update this to the appropriate value. + classFilter := reconciler.AnnotationFilterFunc(v1broker.ClassAnnotationKey, classValue, false /*allowUnset*/) + + // TODO: setup additional informers here. + // TODO: remember to use the classFilter from above to filter appropriately. + + r := &Reconciler{} + impl := v1broker.NewImpl(ctx, r, classValue) + + logger.Info("Setting up event handlers.") + + brokerInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: classFilter, + Handler: controller.HandleAll(impl.Enqueue), + }) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go new file mode 100644 index 00000000000..4af7c0a978a --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package broker + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + broker "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/broker" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason BrokerReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "BrokerReconciled", "Broker reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Broker resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ broker.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ broker.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.Broker) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.Broker) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go new file mode 100644 index 00000000000..4b8baabc07a --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go @@ -0,0 +1,118 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package eventtype + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + versionedscheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + client "knative.dev/eventing/pkg/client/injection/client" + eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "eventtype-controller" + defaultFinalizerName = "eventtypes.eventing.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + eventtypeInformer := eventtype.Get(ctx) + + rec := &reconcilerImpl{ + Client: client.Get(ctx), + Lister: eventtypeInformer.Lister(), + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go new file mode 100644 index 00000000000..8249565b8b6 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go @@ -0,0 +1,357 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package eventtype + +import ( + context "context" + json "encoding/json" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.EventType. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.EventType. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.EventType) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.EventType. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.EventType. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.EventType) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.EventType resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister eventingv1.EventTypeLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventingv1.EventTypeLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.EventTypes(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + logger.Warnw("Failed to set finalizers", zap.Error(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) + + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + logger.Warnw("Failed to clear finalizers", zap.Error(err)) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, corev1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1.EventType, desired *v1.EventType) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1().EventTypes(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1().EventTypes(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.EventType) (*v1.EventType, error) { + + getter := r.Lister.EventTypes(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1().EventTypes(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.EventType) (*v1.EventType, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.EventType, reconcileEvent reconciler.Event) (*v1.EventType, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go new file mode 100644 index 00000000000..287c617e9cd --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package eventtype + +import ( + context "context" + + eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" + v1eventtype "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/eventtype" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for EventType and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + eventtypeInformer := eventtype.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1eventtype.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + eventtypeInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go new file mode 100644 index 00000000000..dd6b073d2ae --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package eventtype + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + eventtype "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/eventtype" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason EventTypeReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "EventTypeReconciled", "EventType reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for EventType resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ eventtype.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ eventtype.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/listers/eventing/v1/broker.go b/pkg/client/listers/eventing/v1/broker.go new file mode 100644 index 00000000000..c6dca9da079 --- /dev/null +++ b/pkg/client/listers/eventing/v1/broker.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// BrokerLister helps list Brokers. +type BrokerLister interface { + // List lists all Brokers in the indexer. + List(selector labels.Selector) (ret []*v1.Broker, err error) + // Brokers returns an object that can list and get Brokers. + Brokers(namespace string) BrokerNamespaceLister + BrokerListerExpansion +} + +// brokerLister implements the BrokerLister interface. +type brokerLister struct { + indexer cache.Indexer +} + +// NewBrokerLister returns a new BrokerLister. +func NewBrokerLister(indexer cache.Indexer) BrokerLister { + return &brokerLister{indexer: indexer} +} + +// List lists all Brokers in the indexer. +func (s *brokerLister) List(selector labels.Selector) (ret []*v1.Broker, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Broker)) + }) + return ret, err +} + +// Brokers returns an object that can list and get Brokers. +func (s *brokerLister) Brokers(namespace string) BrokerNamespaceLister { + return brokerNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// BrokerNamespaceLister helps list and get Brokers. +type BrokerNamespaceLister interface { + // List lists all Brokers in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Broker, err error) + // Get retrieves the Broker from the indexer for a given namespace and name. + Get(name string) (*v1.Broker, error) + BrokerNamespaceListerExpansion +} + +// brokerNamespaceLister implements the BrokerNamespaceLister +// interface. +type brokerNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Brokers in the indexer for a given namespace. +func (s brokerNamespaceLister) List(selector labels.Selector) (ret []*v1.Broker, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Broker)) + }) + return ret, err +} + +// Get retrieves the Broker from the indexer for a given namespace and name. +func (s brokerNamespaceLister) Get(name string) (*v1.Broker, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("broker"), name) + } + return obj.(*v1.Broker), nil +} diff --git a/pkg/client/listers/eventing/v1/eventtype.go b/pkg/client/listers/eventing/v1/eventtype.go new file mode 100644 index 00000000000..260b3ff14fd --- /dev/null +++ b/pkg/client/listers/eventing/v1/eventtype.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// EventTypeLister helps list EventTypes. +type EventTypeLister interface { + // List lists all EventTypes in the indexer. + List(selector labels.Selector) (ret []*v1.EventType, err error) + // EventTypes returns an object that can list and get EventTypes. + EventTypes(namespace string) EventTypeNamespaceLister + EventTypeListerExpansion +} + +// eventTypeLister implements the EventTypeLister interface. +type eventTypeLister struct { + indexer cache.Indexer +} + +// NewEventTypeLister returns a new EventTypeLister. +func NewEventTypeLister(indexer cache.Indexer) EventTypeLister { + return &eventTypeLister{indexer: indexer} +} + +// List lists all EventTypes in the indexer. +func (s *eventTypeLister) List(selector labels.Selector) (ret []*v1.EventType, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.EventType)) + }) + return ret, err +} + +// EventTypes returns an object that can list and get EventTypes. +func (s *eventTypeLister) EventTypes(namespace string) EventTypeNamespaceLister { + return eventTypeNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// EventTypeNamespaceLister helps list and get EventTypes. +type EventTypeNamespaceLister interface { + // List lists all EventTypes in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.EventType, err error) + // Get retrieves the EventType from the indexer for a given namespace and name. + Get(name string) (*v1.EventType, error) + EventTypeNamespaceListerExpansion +} + +// eventTypeNamespaceLister implements the EventTypeNamespaceLister +// interface. +type eventTypeNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all EventTypes in the indexer for a given namespace. +func (s eventTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.EventType, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.EventType)) + }) + return ret, err +} + +// Get retrieves the EventType from the indexer for a given namespace and name. +func (s eventTypeNamespaceLister) Get(name string) (*v1.EventType, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("eventtype"), name) + } + return obj.(*v1.EventType), nil +} diff --git a/pkg/client/listers/eventing/v1/expansion_generated.go b/pkg/client/listers/eventing/v1/expansion_generated.go new file mode 100644 index 00000000000..08088029b1e --- /dev/null +++ b/pkg/client/listers/eventing/v1/expansion_generated.go @@ -0,0 +1,43 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// BrokerListerExpansion allows custom methods to be added to +// BrokerLister. +type BrokerListerExpansion interface{} + +// BrokerNamespaceListerExpansion allows custom methods to be added to +// BrokerNamespaceLister. +type BrokerNamespaceListerExpansion interface{} + +// EventTypeListerExpansion allows custom methods to be added to +// EventTypeLister. +type EventTypeListerExpansion interface{} + +// EventTypeNamespaceListerExpansion allows custom methods to be added to +// EventTypeNamespaceLister. +type EventTypeNamespaceListerExpansion interface{} + +// TriggerListerExpansion allows custom methods to be added to +// TriggerLister. +type TriggerListerExpansion interface{} + +// TriggerNamespaceListerExpansion allows custom methods to be added to +// TriggerNamespaceLister. +type TriggerNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/eventing/v1/trigger.go b/pkg/client/listers/eventing/v1/trigger.go new file mode 100644 index 00000000000..bd362b5c5fc --- /dev/null +++ b/pkg/client/listers/eventing/v1/trigger.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// TriggerLister helps list Triggers. +type TriggerLister interface { + // List lists all Triggers in the indexer. + List(selector labels.Selector) (ret []*v1.Trigger, err error) + // Triggers returns an object that can list and get Triggers. + Triggers(namespace string) TriggerNamespaceLister + TriggerListerExpansion +} + +// triggerLister implements the TriggerLister interface. +type triggerLister struct { + indexer cache.Indexer +} + +// NewTriggerLister returns a new TriggerLister. +func NewTriggerLister(indexer cache.Indexer) TriggerLister { + return &triggerLister{indexer: indexer} +} + +// List lists all Triggers in the indexer. +func (s *triggerLister) List(selector labels.Selector) (ret []*v1.Trigger, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Trigger)) + }) + return ret, err +} + +// Triggers returns an object that can list and get Triggers. +func (s *triggerLister) Triggers(namespace string) TriggerNamespaceLister { + return triggerNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TriggerNamespaceLister helps list and get Triggers. +type TriggerNamespaceLister interface { + // List lists all Triggers in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Trigger, err error) + // Get retrieves the Trigger from the indexer for a given namespace and name. + Get(name string) (*v1.Trigger, error) + TriggerNamespaceListerExpansion +} + +// triggerNamespaceLister implements the TriggerNamespaceLister +// interface. +type triggerNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Triggers in the indexer for a given namespace. +func (s triggerNamespaceLister) List(selector labels.Selector) (ret []*v1.Trigger, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Trigger)) + }) + return ret, err +} + +// Get retrieves the Trigger from the indexer for a given namespace and name. +func (s triggerNamespaceLister) Get(name string) (*v1.Trigger, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("trigger"), name) + } + return obj.(*v1.Trigger), nil +} From 9db04dd8b11f22ab03354c3f40d5252045270712 Mon Sep 17 00:00:00 2001 From: Ville Aikas Date: Mon, 22 Jun 2020 10:41:54 -0700 Subject: [PATCH 2/6] ducks to v1 --- pkg/apis/eventing/v1/broker_types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/eventing/v1/broker_types.go b/pkg/apis/eventing/v1/broker_types.go index d740928e51c..0fc1b1177d5 100644 --- a/pkg/apis/eventing/v1/broker_types.go +++ b/pkg/apis/eventing/v1/broker_types.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" @@ -77,7 +77,7 @@ type BrokerSpec struct { // Delivery is the delivery specification for Events within the Broker mesh. // This includes things like retries, DLQ, etc. // +optional - Delivery *eventingduckv1beta1.DeliverySpec `json:"delivery,omitempty"` + Delivery *eventingduckv1.DeliverySpec `json:"delivery,omitempty"` } // BrokerStatus represents the current state of a Broker. From e1482748bb77f08eefd1290aa04e6239913b432a Mon Sep 17 00:00:00 2001 From: Ville Aikas Date: Mon, 22 Jun 2020 15:12:16 -0700 Subject: [PATCH 3/6] add types, boilerplate conversion --- pkg/apis/eventing/v1/broker_conversion.go | 4 +- pkg/apis/eventing/v1/eventtype_conversion.go | 4 +- pkg/apis/eventing/v1/trigger_conversion.go | 4 +- pkg/apis/eventing/v1/zz_generated.deepcopy.go | 4 +- .../eventing/v1beta1/broker_conversion.go | 31 ++++- .../v1beta1/broker_conversion_test.go | 2 +- .../eventing/v1beta1/eventtype_conversion.go | 33 ++++- .../eventing/v1beta1/trigger_conversion.go | 39 +++++- .../v1beta1/trigger_conversion_test.go | 2 +- .../eventing/v1/broker/controller.go | 23 +++- .../eventing/v1/broker/reconciler.go | 123 ++++++++++++++---- .../eventing/v1/broker/stub/reconciler.go | 21 +++ .../eventing/v1/eventtype/controller.go | 23 +++- .../eventing/v1/eventtype/reconciler.go | 123 ++++++++++++++---- .../eventing/v1/eventtype/stub/reconciler.go | 21 +++ 15 files changed, 387 insertions(+), 70 deletions(-) diff --git a/pkg/apis/eventing/v1/broker_conversion.go b/pkg/apis/eventing/v1/broker_conversion.go index 0f7d820ed94..30f555c43ba 100644 --- a/pkg/apis/eventing/v1/broker_conversion.go +++ b/pkg/apis/eventing/v1/broker_conversion.go @@ -25,10 +25,10 @@ import ( // ConvertTo implements apis.Convertible func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) + return fmt.Errorf("v1 is the highest known version, got: %T", sink) } // ConvertFrom implements apis.Convertible func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) + return fmt.Errorf("v1 is the highest known version, got: %T", source) } diff --git a/pkg/apis/eventing/v1/eventtype_conversion.go b/pkg/apis/eventing/v1/eventtype_conversion.go index 3b36fca9774..a9ad6bfdbe3 100644 --- a/pkg/apis/eventing/v1/eventtype_conversion.go +++ b/pkg/apis/eventing/v1/eventtype_conversion.go @@ -25,10 +25,10 @@ import ( // ConvertTo implements apis.Convertible func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) + return fmt.Errorf("v1 is the highest known version, got: %T", sink) } // ConvertFrom implements apis.Convertible func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) + return fmt.Errorf("v1 is the highest known version, got: %T", source) } diff --git a/pkg/apis/eventing/v1/trigger_conversion.go b/pkg/apis/eventing/v1/trigger_conversion.go index e856396e321..0df6b92555c 100644 --- a/pkg/apis/eventing/v1/trigger_conversion.go +++ b/pkg/apis/eventing/v1/trigger_conversion.go @@ -25,10 +25,10 @@ import ( // ConvertTo implements apis.Convertible func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) + return fmt.Errorf("v1 is the highest known version, got: %T", sink) } // ConvertFrom implements apis.Convertible func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) + return fmt.Errorf("v1 is the highest known version, got: %T", source) } diff --git a/pkg/apis/eventing/v1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1/zz_generated.deepcopy.go index dcda76b4000..70c532fbe33 100644 --- a/pkg/apis/eventing/v1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ package v1 import ( runtime "k8s.io/apimachinery/pkg/runtime" - v1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + apisduckv1 "knative.dev/eventing/pkg/apis/duck/v1" apis "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -98,7 +98,7 @@ func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { } if in.Delivery != nil { in, out := &in.Delivery, &out.Delivery - *out = new(v1beta1.DeliverySpec) + *out = new(apisduckv1.DeliverySpec) (*in).DeepCopyInto(*out) } return diff --git a/pkg/apis/eventing/v1beta1/broker_conversion.go b/pkg/apis/eventing/v1beta1/broker_conversion.go index f0c61ca95c9..8f1cd7c9e67 100644 --- a/pkg/apis/eventing/v1beta1/broker_conversion.go +++ b/pkg/apis/eventing/v1beta1/broker_conversion.go @@ -20,15 +20,38 @@ import ( "context" "fmt" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/pkg/apis" ) // ConvertTo implements apis.Convertible -func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *Broker) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *v1.Broker: + sink.Spec.Config = source.Spec.Config + if err := source.Spec.Delivery.ConvertTo(ctx, sink.Spec.Delivery); err != nil { + return err + } + sink.Status.Status = source.Status.Status + sink.Status.Address = source.Status.Address + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *Broker) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *v1.Broker: + sink.Spec.Config = source.Spec.Config + if err := source.Spec.Delivery.ConvertFrom(ctx, sink.Spec.Delivery); err != nil { + return err + } + sink.Status.Status = source.Status.Status + sink.Status.Address = source.Status.Address + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } diff --git a/pkg/apis/eventing/v1beta1/broker_conversion_test.go b/pkg/apis/eventing/v1beta1/broker_conversion_test.go index aeb8b28969e..af182531610 100644 --- a/pkg/apis/eventing/v1beta1/broker_conversion_test.go +++ b/pkg/apis/eventing/v1beta1/broker_conversion_test.go @@ -22,7 +22,7 @@ import ( ) func TestBrokerConversionBadType(t *testing.T) { - good, bad := &Broker{}, &Broker{} + good, bad := &Broker{}, &Trigger{} if err := good.ConvertTo(context.Background(), bad); err == nil { t.Errorf("ConvertTo() = %#v, wanted error", bad) diff --git a/pkg/apis/eventing/v1beta1/eventtype_conversion.go b/pkg/apis/eventing/v1beta1/eventtype_conversion.go index 6ef342c8739..14a6dbaefae 100644 --- a/pkg/apis/eventing/v1beta1/eventtype_conversion.go +++ b/pkg/apis/eventing/v1beta1/eventtype_conversion.go @@ -20,15 +20,40 @@ import ( "context" "fmt" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/pkg/apis" ) // ConvertTo implements apis.Convertible -func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *EventType) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *v1.EventType: + sink.Spec.Type = source.Spec.Type + sink.Spec.Source = source.Spec.Source + sink.Spec.Schema = source.Spec.Schema + sink.Spec.SchemaData = source.Spec.SchemaData + sink.Spec.Broker = source.Spec.Broker + sink.Spec.Description = source.Spec.Description + sink.Status.Status = source.Status.Status + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *EventType) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *v1.EventType: + sink.Spec.Type = source.Spec.Type + sink.Spec.Source = source.Spec.Source + sink.Spec.Schema = source.Spec.Schema + sink.Spec.SchemaData = source.Spec.SchemaData + sink.Spec.Broker = source.Spec.Broker + sink.Spec.Description = source.Spec.Description + sink.Status.Status = source.Status.Status + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } diff --git a/pkg/apis/eventing/v1beta1/trigger_conversion.go b/pkg/apis/eventing/v1beta1/trigger_conversion.go index dc96d461d1e..455b4929260 100644 --- a/pkg/apis/eventing/v1beta1/trigger_conversion.go +++ b/pkg/apis/eventing/v1beta1/trigger_conversion.go @@ -20,15 +20,46 @@ import ( "context" "fmt" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/pkg/apis" ) // ConvertTo implements apis.Convertible -func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *Trigger) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *v1.Trigger: + sink.Spec.Broker = source.Spec.Broker + sink.Spec.Subscriber = source.Spec.Subscriber + if source.Spec.Filter != nil { + sink.Spec.Filter = &v1.TriggerFilter{} + } + for k, v := range source.Spec.Filter.Attributes { + sink.Spec.Filter.Attributes[k] = v + } + sink.Status.Status = source.Status.Status + sink.Status.SubscriberURI = source.Status.SubscriberURI + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *Trigger) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *v1.Trigger: + sink.Spec.Broker = source.Spec.Broker + sink.Spec.Subscriber = source.Spec.Subscriber + if source.Spec.Filter != nil { + sink.Spec.Filter = &TriggerFilter{} + } + for k, v := range source.Spec.Filter.Attributes { + sink.Spec.Filter.Attributes[k] = v + } + sink.Status.Status = source.Status.Status + sink.Status.SubscriberURI = source.Status.SubscriberURI + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } diff --git a/pkg/apis/eventing/v1beta1/trigger_conversion_test.go b/pkg/apis/eventing/v1beta1/trigger_conversion_test.go index acb94918207..eb5253f7cbc 100644 --- a/pkg/apis/eventing/v1beta1/trigger_conversion_test.go +++ b/pkg/apis/eventing/v1beta1/trigger_conversion_test.go @@ -22,7 +22,7 @@ import ( ) func TestTriggerConversionBadType(t *testing.T) { - good, bad := &Trigger{}, &Trigger{} + good, bad := &Trigger{}, &Broker{} if err := good.ConvertTo(context.Background(), bad); err == nil { t.Errorf("ConvertTo() = %#v, wanted error", bad) diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/controller.go b/pkg/client/injection/reconciler/eventing/v1/broker/controller.go index 5fc2915d5c4..1c907939345 100644 --- a/pkg/client/injection/reconciler/eventing/v1/broker/controller.go +++ b/pkg/client/injection/reconciler/eventing/v1/broker/controller.go @@ -25,6 +25,8 @@ import ( 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" @@ -35,6 +37,7 @@ import ( kubeclient "knative.dev/pkg/client/injection/kube/client" controller "knative.dev/pkg/controller" logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" ) const ( @@ -59,9 +62,27 @@ func NewImpl(ctx context.Context, r Interface, classValue string, optionsFns ... brokerInformer := broker.Get(ctx) + lister := brokerInformer.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: brokerInformer.Lister(), + Lister: lister, reconciler: r, finalizerName: defaultFinalizerName, classValue: classValue, diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go index 0cf1a49a876..c93e5842e23 100644 --- a/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1/broker/reconciler.go @@ -21,6 +21,7 @@ package broker import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -28,6 +29,7 @@ import ( 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" @@ -63,8 +65,30 @@ type Finalizer interface { FinalizeKind(ctx context.Context, o *v1.Broker) reconciler.Event } +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Broker if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1.Broker. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1.Broker) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Broker 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.Broker. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1.Broker) reconciler.Event +} + // reconcilerImpl implements controller.Reconciler for v1.Broker 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 @@ -92,13 +116,39 @@ type reconcilerImpl struct { // 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 eventingv1.BrokerLister, recorder record.EventRecorder, r Interface, classValue string, options ...controller.Options) controller.Reconciler { // Check the options function input. It should be 0 or 1. if len(options) > 1 { logger.Fatalf("up to one options struct is supported, found %d", len(options)) } + // 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, @@ -123,6 +173,25 @@ func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versio 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) @@ -131,15 +200,6 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Add the recorder to context. ctx = controller.WithEventRecorder(ctx, r.Recorder) - // Convert the namespace/name string into a distinct namespace and name - - namespace, name, err := cache.SplitMetaNamespaceKey(key) - - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Get the resource with this namespace/name. getter := r.Lister.Brokers(namespace) @@ -166,24 +226,32 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { var reconcileEvent reconciler.Event if resource.GetDeletionTimestamp().IsZero() { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + 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) + } - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) - } + reconciler.PreProcessReconcile(ctx, resource) - 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) - // 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) - reconciler.PostProcessReconcile(ctx, resource) + } else if isROI { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveKind")) - } else if fin, ok := r.reconciler.(Finalizer); ok { + // 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")) @@ -191,8 +259,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } + } 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. @@ -201,6 +275,9 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // 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", diff --git a/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go index 4af7c0a978a..85855a23644 100644 --- a/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1/broker/stub/reconciler.go @@ -46,6 +46,15 @@ var _ broker.Interface = (*Reconciler)(nil) // Optionally check that our Reconciler implements Finalizer //var _ broker.Finalizer = (*Reconciler)(nil) +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ broker.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 _ broker.ReadOnlyFinalizer = (*Reconciler)(nil) + // ReconcileKind implements Interface.ReconcileKind. func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.Broker) reconciler.Event { // TODO: use this if the resource implements InitializeConditions. @@ -64,3 +73,15 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.Broker) re // // 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 *eventingv1.Broker) 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 *eventingv1.Broker) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +//} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go index 4b8baabc07a..e8a1b37fab9 100644 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go @@ -25,6 +25,8 @@ import ( 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" @@ -35,6 +37,7 @@ import ( kubeclient "knative.dev/pkg/client/injection/kube/client" controller "knative.dev/pkg/controller" logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" ) const ( @@ -56,9 +59,27 @@ func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsF eventtypeInformer := eventtype.Get(ctx) + lister := eventtypeInformer.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: eventtypeInformer.Lister(), + Lister: lister, reconciler: r, finalizerName: defaultFinalizerName, } diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go index 8249565b8b6..a572fa039fd 100644 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go @@ -21,6 +21,7 @@ package eventtype import ( context "context" json "encoding/json" + fmt "fmt" reflect "reflect" zap "go.uber.org/zap" @@ -28,6 +29,7 @@ import ( 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" @@ -63,8 +65,30 @@ type Finalizer interface { FinalizeKind(ctx context.Context, o *v1.EventType) reconciler.Event } +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.EventType if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1.EventType. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1.EventType) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.EventType 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.EventType. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1.EventType) reconciler.Event +} + // reconcilerImpl implements controller.Reconciler for v1.EventType 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 @@ -89,13 +113,39 @@ type reconcilerImpl struct { // 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 eventingv1.EventTypeLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { // Check the options function input. It should be 0 or 1. if len(options) > 1 { logger.Fatalf("up to one options struct is supported, found %d", len(options)) } + // 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, @@ -119,6 +169,25 @@ func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versio 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) @@ -127,15 +196,6 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // Add the recorder to context. ctx = controller.WithEventRecorder(ctx, r.Recorder) - // Convert the namespace/name string into a distinct namespace and name - - namespace, name, err := cache.SplitMetaNamespaceKey(key) - - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Get the resource with this namespace/name. getter := r.Lister.EventTypes(namespace) @@ -155,24 +215,32 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { var reconcileEvent reconciler.Event if resource.GetDeletionTimestamp().IsZero() { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + 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) + } - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - logger.Warnw("Failed to set finalizers", zap.Error(err)) - } + reconciler.PreProcessReconcile(ctx, resource) - 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) - // 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) - reconciler.PostProcessReconcile(ctx, resource) + } else if isROI { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ObserveKind")) - } else if fin, ok := r.reconciler.(Finalizer); ok { + // 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")) @@ -180,8 +248,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = fin.FinalizeKind(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - logger.Warnw("Failed to clear finalizers", zap.Error(err)) + return fmt.Errorf("failed to clear finalizers: %w", err) } + } 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. @@ -190,6 +264,9 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { // 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", diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go index dd6b073d2ae..186a794159b 100644 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go +++ b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go @@ -46,6 +46,15 @@ var _ eventtype.Interface = (*Reconciler)(nil) // Optionally check that our Reconciler implements Finalizer //var _ eventtype.Finalizer = (*Reconciler)(nil) +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ eventtype.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 _ eventtype.ReadOnlyFinalizer = (*Reconciler)(nil) + // ReconcileKind implements Interface.ReconcileKind. func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { // TODO: use this if the resource implements InitializeConditions. @@ -64,3 +73,15 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.EventType) // // 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 *eventingv1.EventType) 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 *eventingv1.EventType) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +//} From e00a8e7c21006846cdcfe6fa7ce66c495f0b52ec Mon Sep 17 00:00:00 2001 From: Ville Aikas Date: Mon, 22 Jun 2020 16:11:26 -0700 Subject: [PATCH 4/6] moar v1beta1->v1 manual conversion --- pkg/apis/eventing/v1/broker_lifecycle.go | 4 ++-- pkg/apis/eventing/v1/broker_lifecycle_test.go | 4 ++-- pkg/apis/eventing/v1/broker_validation_test.go | 8 ++++---- pkg/apis/eventing/v1/doc.go | 2 +- pkg/apis/eventing/v1/eventtype_validation_test.go | 10 +++++----- pkg/apis/eventing/v1/test_helper.go | 12 ++++++------ 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/pkg/apis/eventing/v1/broker_lifecycle.go b/pkg/apis/eventing/v1/broker_lifecycle.go index 92972d09992..ebd71cde536 100644 --- a/pkg/apis/eventing/v1/broker_lifecycle.go +++ b/pkg/apis/eventing/v1/broker_lifecycle.go @@ -20,7 +20,7 @@ import ( corev1 "k8s.io/api/core/v1" "knative.dev/eventing/pkg/apis/duck" - duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + duckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" ) @@ -91,7 +91,7 @@ func (bs *BrokerStatus) MarkTriggerChannelFailed(reason, format string, args ... brokerCondSet.Manage(bs).MarkFalse(BrokerConditionTriggerChannel, reason, format, args...) } -func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *duckv1beta1.ChannelableStatus) { +func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *duckv1.ChannelableStatus) { // TODO: Once you can get a Ready status from Channelable in a generic way, use it here... address := cs.AddressStatus.Address if address != nil { diff --git a/pkg/apis/eventing/v1/broker_lifecycle_test.go b/pkg/apis/eventing/v1/broker_lifecycle_test.go index 9265a4f86ce..5c6fd43c112 100644 --- a/pkg/apis/eventing/v1/broker_lifecycle_test.go +++ b/pkg/apis/eventing/v1/broker_lifecycle_test.go @@ -19,7 +19,7 @@ import ( "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" - duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" @@ -312,7 +312,7 @@ func TestBrokerIsReady(t *testing.T) { bs.PropagateIngressAvailability(ep) } if test.markTriggerChannelReady != nil { - var c *duckv1beta1.ChannelableStatus + var c *eventingduckv1.ChannelableStatus if *test.markTriggerChannelReady { c = TestHelper.ReadyChannelStatus() } else { diff --git a/pkg/apis/eventing/v1/broker_validation_test.go b/pkg/apis/eventing/v1/broker_validation_test.go index 75535127f33..774d55fd27a 100644 --- a/pkg/apis/eventing/v1/broker_validation_test.go +++ b/pkg/apis/eventing/v1/broker_validation_test.go @@ -22,7 +22,7 @@ import ( "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" ) @@ -145,7 +145,7 @@ func TestValidate(t *testing.T) { name: "invalid delivery, invalid delay string", b: Broker{ Spec: BrokerSpec{ - Delivery: &eventingduckv1beta1.DeliverySpec{ + Delivery: &eventingduckv1.DeliverySpec{ BackoffDelay: &invalidString, }, }, @@ -163,7 +163,7 @@ func TestValidate(t *testing.T) { } func TestValidSpec(t *testing.T) { - bop := eventingduckv1beta1.BackoffPolicyExponential + bop := eventingduckv1.BackoffPolicyExponential tests := []struct { name string spec BrokerSpec @@ -190,7 +190,7 @@ func TestValidSpec(t *testing.T) { Kind: "kind", APIVersion: "apiversion", }, - Delivery: &eventingduckv1beta1.DeliverySpec{BackoffPolicy: &bop}, + Delivery: &eventingduckv1.DeliverySpec{BackoffPolicy: &bop}, }, }, {}} diff --git a/pkg/apis/eventing/v1/doc.go b/pkg/apis/eventing/v1/doc.go index 6de34688b38..312443ded79 100644 --- a/pkg/apis/eventing/v1/doc.go +++ b/pkg/apis/eventing/v1/doc.go @@ -14,7 +14,7 @@ * limitations under the License. */ -// Package v1beta1 is the v1beta1 version of the API. +// Package v1 is the v1 version of the API. // +k8s:deepcopy-gen=package // +groupName=eventing.knative.dev package v1 diff --git a/pkg/apis/eventing/v1/eventtype_validation_test.go b/pkg/apis/eventing/v1/eventtype_validation_test.go index e522581604f..ed1ce13050e 100644 --- a/pkg/apis/eventing/v1/eventtype_validation_test.go +++ b/pkg/apis/eventing/v1/eventtype_validation_test.go @@ -137,7 +137,7 @@ func TestEventTypeImmutableFields(t *testing.T) { want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1beta1.EventTypeSpec}.Broker: + Details: `{v1.EventTypeSpec}.Broker: -: "original-broker" +: "test-broker" `, @@ -161,7 +161,7 @@ func TestEventTypeImmutableFields(t *testing.T) { want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1beta1.EventTypeSpec}.Type: + Details: `{v1.EventTypeSpec}.Type: -: "original-type" +: "test-type" `, @@ -185,7 +185,7 @@ func TestEventTypeImmutableFields(t *testing.T) { want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1beta1.EventTypeSpec}.Source.Host: + Details: `{v1.EventTypeSpec}.Source.Host: -: "original-source" +: "test-source" `, @@ -211,7 +211,7 @@ func TestEventTypeImmutableFields(t *testing.T) { want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1beta1.EventTypeSpec}.Schema.Host: + Details: `{v1.EventTypeSpec}.Schema.Host: -: "original-schema" +: "test-schema" `, @@ -239,7 +239,7 @@ func TestEventTypeImmutableFields(t *testing.T) { want: &apis.FieldError{ Message: "Immutable fields changed (-old +new)", Paths: []string{"spec"}, - Details: `{v1beta1.EventTypeSpec}.Description: + Details: `{v1.EventTypeSpec}.Description: -: "original-description" +: "test-description" `, diff --git a/pkg/apis/eventing/v1/test_helper.go b/pkg/apis/eventing/v1/test_helper.go index 49073aec4d9..64e8d112c7b 100644 --- a/pkg/apis/eventing/v1/test_helper.go +++ b/pkg/apis/eventing/v1/test_helper.go @@ -19,7 +19,7 @@ package v1 import ( corev1 "k8s.io/api/core/v1" - duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" @@ -105,18 +105,18 @@ func (testHelper) AvailableEndpoints() *corev1.Endpoints { return ep } -func (testHelper) ReadyChannelStatus() *duckv1beta1.ChannelableStatus { - cs := &duckv1beta1.ChannelableStatus{ +func (testHelper) ReadyChannelStatus() *eventingduckv1.ChannelableStatus { + cs := &eventingduckv1.ChannelableStatus{ Status: duckv1.Status{}, AddressStatus: duckv1.AddressStatus{ Address: &duckv1.Addressable{ URL: &apis.URL{Scheme: "http", Host: "foo"}, }, }, - SubscribableStatus: duckv1beta1.SubscribableStatus{}} + SubscribableStatus: eventingduckv1.SubscribableStatus{}} return cs } -func (t testHelper) NotReadyChannelStatus() *duckv1beta1.ChannelableStatus { - return &duckv1beta1.ChannelableStatus{} +func (t testHelper) NotReadyChannelStatus() *eventingduckv1.ChannelableStatus { + return &eventingduckv1.ChannelableStatus{} } From af98ca3198fb96e821082d4b004a5a90e50494bc Mon Sep 17 00:00:00 2001 From: Ville Aikas Date: Tue, 23 Jun 2020 07:18:19 -0700 Subject: [PATCH 5/6] fix pr comments --- hack/update-codegen.sh | 2 +- pkg/apis/eventing/v1/register.go | 2 +- pkg/apis/eventing/v1/trigger_types.go | 1 + .../eventing/v1/trigger/controller.go | 139 ++++++ .../eventing/v1/trigger/reconciler.go | 434 ++++++++++++++++++ .../eventing/v1/trigger/stub/controller.go | 54 +++ .../eventing/v1/trigger/stub/reconciler.go | 87 ++++ 7 files changed, 717 insertions(+), 2 deletions(-) create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/reconciler.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go create mode 100644 pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 2c2567cf168..11304cfa1f6 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -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 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 configs:v1alpha1" \ + "eventing:v1beta1 eventing:v1 messaging:v1beta1 flows:v1beta1 sources:v1alpha1 sources:v1alpha2 duck:v1alpha1 duck:v1beta1 duck:v1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/eventing/v1/register.go b/pkg/apis/eventing/v1/register.go index 2d243ad9316..176bf23b31d 100644 --- a/pkg/apis/eventing/v1/register.go +++ b/pkg/apis/eventing/v1/register.go @@ -25,7 +25,7 @@ import ( ) // SchemeGroupVersion is group version used to register these objects -var SchemeGroupVersion = schema.GroupVersion{Group: eventing.GroupName, Version: "v1beta1"} +var SchemeGroupVersion = schema.GroupVersion{Group: eventing.GroupName, Version: "v1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { diff --git a/pkg/apis/eventing/v1/trigger_types.go b/pkg/apis/eventing/v1/trigger_types.go index 67eb11453bd..ae1005ce40c 100644 --- a/pkg/apis/eventing/v1/trigger_types.go +++ b/pkg/apis/eventing/v1/trigger_types.go @@ -34,6 +34,7 @@ const ( ) // +genclient +// +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Trigger represents a request to have events delivered to a consumer from a diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/controller.go b/pkg/client/injection/reconciler/eventing/v1/trigger/controller.go new file mode 100644 index 00000000000..9a7c7c077b9 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/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 trigger + +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" + trigger "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +const ( + defaultControllerAgentName = "trigger-controller" + defaultFinalizerName = "triggers.eventing.knative.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + triggerInformer := trigger.Get(ctx) + + lister := triggerInformer.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/eventing/v1/trigger/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/trigger/reconciler.go new file mode 100644 index 00000000000..5d6bc163928 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/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 trigger + +import ( + context "context" + json "encoding/json" + fmt "fmt" + reflect "reflect" + + zap "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + 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/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Trigger. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1.Trigger. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1.Trigger) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Trigger. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1.Trigger. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1.Trigger) reconciler.Event +} + +// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1.Trigger if they want to process resources for which +// they are not the leader. +type ReadOnlyInterface interface { + // ObserveKind implements logic to observe v1.Trigger. + // This method should not write to the API. + ObserveKind(ctx context.Context, o *v1.Trigger) reconciler.Event +} + +// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1.Trigger 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.Trigger. + // This method should not write to the API. + ObserveFinalizeKind(ctx context.Context, o *v1.Trigger) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1.Trigger 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 eventingv1.TriggerLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +// 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 eventingv1.TriggerLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + // 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.Triggers(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + 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.Trigger, desired *v1.Trigger) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.EventingV1().Triggers(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.EventingV1().Triggers(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.Trigger) (*v1.Trigger, error) { + + getter := r.Lister.Triggers(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.EventingV1().Triggers(resource.Namespace) + + resourceName := resource.Name + resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resourceName, err) + } else { + r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.Trigger) (*v1.Trigger, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.Trigger, reconcileEvent reconciler.Event) (*v1.Trigger, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == corev1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go new file mode 100644 index 00000000000..763d680a2b9 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package trigger + +import ( + context "context" + + trigger "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger" + v1trigger "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/trigger" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Trigger and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + triggerInformer := trigger.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1trigger.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + triggerInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/trigger/stub/reconciler.go new file mode 100644 index 00000000000..85b7ad70632 --- /dev/null +++ b/pkg/client/injection/reconciler/eventing/v1/trigger/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 trigger + +import ( + context "context" + + v1 "k8s.io/api/core/v1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + trigger "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/trigger" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason TriggerReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "TriggerReconciled", "Trigger reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Trigger resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ trigger.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ trigger.Finalizer = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements ReadOnlyInterface +// Implement this to observe resources even when we are not the leader. +//var _ trigger.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 _ trigger.ReadOnlyFinalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.Trigger) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.Trigger) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} + +// Optionally, use ObserveKind to observe the resource when we are not the leader. +// func (r *Reconciler) ObserveKind(ctx context.Context, o *eventingv1.Trigger) 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 *eventingv1.Trigger) reconciler.Event { +// // TODO: add custom observation logic here. +// return nil +//} From 85923406355efe950f8db5a387bbe618a3becbf1 Mon Sep 17 00:00:00 2001 From: Ville Aikas Date: Tue, 23 Jun 2020 09:09:23 -0700 Subject: [PATCH 6/6] remove eventtypes --- pkg/apis/eventing/v1/eventtype_conversion.go | 34 -- .../eventing/v1/eventtype_conversion_test.go | 34 -- pkg/apis/eventing/v1/eventtype_defaults.go | 29 -- .../eventing/v1/eventtype_defaults_test.go | 87 ---- pkg/apis/eventing/v1/eventtype_lifecycle.go | 103 ----- .../eventing/v1/eventtype_lifecycle_test.go | 257 ----------- pkg/apis/eventing/v1/eventtype_types.go | 119 ----- pkg/apis/eventing/v1/eventtype_types_test.go | 39 -- pkg/apis/eventing/v1/eventtype_validation.go | 62 --- .../eventing/v1/eventtype_validation_test.go | 258 ----------- pkg/apis/eventing/v1/register.go | 2 - pkg/apis/eventing/v1/zz_generated.deepcopy.go | 104 ----- .../eventing/v1beta1/eventtype_conversion.go | 29 +- .../typed/eventing/v1/eventing_client.go | 5 - .../versioned/typed/eventing/v1/eventtype.go | 191 -------- .../eventing/v1/fake/fake_eventing_client.go | 4 - .../typed/eventing/v1/fake/fake_eventtype.go | 140 ------ .../typed/eventing/v1/generated_expansion.go | 2 - .../externalversions/eventing/v1/eventtype.go | 89 ---- .../externalversions/eventing/v1/interface.go | 7 - .../informers/externalversions/generic.go | 2 - .../eventing/v1/eventtype/eventtype.go | 52 --- .../eventing/v1/eventtype/fake/fake.go | 40 -- .../eventing/v1/eventtype/controller.go | 139 ------ .../eventing/v1/eventtype/reconciler.go | 434 ------------------ .../eventing/v1/eventtype/stub/controller.go | 54 --- .../eventing/v1/eventtype/stub/reconciler.go | 87 ---- pkg/client/listers/eventing/v1/eventtype.go | 94 ---- .../eventing/v1/expansion_generated.go | 8 - 29 files changed, 2 insertions(+), 2503 deletions(-) delete mode 100644 pkg/apis/eventing/v1/eventtype_conversion.go delete mode 100644 pkg/apis/eventing/v1/eventtype_conversion_test.go delete mode 100644 pkg/apis/eventing/v1/eventtype_defaults.go delete mode 100644 pkg/apis/eventing/v1/eventtype_defaults_test.go delete mode 100644 pkg/apis/eventing/v1/eventtype_lifecycle.go delete mode 100644 pkg/apis/eventing/v1/eventtype_lifecycle_test.go delete mode 100644 pkg/apis/eventing/v1/eventtype_types.go delete mode 100644 pkg/apis/eventing/v1/eventtype_types_test.go delete mode 100644 pkg/apis/eventing/v1/eventtype_validation.go delete mode 100644 pkg/apis/eventing/v1/eventtype_validation_test.go delete mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go delete mode 100644 pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go delete mode 100644 pkg/client/informers/externalversions/eventing/v1/eventtype.go delete mode 100644 pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go delete mode 100644 pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go delete mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go delete mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go delete mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go delete mode 100644 pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go delete mode 100644 pkg/client/listers/eventing/v1/eventtype.go diff --git a/pkg/apis/eventing/v1/eventtype_conversion.go b/pkg/apis/eventing/v1/eventtype_conversion.go deleted file mode 100644 index a9ad6bfdbe3..00000000000 --- a/pkg/apis/eventing/v1/eventtype_conversion.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2020 The Knative Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "context" - "fmt" - - "knative.dev/pkg/apis" -) - -// ConvertTo implements apis.Convertible -func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1 is the highest known version, got: %T", sink) -} - -// ConvertFrom implements apis.Convertible -func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1 is the highest known version, got: %T", source) -} diff --git a/pkg/apis/eventing/v1/eventtype_conversion_test.go b/pkg/apis/eventing/v1/eventtype_conversion_test.go deleted file mode 100644 index 39145489459..00000000000 --- a/pkg/apis/eventing/v1/eventtype_conversion_test.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "context" - "testing" -) - -func TestEventTypeConversionBadType(t *testing.T) { - good, bad := &EventType{}, &EventType{} - - if err := good.ConvertTo(context.Background(), bad); err == nil { - t.Errorf("ConvertTo() = %#v, wanted error", bad) - } - - if err := good.ConvertFrom(context.Background(), bad); err == nil { - t.Errorf("ConvertFrom() = %#v, wanted error", good) - } -} diff --git a/pkg/apis/eventing/v1/eventtype_defaults.go b/pkg/apis/eventing/v1/eventtype_defaults.go deleted file mode 100644 index fa02a0d929c..00000000000 --- a/pkg/apis/eventing/v1/eventtype_defaults.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import "context" - -func (et *EventType) SetDefaults(ctx context.Context) { - et.Spec.SetDefaults(ctx) -} - -func (ets *EventTypeSpec) SetDefaults(ctx context.Context) { - if ets.Broker == "" { - ets.Broker = "default" - } -} diff --git a/pkg/apis/eventing/v1/eventtype_defaults_test.go b/pkg/apis/eventing/v1/eventtype_defaults_test.go deleted file mode 100644 index 3f73f59bf11..00000000000 --- a/pkg/apis/eventing/v1/eventtype_defaults_test.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "context" - "testing" - - "github.com/google/go-cmp/cmp" - - "knative.dev/pkg/apis" -) - -func TestEventTypeDefaults(t *testing.T) { - testSource := apis.HTTP("test-source") - testSchema := apis.HTTP("test-schema") - testCases := map[string]struct { - initial EventType - expected EventType - }{ - "nil spec": { - initial: EventType{}, - expected: EventType{ - Spec: EventTypeSpec{ - Broker: "default", - }, - }, - }, - "broker empty": { - initial: EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "", - Schema: testSchema, - }, - }, - expected: EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "default", - Schema: testSchema, - }, - }, - }, - "broker not set": { - initial: EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Schema: testSchema, - }, - }, - expected: EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "default", - Schema: testSchema, - }, - }, - }, - } - for n, tc := range testCases { - t.Run(n, func(t *testing.T) { - tc.initial.SetDefaults(context.TODO()) - if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { - t.Fatalf("Unexpected defaults (-want, +got): %s", diff) - } - }) - } -} diff --git a/pkg/apis/eventing/v1/eventtype_lifecycle.go b/pkg/apis/eventing/v1/eventtype_lifecycle.go deleted file mode 100644 index 50f9758563b..00000000000 --- a/pkg/apis/eventing/v1/eventtype_lifecycle.go +++ /dev/null @@ -1,103 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - corev1 "k8s.io/api/core/v1" - - "knative.dev/pkg/apis" -) - -var eventTypeCondSet = apis.NewLivingConditionSet(EventTypeConditionBrokerExists, EventTypeConditionBrokerReady) - -const ( - EventTypeConditionReady = apis.ConditionReady - EventTypeConditionBrokerExists apis.ConditionType = "BrokerExists" - EventTypeConditionBrokerReady apis.ConditionType = "BrokerReady" -) - -// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. -func (*EventType) GetConditionSet() apis.ConditionSet { - return eventTypeCondSet -} - -// GetCondition returns the condition currently associated with the given type, or nil. -func (et *EventTypeStatus) GetCondition(t apis.ConditionType) *apis.Condition { - return eventTypeCondSet.Manage(et).GetCondition(t) -} - -// IsReady returns true if the resource is ready overall. -func (et *EventTypeStatus) IsReady() bool { - return eventTypeCondSet.Manage(et).IsHappy() -} - -// GetTopLevelCondition returns the top level Condition. -func (et *EventTypeStatus) GetTopLevelCondition() *apis.Condition { - return eventTypeCondSet.Manage(et).GetTopLevelCondition() -} - -// InitializeConditions sets relevant unset conditions to Unknown state. -func (et *EventTypeStatus) InitializeConditions() { - eventTypeCondSet.Manage(et).InitializeConditions() -} - -func (et *EventTypeStatus) MarkBrokerExists() { - eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerExists) -} - -func (et *EventTypeStatus) MarkBrokerDoesNotExist() { - eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerExists, "BrokerDoesNotExist", "Broker does not exist") -} - -func (et *EventTypeStatus) MarkBrokerExistsUnknown(reason, messageFormat string, messageA ...interface{}) { - eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerExists, reason, messageFormat, messageA...) -} - -func (et *EventTypeStatus) MarkBrokerReady() { - eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) -} - -func (et *EventTypeStatus) MarkBrokerFailed(reason, messageFormat string, messageA ...interface{}) { - eventTypeCondSet.Manage(et).MarkFalse(EventTypeConditionBrokerReady, reason, messageFormat, messageA...) -} - -func (et *EventTypeStatus) MarkBrokerUnknown(reason, messageFormat string, messageA ...interface{}) { - eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerReady, reason, messageFormat, messageA...) -} - -func (et *EventTypeStatus) MarkBrokerNotConfigured() { - eventTypeCondSet.Manage(et).MarkUnknown(EventTypeConditionBrokerReady, - "BrokerNotConfigured", "Broker has not yet been reconciled.") -} - -func (et *EventTypeStatus) PropagateBrokerStatus(bs *BrokerStatus) { - bc := brokerCondSet.Manage(bs).GetTopLevelCondition() - if bc == nil { - et.MarkBrokerNotConfigured() - return - } - switch { - case bc.Status == corev1.ConditionUnknown: - et.MarkBrokerUnknown(bc.Reason, bc.Message) - case bc.Status == corev1.ConditionTrue: - eventTypeCondSet.Manage(et).MarkTrue(EventTypeConditionBrokerReady) - case bc.Status == corev1.ConditionFalse: - et.MarkBrokerFailed(bc.Reason, bc.Message) - default: - et.MarkBrokerUnknown("BrokerUnknown", "The status of Broker is invalid: %v", bc.Status) - } -} diff --git a/pkg/apis/eventing/v1/eventtype_lifecycle_test.go b/pkg/apis/eventing/v1/eventtype_lifecycle_test.go deleted file mode 100644 index 426c08d1aec..00000000000 --- a/pkg/apis/eventing/v1/eventtype_lifecycle_test.go +++ /dev/null @@ -1,257 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - corev1 "k8s.io/api/core/v1" - "knative.dev/pkg/apis" - duckv1 "knative.dev/pkg/apis/duck/v1" -) - -var ( - trueValue = true - falseValue = false -) - -var ( - eventTypeConditionReady = apis.Condition{ - Type: EventTypeConditionReady, - Status: corev1.ConditionTrue, - } - - eventTypeConditionBrokerExists = apis.Condition{ - Type: EventTypeConditionBrokerExists, - Status: corev1.ConditionTrue, - } - - eventTypeConditionBrokerReady = apis.Condition{ - Type: EventTypeConditionBrokerReady, - Status: corev1.ConditionTrue, - } -) - -func TestEventTypeGetConditionSet(t *testing.T) { - r := &EventType{} - - if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { - t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) - } -} - -func TestEventTypeGetCondition(t *testing.T) { - tests := []struct { - name string - ets *EventTypeStatus - condQuery apis.ConditionType - want *apis.Condition - }{{ - name: "single condition", - ets: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{ - eventTypeConditionReady, - }, - }, - }, - condQuery: apis.ConditionReady, - want: &eventTypeConditionReady, - }, { - name: "broker exists condition", - ets: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{ - eventTypeConditionBrokerExists, - }, - }, - }, - condQuery: EventTypeConditionBrokerExists, - want: &eventTypeConditionBrokerExists, - }, { - name: "multiple conditions, condition true", - ets: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{ - eventTypeConditionBrokerExists, - eventTypeConditionBrokerReady, - }, - }, - }, - condQuery: EventTypeConditionBrokerReady, - want: &eventTypeConditionBrokerReady, - }, { - name: "unknown condition", - ets: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{ - eventTypeConditionBrokerReady, - eventTypeConditionReady, - }, - }, - }, - condQuery: apis.ConditionType("foo"), - want: nil, - }} - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.ets.GetCondition(test.condQuery) - if diff := cmp.Diff(test.want, got); diff != "" { - t.Errorf("unexpected condition (-want, +got) = %v", diff) - } - }) - } -} - -func TestEventTypeInitializeConditions(t *testing.T) { - tests := []struct { - name string - ets *EventTypeStatus - want *EventTypeStatus - }{{ - name: "empty", - ets: &EventTypeStatus{}, - want: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: EventTypeConditionBrokerExists, - Status: corev1.ConditionUnknown, - }, { - Type: EventTypeConditionBrokerReady, - Status: corev1.ConditionUnknown, - }, { - Type: EventTypeConditionReady, - Status: corev1.ConditionUnknown, - }, - }, - }, - }, - }, { - name: "one false", - ets: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: EventTypeConditionBrokerExists, - Status: corev1.ConditionFalse, - }}, - }, - }, - want: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: EventTypeConditionBrokerExists, - Status: corev1.ConditionFalse, - }, { - Type: EventTypeConditionBrokerReady, - Status: corev1.ConditionUnknown, - }, { - Type: EventTypeConditionReady, - Status: corev1.ConditionUnknown, - }}, - }, - }, - }, { - name: "one true", - ets: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: EventTypeConditionBrokerReady, - Status: corev1.ConditionTrue, - }}, - }, - }, - want: &EventTypeStatus{ - Status: duckv1.Status{ - Conditions: []apis.Condition{{ - Type: EventTypeConditionBrokerExists, - Status: corev1.ConditionUnknown, - }, { - Type: EventTypeConditionBrokerReady, - Status: corev1.ConditionTrue, - }, { - Type: EventTypeConditionReady, - Status: corev1.ConditionUnknown, - }}, - }, - }}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - test.ets.InitializeConditions() - if diff := cmp.Diff(test.want, test.ets, ignoreAllButTypeAndStatus); diff != "" { - t.Errorf("unexpected conditions (-want, +got) = %v", diff) - } - }) - } -} - -func TestEventTypeConditionStatus(t *testing.T) { - tests := []struct { - name string - markBrokerExists *bool - brokerStatus *BrokerStatus - wantConditionStatus corev1.ConditionStatus - }{{ - name: "all happy", - markBrokerExists: &trueValue, - brokerStatus: TestHelper.ReadyBrokerStatus(), - wantConditionStatus: corev1.ConditionTrue, - }, { - name: "broker exist sad", - markBrokerExists: &falseValue, - brokerStatus: nil, - wantConditionStatus: corev1.ConditionFalse, - }, { - name: "broker ready sad", - markBrokerExists: &trueValue, - brokerStatus: TestHelper.FalseBrokerStatus(), - wantConditionStatus: corev1.ConditionFalse, - }, { - name: "broker ready unknown", - markBrokerExists: &trueValue, - brokerStatus: TestHelper.UnknownBrokerStatus(), - wantConditionStatus: corev1.ConditionUnknown, - }, { - name: "all sad", - markBrokerExists: &falseValue, - brokerStatus: nil, - wantConditionStatus: corev1.ConditionFalse, - }} - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - ets := &EventTypeStatus{} - if test.markBrokerExists != nil { - if *test.markBrokerExists { - ets.MarkBrokerExists() - } else { - ets.MarkBrokerDoesNotExist() - } - } - if test.brokerStatus != nil { - ets.PropagateBrokerStatus(test.brokerStatus) - } - - got := ets.GetTopLevelCondition().Status - if test.wantConditionStatus != got { - t.Errorf("unexpected readiness: want %v, got %v", test.wantConditionStatus, got) - } - }) - } -} diff --git a/pkg/apis/eventing/v1/eventtype_types.go b/pkg/apis/eventing/v1/eventtype_types.go deleted file mode 100644 index 8686872fb01..00000000000 --- a/pkg/apis/eventing/v1/eventtype_types.go +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2020 The Knative Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "knative.dev/pkg/apis" - duckv1 "knative.dev/pkg/apis/duck/v1" - "knative.dev/pkg/kmeta" -) - -// +genclient -// +genreconciler:krshapedlogic=true -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type EventType struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` - - // Spec defines the desired state of the EventType. - Spec EventTypeSpec `json:"spec,omitempty"` - - // Status represents the current state of the EventType. - // This data may be out of date. - // +optional - // TODO might be removed https://github.com/knative/eventing/issues/2750 - Status EventTypeStatus `json:"status,omitempty"` -} - -var ( - // Check that EventType can be validated, can be defaulted, and has immutable fields. - _ apis.Validatable = (*EventType)(nil) - _ apis.Defaultable = (*EventType)(nil) - - // Check that EventType can return its spec untyped. - _ apis.HasSpec = (*EventType)(nil) - - _ runtime.Object = (*EventType)(nil) - - // Check that we can create OwnerReferences to an EventType. - _ kmeta.OwnerRefable = (*EventType)(nil) - - // Check that the type conforms to the duck Knative Resource shape. - _ duckv1.KRShaped = (*EventType)(nil) -) - -type EventTypeSpec struct { - // Type represents the CloudEvents type. It is authoritative. - Type string `json:"type"` - // Source is a URI, it represents the CloudEvents source. - // +optional - Source *apis.URL `json:"source,omitempty"` - // Schema is a URI, it represents the CloudEvents schemaurl extension attribute. - // It may be a JSON schema, a protobuf schema, etc. It is optional. - // +optional - Schema *apis.URL `json:"schema,omitempty"` - // SchemaData allows the CloudEvents schema to be stored directly in the - // EventType. Content is dependent on the encoding. Optional attribute. - // The contents are not validated or manipulated by the system. - // +optional - SchemaData string `json:"schemaData,omitempty"` - // TODO remove https://github.com/knative/eventing/issues/2750 - // Broker refers to the Broker that can provide the EventType. - // +optional - Broker string `json:"broker,omitempty"` - // Description is an optional field used to describe the EventType, in any meaningful way. - // +optional - Description string `json:"description,omitempty"` -} - -// EventTypeStatus represents the current state of a EventType. -type EventTypeStatus struct { - // inherits duck/v1 Status, which currently provides: - // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. - // * Conditions - the latest available observations of a resource's current state. - duckv1.Status `json:",inline"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// EventTypeList is a collection of EventTypes. -type EventTypeList struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ListMeta `json:"metadata,omitempty"` - Items []EventType `json:"items"` -} - -// GetGroupVersionKind returns GroupVersionKind for EventType -func (p *EventType) GetGroupVersionKind() schema.GroupVersionKind { - return SchemeGroupVersion.WithKind("EventType") -} - -// GetUntypedSpec returns the spec of the EventType. -func (e *EventType) GetUntypedSpec() interface{} { - return e.Spec -} - -// GetStatus retrieves the status of the EventType. Implements the KRShaped interface. -func (t *EventType) GetStatus() *duckv1.Status { - return &t.Status.Status -} diff --git a/pkg/apis/eventing/v1/eventtype_types_test.go b/pkg/apis/eventing/v1/eventtype_types_test.go deleted file mode 100644 index 09d5ac826a5..00000000000 --- a/pkg/apis/eventing/v1/eventtype_types_test.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "testing" -) - -func TestEventTypeGetStatus(t *testing.T) { - r := &EventType{ - Status: EventTypeStatus{}, - } - if got, want := r.GetStatus(), &r.Status.Status; got != want { - t.Errorf("GetStatus=%v, want=%v", got, want) - } -} - -func TestEventType_GetGroupVersionKind(t *testing.T) { - src := EventType{} - gvk := src.GetGroupVersionKind() - - if gvk.Kind != "EventType" { - t.Errorf("Should be EventType.") - } -} diff --git a/pkg/apis/eventing/v1/eventtype_validation.go b/pkg/apis/eventing/v1/eventtype_validation.go deleted file mode 100644 index 46939f77e02..00000000000 --- a/pkg/apis/eventing/v1/eventtype_validation.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "context" - - "knative.dev/pkg/apis" - "knative.dev/pkg/kmp" -) - -func (et *EventType) Validate(ctx context.Context) *apis.FieldError { - return et.Spec.Validate(ctx).ViaField("spec") -} - -func (ets *EventTypeSpec) Validate(ctx context.Context) *apis.FieldError { - var errs *apis.FieldError - if ets.Type == "" { - fe := apis.ErrMissingField("type") - errs = errs.Also(fe) - } - // TODO validate Source is a valid URI. - // TODO validate Schema is a valid URI. - // There is no validation of the SchemaData, it is application specific data. - return errs -} - -func (et *EventType) CheckImmutableFields(ctx context.Context, original *EventType) *apis.FieldError { - if original == nil { - return nil - } - - // All fields are immutable. - if diff, err := kmp.ShortDiff(original.Spec, et.Spec); err != nil { - return &apis.FieldError{ - Message: "Failed to diff EventType", - Paths: []string{"spec"}, - Details: err.Error(), - } - } else if diff != "" { - return &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec"}, - Details: diff, - } - } - return nil -} diff --git a/pkg/apis/eventing/v1/eventtype_validation_test.go b/pkg/apis/eventing/v1/eventtype_validation_test.go deleted file mode 100644 index ed1ce13050e..00000000000 --- a/pkg/apis/eventing/v1/eventtype_validation_test.go +++ /dev/null @@ -1,258 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -import ( - "context" - "testing" - - "github.com/google/go-cmp/cmp" - "knative.dev/pkg/apis" -) - -func TestEventTypeValidation(t *testing.T) { - name := "invalid type" - et := &EventType{Spec: EventTypeSpec{}} - - want := &apis.FieldError{ - Paths: []string{"spec.type"}, - Message: "missing field(s)", - } - - t.Run(name, func(t *testing.T) { - got := et.Validate(context.TODO()) - if diff := cmp.Diff(want.Error(), got.Error()); diff != "" { - t.Errorf("EventType.Validate (-want, +got) = %v", diff) - } - }) -} - -func TestEventTypeSpecValidation(t *testing.T) { - testSource := apis.HTTP("test-source") - tests := []struct { - name string - ets *EventTypeSpec - want *apis.FieldError - }{{ - name: "invalid eventtype type", - ets: &EventTypeSpec{}, - want: func() *apis.FieldError { - fe := apis.ErrMissingField("type") - return fe - }(), - }, { - name: "valid eventtype", - ets: &EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.ets.Validate(context.TODO()) - if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { - t.Errorf("%s: Validate EventTypeSpec (-want, +got) = %v", test.name, diff) - } - }) - } -} - -func TestEventTypeImmutableFields(t *testing.T) { - differentSource := apis.HTTP("original-source") - testSource := apis.HTTP("test-source") - testSchema := apis.HTTP("test-schema") - testSchemaData := `{"data": "awesome"}` - differentSchema := apis.HTTP("original-schema") - tests := []struct { - name string - current *EventType - original *EventType - want *apis.FieldError - }{{ - name: "good (no change)", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: testSchema, - SchemaData: testSchemaData, - }, - }, - original: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: testSchema, - SchemaData: testSchemaData, - }, - }, - want: nil, - }, { - name: "new nil is ok", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: testSchema, - }, - }, - original: nil, - want: nil, - }, { - name: "bad (broker change)", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - }, - }, - original: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "original-broker", - }, - }, - want: &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec"}, - Details: `{v1.EventTypeSpec}.Broker: - -: "original-broker" - +: "test-broker" -`, - }, - }, { - name: "bad (type change)", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - }, - }, - original: &EventType{ - Spec: EventTypeSpec{ - Type: "original-type", - Source: testSource, - Broker: "test-broker", - }, - }, - want: &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec"}, - Details: `{v1.EventTypeSpec}.Type: - -: "original-type" - +: "test-type" -`, - }, - }, { - name: "bad (source change)", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - }, - }, - original: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: differentSource, - Broker: "test-broker", - }, - }, - want: &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec"}, - Details: `{v1.EventTypeSpec}.Source.Host: - -: "original-source" - +: "test-source" -`, - }, - }, { - name: "bad (schema change)", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: testSchema, - }, - }, - original: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: differentSchema, - }, - }, - want: &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec"}, - Details: `{v1.EventTypeSpec}.Schema.Host: - -: "original-schema" - +: "test-schema" -`, - }, - }, { - name: "bad (description change)", - current: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: testSchema, - Description: "test-description", - }, - }, - original: &EventType{ - Spec: EventTypeSpec{ - Type: "test-type", - Source: testSource, - Broker: "test-broker", - Schema: testSchema, - Description: "original-description", - }, - }, - want: &apis.FieldError{ - Message: "Immutable fields changed (-old +new)", - Paths: []string{"spec"}, - Details: `{v1.EventTypeSpec}.Description: - -: "original-description" - +: "test-description" -`, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - got := test.current.CheckImmutableFields(context.TODO(), test.original) - if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { - t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) - } - }) - } -} diff --git a/pkg/apis/eventing/v1/register.go b/pkg/apis/eventing/v1/register.go index 176bf23b31d..0ff47f32ffc 100644 --- a/pkg/apis/eventing/v1/register.go +++ b/pkg/apis/eventing/v1/register.go @@ -47,8 +47,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &Broker{}, &BrokerList{}, - &EventType{}, - &EventTypeList{}, &Trigger{}, &TriggerList{}, ) diff --git a/pkg/apis/eventing/v1/zz_generated.deepcopy.go b/pkg/apis/eventing/v1/zz_generated.deepcopy.go index 70c532fbe33..41b8f75e6d9 100644 --- a/pkg/apis/eventing/v1/zz_generated.deepcopy.go +++ b/pkg/apis/eventing/v1/zz_generated.deepcopy.go @@ -132,110 +132,6 @@ func (in *BrokerStatus) DeepCopy() *BrokerStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EventType) DeepCopyInto(out *EventType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventType. -func (in *EventType) DeepCopy() *EventType { - if in == nil { - return nil - } - out := new(EventType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *EventType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EventTypeList) DeepCopyInto(out *EventTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]EventType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeList. -func (in *EventTypeList) DeepCopy() *EventTypeList { - if in == nil { - return nil - } - out := new(EventTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *EventTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EventTypeSpec) DeepCopyInto(out *EventTypeSpec) { - *out = *in - if in.Source != nil { - in, out := &in.Source, &out.Source - *out = new(apis.URL) - (*in).DeepCopyInto(*out) - } - if in.Schema != nil { - in, out := &in.Schema, &out.Schema - *out = new(apis.URL) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeSpec. -func (in *EventTypeSpec) DeepCopy() *EventTypeSpec { - if in == nil { - return nil - } - out := new(EventTypeSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *EventTypeStatus) DeepCopyInto(out *EventTypeStatus) { - *out = *in - in.Status.DeepCopyInto(&out.Status) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EventTypeStatus. -func (in *EventTypeStatus) DeepCopy() *EventTypeStatus { - if in == nil { - return nil - } - out := new(EventTypeStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Trigger) DeepCopyInto(out *Trigger) { *out = *in diff --git a/pkg/apis/eventing/v1beta1/eventtype_conversion.go b/pkg/apis/eventing/v1beta1/eventtype_conversion.go index 14a6dbaefae..011a013eea6 100644 --- a/pkg/apis/eventing/v1beta1/eventtype_conversion.go +++ b/pkg/apis/eventing/v1beta1/eventtype_conversion.go @@ -20,40 +20,15 @@ import ( "context" "fmt" - v1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/pkg/apis" ) // ConvertTo implements apis.Convertible func (source *EventType) ConvertTo(ctx context.Context, to apis.Convertible) error { - switch sink := to.(type) { - case *v1.EventType: - sink.Spec.Type = source.Spec.Type - sink.Spec.Source = source.Spec.Source - sink.Spec.Schema = source.Spec.Schema - sink.Spec.SchemaData = source.Spec.SchemaData - sink.Spec.Broker = source.Spec.Broker - sink.Spec.Description = source.Spec.Description - sink.Status.Status = source.Status.Status - return nil - default: - return fmt.Errorf("unknown version, got: %T", sink) - } + return fmt.Errorf("v1beta1 is the highest known version, got: %T", to) } // ConvertFrom implements apis.Convertible func (sink *EventType) ConvertFrom(ctx context.Context, from apis.Convertible) error { - switch source := from.(type) { - case *v1.EventType: - sink.Spec.Type = source.Spec.Type - sink.Spec.Source = source.Spec.Source - sink.Spec.Schema = source.Spec.Schema - sink.Spec.SchemaData = source.Spec.SchemaData - sink.Spec.Broker = source.Spec.Broker - sink.Spec.Description = source.Spec.Description - sink.Status.Status = source.Status.Status - return nil - default: - return fmt.Errorf("unknown version, got: %T", source) - } + return fmt.Errorf("v1beta1 is the highest known version, got: %T", from) } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go index 33f0a284138..c777463401c 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go @@ -27,7 +27,6 @@ import ( type EventingV1Interface interface { RESTClient() rest.Interface BrokersGetter - EventTypesGetter TriggersGetter } @@ -40,10 +39,6 @@ func (c *EventingV1Client) Brokers(namespace string) BrokerInterface { return newBrokers(c, namespace) } -func (c *EventingV1Client) EventTypes(namespace string) EventTypeInterface { - return newEventTypes(c, namespace) -} - func (c *EventingV1Client) Triggers(namespace string) TriggerInterface { return newTriggers(c, namespace) } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go deleted file mode 100644 index ae2ff540429..00000000000 --- a/pkg/client/clientset/versioned/typed/eventing/v1/eventtype.go +++ /dev/null @@ -1,191 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - v1 "knative.dev/eventing/pkg/apis/eventing/v1" - scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" -) - -// EventTypesGetter has a method to return a EventTypeInterface. -// A group's client should implement this interface. -type EventTypesGetter interface { - EventTypes(namespace string) EventTypeInterface -} - -// EventTypeInterface has methods to work with EventType resources. -type EventTypeInterface interface { - Create(*v1.EventType) (*v1.EventType, error) - Update(*v1.EventType) (*v1.EventType, error) - UpdateStatus(*v1.EventType) (*v1.EventType, error) - Delete(name string, options *metav1.DeleteOptions) error - DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error - Get(name string, options metav1.GetOptions) (*v1.EventType, error) - List(opts metav1.ListOptions) (*v1.EventTypeList, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.EventType, err error) - EventTypeExpansion -} - -// eventTypes implements EventTypeInterface -type eventTypes struct { - client rest.Interface - ns string -} - -// newEventTypes returns a EventTypes -func newEventTypes(c *EventingV1Client, namespace string) *eventTypes { - return &eventTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any. -func (c *eventTypes) Get(name string, options metav1.GetOptions) (result *v1.EventType, err error) { - result = &v1.EventType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("eventtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of EventTypes that match those selectors. -func (c *eventTypes) List(opts metav1.ListOptions) (result *v1.EventTypeList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1.EventTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("eventtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested eventTypes. -func (c *eventTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("eventtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch() -} - -// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any. -func (c *eventTypes) Create(eventType *v1.EventType) (result *v1.EventType, err error) { - result = &v1.EventType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("eventtypes"). - Body(eventType). - Do(). - Into(result) - return -} - -// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any. -func (c *eventTypes) Update(eventType *v1.EventType) (result *v1.EventType, err error) { - result = &v1.EventType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("eventtypes"). - Name(eventType.Name). - Body(eventType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *eventTypes) UpdateStatus(eventType *v1.EventType) (result *v1.EventType, err error) { - result = &v1.EventType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("eventtypes"). - Name(eventType.Name). - SubResource("status"). - Body(eventType). - Do(). - Into(result) - return -} - -// Delete takes name of the eventType and deletes it. Returns an error if one occurs. -func (c *eventTypes) Delete(name string, options *metav1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("eventtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *eventTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { - var timeout time.Duration - if listOptions.TimeoutSeconds != nil { - timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("eventtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Timeout(timeout). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched eventType. -func (c *eventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.EventType, err error) { - result = &v1.EventType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("eventtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go index ce798a54a83..4da4be359cc 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go @@ -32,10 +32,6 @@ func (c *FakeEventingV1) Brokers(namespace string) v1.BrokerInterface { return &FakeBrokers{c, namespace} } -func (c *FakeEventingV1) EventTypes(namespace string) v1.EventTypeInterface { - return &FakeEventTypes{c, namespace} -} - func (c *FakeEventingV1) Triggers(namespace string) v1.TriggerInterface { return &FakeTriggers{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go b/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go deleted file mode 100644 index 05936641b19..00000000000 --- a/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" -) - -// FakeEventTypes implements EventTypeInterface -type FakeEventTypes struct { - Fake *FakeEventingV1 - ns string -} - -var eventtypesResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "eventtypes"} - -var eventtypesKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "EventType"} - -// Get takes name of the eventType, and returns the corresponding eventType object, and an error if there is any. -func (c *FakeEventTypes) Get(name string, options v1.GetOptions) (result *eventingv1.EventType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(eventtypesResource, c.ns, name), &eventingv1.EventType{}) - - if obj == nil { - return nil, err - } - return obj.(*eventingv1.EventType), err -} - -// List takes label and field selectors, and returns the list of EventTypes that match those selectors. -func (c *FakeEventTypes) List(opts v1.ListOptions) (result *eventingv1.EventTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(eventtypesResource, eventtypesKind, c.ns, opts), &eventingv1.EventTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &eventingv1.EventTypeList{ListMeta: obj.(*eventingv1.EventTypeList).ListMeta} - for _, item := range obj.(*eventingv1.EventTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested eventTypes. -func (c *FakeEventTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(eventtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a eventType and creates it. Returns the server's representation of the eventType, and an error, if there is any. -func (c *FakeEventTypes) Create(eventType *eventingv1.EventType) (result *eventingv1.EventType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(eventtypesResource, c.ns, eventType), &eventingv1.EventType{}) - - if obj == nil { - return nil, err - } - return obj.(*eventingv1.EventType), err -} - -// Update takes the representation of a eventType and updates it. Returns the server's representation of the eventType, and an error, if there is any. -func (c *FakeEventTypes) Update(eventType *eventingv1.EventType) (result *eventingv1.EventType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(eventtypesResource, c.ns, eventType), &eventingv1.EventType{}) - - if obj == nil { - return nil, err - } - return obj.(*eventingv1.EventType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeEventTypes) UpdateStatus(eventType *eventingv1.EventType) (*eventingv1.EventType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(eventtypesResource, "status", c.ns, eventType), &eventingv1.EventType{}) - - if obj == nil { - return nil, err - } - return obj.(*eventingv1.EventType), err -} - -// Delete takes name of the eventType and deletes it. Returns an error if one occurs. -func (c *FakeEventTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(eventtypesResource, c.ns, name), &eventingv1.EventType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeEventTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(eventtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &eventingv1.EventTypeList{}) - return err -} - -// Patch applies the patch and returns the patched eventType. -func (c *FakeEventTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.EventType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(eventtypesResource, c.ns, name, pt, data, subresources...), &eventingv1.EventType{}) - - if obj == nil { - return nil, err - } - return obj.(*eventingv1.EventType), err -} diff --git a/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go b/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go index 9dbe76ef962..9877b5eba3e 100644 --- a/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go @@ -20,6 +20,4 @@ package v1 type BrokerExpansion interface{} -type EventTypeExpansion interface{} - type TriggerExpansion interface{} diff --git a/pkg/client/informers/externalversions/eventing/v1/eventtype.go b/pkg/client/informers/externalversions/eventing/v1/eventtype.go deleted file mode 100644 index 7c9034c5a5d..00000000000 --- a/pkg/client/informers/externalversions/eventing/v1/eventtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - time "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" - versioned "knative.dev/eventing/pkg/client/clientset/versioned" - internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" - v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" -) - -// EventTypeInformer provides access to a shared informer and lister for -// EventTypes. -type EventTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.EventTypeLister -} - -type eventTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewEventTypeInformer constructs a new informer for EventType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredEventTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredEventTypeInformer constructs a new informer for EventType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredEventTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.EventingV1().EventTypes(namespace).List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.EventingV1().EventTypes(namespace).Watch(options) - }, - }, - &eventingv1.EventType{}, - resyncPeriod, - indexers, - ) -} - -func (f *eventTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredEventTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *eventTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&eventingv1.EventType{}, f.defaultInformer) -} - -func (f *eventTypeInformer) Lister() v1.EventTypeLister { - return v1.NewEventTypeLister(f.Informer().GetIndexer()) -} diff --git a/pkg/client/informers/externalversions/eventing/v1/interface.go b/pkg/client/informers/externalversions/eventing/v1/interface.go index b152e717d0f..8c36a48dfd2 100644 --- a/pkg/client/informers/externalversions/eventing/v1/interface.go +++ b/pkg/client/informers/externalversions/eventing/v1/interface.go @@ -26,8 +26,6 @@ import ( type Interface interface { // Brokers returns a BrokerInformer. Brokers() BrokerInformer - // EventTypes returns a EventTypeInformer. - EventTypes() EventTypeInformer // Triggers returns a TriggerInformer. Triggers() TriggerInformer } @@ -48,11 +46,6 @@ func (v *version) Brokers() BrokerInformer { return &brokerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } -// EventTypes returns a EventTypeInformer. -func (v *version) EventTypes() EventTypeInformer { - return &eventTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} - // Triggers returns a TriggerInformer. func (v *version) Triggers() TriggerInformer { return &triggerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index b264f0f489e..83ba875db8a 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -65,8 +65,6 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=eventing.knative.dev, Version=v1 case v1.SchemeGroupVersion.WithResource("brokers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Brokers().Informer()}, nil - case v1.SchemeGroupVersion.WithResource("eventtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().EventTypes().Informer()}, nil case v1.SchemeGroupVersion.WithResource("triggers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Triggers().Informer()}, nil diff --git a/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go b/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go deleted file mode 100644 index 838fa4db171..00000000000 --- a/pkg/client/injection/informers/eventing/v1/eventtype/eventtype.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package eventtype - -import ( - context "context" - - v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" - factory "knative.dev/eventing/pkg/client/injection/informers/factory" - controller "knative.dev/pkg/controller" - injection "knative.dev/pkg/injection" - logging "knative.dev/pkg/logging" -) - -func init() { - injection.Default.RegisterInformer(withInformer) -} - -// Key is used for associating the Informer inside the context.Context. -type Key struct{} - -func withInformer(ctx context.Context) (context.Context, controller.Informer) { - f := factory.Get(ctx) - inf := f.Eventing().V1().EventTypes() - return context.WithValue(ctx, Key{}, inf), inf.Informer() -} - -// Get extracts the typed informer from the context. -func Get(ctx context.Context) v1.EventTypeInformer { - untyped := ctx.Value(Key{}) - if untyped == nil { - logging.FromContext(ctx).Panic( - "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1.EventTypeInformer from context.") - } - return untyped.(v1.EventTypeInformer) -} diff --git a/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go b/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go deleted file mode 100644 index 6cda229bf31..00000000000 --- a/pkg/client/injection/informers/eventing/v1/eventtype/fake/fake.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package fake - -import ( - context "context" - - eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" - fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" - controller "knative.dev/pkg/controller" - injection "knative.dev/pkg/injection" -) - -var Get = eventtype.Get - -func init() { - injection.Fake.RegisterInformer(withInformer) -} - -func withInformer(ctx context.Context) (context.Context, controller.Informer) { - f := fake.Get(ctx) - inf := f.Eventing().V1().EventTypes() - return context.WithValue(ctx, eventtype.Key{}, inf), inf.Informer() -} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go deleted file mode 100644 index e8a1b37fab9..00000000000 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package eventtype - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - corev1 "k8s.io/api/core/v1" - 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" - eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "eventtype-controller" - defaultFinalizerName = "eventtypes.eventing.knative.dev" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - eventtypeInformer := eventtype.Get(ctx) - - lister := eventtypeInformer.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/eventing/v1/eventtype/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go deleted file mode 100644 index a572fa039fd..00000000000 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/reconciler.go +++ /dev/null @@ -1,434 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package eventtype - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - zap "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - 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/eventing/v1" - versioned "knative.dev/eventing/pkg/client/clientset/versioned" - eventingv1 "knative.dev/eventing/pkg/client/listers/eventing/v1" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1.EventType. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1.EventType. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1.EventType) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1.EventType. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1.EventType. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1.EventType) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1.EventType if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1.EventType. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1.EventType) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1.EventType 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.EventType. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1.EventType) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1.EventType 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 eventingv1.EventTypeLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// 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 eventingv1.EventTypeLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // 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.EventTypes(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - 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.EventType, desired *v1.EventType) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.EventingV1().EventTypes(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.EventingV1().EventTypes(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1.EventType) (*v1.EventType, error) { - - getter := r.Lister.EventTypes(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.EventingV1().EventTypes(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, corev1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, corev1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1.EventType) (*v1.EventType, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1.EventType, reconcileEvent reconciler.Event) (*v1.EventType, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == corev1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go deleted file mode 100644 index 287c617e9cd..00000000000 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package eventtype - -import ( - context "context" - - eventtype "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/eventtype" - v1eventtype "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/eventtype" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for EventType and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - eventtypeInformer := eventtype.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1eventtype.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - eventtypeInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go b/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go deleted file mode 100644 index 186a794159b..00000000000 --- a/pkg/client/injection/reconciler/eventing/v1/eventtype/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package eventtype - -import ( - context "context" - - v1 "k8s.io/api/core/v1" - eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" - eventtype "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/eventtype" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason EventTypeReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "EventTypeReconciled", "EventType reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for EventType resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ eventtype.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ eventtype.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ eventtype.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 _ eventtype.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *eventingv1.EventType) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *eventingv1.EventType) 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 *eventingv1.EventType) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/listers/eventing/v1/eventtype.go b/pkg/client/listers/eventing/v1/eventtype.go deleted file mode 100644 index 260b3ff14fd..00000000000 --- a/pkg/client/listers/eventing/v1/eventtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 2020 The Knative Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1 "knative.dev/eventing/pkg/apis/eventing/v1" -) - -// EventTypeLister helps list EventTypes. -type EventTypeLister interface { - // List lists all EventTypes in the indexer. - List(selector labels.Selector) (ret []*v1.EventType, err error) - // EventTypes returns an object that can list and get EventTypes. - EventTypes(namespace string) EventTypeNamespaceLister - EventTypeListerExpansion -} - -// eventTypeLister implements the EventTypeLister interface. -type eventTypeLister struct { - indexer cache.Indexer -} - -// NewEventTypeLister returns a new EventTypeLister. -func NewEventTypeLister(indexer cache.Indexer) EventTypeLister { - return &eventTypeLister{indexer: indexer} -} - -// List lists all EventTypes in the indexer. -func (s *eventTypeLister) List(selector labels.Selector) (ret []*v1.EventType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.EventType)) - }) - return ret, err -} - -// EventTypes returns an object that can list and get EventTypes. -func (s *eventTypeLister) EventTypes(namespace string) EventTypeNamespaceLister { - return eventTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// EventTypeNamespaceLister helps list and get EventTypes. -type EventTypeNamespaceLister interface { - // List lists all EventTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1.EventType, err error) - // Get retrieves the EventType from the indexer for a given namespace and name. - Get(name string) (*v1.EventType, error) - EventTypeNamespaceListerExpansion -} - -// eventTypeNamespaceLister implements the EventTypeNamespaceLister -// interface. -type eventTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all EventTypes in the indexer for a given namespace. -func (s eventTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.EventType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.EventType)) - }) - return ret, err -} - -// Get retrieves the EventType from the indexer for a given namespace and name. -func (s eventTypeNamespaceLister) Get(name string) (*v1.EventType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("eventtype"), name) - } - return obj.(*v1.EventType), nil -} diff --git a/pkg/client/listers/eventing/v1/expansion_generated.go b/pkg/client/listers/eventing/v1/expansion_generated.go index 08088029b1e..7a8772ae63b 100644 --- a/pkg/client/listers/eventing/v1/expansion_generated.go +++ b/pkg/client/listers/eventing/v1/expansion_generated.go @@ -26,14 +26,6 @@ type BrokerListerExpansion interface{} // BrokerNamespaceLister. type BrokerNamespaceListerExpansion interface{} -// EventTypeListerExpansion allows custom methods to be added to -// EventTypeLister. -type EventTypeListerExpansion interface{} - -// EventTypeNamespaceListerExpansion allows custom methods to be added to -// EventTypeNamespaceLister. -type EventTypeNamespaceListerExpansion interface{} - // TriggerListerExpansion allows custom methods to be added to // TriggerLister. type TriggerListerExpansion interface{}